|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

(S)Download the packet class with program block.


vmm_switch_4.tar
Browse the code in vmm_switch_4.tar


(S)Run the simulation
vcs -sverilog -f filelist -R -ntb_opts rvm

(S)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