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

Subversion Repositories 1000base-x

[/] [1000base-x/] [trunk/] [testbench/] [rtl/] [verilog/] [ethernet_threads.v] - Rev 4

Compare with Previous | Blame | View Log

/////////////////////////////////////////////////////////////////////
////                                                              ////
////  File name "ethernet_threads.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                     ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
////                                                              ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
 
`include "timescale_tb.v"
 
`include "ge_1000baseX_constants.v"
 
package ethernet_threads;
 
  import tb_utils::hexformat;
 
  import packet::Packet;
  import packet::PacketMailBox;
 
  import ethernet_frame::EthernetFrame;
  import ethernet_frame::FrameMailBox;
  import ethernet_frame::ethernet_address_t;
 
`define VALID 1'b1
`define INVALID 1'b0
 
  virtual class TxThread;
    virtual task run(PacketMailBox mbx);
    endtask
 
    virtual task pass_to_checker(Packet p, PacketMailBox mbx);
      mbx.put(p);
    endtask
  endclass
 
 
   virtual class RxThread;
     virtual task run(ref int errors, PacketMailBox mbx);
     endtask
   endclass
 
   function [15:0] reorder(input [15:0] x);
      reorder = {x[7:0], x[15:8]};
 
   endfunction // byte_swap
 
 
   //******************************************************************************
   // 8B/10B random
   //******************************************************************************
 
   function automatic void random(int seed=-1, output int value);
 
      if (seed >= 0) begin int tmp = $urandom(seed); end
 
      value = $urandom() & 'hff;
 
   endfunction // random
 
  //******************************************************************************
  // Ethernet frame sending thread...
  //******************************************************************************
  class GmiiTxThread extends TxThread;
    virtual gmii_tx_if   tx;
    ethernet_address_t   dst_addr;
    ethernet_address_t   src_addr;
    int                  length;
    int                  num_frames;
    int                  spacing;
 
    // Do nothing constructor.
    function new(); endfunction
 
    // Use a static function for construction so we can use :: notation.
    static function GmiiTxThread NEW(
      virtual gmii_tx_if  tx,
      ethernet_address_t  dst_addr,
      ethernet_address_t  src_addr,
      int                 length,
      int                 num_frames,
      int                 spacing
    );
      GmiiTxThread x = new();
      x.tx           = tx;
      x.dst_addr     = dst_addr;
      x.src_addr     = src_addr;
      x.length       = length;
      x.num_frames   = num_frames;
      x.spacing      = spacing;
      return x;
    endfunction
 
    virtual task run(PacketMailBox mbx);
      EthernetFrame frame;
 
      for(int i=0; i<num_frames; i++)
        begin
          int len = length<0 ? i-length : length;
 
          $display("\nSending Ethernet frame: %0d, length: %0d", i, len);
 
          frame = new(dst_addr, src_addr, .length(len));
 
          //$display("Transmit: %s", frame.repr_verbose(20,20));
            $display("Transmit: %s", frame.dump());
 
          tx.queue_frame(EthernetFrame'(frame));
          pass_to_checker(frame, mbx);
          # spacing;
       end
 
      mbx.put(null);
    endtask
  endclass
 
 
  //******************************************************************************
  // Ethernet frame checking thread...
  //******************************************************************************
  class GmiiRxThread extends RxThread;
    virtual gmii_rx_if  rx;
    ethernet_address_t  dst_addr;
    time                timeout_first;
    time                timeout_rest;
    int                 dut_will_pad;
 
    // Do nothing constructor.
    function new(); endfunction
 
    // Use a static function for construction so we can use :: notation.
    static function GmiiRxThread NEW(
      input virtual gmii_rx_if   rx,
      input ethernet_address_t   dst_addr,
      input time                 timeout_first,
      input time                 timeout_rest,
      input int                  dut_will_pad=1
    );
      GmiiRxThread x = new();
      x.rx      = rx;
      x.dst_addr            = dst_addr;
      x.timeout_first = timeout_first;
      x.timeout_rest  = timeout_rest;
      x.dut_will_pad  = dut_will_pad;
      return x;
    endfunction
 
    virtual task run(ref int errors, PacketMailBox mbx);
      string         mod_name = string'(rx.whoami());
      FrameMailBox   rx_mbx = new();
      Packet         p;
      EthernetFrame  expected_frames[$];
      int            finished = 0;
      EthernetFrame  frame;
      time           end_time;
      time           timeout = timeout_first;
      int            matched;
      int 	     frames_matched = 0;
 
      rx.register_mailbox(ethernet_address_t'(dst_addr), FrameMailBox'(rx_mbx));
 
      while(1)
        begin
          // Fetch the next cell to be matched from the FIFO...
          if(!finished)
            begin
              mbx.get(p);
              if(p==null)
                finished = 1;
              else begin
                EthernetFrame expected = EthernetFrame'(p);
 
                // If the DUT pads frames up to the minimum Ethernet frame size then
                // we must pad the expected frame also!
                if(dut_will_pad)
                  expected.pad_up();
 
                expected_frames.push_back(expected);
                end
            end
 
          if(expected_frames.size()==0)
            break;
 
          // Wait for a frame to be received
          end_time = $time + timeout;
          timeout = timeout_rest;
          while((rx_mbx.try_get(frame)==0) && ($time<end_time))
            #100ns;
 
          if(frame==null)
            begin
              $display("%s: %0t: Error, frame timed out for address %s.", mod_name, $time, ethernet_frame::fmt_addr(dst_addr));
              errors += 1;
 
              // A timeout probably means the link is broken, so don't waste too much time waiting...
              if(finished)
                begin
                  void'(expected_frames.pop_back());
                  timeout_rest = timeout_rest / 2;
                end
            end
          else
            begin
              // Search the list of expected cells for one matching the received frames
              matched = 0;
              for(int i=0; i<expected_frames.size(); i++)
                if(frame.raw==expected_frames[i].raw)
                  begin
                    if(i==0) begin
                       $display("%s: -> Frame matched O.K %03d", mod_name, frames_matched++);
                    end
		    else
                      $display("%s: -> Frame did not match the next expected frame but did match frame number %0d.", mod_name, i);
                    expected_frames.delete(i);
                    matched = 1;
                    break;
                  end
 
              if(!matched)
                begin
                   $display("%s: %0t: -> Unexpected frame received.", mod_name, $time);
		   $display("  Rec: %s", frame.repr_verbose(25,10));
                   $display("  Exp: %s", expected_frames[0].repr_verbose(25,10));
                  errors += 1;
                end
            end
        end
 
      rx.unregister_mailbox(ethernet_address_t'(dst_addr));
 
      $display("%s: GmiiRxThread for %s has completed.", mod_name, ethernet_frame::fmt_addr(dst_addr));
    endtask
  endclass
 
 
  //******************************************************************************
  // Ignore frames from the specified address.
  //******************************************************************************
  task EtherIgnoreThread(
    virtual gmii_rx_intf rx,
    ethernet_address_t      dst_addr
  );
    FrameMailBox rx_mbx = new();
    EthernetFrame   frame;
 
    rx.register_mailbox(ethernet_address_t'(dst_addr), FrameMailBox'(rx_mbx));
 
    while(1)
      rx_mbx.get(frame);
  endtask
 
 
  //******************************************************************************
  // This structure specifies a traffic stream to be sent between two points.
  //******************************************************************************
  typedef struct {
    TxThread tx; RxThread rxi;
  } EthernetFlowEntry;
 
  //******************************************************************************
  // Traffic send/check task.
  //******************************************************************************
  class EthernetFlow;
 
    EthernetFlowEntry flow_table[$];
 
    function void create(TxThread s, RxThread c);
      EthernetFlowEntry f = '{s, c};
      flow_table.push_back(f);
    endfunction
 
    function void clear();
      flow_table = {};
    endfunction
 
    task start(ref int errors);
       EthernetFlowEntry f;
       int       local_errors = 0;
 
      $display("%m: Starting traffic flow.");
 
      // Launch all the send/receive threads...
      for(int i=0; i<flow_table.size(); i++)
        begin
          f = flow_table[i];
 
          fork
            PacketMailBox mbx = new();
 
            f.tx.run(mbx);
 
            if(f.rxi)
              f.rxi.run(local_errors, mbx);
          join_none
 
          #0; // Wait for the forked threads to start before changing their parameters!!!
        end
 
      wait fork;
 
      errors += local_errors;
 
      $display("%m: %0tns: All threads completed.", $time);
 
    endtask
  endclass
 
endpackage
 
 

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.