|HOME |ABOUT |ARTICLES |ACK |FEEDBACK |TOC |LINKS |BLOG |JOBS |


Tutorials



PHASE 4 PACKET


In this Phase , We will define a packet and then test it whether it is generating as expected.

Packet is modeled using class. Packet class should be able to generate all possible packet types randomly. Packet class should also implement allocate(), psdisplay(), copy(), compare(), byte_pack() and byte_unpack()  of vmm_data methods.

Using vmm macros, we will create atomic generator and channel for Packet.

We will write the packet class in Packet.sv file. Packet class variables and constraints have been derived from stimulus generation plan.

Revisit Stimulus Generation Plan
1) Packet DA: Generate packet DA with the configured address.
2) Payload length: generate payload length ranging from 2 to 255.
3) Correct or Incorrect Length field.
4) Generate good and bad FCS.



1) Declare FCS types as enumerated data types. Name members as GOOD_FCS and BAD_FCS.

typedef enum { GOOD_FCS, BAD_FCS } fcs_kind_t;

2) Declare the length type as enumerated data type. Name members as GOOD_LENGTH and BAD_LENGTH.

typedef enum { GOOD_LENGTH, BAD_LENGTH } length_kind_t;

3) Extend vmm_data class to define Paclet class.

class Packet extends vmm_data;

4) Declare a vmm_log object and construct it.

static vmm_log log = new("Packet","Class");

5) Declare the length type and fcs type variables as rand.

rand fcs_kind_t     fcs_kind;
rand length_kind_t  length_kind;

6) Declare the packet field as rand. All fields are bit data types. All fields are 8 bit packet array. Declare the payload as dynamic array.

rand bit [7:0] length;
rand bit [7:0] da;
rand bit [7:0] sa;
rand bit [7:0] data[];//Payload using Dynamic array,size is generated on the fly
rand byte fcs;

7) Constraint the DA field to be any one of the configured address.

constraint address_c { da inside {`P0,`P1,`P2,`P3} ; }

8) Constrain the payload dynamic array size to between 1 to 255.

constraint payload_size_c { data.size inside { [1 : 255]};}

9) Constrain the payload length to the length field based on the length type.

constraint length_kind_c { 
   (length_kind == GOOD_LENGTH) -> length == data.size; 
   (length_kind == BAD_LENGTH)  -> length == data.size + 2 ; }


Use solve before to direct the randomization to generate first the payload dynamic array size and then randomize length field.

constraint solve_size_length { solve  data.size before length; }

10) Define a port_randomize method. In this method calculate the fcs based on the fcs_kind.

function void post_randomize();
     if(fcs_kind == GOOD_FCS)
         fcs = 8'b0;
     else
        fcs = 8'b1;
     fcs = cal_fcs();
endfunction : post_randomize

11) Define the FCS method.

virtual function byte cal_fcs;
  integer i;
  byte result ;
  result = 0;
  result = result ^ da;
  result = result ^ sa;
  result = result ^ length;
  for (i = 0;i< data.size;i++)
  result = result ^ data[i];
  result = fcs ^ result;
  return result;
endfunction : cal_fcs


12) Define acllocate() method.

virtual function vmm_data allocate();
     Packet pkt;
     pkt = new();
     return pkt;
endfunction:allocate

13) Define psdisplay() method. psdisplay() method displays the current value of the packet fields to a string.

virtual function string psdisplay(string prefix = "");
    int i;
 
    $write(psdisplay, "   %s   packet #%0d.%0d.%0d\n", prefix,this.stream_id, this.scenario_id, this.data_id);
    $write(psdisplay, "   %s%s   da:0x%h\n", psdisplay, prefix,this.da);
    $write(psdisplay, "   %s%s   sa:0x%h\n", psdisplay, prefix,this.sa);
    $write(psdisplay, "   %s%s   length:0x%h (data.size=%0d)\n", psdisplay, prefix,this.length,this.data.size());
    $write(psdisplay, "   %s%s   data[%0d]:0x%h", psdisplay, prefix,0,data[0]);
    if(data.size() > 1)
        $write(psdisplay, "   data[%0d]:0x%h", 1,data[1]);
    if(data.size() > 4)
        $write(psdisplay, "  ....  ");
    if(data.size() > 2)
        $write(psdisplay, "   data[%0d]:0x%h", data.size() -2,data[data.size() -2]);
    if(data.size() > 3)
        $write(psdisplay, "   data[%0d]:0x%h", data.size() -1,data[data.size() -1]);
    $write(psdisplay, "\n   %s%s   fcs:0x%h \n", psdisplay, prefix, this.fcs);
    
 endfunction

14) Define copy() method. copy() method copies the current values of the object instance.

