Checking is an important aspects when 'e' is concerned. For good methodology, checkers must be separated from the drives and scenarios. In this section we are going to see the description of packing and unpaking that are used to convert the abstract data models into bits and bytes and vice versa. Then we are going to see how the data checking is performed.
The verification engineers works with abstract structs at the input of the DUT and there are 'e' constructs that will convert these abstract struct instances into a list of bits and bytes. These bits are then applied to the HDL signals of DUT. The 'e' language provides the pack() and unpack() mechanism to do this conversion.
Before going into the details of packing and un-packing methods, it is better to understand the concept of physical and virtual field. Though, we have studied those concepts in the previous section, I am going to explain these concepts in relation with packing and un-packing.
Physical Field
As we saw in the previous section, there are 2 types of fields in any struct, physical and virtual fields.
====================================================================
<'
type packet_id : [IN, OUT, SETUP]; -- Virtual field
struct hub_packet
{
pid : packet_id; // Virtual field
%pid_type : uint(bits:8); // Physical field
%syn : uint(bits:32); // Physical field
keep soft syn == 32'h8000_0000;
%dev_add : uint(bits:7); -- Physical field
keep soft dev_add in [1..63]
%ep_no : uint(bits:4); -- Physical field
keep soft ep_no in [1..15]
%data : list of uint(bits:16); -- Physical field
// Virtual fields are used to control the generation.
// Here pid is of type and use to generate pid_type
// which is physical field and injected into DUT
keep pid == IN => pid_type == 8'h69;
};
'>
====================================================================
Packing
Packing is commonly used to prepare a high level data (Abstract data model) into low level data (bits and bytes) that is being applied to DUT.
Packing performs concatenation of items - items in a list or fields in a struct - in the order specified by the pack options parameters and return a list of bits or bytes. The following program shows the usage of packing method. I just taken this program from one of my project and also you can find out in the previous sections.
====================================================================
<'
import hub_packet; // import the hub_packet here
unit hub_driver // define a hub_driver unit
{
!current_packet : hub_packet; // do not generate this packet initially
!delay : uint;
keep soft delay in [1..10];
event rise_clk is rise ('clock_in') @sim; // declare an event
generate_and_drive () @ rise_clk is // generate the packets now
{
gen delay;
wait [delay];
gen current_packet;
drive_packet (current_packet); // drive the packet to DUT
wait [500];
stop_run(); // End of simulation
}; // end of generate_and_drive method
// drive the packet to DUT 16 bits for single clock
// declare a variable packet_packed
drive_packet (packet : hub_packet) : list of uint(bits : 16) @rise_clk is
{
var packet_packed : list of uint(bits:16);
// There are two options used with pack() method
// packing.high : Starts filling the fields into higher order bit position
// packing.low : Starts filling the fields into lower order bit position
run() is also
{ // call the method at the start of simulation
start gen_and_drive();
}; // End of run()
}; // End of unit
'>
====================================================================
Unpacking
The unpack() method does exactly the opposite of packing. Unpacking is used to convert a raw bits and bytes into a high level of data by storing the bits of the value expression into the target expression.
====================================================================
<'
struct unpack {
%field1 : uint(bits:3);
%field2 : uint (bits:5);
%field3 : uint(bits:8);
};
extend sys
{
post_generate () is also
{
// Instantiate the target struct instance
var unpack_inst : unpack;
var packed_data : list of bit;
// The source list of bytes
packed_data = {1;1;1;1;0;0;0;01;0;0;1;1;0;0;1}; // 1111 LSB
// The first one, packing.high - fill the bits in MSB
// The second one, packed_data is the source file
// The third one, target file
unpack (packing.high, packed_data, unpack_inst);
// This function unpacks as follows
//field1 = 100
//field2 = 11001
//field3 = 00001111
}; // End of post_generate()
}; // End of extend
'>
====================================================================
Data checking
We know that pack and unpack methods are used to convert high level data into low level data and vice versa respectively. So it is recommended that all the verification should be done in 'e' code by means of abstract structs. In 'e', two structs can be compared field by field to check the mismatches.
deep_compare() compares both the sturcts for virtual as well as physical fields.
deep_compare_physical() compares both the structs for physical fields only.
Comparisons should be done only inside the method
diff = deep_compare_physical (struct1[0], struct1[1], 10);
if (diff.size() != 0 { // If there are mismatches
out(diff)}; // Print out mismatches
diff is locally declared variable inside a method; pmi[0] is the first struct and pmi[1] is the second struct; 10 is the maximum number of differences.
Check that action
The check that action performs a data comparisons and depends on the results, print a message.
check that 'top.error' == 1 else dut_error ( "Error bit is not asserted");
dut_error() method is used to specify a DUT error message string. This is usually associated with an if action or check that action.
Check Failure Effects
'e' allows you to change the behavior of error messages without touching the original 'e' code. This can be done either from an extension of the existing 'e' code for from the 'e' simulator. Check failure effects can be set by using the set_check() routine from 'e' code or the set check command from the specman elite prompt.
Example shows how to extend the setup() method of sys to set up check effects.
====================================================================
<'
extend sys
{
setup () is also {
// Specman issues a warning and continues execution
set_check ("..", WARNING);
// Specman issues an error messae and continues execution
set_check ("..", ERROR_CONTINUE);
// Specman issues an error messae and break the run
set_check ("..", ERROR);
}; // End of setup()
}; // End of extend
'>
====================================================================
Temporal Checking
Checking can be performed to test the success or failure of any temporal expressions. The expect struct member defines temporal rules. If the temporal expression fails at its sampling event, the rule is violated and an error is reported.
====================================================================
<'
struct expect
{
event txmit_start;
event txmit_end;
event clk is rise('~/top/clk');
event cycle_period;
expect cycle_period is // Set up a rule for that event
// If tx_start occurs, tx_end must occur
// within 9 cycles of @clk
@txmit_start => {[0..9]; @txmit_end} @clk
else
dut_error("Bus cycle didn't end");
}; // End of struct
'>
====================================================================
On struct member
The on struct member executes a block of actions immediately whenever a specified trigger event is emitted.
The verification engineers works with abstract structs at the input of the DUT and there are 'e' constructs that will convert these abstract struct instances into a list of bits and bytes. These bits are then applied to the HDL signals of DUT. The 'e' language provides the pack() and unpack() mechanism to do this conversion.
Before going into the details of packing and un-packing methods, it is better to understand the concept of physical and virtual field. Though, we have studied those concepts in the previous section, I am going to explain these concepts in relation with packing and un-packing.
Physical Field
As we saw in the previous section, there are 2 types of fields in any struct, physical and virtual fields.
Physical fields are extracted from the design spec. and their values need to be injected into DUT. Virtual fields are used to control the generation of physical field and also used for the subtypes. Following program shows the difference b/w both the fields.
====================================================================
<'
type packet_id : [IN, OUT, SETUP]; -- Virtual field
struct hub_packet
{
pid : packet_id; // Virtual field
%pid_type : uint(bits:8); // Physical field
%syn : uint(bits:32); // Physical field
keep soft syn == 32'h8000_0000;
%dev_add : uint(bits:7); -- Physical field
keep soft dev_add in [1..63]
%ep_no : uint(bits:4); -- Physical field
keep soft ep_no in [1..15]
%data : list of uint(bits:16); -- Physical field
// Virtual fields are used to control the generation.
// Here pid is of type and use to generate pid_type
// which is physical field and injected into DUT
keep pid == IN => pid_type == 8'h69;
};
'>
====================================================================
Packing
Packing is commonly used to prepare a high level data (Abstract data model) into low level data (bits and bytes) that is being applied to DUT.
Packing performs concatenation of items - items in a list or fields in a struct - in the order specified by the pack options parameters and return a list of bits or bytes. The following program shows the usage of packing method. I just taken this program from one of my project and also you can find out in the previous sections.
====================================================================
<'
import hub_packet; // import the hub_packet here
unit hub_driver // define a hub_driver unit
{
!current_packet : hub_packet; // do not generate this packet initially
!delay : uint;
keep soft delay in [1..10];
event rise_clk is rise ('clock_in') @sim; // declare an event
generate_and_drive () @ rise_clk is // generate the packets now
{
gen delay;
wait [delay];
gen current_packet;
drive_packet (current_packet); // drive the packet to DUT
wait [500];
stop_run(); // End of simulation
}; // end of generate_and_drive method
// drive the packet to DUT 16 bits for single clock
// declare a variable packet_packed
drive_packet (packet : hub_packet) : list of uint(bits : 16) @rise_clk is
{
var packet_packed : list of uint(bits:16);
// There are two options used with pack() method
// packing.high : Starts filling the fields into higher order bit position
// packing.low : Starts filling the fields into lower order bit position
packet_packed=(pack(packing.low,%{syn[15:0]},%{syn[31:16]},%{ep[0],
dev_add[6:0],pid_type}, %{crc_5,ep[3:1],eop}));
}; // End of drive_packet methoddev_add[6:0],pid_type}, %{crc_5,ep[3:1],eop}));
run() is also
{ // call the method at the start of simulation
start gen_and_drive();
}; // End of run()
}; // End of unit
'>
====================================================================
Unpacking
The unpack() method does exactly the opposite of packing. Unpacking is used to convert a raw bits and bytes into a high level of data by storing the bits of the value expression into the target expression.
====================================================================
<'
struct unpack {
%field1 : uint(bits:3);
%field2 : uint (bits:5);
%field3 : uint(bits:8);
};
extend sys
{
post_generate () is also
{
// Instantiate the target struct instance
var unpack_inst : unpack;
var packed_data : list of bit;
// The source list of bytes
packed_data = {1;1;1;1;0;0;0;01;0;0;1;1;0;0;1}; // 1111 LSB
// The first one, packing.high - fill the bits in MSB
// The second one, packed_data is the source file
// The third one, target file
unpack (packing.high, packed_data, unpack_inst);
// This function unpacks as follows
//field1 = 100
//field2 = 11001
//field3 = 00001111
}; // End of post_generate()
}; // End of extend
'>
====================================================================
Data checking
We know that pack and unpack methods are used to convert high level data into low level data and vice versa respectively. So it is recommended that all the verification should be done in 'e' code by means of abstract structs. In 'e', two structs can be compared field by field to check the mismatches.
deep_compare() compares both the sturcts for virtual as well as physical fields.
deep_compare_physical() compares both the structs for physical fields only.
Comparisons should be done only inside the method
diff = deep_compare_physical (struct1[0], struct1[1], 10);
if (diff.size() != 0 { // If there are mismatches
out(diff)}; // Print out mismatches
diff is locally declared variable inside a method; pmi[0] is the first struct and pmi[1] is the second struct; 10 is the maximum number of differences.
Check that action
The check that action performs a data comparisons and depends on the results, print a message.
check that 'top.error' == 1 else dut_error ( "Error bit is not asserted");
dut_error() method is used to specify a DUT error message string. This is usually associated with an if action or check that action.
Check Failure Effects
'e' allows you to change the behavior of error messages without touching the original 'e' code. This can be done either from an extension of the existing 'e' code for from the 'e' simulator. Check failure effects can be set by using the set_check() routine from 'e' code or the set check command from the specman elite prompt.
Example shows how to extend the setup() method of sys to set up check effects.
====================================================================
<'
extend sys
{
setup () is also {
// Specman issues a warning and continues execution
set_check ("..", WARNING);
// Specman issues an error messae and continues execution
set_check ("..", ERROR_CONTINUE);
// Specman issues an error messae and break the run
set_check ("..", ERROR);
}; // End of setup()
}; // End of extend
'>
====================================================================
Temporal Checking
Checking can be performed to test the success or failure of any temporal expressions. The expect struct member defines temporal rules. If the temporal expression fails at its sampling event, the rule is violated and an error is reported.
====================================================================
<'
struct expect
{
event txmit_start;
event txmit_end;
event clk is rise('~/top/clk');
event cycle_period;
expect cycle_period is // Set up a rule for that event
// If tx_start occurs, tx_end must occur
// within 9 cycles of @clk
@txmit_start => {[0..9]; @txmit_end} @clk
else
dut_error("Bus cycle didn't end");
}; // End of struct
'>
====================================================================
On struct member
The on struct member executes a block of actions immediately whenever a specified trigger event is emitted.
4 comments:
Sweet blog! I found it while searching on Yahoo News.
Do you have any tips on how to get listed in Yahoo News?
I've been trying for a while but I never seem to get there! Thanks
Take a look at my page ... chinese restaurants in concord nh
This post is truly a pleasant one it helps new web users, who are wishing in favor of blogging.
my homepage - natural back pain relief for pregnant women
I do agree with all of the ideas you've introduced to your post. They're
very convincing and will certainly work. Nonetheless, the posts are
very brief for starters. Could you please
lengthen them a bit from next time? Thank you for the post.
Also visit my web page kissimmee.com
Do you mind if I quote a couple of your articles
as long as I provide credit and sources back to your webpage?
My website is in the exact same niche as yours and
my visitors would genuinely benefit from some of the information you present here.
Please let me know if this alright with you. Thanks a lot!
Here is my page ... floristry program in houston texas
Post a Comment