virtual function vmm_data copy(vmm_data to = null);
    Packet cpy;
 
    // Copying to a new instance?
    if (to == null) 
       cpy = new;
     else
 
    // Copying to an existing instance. Correct type?
    if (!$cast(cpy, to))    
       begin
       `vmm_fatal(this.log, "Attempting to copy to a non packet instance");
       copy = null;
       return copy;
       end
    
 
    super.copy_data(cpy);
    
    cpy.da = this.da;
    cpy.sa = this.sa;
    cpy.length = this.length;
    cpy.data = new[this.data.size()];
    foreach(data[i])
        begin
       cpy.data[i] = this.data[i];
        end                    
    cpy.fcs = this.fcs;
    copy = cpy;
 endfunction:copy

15) Define Compare() method. Compares the current value of the object instance with the specified object instance.
If the value is different, FALSE is returned.

virtual function bit compare(input vmm_data   to,output string diff,input int   kind = -1);
    Packet cmp;
 
    compare = 1; // Assume success by default.
    diff    = "No differences found";
    
    if (!$cast(cmp, to)) 
    begin
       `vmm_fatal(this.log, "Attempting to compare to a non packet instance");
       compare = 0;
       diff = "Cannot compare non packets";
       return compare;
     end 
 
    // data types are the same, do comparison:
    if (this.da != cmp.da) 
    begin
       diff = $psprintf("Different DA values: %b != %b", this.da, cmp.da);
       compare = 0;
       return compare;
    end 
      
    if (this.sa != cmp.sa) 
    begin
       diff = $psprintf("Different SA values: %b != %b", this.sa, cmp.sa);
       compare = 0;
       return compare;
    end 
    if (this.length != cmp.length) 
    begin
       diff = $psprintf("Different LEN values: %b != %b", this.length, cmp.length);
       compare = 0;
       return compare;
    end 
 
    foreach(data[i]) 
       if (this.data[i] != cmp.data[i]) 
       begin
          diff = $psprintf("Different data[%0d] values: 0x%h != 0x%h",i, this.data[i], cmp.data[i]);
          compare = 0;
          return compare;
       end 
    if (this.fcs != cmp.fcs) 
    begin
       diff = $psprintf("Different FCS values: %b != %b", this.fcs, cmp.fcs);
       compare = 0;
       return compare;
    end 
 endfunction:compare


16)Define byte_pack() method().


Packing is commonly used to convert the high level data to low level data that can be applied to DUT.  In packet class various fields are generated. Required fields are concatenated to form a stream of bytes which can be driven conveniently to DUT interface by the driver.

virtual function int unsigned byte_pack(
                     ref logic [7:0] bytes[],
                     input int unsigned offset =0 ,
                     input int   kind = -1);
      byte_pack = 0;
      bytes = new[this.data.size() + 4];
      bytes[0] = this.da;
      bytes[1] = this.sa;
      bytes[2] = this.length;

      foreach(data[i])
          bytes[3+i] = data[i];

      bytes[this.data.size() + 3 ] = fcs;
      byte_pack = this.data.size() + 4;
endfunction:byte_pack  

17) Define byte_unpack() method:


The unpack() method does exactly the opposite of pack method. Unpacking is commonly used to convert a data stream coming from DUT to high level data packet object.

virtual function int unsigned byte_unpack(
                     const ref logic [7:0] bytes[],
                     input int unsigned offset = 0,
                     input int len = -1,
                     input int kind = -1);
      this.da = bytes[0];
      this.sa = bytes[1];
      this.length = bytes[2];
      this.fcs = bytes[bytes.size() -1];
      this.data = new[bytes.size() - 4];
      foreach(data[i])
      this.data[i] = bytes[i+3];
      return bytes.size();
endfunction:byte_unpack



18) Define Packet_channel for Packet using macro.

`vmm_channel(Packet)

19) Define Packet_atomic_gen for generating Packet instances using macro.

`vmm_atomic_gen(Packet, "Packet Gen")


Packet Class Source Code

`ifndef GUARD_PACKET
`define GUARD_PACKET

//Define the enumerated types for packet types
typedef enum { GOOD_FCS, BAD_FCS } fcs_kind_t;
typedef enum { GOOD_LENGTH, BAD_LENGTH } length_kind_t;

class Packet extends vmm_data;

static vmm_log log = new("Packet","Class");

rand fcs_kind_t     fcs_kind;
rand length_kind_t  length_kind;

rand bit [7:0] length;
rand bit [7:0] da;
rand bit [7:0] sa;
rand bit [7:0] data[];//Payload using Dynamic array,size is generated on the fly
rand byte fcs;

constraint address_c { da inside {`P0,`P1,`P2,`P3} ; }

constraint payload_size_c { data.size inside { [1 : 255};}

constraint length_kind_c { 
     (length_kind == GOOD_LENGTH) -> length == data.size; 
     (length_kind == BAD_LENGTH)  -> length == data.size + 2 ; }
                
constraint solve_size_length { solve  data.size before length; }

function new();
     super.new(this.log);
endfunction:new

function void post_randomize();
     if(fcs_kind == GOOD_FCS)
         fcs = 8'b0;
     else
        fcs = 8'b1;
     fcs = cal_fcs();
endfunction : post_randomize

///// method to calculate the fcs /////
virtual function byte cal_fcs;
     integer i;
     byte result ;
     result = 0;
     result = result ^ da;
     result = result ^ sa;
     result = result ^ length;
     for (i = 0;i< data.size;i++)
     result = result ^ data[i];
     result = fcs ^ result;
     return result;
endfunction : cal_fcs

virtual function vmm_data allocate();
     Packet pkt;
     pkt = new();
     return pkt;
endfunction:allocate

virtual function string psdisplay(string prefix = "");
    int i;
 
    $write(psdisplay, "   %s   packet #%0d.%0d.%0d\n", prefix,this.stream_id, this.scenario_id, this.data_id);
    $write(psdisplay, "   %s%s   da:0x%h\n", psdisplay, prefix,this.da);
    $write(psdisplay, "   %s%s   sa:0x%h\n", psdisplay, prefix,this.sa);
    $write(psdisplay, "   %s%s   length:0x%h (data.size=%0d)\n", psdisplay, prefix,this.length,this.data.size());
    $write(psdisplay, "   %s%s   data[%0d]:0x%h", psdisplay, prefix,0,data[0]);
    if(data.size() > 1)
        $write(psdisplay, "   data[%0d]:0x%h", 1,data[1]);
    if(data.size() > 4)
        $write(psdisplay, "  ....  ");
    if(data.size() > 2)
        $write(psdisplay, "   data[%0d]:0x%h", data.size() -2,data[data.size() -2]);
    if(data.size() > 3)
        $write(psdisplay, "   data[%0d]:0x%h", data.size() -1,data[data.size() -1]);
    $write(psdisplay, "\n   %s%s   fcs:0x%h \n", psdisplay, prefix, this.fcs);
    
 endfunction
 
 
virtual function vmm_data copy(vmm_data to = null);
    Packet cpy;
 
    // Copying to a new instance?
    if (to == null) 
       cpy = new;
     else
 
    // Copying to an existing instance. Correct type?
    if (!$cast(cpy, to))    
       begin
       `vmm_fatal(this.log, "Attempting to copy to a non packet instance");
       copy = null;
       return copy;
       end
    
 
    super.copy_data(cpy);
    
    cpy.da = this.da;
    cpy.sa = this.sa;
    cpy.length = this.length;
    cpy.data = new[this.data.size()];
    foreach(data[i])
        begin
       cpy.data[i] = this.data[i];
        end                    
    cpy.fcs = this.fcs;
    copy = cpy;
 endfunction:copy
 
 
 
virtual function bit compare(input vmm_data   to,output string diff,input int   kind = -1);
    Packet cmp;
 
    compare = 1; // Assume success by default.
    diff    = "No differences found";
    
    if (!$cast(cmp, to)) 
    begin
       `vmm_fatal(this.log, "Attempting to compare to a non packet instance");
       compare = 0;
       diff = "Cannot compare non packets";
       return compare;
     end 
 
    // data types are the same, do comparison:
    if (this.da != cmp.da) 
    begin
       diff = $psprintf("Different DA values: %b != %b", this.da, cmp.da);
       compare = 0;
       return compare;
    end 
      
    if (this.sa != cmp.sa) 
    begin
       diff = $psprintf("Different SA values: %b != %b", this.sa, cmp.sa);
       compare = 0;
       return compare;
    end 
    if (this.length != cmp.length) 
    begin
       diff = $psprintf("Different LEN values: %b != %b", this.length, cmp.length);
       compare = 0;
       return compare;
    end 
 
    foreach(data[i]) 
       if (this.data[i] != cmp.data[i]) 
       begin
          diff = $psprintf("Different data[%0d] values: 0x%h != 0x%h",i, this.data[i], cmp.data[i]);
          compare = 0;
          return compare;
       end 
    if (this.fcs != cmp.fcs) 
    begin
       diff = $psprintf("Different FCS values: %b != %b", this.fcs, cmp.fcs);
       compare = 0;
       return compare;
    end 
 endfunction:compare

virtual function int unsigned byte_pack(
                     ref logic [7:0] bytes[],
                     input int unsigned offset =0 ,
                     input int   kind = -1);
      byte_pack = 0;
      bytes = new[this.data.size() + 4];
      bytes[0] = this.da;
      bytes[1] = this.sa;
      bytes[2] = this.length;

      foreach(data[i])
          bytes[3+i] = data[i];

      bytes[this.data.size() + 3 ] = fcs;
      byte_pack = this.data.size() + 4;
endfunction:byte_pack    

virtual function int unsigned byte_unpack(
                     const ref logic [7:0] bytes[],
                     input int unsigned offset = 0,
                     input int len = -1,
                     input int kind = -1);
      this.da = bytes[0];
      this.sa = bytes[1];
      this.length = bytes[2];
      this.fcs = bytes[bytes.size() -1];
      this.data = new[bytes.size() - 4];
      foreach(data[i])
      this.data[i] = bytes[i+3];
      return bytes.size();
endfunction:byte_unpack

endclass

/////////////////////////////////////////////////////////
//// Create vmm_channel and vmm_atomic_gen for packet////
/////////////////////////////////////////////////////////
`vmm_channel(Packet)
`vmm_atomic_gen(Packet, "Packet Gen")




Now we will write a small program to test our packet implantation. This program block is not used to verify the DUT.

Write a simple program block and do the instance of packet class. Randomize the packet and call the display method to analyze the generation. Then pack the packet in to bytes and then unpack bytes and then call compare method to check all the methods.


Program Block Source Code

program test;

packet pkt1 = new();
packet pkt2 = new();
logic [7:0] bytes[];
initial
repeat(10)
if(pkt1.randomize)
begin
$display(" Randomization Successes full.");
pkt1.display();
void'(pkt1.byte_pack(bytes));
pkt2 = new();
pkt2.byte_unpack(bytes);
if(pkt2.compare(pkt1))
$display(" Packing, Unpacking and compare worked");
else
$display(" *** Something went wrong in Packing or Unpacking or compare ***");

end
else
$display(" *** Randomization Failed ***");

endprogram

Download the packet class with program block.

vmm_switch_4.tar
Browse the code in vmm_switch_4.tar

Run the simulation
vcs -sverilog -f filelist -R -ntb_opts rvm

Log file report:

 Randomization Sucessesfull.
   Pkt1   packet #0.0.0
   Pkt1   da:0x00
   Pkt1   sa:0x40
   Pkt1   length:0xbe (data.size=190)
   Pkt1   data[0]:0xf7   data[1]:0xa6  ....     data[188]:0x49   data[189]:0x79
   Pkt1   fcs:0x1a

   Pkt2   packet #0.0.0
   Pkt2   da:0x00
   Pkt2   sa:0x40
   Pkt2   length:0xbe (data.size=190)
   Pkt2   data[0]:0xf7   data[1]:0xa6  ....     data[188]:0x49   data[189]:0x79
   Pkt2   fcs:0x1a

 Packing,Unpacking and compare worked
 Randomization Sucessesfull.
   Pkt1   packet #0.0.0
   Pkt1   da:0x33
   Pkt1   sa:0xfd
   Pkt1   length:0xc7 (data.size=199)
   Pkt1   data[0]:0x1e   data[1]:0x80  ....     data[197]:0x15   data[198]:0x30
   Pkt1   fcs:0xa5

   Pkt2   packet #0.0.0
   Pkt2   da:0x33
   Pkt2   sa:0xfd
   Pkt2   length:0xc7 (data.size=199)
   Pkt2   data[0]:0x1e   data[1]:0x80  ....     data[197]:0x15   data[198]:0x30
   Pkt2   fcs:0xa5

 Packing,Unpacking and compare worked
 Randomization Sucessesfull.
   Pkt1   packet #0.0.0
   Pkt1   da:0x00
   Pkt1   sa:0xa6
   Pkt1   length:0x9b (data.size=155)
   Pkt1   data[0]:0x72   data[1]:0x9f  ....     data[153]:0x53   data[154]:0x4b
   Pkt1   fcs:0x24

   Pkt2   packet #0.0.0
   Pkt2   da:0x00
   Pkt2   sa:0xa6
   Pkt2   length:0x9b (data.size=155)
   Pkt2   data[0]:0x72   data[1]:0x9f  ....     data[153]:0x53   data[154]:0x4b
   Pkt2   fcs:0x24
..........
..........
..........



Index
Introduction
Specification
Verification Plan
Phase 1 Top
Phase 2 Environment
Phase 3 Reset
Phase 4 Packet
Phase 5 Generator
Phase 6 Driver
Phase 7 Receiver
Phase 8 Scoreboard
Phase 9 Coverage

Report a Bug or Comment on This section - Your input is what keeps Testbench.in improving with time!





<< PREVIOUS PAGE

TOP

NEXT PAGE >>

copyright © 2007-2017 :: all rights reserved www.testbench.in::Disclaimer