Basha System Verilog PPT
Basha System Verilog PPT
Chand Basha
What is Design Verification
The verification effort takes almost 70% of the total design cycle time.
Due to the complex functionality of designs that could lead to more bugs
1. Increase in features lead to an increase in logic functionality –
more gates and flip-flops
2. Multiple clocks and deeper pipelines are being introduced to
improve performance
3. Numerous power states are being added in designs to save energy
Non Self-Checking: They are coded such that if the program reaches the
last line of the testcase then it is a successful design code
Examples are Random, Constrained Random , Stress
Test Plan
In test plan, we prepare a road map for how do achieve the goal, it is a
living document.
Test plan includes, introduction, assumptions, list of test cases, list of
features to be tested, approach, deliverables, resources, risks and
scheduling, entry and exit criteria.
Test plan helps verification engineer to understand how the verification
should be done.
A test plan could come in many forms, such as a spreadsheet, a document
or a simple text file.
Sometimes, test plan simply reside in the engineer's head which is
dangerous in which the process cannot be properly measured and
controlled.
Test plan also contains the descriptions of TestBench architecture and
description of each component and its functionality.
3. Testbench Environment: It includes different types of environment to
be developed for effectively verifying the DUT
Verilog and VHDL languages are used for describing a digital system
like a network switch or a microprocessor or a memory or a flip−flop.
It was rather difficult to have two languages, one for design and other
for verification.
Thats why the tweak is, if you write the DUT in positive edge of clock
then you have to drive the TB at the negative edge of clock.
This will remove race condition but not completely, more often Verilog
TB suffers time zero race condition.
time_unit argument
The time_unit argument specifies more than just a time unit. It specifies both
a magnitude(1, 10, 100) and a time unit(s,ms,us,ns, ps,fs)!
For example, ns (a time unit) by itself is not a complete time_unit value; but 10ns (a
magnitude(10)and a time unit(ns)) is.
Valid time units
Here is a list all valid time units. You can use any of these time units (along with a
magnitude, which I'll get to next) to specify your time_unit value
s seconds
ms milliseconds
us microseconds (μs)
ns nanoseconds
ps picoseconds
fs femtoseconds
time unit magnitude
Valid magnitudes
There are only three valid magnitudes for use in time_unit arguments.
They are:
1, 10, and 100.
If you were to use a magnitude of 1000, for example, when specifying
a time_unit value, your compiler would report an error and fail to compile
your code. Here's what I see when I try to compile a testbench file that
contains a time_unit value with an invalid magnitude of 1000ns:
Time precision
When the time specified by the time_precision value is longer than the time
specified by the time_unit value, I get a compiler error.
The `timescale compiler directive begins with a backtick (`) followed by the
word timescale, followed by the time_unit argument (which can have a magnitude
of 1, 10, or 100 and a time unit of s, ms, us, ns, ps, or fs), followed by a backslash (/),
followed by the time_precision argument, which can have any of the magnitudes and
time units the time_unit can have, but whose value must represent a length of time
equal to, or shorter than, that which the value of the time_unit argument represents.
Time precision
That is how the compiler uses the arguments of the `timescale directive!
Once again (for those visitors using screen readers), this is how the compiler
uses the arguments of the `timescale directive:
Multiply each #delay value in this module by ______________
(insert time_unit); then, round the result to the nearest ______________
(insert time_precision)."
Time precision
The first thing that code tells the simulator is that we want the simulator to
multiply each of our delay statements by 10ns.
For example, if we have a delay statement that looks like this: #5, we are
telling the simulator we want the simulator to delay
for 50ns50ns (since 5×5× 10ns =50ns=50ns).
I'm going to call the result of that multiplication (i.e. the 50ns50ns),
the unrounded delay
The second thing that code tells the simulator is that we want the simulator to
round the unrounded delay to the nearest 1ns (the time_precision). In other
words, if we have an unrounded delay of 50.5ns, we are telling the simulator
we want the simulator to round it (up, in this case) to 51ns. If the unrounded
delay were 50.4, it would round down to 50ns. The important thing is the
result is always a multiple of the second argument, the time_precision.
Example-1
In the first case, I'll use a time_unit of 10ns and a time_precision of 1ns.
My testbench only has a single delay statement in it: #3.5.
I expect the compiler to do what it does with every delay statement: multiply it
by the time_unit (i.e. 3.5×3.5× 10ns =35ns=35ns); then round that to the
nearest time_precision... which, in this case, wouldn't affect
the 35ns35ns because 35ns35ns is already a multiple of 1ns.
Here's the actual code I'll use in the first case. It defines a single testbench
module, initializes a signal (my_signal) to 0 at the beginning of the simulation,
delays for a while (we'll see how long in a minute), then sets the signal to 1.
Output in waveform:
my_signal started out at 0. Then, 35ns into the
simulation, my_testbench set it to 1.
Example-2
What if I were to change the time_precision to 10ns, time unit of 10ns, I want
you to predict the time at which my_testbench will set my_signal to 1. Ready?
Here goes!
First, the code (note: only the time_precision changed, but you can double-
check the rest if you want):
Output in waveform:
expected, the compiler converted the delay value to an actual time duration just
like last time: it multiplied the delay value by
the time_unit (i.e. 3.5×3.5× 10ns =35ns=35ns); then rounded that result to the
nearest time_precision (i.e. 10ns). In this case, however, the rounding process
actually affected the result! That's because 35ns35ns isn't a multiple of
this time_precision (i.e. 35ns35ns is not a multiple of 10ns). So the compiler
rounded 35ns35ns to the nearest multiple of 10ns, which is 40ns40ns. So when
simulation time reached 40ns40ns, my_testbench set my_signal to 1.
DATA TYPES
Data Types
Data types define the type of data a variable can hold or store
SystemVerilog adds a new 2-state data types that can only have bits with 0 or 1
values unlike verilog 4-state data types which can have 0, 1, X and Z.
SystemVerilog also allows user to define new data types
2-state data types can make simulate faster, take less memory, and are preferred
in some design styles.
4. Real 4 Verilog
5. Real 4 Verilog
time
6. time 4 Unsigned 64 Verilog
Data Types
S.No TYPE 2 State datatypes/ Signed/ No. of bits/ Verilog/
4 State datatypes Unsigned Size System
Verilog
7. bit 2 unsigned User SystemVerilog
specific
8. byte 2 signed 8bit SystemVerilog
reg:
The register variables are used in procedural blocks which store values from
one assignment to the next.
Reg data type is used in Behavioral Modelling
Reg are used to model both combinational and sequential
Reg can be driven inside initial and always block
Default value for reg is x
reg is evaluated when there is a change in sensitivity list
wire:
A wire is a net type used to model physical connections - it does not store
values, but takes the value of its driver
It is used in structural modelling
Wire data type cannot be used in procedural blocks such as always and initial
Default value for wire is z
.
Data Types
integer:
It is a signed integer variable, 32-bits wide
real:
The register variables are used in procedural blocks which store values from
one assignment to the next.
Real numbers can be specified in either decimal notation or in scientific
notation
real time:
It is a type real used for storing time as a floating point value
time:
It is typically 64 bit unsigned value that is the simulation time
The system function $time provides the simulation time
.
System verilog Data Types
• SystemVerilog has introduced several 2-state (0 and 1 value) data types to improve
simulator speed and reduce its memory usage
• bit: It is a unsigned 2-state data type. A bit can be either 0 or 1 which represents a
single bit. Example: bit[31:0] a;
• byte: It is a signed 2-state data type with a size of 8bits. Example: byte a;
• shortint: It is a signed 2 –state data type with a size of 16-bits. Example: shortint a;
• int: It is a signed 2-state data type with a size of 32-bits. Example: int a;
• ‘x’ and ‘z’ values received from the DUV might automatically be converted to
0’s in the testbench leading to undesirable
.
Logic:
Reg can only be driven in procedural blocks like always and initial while wire
data types can only be driven in assign statements
System verilog introduces a new 4-state data type called logic that can be
driven in both procedural and continuous assign statements
Example:
logic a;
assign a = b ^ c;
always (c or d) a = c + d;
.
Characteristics:
Class:
• Class is a user-defined data type that includes data(class properties),functions and
tasks that operate on data.
• Functions and tasks are called as methods , both are members of the class.
• Classes allow objects to be dynamically created, deleted assigned and accessed
via object handles
Void:
• The void data type represents non-existent data.
• This type can be specified as the return type of functions, indicating no return
value
• Void’(function _call()); task void display();
function void display(); #10 $display(“not return any
$display(“not return any value”); value”);
endfunction endtask
Chandle:
• Chandle datatype is used for storing the pointer, while using DPI
Structures
.
Union
32bit size memory
because largest datatype
data_in size here is 32-bit,
Address different datatypes are
Data_out stored in single location
Str1 != Str2 Inequality Operation: This is the exact opposite of the equality
operation
Str1 < Str2 Comparison Operation: Returns a 1 if the result of the given
comparison is true
Str1 <= Str2
Str1 > Str2
Str1 >= Str2
{Str1,Str2,...,Strn} Concatenation Operation: Appends the ‘n’ individual string
operands together. The operands can be of string type or can be
string literals
• These methods or functions are called after the string object name with a
period “.” between the object name and the function name.
• function int len(): Returns the length of the string, i.e., the number of characters in
the string as an integer value
• function void putc(int i, byte c): Replaces the ith character in the string with
character ‘c’
• function byte getc(int i): Returns the ith character of the string
• function string toupper(): Returns a string with characters in the string converted to
uppercase. The original string remains unchanged
• function string tolower(): Returns a string with characters in the string converted to
lowercase. The original string remains unchanged
• function int compare(string s): str1.compare(str2) – compares strings str1 and str2.
Return '0' if equal, a positive value if str1 comes after str2, and a negative value if str1
comes before str2
.
• function int icompare(string s): str1.icompare(str2) – case insensitive comparison of
strings str1 and str2
• function string substr(int i, int j): str.substr(i,j) - returns a new string that is a sub-string
consisting of characters in position i through j in string str
• function integer atoi(): String to integer conversion – returns the integer corresponding to
the ASCII decimal representation of the string
• function void itoa(integer i): Integer to string conversion. This is the inverse of the
function atoi()
string a = “AEIOU”;
string b = “alonso”;
string c = “123”;
byte subs1;
string subs2, lc, uc;
integer asiz, val;
asiz = a.len();// asiz is assigned the value 5 as the string ‘a’ initialized to “AEIOU” has 5 characters
subs1 = b.getc(5);// subs1 gets ‘o’ which is the 5th character of string ‘b’ initialized to “alonso”
uc = b.toupper(); // uc gets “ALONSO” which is all uppercase of string ‘b’
lc = a.tolower(); // lc gets “aeiou” which is all lowercase of string ‘a’
subs2 = a.substr(1,3); // subs2 gets “EIO” which is the 1st to 3rd characters of string ‘a’
typedef
.
• Verilog 2001 does not allow users the freedom to extend net and variable
types to create their own data types for some specific purpose
• SystemVerilog introduces user-defined data types like those present in the
‘C’ programming language
• Here users can create and manipulate their own complex data types for
specific purposes like simulation, emulation etc
• Most values in a testbench are positive integers and so having a signed
integer could cause problems
• So the unsigned, 2-state 32-bit integer type ‘uint’ or ‘usint’ (as shown in the
example) is used in such testbenches.
typedef example
typedef int unsigned unsint; // Define a new 32-bit unsigned 2-state integer type
typedef bit [31:0] uint; // – a new 32-bit unsigned 2-state integer type
unsint a, b; // Declaring variables with the new ‘unsint’ type
uint c, d; // a, b, c and d are 32-bit unsigned 2-state integers
typedef logic [15:0] bits16; // Defining a new 16-bit type called ‘bits16’
bits16 word1, word2; // These are 2 16-bit words
typedef logic [3:0] nibble; // Defining a new 4-bit type called ‘nibble’
nibble [15:0] vec; // vec is a 64-bit vector made from 16 nibble types
Enumerated Data Type
.
Examples:
enum {red,amber,green} tlc; // anonymous int type used for a traffic light controller
enum {INIT,START,STOP,FINAL,ABORT} power_ctrl_fsm; // States of a finite state machine
enum {idle = 1, start = 2, pause = 4, load = 8, done = 16} onehotstate; // Explicit values defined
below to do one-hot encoding
enum bit [2:0] {ST0 = 3’b001, ST1 = 3’b010, ST2 = 3’b100} state_encoding; // Encoding must
match the length of the 3-bit enum data type defined below
enum logic {underflow, overflow, divbyzero, io_err} error_codes; // Error codes can be stored as an
enum declaration
enum logic [2:0] {ADD, SUB, MUL, MOV, LD, AND, XOR, NEG} opcode; // Opcodes can be stored as
an enum declaration
enum bit {FALSE=1’b0, TRUE=1’b1} boolean; // Declaring a boolean type below
enum {W=1, X, Y=8, Z} missing_val; // Missing values for enum names
• function enum first(): Returns the value of the first member of the enumeration
• function enum last(): Returns the value of the last member of the enumeration
• function enum next(int unsigned N = 1): Returns the Nth-next enumeration value
(default is the next one) starting from the current value of the given variable
• function enum prev(int unsigned N = 1): Returns the Nth-previous enumeration value
(default is the previous one) starting from the current value of the given variable
• function string name(): Returns the string representation of the given enumeration value.
If the given value is not a member of the enumeration, the name() method returns the
empty string
Enumerated Type Methods
• An array is a collection of elements, all of the same type, and accessed using its
name and one or more indices
• The array data type for a net or variable is an aggregate declaration that was either
a scalar or a vector
• Verilog 2001 required that the low and high array limits must be part of the array
declaration
• SystemVerilog has introduced the compact array declaration style, where just
giving the array size along with the array name declaration is enough
Array Struct
A group of elements of same A group of elements of different data type
data type is called Array is called struct
Collection of variables of same data type Collection of variables of different data types.
int addr[10]; //Array of int type
typedef enum logic {INVALID_PKT,VALID_PKT} pkt_type;
bit [31:0] data[63]; //Array of bit type
typedef struct packed {
byte addr;
pkt_type valid;
bit [31:0] data;
} mem_pkt;
.
Fixed size array
In fixed size array, array size will be constant throughout the simulation.
Once the array is declared no need to create it. By default, the array will be
initialized with value ‘0’.
int mdarr [8][8]; //Same example as above, System Verilog’s compact declaration style
Single
. dimension/Multi dimension Array Outputs:
-------displaying array1-------
array1[0] = 0
module fixedsize_array; array1[1] = 1
//declaration of array’s
array1[2] = 2
int array1[6]; //single dimension array
int array2[5:0]; //single dimension array
array1[3] = 3
int array3[2:0][3:0]; //multi dimension array array1[4] = 4
initial begin array1[5] = 5
//array initialization -------displaying array2-------
array1 = '{0,1,2,3,4,5}; array2[0] = 5
array2 = '{0,1,2,3,4,5}; array2[1] = 4
array3 = '{'{0,1,2,3},'{4,5,6,7},'{8,9,10,11}};
array2[2] = 3
//displaying array elements
$display("-------displaying array1-------");
array2[3] = 2
foreach(array1[i]) $display("\t array1[%0d] = %0d",i,array1[i]); array2[4] = 1
array2[5] = 0
$display("-------displaying array2-------"); -------displaying array3-------
for(int i=0;i<6;i++) $display("\t array2[%0d] = %0d",i,array2[i]); array3[2][3] = 0
array3[2][2] = 1
$display("-------displaying array3-------");
array3[2][1] = 2
foreach(array3[i,j]) $display("\t array3[%0d][%0d] =
%0d",i,j,array3[i][j]);
array3[2][0] = 3
array3[1][3] = 4
$display("-------displaying uninitialized array4-------"); array3[1][2] = 5
for(int i=0;i<5;i++) $display("\t array4[%0d] = %0d",i,array4[i]); array3[1][1] = 6
end array3[1][0] = 7
endmodule array3[0][3] = 8
array3[0][2] = 9
array3[0][1] = 10
array3[0][0] = 11
.
Packed Array
• A packed array is one where the dimensions of the array is declared before the
array object name
Syntax : <data_type> <range (optional)>* <array_name>;
Example:
logic [2:0][9:0] mymix_array [0:3] [0:5] [2]; // Is a mixed 5-dimensional array with 2 packed
// dimensions – [2:0] and [9:0], and 3 unpacked
// dimensions - [0:3], [0:5] and [0:7]
All unpacked dimensions are first referenced from the left-most to the
right-most dimension in that order
All packed dimensions are then referenced from the left-most to the right-
most dimension in that order
packets Bits size row column frame
03 2 1 0
1
2 2frames
Example-2
bit [3:0][7:0]mix_arr[0:2]; mix_arr[0][0],
mix_arr[1][3][4]
mix_arr[2][0]
.
Dynamic Array
In Verilog fixed array, the size of the array is not known until run-time
SystemVerilog has introduced dynamic arrays that can be allocated and re-
sized during simulation so that a minimal amount of memory is used
Example:
integer i_dynarr[]; // Dynamic array of integers
bit [31:0] word_dynarr[]; // Dynamic array of 32-bit vectors
.
This means that the array size is not specified at compile time, rather it will be
given later at run time
In reality, only a subset of control signals would be used, thus wasting the
remaining memory
A dynamic array that can be allocated and re-sized during simulation will avoid
this unnecessary memory allocation
.
Dynamic Array Methods
The methods or functions are called after the dynamic array object name
with a period “.” between the object name and the function name.
Constructor ---------new[value]:
Sets the size of a dynamic array and initializes its elements or changes
the size of the array at run-time
If the value is zero, the array shall become empty. If the value is
negative, then it is an error.
Function int-------- size():
The size() method returns the current size of a dynamic array or returns
zero if the array has not been created
Function void-------delete():
The delete() method empties the array, resulting in a zero-sized array.
dyn1
0
dyn2
1
1 0
2
module dy_a(); 1
int dyn1[], dyn2[]; // Declare 2 dynamic arrays – dyn1 & dyn2 3 2
int size1; 2
initial dyn2 3
begin 5 0
dyn1=new[4]; 1 // Allocate space for 4 elements 10 1
size1 = dyn1.size(); // Returns size of dyn1, which is 4
3 15 2
dyn2=dyn1; 2 // Copy the ‘dyn1’ array
dyn2= ‘{5, 10, 15, 20}; 3 // Modify the copy 20 3 dyn1
dyn1=new[7](dyn2); 4 // Allocate space for 7 elements & copy the existing 5 0
elements
10 1
dyn1.delete();// Delete elements of the dynamic array
end 15 2
endmodule 4 20 3
4
5
6
.
Associative Array
SV allocates memory for an element only when data is written into the
associative array
This is a big advantage in that it saves tremendous amounts of memory
space in comparison with dynamic arrays where the full memory is allocated
even if only one element is written into it.
In Verilog array indices can only be integer values. However, associative
array indices in SV can be of any type.
. If an attempt is made to read an invalid (non-existent) associative array entry,
then the simulator will issue a warning and will return the value ‘x’ for a 4-
state integral type or a value ‘0’ for a 2-state integral type
This would take up significantly much lesser memory than the entire array
normally used in Verilog.
initial
begin
array_a[0] = 4’b0101; A standard array Associative array
array_a[8] = 4’b0111; (Contiguous) (Non-Contiguous)
array_a[30] = 4’b1101; 0 4’b0101 0 4’b0101
array_a[31] = 4’b0110; …….. No memory
end 4’b0111 allocated for
8 4’b0111 8
unused
…….
elements
30 4’b1101 30 4’b1101
Memory 31 4’b0110 31 4’b0110
allocated for
even unused
elements
.
Associative Array Methods
Size() or num():
The num() or size() method returns the number of entries in the associative array
int temp,imem[*];
imem[ 2'd3 ] = 1;
imem[ 16'hffff ] = 2;
imem[ 4'b1000 ] = 3;
$display( "%0d entries", imem.num );
delete():
The delete() method removes the entry at the specified index
integer map[string];
map[ “data" ] = 1;
map[ “address" ] = 2;
map[ “control" ] = 3;
map.delete( “control" ); // Remove entry whose index is “control“
from array "map“, i.e., value 3
map.delete(); // Remove all entries from the associative array "map"
.
exists():
The exists() function checks whether an element exists at the specified index
within the given array.
if the element exists it returns 1, otherwise it returns 0
integer map[string];
integer count = 0;
map[ “data" ] = 1;
map[ “address" ] = 2;
map[ “control" ] = 3;
if(map.exists( “data" )) // Checks whether an element exists at the index ‘data’ in array ‘map’.
// In this case the value 3 exists and hence the function returns a 1
count = count + 1;
.
first():
Assigns to the given index variable the value of the first (smallest)
index in the associative array.
It returns 0 if the array is empty, and 1 otherwise
string s;
integer map[string];
map[ “address" ] = 1;
map[ “control" ] = 2; map[ “data" ] = 3;
if(map.first(s))
// Assigns the first index “address” to the string ‘s’ ,returns 1 as the array is not empty
$display( "First entry is : map[ %s ] = %0d\n", s, map[s] );
// Display statement is executed to show “First entry is : map[address] = 1”
. last():
Assigns to the given index variable the value of the final (largest) index in
the associative array. It returns 0 if the array is empty, and 1 otherwise
string s;
integer map[string]; map[ “address" ] = 1;
map[ “control" ] = 2;
map[ “data" ] = 3;
if(map.last(s))
// Assigns the last index “data” to the string ‘s’ and returns 1 as the array is not empty
$display( “Last entry is : map[ %s ] = %0d\n", s, map[s] );
string s;
integer map[string]; map[ “address" ] = 1; map[ “control" ] = 2;
if(map.first(s))
// Assigns the first index “address” to the string ‘s’ and returns 1 as the array is not empty
do
$display( "%s : %d\n", s, map[s]);
while(map.next(s));
// This do-while loop iterates twice, the first time for “address” and the second time for
“control”.
// After that the map.next(s) function returns a 0 as there are no more indices, and the
loop terminates.
. prev():
Finds the largest index whose value is smaller than the given index
argument.
If there is a previous entry, the index variable is assigned the index of
the previous entry, and the function returns 1.
Otherwise, the index is unchanged, and the function returns 0
string s;
integer map[string]; map[ “address" ] = 1; map[ “control" ] = 2;
if(map.last(s))
// Assigns the last index “control” to the string ‘s’ and returns 1 as the array is not empty
do
$display( "%s : %d\n", s, map[s]);
while(map.prev(s));
// This do-while loop iterates twice, the first time for “control” and the second time for
“address”.
// After that the map.prev(s) function returns a 0 as there are no more indices, and the
loop terminates.
Queues
. A queue is a variable-size, ordered collection of homogeneous (same type)
unpacked array elements.
int q[$] = {2, 4, 8}; // Initialized integer queue ‘q’ with 3 elements – 2, 4 and 8
int p[$]; // Un-initialized integer queue ‘p’
int e, pos;
e = q[0]; // read the first (left-most) element of ‘q’; ‘e’ gets the value 2
e = q[$]; // read the last (right-most) element of ‘q’; ‘e’ gets the value 8
q[0] = e; // write the value of ‘e’ as the first element in ‘q’
p = q; // copy contents of ‘q’ to ‘p’
q = { q, 6 }; // insert ’6’ at the end of the queue ‘q’ (append the value 6)
q = { e, q }; // insert the value of ’e’ at the beginning of the queue ‘q’ (prepend the value of ‘e’)
q = q[1:$]; // delete the first (left-most) element of ‘q’
q = q[0:$-1]; // delete the last (right-most) element of ‘q’
q = q[1:$-1]; // delete the first and last elements of ‘q’
q = {}; // clear the queue contents, i.e., delete all elements of ‘q’
q = { q[0:pos-1], e, q[pos,$] }; // insert ’e’ in the queue ‘q’ at the position ‘pos’
q = { q[0:pos], e, q[pos+1,$] }; // insert ’e’ in the queue ‘q’ after the position ‘pos’
Queue Methods
These methods or functions are called after the queue object name with a period
“.” between the object name and the function name
Function int size(): Returns the number of items in the queue. If the queue is
empty, it returns 0.
Q.size() returns 4 for the integer queue, Q[$] = {8, 2, 1, 20}; containing 4
integer values - 8, 2, 1 and 20
Function void insert (int index, queue_type item): Inserts the given item at
the specified index position
Q.insert (i, e) is equivalent to Q = {Q[0:i-1], e, Q[i:$]}
Function void delete (int index): Deletes the item from the specified index
position
Q.delete (i) is equivalent to Q = {Q[0:i-1], Q[i+1:$]}
Queue Methods
Function queue_type pop_front(): Removes and returns the first element of
the queue
e = Q.pop_front () is equivalent to e = Q[0]; Q = Q[1:$]
Function void push_front (queue_type item): Inserts the given element at the
front of the queue
Q.push_front (e) is equivalent to Q = {e, Q}
Function void push_back (queue_type item): Inserts the given element at the
end of the queue
Q.push_back (e) is equivalent to Q = {Q, e}
Queue Methods
integer int_q[$] = {20, 30, 40, 50}; // Initialized integer queue ‘int_q’ with 4 elements –
20, 30, 40 and 50
integer qs, val;
qs = int_q.size(); // The queue ‘int_q’ has 4 elements and hence the size is 4. ‘qs’ gets
the value 4.
int_q.push_front(10); // Inserts the value 10 at the beginning of the queue ‘int_q’. Now
‘int_q’ has 5 elements – 10, 20, 30, 40 and 50 in that order.
int_q.push_back(60); // Inserts the value 60 at the end of the queue ‘int_q’. Now ‘int_q’
has 6 elements – 10, 20, 30, 40, 50 and 60 in that order.
int_q.insert(3, 35); // New element 35 added at index position 3 in the queue ‘int_q’.
Now ‘int_q’ has 7 elements – 10, 20, 30, 35, 40, 50 and 60 in that order.
int_q.delete(3); // Deletes the element from index position 3 in the queue ‘int_q’. Now
‘int_q’ has 6 elements – 10, 20, 30, 40, 50 and 60 in that order.
val = int_q.pop_front(); // Removes and returns the first element of the queue ‘int_q’.
‘val’ now holds the value 10, while ‘int_q’ has 5 elements – 20, 30, 40, 50 and 60 in
that order.
val = int_q.pop_back(); // Removes and returns the last element of the queue ‘int_q’.
‘val’ now holds the value 60, while ‘int_q’ has 4 elements – 20, 30, 40 and 50 in that
order.
Array Classification
qi = IA.find(x) with (x > 30); // Find all items in IA that are greater than 30
qi = IA.find_index with (item == 8); // Find indices of all items in IA that are equal to 8
qs = SA.find_first with (item == “address"); // Find the first item in SA that is equal to “address”
qs = SA.find_last(z) with (z == “data"); // Find the last item in SA that is equal to “data”
qi = SA.find_last_index(p) with (p > "Z"); // Find the index of last item in SA that is greater than “Z”
qi = IA.min; // Find the smallest item in IA
qs = SA.max with (item.atoi); // Find the string with largest numerical value in SA
qs = SA.unique; // Find all unique string elements in SA
qs = SA.unique(rv) with (rv.toupper); // Find all unique strings in upper-case in the array SA
Array Ordering Methods
• Unlike array locator methods, these array ordering methods change the
contents of the original array
• These methods or functions are called after the array object name with a
period “.” between the object name and the function name
reverse():
• Reverses the order of the elements in an array. Specifying a ‘with’ clause
shall be a compiler error.
sort():
• Sorts the array in ascending order. An optional condition can be specified
using the expression in the ‘with’ clause.
rsort():
• Sorts the array in descending order. An optional condition can be specified
using the expression in the ‘with’ clause.
shuffle():
• Randomizes the order of the elements in the array. Specifying a ‘with’
clause shall be a compiler error.
Array Ordering Methods
For exhaustive testing, say the input stimuli Next the array needs to be sorted in
need to be given to the test bench in an descending order. Then the rsort()
ascending order. The sort() method is used method is used.
to achieve this.
Example:
byte da[] = {1,2,3,4};
int ans;
ans = da.sum ; // ans is 10 => 1 + 2 + 3 + 4
ans = da.product ; // ans is 24 => 1 * 2 * 3 * 4
ans = da.xor with (item + 6); // ans is 12 => 7 ^ 8 ^ 9 ^ 10
OOPS CONCEPT
Introduction
• Programming languages such as C and hardware description languages such
Verilog 2001 are structured languages
• These languages which executed sequentially, depending on the instruction
received through subroutines and function calls
• OOP concept of class and object brings dynamicness within the code and most
importantly make the code reusable
• Object-Oriented Programming (OOP) helps to create complex data types and
also to tie them together with routines that manipulate them.
• OOP helps in isolating the testbench from the design details.
• Therefore the code is easier to maintain, can be extended and is re-usable for
system-level testing and also for use in testing of future projects
• OOP makes it very easy to partition a testbench into specific blocks that work
together in accomplishing the verification task
Advantages of OOP
• The concept of OOP related features brings the idea of Reusability, dynamic
nature, inter communication within the blocks, multithreading,etc which
are missing in procedural language
1. Introduces concept of Inheritance which is useful in extending the
properties of base class into child class along with its existing methods
which increases code reusability and minimises code length.
2. Introduces the concept of Encapsulation which is a data hiding property
within a class so that a particular data member can remain private.
3. Introduces polymorphism concept using virtual methods which is useful in
overriding class properties and methods.
4. Introduces abstract class concept which is just a placeholder for a class and
object can not be created out of it and the use of it comes in task and
function call.
5. Introduces shallow copy,deep copy and object copy concept which are missing
in procedural language
8. OOP divides the code into modules, i.e., every class has its part of the code and
you can make many instances of these classes, which you will avoid repeating
the code, also will be readable and extendable
OOP Terminology
Terminology Example
Class: This forms the base of OOP. The class “4-Wheeler” is a class which describes the
description describes all the properties, different kinds of 4-wheeler vehicles present,
behavior and identity of objects present properties like make, color etc. and how each
within it of them behave
Object: This is an instance of the class “Car”, “Truck” and “Mini-Bus” are instances
of “4- Wheeler” vehicles
Handle: This is a pointer to the object that “Registration Number” is unique to every 4-
cannot be Modified wheeler
vehicle and in a way is its handle
Properties: These are variables that define “Make”, “Color”, “Mileage”, “Speed” and
the contents and characteristics of the “Electric/Petrol/Diesel/Hybrid Type” are
instance of a class common characteristics that will be defined
for all instances of 4-wheeler vehicles
Methods: These are tasks or functions that “Gears” to increase or decrease the engine
operate revs and “Drive Mode” to control the fuel
on the properties in an instance of the class consumption are functions that operate on
and control the “speed” and “mileage”
properties respectively
Classes, Properties & Methods
• A class is a user-defined data type that contains a collection of data items and a set
of subroutines that operate on that data.
• These data items in a class are referred to as class properties, and its subroutines
are called methods
• Class properties and methods, define the contents and capabilities of that class
• Class is used to combine or encapsulate manipulation methods and data properties
as a single unit
• Any data type can be used in the class property declaration
• The properties and functions/tasks in a class are also referred to as “members” of a
class
• Classes provide a template or framework for use in testbenches during verification
• Classes in SystemVerilog are typically defined in either a program block or module
or a package, but its definition is not limited to only these
Classes, Properties & Methods
Syntax: Example:
class class_name; class int_operations;
<data type 1 / property 1 declaration>; //Properties
: int i;
<data type p / property p declaration>; int j;
<(method 1) task 1 / function 1 declaration>; //Methods
: task addprint();
<(method q) task q / function q declaration>; $display(“i + j = %d”, i+j);
endclass endtask
task mulprint();
$display(“i * j = %d”, i*j);
endtask
task subprint();
$display(“i - j = %d”, i-j);
endtask
endclass
Handles & Objects
• An object is an instance of the class. A handle is nothing but a variable
declaration of the class type – it is a pointer to the object that cannot be
modified
Features and Characteristics:
• Every class has an inbuilt function new() called as the class constructor. This
function allocates memory to store the variables of an object
• An object of a class is created by first declaring a variable of that class name,
which is nothing but its handle and then calling the new() function and
assigning it to the variable
Syntax: Syntax:
// For declaring a handle // For creating an object
class_name var_handle_1_name, … var_handle_1_name = new(); // Object 1
var_handle_n_name; var_handle_n_name = new(); // Object 2
• Uninitialized object handles are set by default to the special value null
Continu…..
• The compiler does the following when an object is created with the handle
using the function new():
• Allocates space for all the properties in the class
• Initializes all the properties to their default value (‘0’ for 2-state variables
and ‘x’ for 4-state ones)
• Returns the address where the object is stored - the handle gets this address
• An uninitialized object can be detected by comparing its handle with null
• SystemVerilog de-allocates memory for an object only if there are no handles
pointing to it
• The properties or methods of any object can be accessed by using a period “.”
between the object name and the property or method name
• OOP allows for objects to be created and destroyed dynamically
Example for class handle and object
class simple;
int i; //Properties
int j;
task printf(); //Methods
$display(“%d, %d”, i, j);
endtask
endclass
module simple_class;
initial
begin
simple obj_1; //Declaring handles
simple obj_2;
obj_1 = new();//Creating objects
obj_2 = new();
obj_1.i = 2; //Accessing properties & methods using objects
obj_2.i = 4;
obj_1.printf();
obj_2.printf();
end
endmodule
Why do we need parameterization for classes
• At times it would be much easier to write a generic class which can be instantiated
in multiple ways to achieve different arrays size or different datatypes
• This avoids the need to rewrite the code for specific features like size or type instead
allow a single specification to be used for different objects
• Parameters are like constants that are local to the specified class
• Classes are allowed to have default value for each parameter that can be overridden
during class instantiation
module tb;
// Override default value of 8 with the given values in #()
something #(16) sth1; // pass 16 as "size" to this class object
something #(.size (8)) sth2; // pass 8 as "size" to this class object
typedef something #(4) td_nibble; // create an alias for a class with "size" = 4 as "nibble"
td_nibble nibble;
initial begin // 1. Instantiate class objects
sth1 = new;
sth2 = new;
nibble = new;
// 2. Print size of "out" variable. $bits() system task will return
// the number of bits in a given variable Output:
sth1.out = 16
$display ("sth1.out = %0d bits", $bits(sth1.out)); bits sth2.out = 8
$display ("sth2.out = %0d bits", $bits(sth2.out)); bits nibble.out = 4 bits
$display ("nibble.out = %0d bits", $bits(nibble.out));
end
endmodule
typedef class
Syntax:
typedef class class_name;
With out typedef With typedef
EXAMPLE
class StringList;
endclass
class StringTree;
endclass
// StringList::Node is different from StringTree::Node
Why Use Nested Classes
• It is a way of logically grouping classes that are only used in one place.
• It increases encapsulation.
• Nested classes can lead to more readable and maintainable code.
• Logical grouping of classes : If a class is useful to only one other class, then
it is logical to embed it in that class and keep the two together. Nesting such
"helper classes" makes their package more streamlined.
Example
class BlueTooth; • int variable objcnt is static and so only one copy
static int objcnt = 0; // Counter for # of objects created of it is created, irrespective of however many
int uid; // Unique instance ID BlueTooth instances are created
function new(); • int variable uid is not static and so instances bt1
uid = objcnt++; // Set unique ID, incr the obj count and bt2 have individual copies of uid
endfunction
endclass
module sample();
BlueTooth bt1,bt2;// Declare handles of 2 BlueTooth objects here BlueTooth bt1, bt2;
Initial
Output
begin
bt1.uid=0 bt2.uid=1
bt1 = new; // Object1 created here
bt1.objcnt=1 bt2.objcnt=2
$display(“First id=%d, Object count=%d”,bt1.uid,bt1.objcnt);
bt1.objcnt=2
bt2 = new; // Object2 created here
$display("Second id=%d, Object count=%d, Object count=%d”,bt2.uid,bt1.objcnt,bt2.objcnt);
end
endmodule
//The static class The static class
properties can be properties can be used
accessed using without creating an
class name. object of that type EXAMPLE: using the
EXAMPLE: Using EXAMPLE: using EXAMPLE: without object name, without
object name class name creating object creating object
class A ; class A ; class A ; class A ;
static int i; static int i; static int i; static int i;
endclass endclass endclass endclass
The SystemVerilog IEEE 1800-2012 LRM states that the this keyword shall
only be used within non-static class methods, or else an error is generated
Example:
ivar’ is both a property of the class and an argument to the
class example_this; integer ivar; function new.
function new (integer ivar) In the function new, an unqualified reference to ivar (without the
‘this’ keyword) is resolved by looking at the innermost scope of
this.ivar = ivar; the variable. Here, it refers to the function argument declaration.
// ivar = this.ivar; is also allowed
endfunction A qualified reference to ivar (with the ‘this’ keyword). refers to
the instance class property for the current instance.
endclass
With this keyword Without this keyword
When using the super keyword within the new function, super.new shall be
the first statement executed in the constructor
Example:
class Base;
typedef enum {bin,oct,dec,hex,frac} radix;
static task print(int n, radix r);
...
endtask endclass
...
Base b = new; int bin = 321;
b.print(bin, Base::bin); // Base::bin and bin are different Base::print(666, Base::hex);
extern keyword
The main use of the extern keyword is for better understanding and readability
it would be convenient to be able to move method definitions out of the body of
the class declaration.
Class definitions can become very long with a lot of lines between class and
endclass
It makes difficult to understand what all functions and variables exists within
the class, because each function and task occupies a lot of lines
If the definition of the method written outside the body of the class then the
method is called an external method
extern keyword
external function. The definition of the function written outside the class body
is referred to as an external function
external task. The definition of the task written outside the class body is
referred to as an external task
To do this, need to declare the method (Function/Task) with an externkeyword
in the class body along with
i. any qualifiers (local, protected or virtual) ii. full argument list
The extern qualifier indicates that the body of the method (its implementation)
is to be found outside the class declaration
Before the method name, the class name should be specified with a class
resolution operator to specify to which class the method corresponds to.
Note:
Number of arguments, arguments name and argument type should match
between method declaration and method definition
extern function extern task
/class with extern function /class with extern task
class packet; class packet;
bit [31:0] addr; bit [31:0] addr;
bit [31:0] data; bit [31:0] data;
//function declaration - extern indicates out-of- //task declaration - extern indicates out-of-body
body declaration declaration
extern virtual function void display(); extern virtual task display();
endclass endclass
//function implementation outside class body //task implementation outside class body
function void packet::display(); task packet::display();
$display("Addr = %0d Data = %0d",addr,data); $display("Addr = %0d Data = %0d",addr,data);
endfunction endtask
By using inheritance we can reuse the methods of base class without need to
redefining in child class
A derived class may add new properties and methods, or modify the inherited
properties and methods
If the class is derived from a derived class, then it is referred to as Multilevel
inheritance
Inheritance Example
class parent; class parent_class;
task printf(); bit [31:0] addr;
$display(" THIS IS PARENT CLASS "); endclass
endtask
endclass class child_class extends parent_class;
bit [31:0] data;
class subclass extends parent; endclass
task printf();
$display(" THIS IS SUBCLASS "); module inheritence;
endtask initial begin
endclass child_class c = new();
c.addr = 10;
program main; c.data = 20;
initial $display("Value of addr = %0d data =
begin %0d",c.addr,c.data);
parent p; end
subclass s; endmodule
p = new(); Output
s = new(); THIS IS PARENT CLASS
THIS IS SUBCLASS Output
p.printf();
addr = 10
s.printf();
end
data = 20
endprogram
What Can Do In A Subclass:
Subclass inherits all of the public and protected members of its parent class.
The inherited members as is, replace them, hide them, or supplement them with
new members
You can declare a field in the subclass with the same name as the one in the
superclass, thus hiding it (not recommended)
You can write a new instance method in the subclass that has the same
signature as the one in the superclass, thus overriding it.
You can write a new static method in the subclass that has the same signature
as the one in the superclass, thus hiding it.
You can declare new methods in the subclass that are not in the superclass.
You can write a subclass constructor that invokes the constructor of the
superclass, either implicitly or by using the keyword super.
Composition
Definition:
The manual extension of a class is called composition
class NetworkPacket;
// Handle to the parent-class declared below
Packet intranet_packet;
// Other properties & methods of class NetworkPacket
int header, trailer;
function linkpackets()
:
endfunction
endclass
• Packet is the parent-class containing the integer properties payload and checksum
• All references to the Packet class are made through this handle.
Comparison of Inheritance & Composition
Inheritance Composition
• All the properties and methods of a • All the properties and methods of a
parent- class are also available to the parent- class are also available to the
sub-class if the sub-class has sub-class if the sub-class has
inherited everything from the parent- inherited everything from the parent-
class class
• Possible to extend/override the • Not possible to extend/override the
methods of the parent-class from a methods of the parent-class from a
sub-class sub-class
• Need for abstract classes is that you can generalize the super class from which
child classes can share its methods.
• When different classes have need few common set of properties/ methods (that
they can use /override), the concept of virtual/abstract class comes in to picture.
• The common base-class is characterized as abstract by specifying it along with
the ‘virtual’ keyword
Continu…
• In an abstract class, the properties and methods are only specified and are not
fully defined – this class is therefore incomplete
• Virtual classes can have virtual methods that are overridden in derived classes.
Once a virtual method is defined, all derived classes that define the same
method must use the same number and type of arguments, as well as the return
value type (if any)
• The virtual keyword is used to express the fact that derived classes could
redefine the properties and must override the methods to complete the required
functionality
• Virtual classes create a template from which real classes are derived
Example for Abstract class
Example:
There CAN'T be a definition of the pure virtual function in the base class.
There MUST be a definition of the pure virtual function in the derived clas
Pure virtual method
class Base;
pure virtual task disp();
end class
program main
initial
begin
Base B;
B = new();
B.disp();
end
endprogram
RESULT
• So, if any method declared as virtual in the base class then by default same
method works as virtual in child class.
Continu…
• When the class object executes the virtual method, the correct
implementation is chosen and executed at run-time.
• Simply put, the OOP term for multiple methods sharing a common name
is called polymorphism
Features and Characteristics:
• Methods declared with the keyword virtual are referred to as virtual methods
i. Virtual function ii. Virtual task
• A function declared with a virtual keyword before the function keyword is
referred to as virtual Function
• A task declared with a virtual keyword before the task keyword is referred to as
virtual task
Output
Output
Compilation error
i=10// protet variable can be
//local keyword
access from outside the class
properties can
access from
outside the class
Shallow copy
packet pkt_2;
pkt_2 = new pkt_1;
In the last statement, pkt_2 is created and class properties were copied from
pkt_1 to pkt_2, this is called as “shallow copy”.
Shallow copy allocates the memory, copies the variable values and returns the
memory handle.
In shallow copy, All of the variables are copied across: integers, strings,
instance handles, etc.
Deep copy
Deep copy copies all the class members and its nested class members.
Unlike in shallow copy, only nested class handles will be copied.
In shallow copy, Objects will not be copied, only their handles will be copied.
To perform a full or deep copy, the custom method needs to be added.
In the custom method, a new object is created, all the class properties will be
copied to a new handle and the new handle will be returned.
packet pkt_1;
pkt_1 = new();
pkt_2 = new ();
pkt_2=pkt1.copy();
Casting
• Casting means the conversion of one data type to another data type.
• During value or variable assignment to a variable, it is required to assign value or
variable of the same data type.
• Some situations need assignment of different data type, in such situations, it is
necessary to convert data type and assign.
• Otherwise, the assignment of different data type results in a compilation error.
• The method of data type conversion is called casting.
• In system Verilog, there are two types of casting,
• Static casting
• Dynamic casting
Static casting
• SystemVerilog static casting is not applicable to OOP
• Static casting converts one data type to another compatible data types (example
string to int)
• As the name says ‘Static’, the conversion data type is fixed
• Static casting will be checked during compilation, so there won’t be run-time
checking and error reporting
• Casting is applicable to value, variable or to an expression
• A data type can be changed by using a cast ( ‘ ) operation
• The vale/variable/expression to be cast must be enclosed in parentheses or within
concatenation or replication braces
real r_a;
int i_a;
initial begin
$cast(child_class,parent_class);
Why is it called as dynamic casting?
• Parent class assignment with child class example.
• Type of parent class is changing dynamically i.e on declaration it is of parent class
type, on child class assignment it is of child class type.
• Parent class handle during $cast execution is considered for the assignment, so it
referred to as dynamic casting.
• Every formal argument has one of the following directions. The default is input.
• input
• output
• inout
• ref
• Each formal argument has a data type that can be explicitly declared or inherited
from the previous argument.
• If the data type is not explicitly declared, then the default data type is logic.
Output Output
Value of x=15 Value of X=15
function
• A Function can contain declarations of range, returned type, parameters, input
arguments, registers, and events.
• A function without a range or return type declaration returns a one-bit value
• Any expression can be used as a function call argument
• Functions cannot contain any time-controlled statements, and they cannot enable
tasks
• Functions can return only one value
• SystemVerilog function can be,
i. static ii. automatic
i. Static Function
Static functions share the same storage space for all function calls.
ii. Automatic Function
Automatic functions allocate unique, stacked storage for each function call.
Capabilities of SV function
• to declare an automatic variable in static functions
• to declare the static variable in automatic functions
• more capabilities for declaring function ports
• multiple statements within a function without requiring a begin…end or fork…join
block
• returning from the function before reaching the end of the function
• Passing values by reference, value, names, and position
• default argument values
• function output and inout ports
• the default direction of argument is input if no direction has been specified.
• default arguments type is logic if no type has been specified.
Capabilities of SV function
• A function declaration shall implicitly declare a variable, internal to the function,
with the same name as the function.
• This variable has the same type as the function return value
• Functions can be declared as type void – these do not have a return value
• Functions can have the same formal arguments as tasks. The default argument
direction is input.
• In addition to this, argument directions of output, inout and ref are allowed. Once a
direction is given, subsequent formals default to the same direction
• Each formal argument has a data type that can be explicitly declared or inherited
from the previous argument.
• If the data type is not explicitly declared, then the default data type is logic
• Arguments can be passed by name, position and reference as well
• Arguments can be assigned some default value
function arguments in parentheses function arguments in declarations
and mentioning directions
void'(nv_fn_name());
Void function Example
module sv_function;
int x;
//void function to display current simulation time
function void current_time;
$display("\tCurrent simulation time is %0d",$time);
endfunction
initial begin
#10;
current_time();
#20;
current_time();
end
Endmodule
Output
Current simulation time is 10
Current simulation time is 30
Difference between Task and function
Tasks Function
A function cannot call other tasks, but
A task can call other tasks and can call other functions
functions
Within a function, no event, delay or
timing control statements are
A task can contain an event, delay or permitted.
timing control statements. Hence, a function cannot consume
Hence, a task can consume time time and the statements in the
body of a function will execute in
one simulation time unit
A task does not return a value A function has to return a single value
A task invocation can have zero or more In the function invocation at least one
arguments passed argument needs to be passed
Tasks are non-synthesizable, if they Functions are synthesizable
contain timing control statements
Pass by Value vs Pass by Reference
Pass by value Pass by reference
In pass by value ,if u change any In pass by reference, if u change any
arguments in function it wont reflect on arguments in function it will reflect on
outside the class outside the class also
value of a=10, b=20 and c=40. conditions a<b and Value of a=50, b=20 and c=40, conditions
a<c are true, a<b and a<c are false,
Therefore on execution, simulator issue a run time Therefore on execution, simulator issue a run
warning. time warning.
//Unique: all conditions should be true
module unique_if;
//variables declaration module unique_if;
int a,b,c; //variables declaration
initial begin int a,b,c;
//initialization initial begin
a=10; //initialization
b=20; a=50;
c=40; b=20;
unique if ( a < b ) $display("\t a is less than b"); c=40;
else if ( a < c ) $display("\t a is less than c"); unique if ( a < b ) $display("\t a is less than
else $display("\t a is greater than b and c"); b");
end else if ( a < c ) $display("\t a is less than
endmodule c");
end
Output endmodule Output
a is less than b RT Warning: No condition matches in
More than one conditions match 'unique if' statement
in 'unique if' statement
Unique case
module unique_case (); module unique_case ();
byte a = 0; byte a = 0;
// unique case // unique case
always @ (*) always @ (*)
begin begin
unique case(a) unique case(a) inside
0,1: $display("Unique Case 0 or 1"); [0 : 3]: $display("Unique Case inside 0 to 3");
2 : $display("Unique Case 2"); 2 : $display("Unique Case inside 2");
4 : $display("Unique Case 4"); 4 : $display("Unique Case inside 4");
endcase endcase
end end Output
Endmodule endmodule Unique Case inside 0 to 3
Warning: More than one conditions
initial begin Output initial begin
match in 'unique case' statement.
repeat (7) begin Unique Case 0 or 1 repeat (7) begin Unique Case inside 0 to 3
Unique case 2
#1 a ++; #1 a ++; Unique Case inside 0 to 3
Unique Case 4
end end Unique Case inside 4
#1 $finish; #1 $finish;
end endmodule end endmodule
priority
priority if
• It evaluates all the conditions in sequential order.
• In the following conditions simulator issue a run time error/warning
• No condition is true or final if doesn’t have corresponding else
priority case
• A priority case acts only on first match.
priority if
No condition is true or final if doesn’t have corresponding value of a=10,b=20 and c=40.
else. conditions a<b and a<c are true, as it is priority
value of a=50,b=20 and c=40. conditions a<b and a<c based, simulator
are false, considers the first match. therefore there will be no
therefore simulator issue a run time warning. simulator warning message.
Output: Output
No condition matches in 'priority if' statement a is less than b
priority case
// A priority case acts only on first match.
module priority_case ();
byte a = 0;
// priority case
always @ (*)
begin
priority casez(a)
3'b00?: $display("Priority Casez 0 or 1"); 3'b0??: $display("Priority Casez
2 or 3");
endcase
end
endmodule
initial begin Output
repeat (7) begin Priority Casez 0 or 1
#1 a ++; Priority Casez 2 or 3
end Priority Casez 2 or 3
#1 $finish;
end endmodule
What are loops ?
module while_loop;
int a;
initial begin
$display("-----------------------------------------------------------------");
while(a<5) Output
begin Value of a=0
$display("\tValue of a=%0d",a); Value of a=1
a++; Value of a=2
end Value of a=3
$display("-----------------------------------------------------------------");
Value of a=4
end
endmodule
do-while loop
In do-while,
• the condition will be checked after the execution of statements inside the
loop
• the condition can be any expression
• do-while is similar to while loop but in case of while loop execution of
statements happens only if the condition is true.
• In a do while, statements inside the loop will be executed at least once
even if the condition is not satisfied.
do-while loop
module do_while;
int a;
initial begin
$display("-----------------------------------------------------------------");
do
begin//the condition will be checked after the execution of statements inside the
loop
$display("\tValue of a=%0d",a);
a++;
end Output:
while(a<5); Value of a=0
Value of a=1
$display("-----------------------------------------------------------------"); Value of a=2
end Value of a=3
endmodule
Value of a=4
foreach loop
• SystemVerilog foreach specifies iteration over the elements of an array.
• The loop variable is considered based on elements of an array and the
number of loop variables must match the dimensions of an array.
module for_loop; module for_loop;
int a[4];
int a[3][2];
initial begin
$display("---------------------------"); initial begin
foreach(a[i]) a[i] = i; $display("---------------------------");
foreach(a[i]) $display("\tValue of foreach(a[i,j]) a[i][j] = i+j;
a[%0d]=%0d",i,a[i]); foreach(a[i,j]) $display("\tValue of
$display("---------------------------");
a[%0d][%0d]=%0d",i,j,a[i][j]);
end
$display("--------------------------");
endmodule Output
Output end
Value of a[0]=0 Value of a[0][0]=0
Value of a[1]=1
endmodule Value of a[0][1]=1
Value of a[2]=2 Value of a[1][0]=1
Value of a[3]=3 Value of a[1][1]=2
Value of a[2][0]=2
Value of a[2][1]=3
break
The execution of a break statement leads to the end of the loop
break shall be used in all the loop constructs (while, do-while,
foreach, for, repeat and forever)
Syntax: break;
Continue
Execution of continue statement leads to skip the execution of
statements followed by continue and jump to next loop or
iteration value
Example for ‘break’
module break_in_do_while_loop; module break_in_loop; module repeat_loop_break;
int i; int i;
initial begin initial begin initial begin
$display("----------------"); $display("---------------------"); $display("----------------------");
i = 8; for(int i=0;i<8;i++) begin repeat(5) begin
do $display("\tValue of $display("\tValue of
begin i=%0d",i); i=%0d",i);
$display("\tValue of i=%0d",i); if(i == 4) begin if(i == 2) begin
if(i == 4) begin $display("\tCalling break,"); $display("\tCalling break,");
$display("\tCalling break,"); break; break;
break; end end
end end i++;
i--; $display("-------------------"); end
end end
while(i!=0); endmodule $display("----------------------");
$display("---------------"); end
end Output endmodule
endmodule Value of i=0
Output Value of i=1 Output
Value of i=8 Value of i=2 Value of i=0
Value of i=7 Value of i=3 Value of i=1
Value of i=6 Value of i=4 Value of i=2
Value of i=5 Calling break, Calling break
Value of i=4
Calling break,
Example for continue
module continue_in_loop;
initial begin
$display("-------------------------------------------------
----------------");
begin : "MY_NAMED_BLOCK1“
Fork : “MY_NAMED_BLOCK2”
@*
@ (*)
event expression , iff
For example: What this does is when reset is LOW, block will be
triggered
always blocks in System verilog
• Fork-join is executed only when all the child threads inside the fork-
join has finished
• So, the checker will have to wait until all the child threads in the fork-
join to finish before it can be proceed
Example: Assume that one set of input and output can be verified for every 1ns
Two 32-bit input stimulus i.e., 2^64 possible scenarios
To verify every scenario it takes 500 years simulation testing impossible
For large designs having different combination of specifying stimuli takes somuch of time,
that’s y going for randomisation
bit[31:0]A
bit[31:0]sum
FA
bit[31:0]B
random variable
• The class variables which get random values on randomization are called
random variables.
• In order to make variables as random variables, Class variables need to be
declared using the rand and randc type-modifier keywords.
• Following types can be declared as rand and randc,
singular variables of any integral type
arrays
arrays size
object handle’s
• In order to randomize the object variables, the user needs to call randomize()
method
• Example: object.randomize();
rand , randc
• rand keyword is used to randomize the • randc is random-cyclic.
variables • If randc keyword assign to
• If rand keyword assign to random random variables then same
variables then same values might be values doesn’t get repeat until
repeat, before all possible values have every possible value has been
been return over the entire range return
class packet; class packet;
rand bit [1:0] addr1; randc bit [2:0] addr1;
endclass endclass
Output Output
addr1 = 1 addr2 = 4
module rand_methods; module rand_methods;
addr1 = 4 addr2 = 2
initial begin initial begin
addr1 = 4 addr2 = 3
packet pkt; packet pkt;
addr1 = 2 addr2 = 1
pkt = new(); pkt = new();
addr1 = 3 addr2 = 0
repeat(10) begin repeat(10) begin
addr1 = 3 addr2 = 1
pkt.randomize(); pkt.randomize();
addr1 = 2 addr2 = 3
$display("\taddr1 = %0d \t addr2 $display("\taddr1 = %0d \ addr2 =
addr1 = 1 addr2 = 4
= %0d",pkt.addr1,pkt.addr2); %0d",pkt.addr1,pkt.addr2);
addr1 = 4 addr2 = 2
end end
addr1 = 2 addr2 = 0
end end
endmodule endmodule
random variable
• The variable declared without rand or randc will not get random values
on randomization
• What if for some reason it is required not to generate a random value for
a random variable
• Yes, it is possible to disable the randomization of a variable by using the
SystemVerilog randomization method rand_mode
rand_mode syntax
<object_hanlde>.<variable_name>.rand_mode(enable);
//enable = 1, randomization enable
//enable = 0, randomization disable
rand_mode method
class packet;
rand bit [7:0] addr;
randc bit wr_rd;
bit tmp_wr_rd;
• Simply running randomized tests do not make much sense because there
will be many invalid cases
• The way we create randomized tests with valid configuration is by use of
constraints
• Such verification style is called Constraint random verification
• In some situations it is required to control the values getting assigned on
randomization, this can be achieved by writing constraints.
• By writing constraints to a random variable, the user can get specific
value on randomization.
• Constraints to a random variable shall be written in constraint blocks.
Constraint blocks
• Constraint blocks are class members like tasks, functions, and variables
• Constraint blocks will have a unique name within a class
• Constraint blocks consist of conditions or expressions to limit or control
the values for a random variable
• Constraint blocks are enclosed within curly braces { }
• Constraint blocks can be defined inside the class or outside the class like
extern methods, constraint block defined outside the class is called as
extern constraint block
constraint addr_1_range { addr inside {[start_ad constraint addr_1_range { !(addr inside {[start_addr:end
dr:end_addr]}; } _addr]}); }
endclass endclass
The := operator assigns the specified The :/ operator assigns the specified weight
weight to the item, or if the item is a to the item, or if the item is a range,
range, specified weight to every specified weight/n to every value in the
value in the range. range. where n is the number of values in
the range.
addr dist { 2 := 5, [10:12] := 8 };
addr dist { 2 :/ 5, [10:12] :/ 8 };
for addr == 2 , weight 5 for addr == 2 , weight 5
addr == 10, weight 8 addr == 10, weight 8/3
addr == 11, weight 8 addr == 11, weight 8/3
addr == 12, weight 8 addr == 12, weight 8/3
:= :/
class packet; class packet;
rand bit [3:0] addr_1; rand bit [3:0] addr_1;
rand bit [3:0] addr_2; rand bit [3:0] addr_2;
• If the expression on the LHS of implication operator (->) is true, then the
only constraint on the RHS will be considered
Implication constraint
class packet;
rand bit [3:0] addr;
string addr_range;
constraint address_range { (addr_range == "small") -> (addr < 8);}
endclass
module constr_implication;
initial begin Output:
packet pkt;
addr_range = small addr = 6
pkt = new();
addr_range = small addr = 2
pkt.addr_range = "small"; addr_range = small addr = 1
$display("------------------------------------"); addr_range = small addr = 4
repeat(4) begin
pkt.randomize();
$display("\taddr_range = %s addr = %0d",pkt.addr_range,pkt.addr);
end
$display("------------------------------------");
end
endmodule
if else constraint
module static_constr;
initial begin
packet pkt;
pkt = new();
$display("Before Constraint disable");
$display("Value of constraint mode = %0d",pkt.addr_range.constraint_mode());
pkt.randomize();
$display("\taddr = %0d",pkt.addr);
//disabling constraint
pkt.addr_range.constraint_mode(0);
$display("After Constraint disable");
$display("Value of constraint mode = %0d",pkt.addr_range.constraint_mode());
pkt.randomize();
$display("\taddr = %0d",pkt.addr); Output
Before Constraint disable
end
Value of constraint mode = 1 addr = 15
Endmodule
After Constraint disable
Value of constraint mode = 0 addr = 1
//with constraint disabled //without constraint disabled
class packet;
rand bit [3:0] addr;
class packet;
constraint addr_range { addr inside {5,10,15}; } rand bit [3:0] addr;
endclass
constraint addr_range { addr inside {5,10}; }
module static_constr; endclass
initial begin
packet pkt; module static_constr;
pkt = new();
initial begin
$display("Before Constraint disable");
repeat(2) begin //{ packet pkt;
pkt.randomize(); pkt = new();
$display("\taddr = %0d",pkt.addr);
end //} pkt.randomize();
//disabling constraint $display("\taddr = %0d",pkt.addr);
pkt.addr_range.constraint_mode(0); end
$display("After Constraint disable");
Endmodule
repeat(2) begin //{
pkt.randomize();
$display("\taddr = %0d",pkt.addr);
end //}
end Output
Output
endmodule addr = 5
Before Constraint disable
addr = 15 addr = 5
After Constraint disable
addr = 9 addr = 14
Static constraint
• Constraints will be written inside the class. inline constraint allows the user
to add extra constraints to existing constraints written inside the class. inline
constraints will be written outside the class i.e along with the randomize
method call.
• The inline constraint is written using with keyword
• During randomization, constraint solver will consider both inline constraints
and constraints written inside the class
• The inline constraint will not override the constraints written inside the class
• The inline constraint shouldn’t conflict with the constraint written inside the
class, else it will lead to randomization failure
• For example, constraint inside the class written as var < 5, and inline
constraint written as var > 5
module func_constr;
initial begin
packet pkt;
pkt = new();
repeat(3) begin
pkt.randomize();
$display("\tstart_addr = %0d end_addr =",pkt.start_addr,pkt.end_addr);
end
end
endmodule
Soft Constraints
class packet;
rand bit a;
rand bit b;
Error-[CNST-CIF] Constraints
constraint a_value { a == 1; }
inconsistency failure testbench.sv,
constraint b_value { if(a == 0) b == 1;
18 Constraints are inconsistent and
else b == 0; }
cannot be solved. Please check the
endclass
inconsistent constraints being
printed above and rewrite them.
module bidirectional_const;
initial begin
packet pkt;
pkt = new();
pkt.randomize() with { b == 1; };
$display("Value of a = %0d \tb = %0d",pkt.a,pkt.b);
end
endmodule
Solve Before Constraints
• Solve before is the constraint property. solve before is used inside the
constraint block to specify the order of constraint solving
Syntax :constraint sab { solve a before b;}
• If the variables are dependent, due to the bidirectional nature of constraints
value of one variable will influence the value of another variable.
• Solve before constraints are used to force the constraint solver to choose
the order in which constraints are solved.
• Constraint solver will give equal weight-age to all the possible values. i.e On
multiple randomization solver should assign all the possible values.
class pakcet;
rand bit a;
rand bit [3:0] b;
constraint a_b { (a == 1) -> b == 0; } //a -> 0 and 1; 2 possible values
//b -> 0 to 15; 16 possible values
endclass
without solve before with solve before
class packet; class packet;
rand bit a; rand bit a;
rand bit [3:0] b; rand bit [3:0] b;
3. $urandom_range( )
• The $urandom_range() function returns an unsigned integer within a
specified range.
addr1 = $urandom_range(30,20);
addr2 = $urandom_range(20); //takes max value as '0'
addr3 = $urandom_range(20,30); //considers max value as '30' and min value
as '20'
$display("addr1=%0d, addr2=%0d, addr3=%0d",addr1,addr2,addr3);
end
endmodule
INTERPROCESS
SYNCHRONIZATION
AND
COMMUNICATION
Semaphore
• Semaphore is a SystemVerilog built-in class, used for access control to
shared resources, and for basic synchronization.
• A semaphore is like a bucket with the number of keys.
• Processes using semaphores must first procure a key from the bucket before
they can continue to execute, All other processes must wait until a sufficient
number of keys are returned to the bucket.
• Imagine a situation where two processes try to access a shared memory area.
• where one process tries to write and the other process is trying to read the
same memory location. this leads to an unexpected result.
• A semaphore can be used to overcome this situation.
• the new method will create the semaphore with number_of_keys keys in a
bucket; where number_of_keys is integer variable.
• the default number of keys is ‘0’
• the new() method will return the semaphore handle or null if the semaphore
cannot be created
put( );
• The semaphore put() method is used to return key/keys to a semaphore.
• When the semaphore_name.put() method is called, the specified number of keys
are returned to the semaphore.
• The default number of keys returned is 1.
Syntax:semaphore_name.put(number_of_keys);
or
semaphore_name.put();
get();
• The semaphore get() method is used to get key/keys from a semaphore.
• When the semaphore_name.get() method is called,
• If the specified number of keys are available, then the method returns and
execution continues
• If the specified number of keys are not available, then the process blocks until
the keys become available
• The default number of keys requested is 1
Syntax:semaphore_name.get(number_of_keys);
or
semaphore_name.sget();
//two processes accessing the same resource
module semaphore_ex;
semaphore sema; //declaring semaphore sema
initial begin
sema=new(1); //creating sema with '1' key
fork
display(); //process-1
display(); //process-2
join
end Output
#0 Current simulation time
//display method #30 Current simulation time
task automatic display();
sema.get(); //getting '1' key from sema
$display($time,"\tCurrent Simulation Time");
#30;
sema.put(); //putting '1' key to sema
endtask
endmodule
Mailbox
• A mailbox is a communication mechanism that allows messages to be
exchanged between processes.
• The process which wants to talk to another process posts the message to a
mailbox, which stores the messages temporarily in a system defined memory
object, to pass it to the desired process.
Based on the sizes mailboxes are categorized as,
• bounded mailbox
• unbounded mailbox
A bounded mailbox is with the size defined. mailbox becomes full when on
storing a bounded number of messages.
• A process that attempts to place a message into a full mailbox shall be
suspended until enough space becomes available in the mailbox queue.
Unbounded mailboxes are with unlimited size.
Mailbox types
• There are two types of mailboxes,
Generic Mailbox
Parameterized mailbox
• Mailbox only has fifo element ordering, • In queue we can access head,tail and
can’t access specific index of mailbox middle of the elements
.
• Here we can use push,pop methods to
• mailbox is an higher level concept that store and elements from queue
is built in class around a combination
of queues and semaphores. Here we • Queue can be bounded and
can put,get methods unbounded
• Events are static objects useful for synchronization between the process.
• Events operations are of two staged processes in which one process will
trigger the event, and the other processes will wait for an event to be
triggered.
• Events are triggered using -> operator or ->> operator
• wait for an event to be triggered using @ operator or wait() construct
• SystemVerilog events act as handles to synchronization queues.
• Thus, they can be passed as arguments to tasks, and they can be assigned to
one another or compared.
1. Event triggering
i. -> operator
• Named events are triggered via the -> operator.
• Triggering an event unblocks all processes currently waiting on that event.
ii. ->> operator
• Non-blocking events are triggered using the ->> operator.
iii. wait_order();
• The wait_order construct is blocking the process until all of the specified
events are triggered in the given order (left to right). event trigger with out
of order will not unblock the process.
wait_order(a,b,c);
• Blocks the process until events a, b, and c trigger in the order a –> b –> c. If
the events trigger out of order, a run-time error is generated.
wait_order(a,b,c); else $display (“events out of order”);
• In this example, the fail statement specifies that upon failure of the
construct, a user message is displayed, but without an error being generated.
//the event waiting with @ operator //trigger first and then waiting for a trigger
module events_x();
module events_ex; event ev_1; //declaring event ev_1
event ev_1; //declaring event ev_1 initial begin
fork
initial begin //process-1, triggers the event
fork begin
//process-1, triggers the event #40;
begin $display($time,"\tTriggering The Event");
#40; ->ev_1;
$display($time,"\tTriggering The Event"); end
->ev_1; //process-2, wait for the event to trigger
end begin
$display($time,"\tWaiting for the Event to
//process-2, wait for the event to trigger trigger");
begin #60;
$display($time,"\tWaiting for the Event to @(ev_1.triggered);
trigger"); $display($time,"\tEvent triggered");
@(ev_1.triggered); end
join Output
$display($time,"\tEvent triggered");
end #0Waiting for the Event to trigger
end
join Output initial begin #40 Triggering The Event
#0Waiting for the Event to trigger #100; #100 Ending the simulation
end
endmodule #40 Triggering The Event $display($time,"\tEnding the Simulation");
#40 Event triggered $finish;
end
endmodule
Program block
• The Program construct provides a race-free interaction between the design and
the testbench
• All elements declared within the program block will get executed in the Reactive
region.
• Suppose if we r writing both design & tb using module block, both executed in
active region then race around condition will occurred.
• Non-blocking assignments within the module are scheduled in the active region,
initial blocks within program blocks are scheduled in the Reactive region.
• Statements within a program block (scheduled in the Reactive region) that are
sensitive to changes in design signals declared in modules (scheduled in the
active region)
• An active region is scheduled before the reactive region this avoids the race
condition between testbench and design.
program test(input clk, input [7:0] addr, output [7:0] wdata);
...
endprogram
or
program test (interface mem_intf);
...
endprogram
Program block,
• can be instantiated and ports can be connected the same as a module
• can contain one or more initial blocks
• cannot contain always blocks, modules, interfaces, or other programs
• In the program block, variables can only be assigned using blocking
assignments.
• Using non-blocking assignments within the program shall be an error
• They are typically instantiated at the top-level
• Clocks are never generated in program blocks
• In conjunction with clocking blocks, program blocks schedule events in the
“Reactive region” of the stratified queue thereby helping prevent race
conditions that exist between the design and the testbench
• Program block can be used inside interface and module
Difference b/w module & program blocks
Module block Program block
2. The modport is specified directly when instantiating the modules that connect
to the interface signals in the top level module
module top();
logic clk = 1'b0; logic reset= 1'b0;
initial begin
// Clock Generation Logic forever #25 clk = ~clk;
// Reset Generation Logic #150 reset = 1’b0;
end
arb_interface arbif(clk, reset); // Interface Instantiation arbiter
duv(arbif.FOR_DUV); // Arbiter DUV Instantiation testbench
tb(arbif.FOR_TB); // Testbench Instantiation
endmodule
Clocking block
Clocking signal
• Signals sampled and driven by the clocking block, from_DUT and to_DUT
are the clocking signals
Clocking skew
• Clocking skew specifies the moment (w.r.t clock edge) at which input and
output clocking signals are to be sampled or driven respectively. A skew must
be a constant expression and can be specified as a parameter.
Clocking block events
• The clocking event of a clocking block is available directly by using the
clocking block name, regardless of the actual clocking event used to declare
the clocking block.
• The clocking event of the cb clocking block can be used to wait for that
particular event: @(cb).
• The above statement is equivalent to @(posedge clk).
Cycle delay: ##
• The ## operator can be used to delay execution by a specified number of
clocking events, or clock cycles.
Example:
## 8; // wait 8 clock cycles
## (a + 1); // wait a+1 clock cycles
Example:
clocking grp_sysclk@(posedge sysclk);
default input #10ns output #3ns;// Clocking skews defined here input request, enable, data;
output negedge grant;
// Override the default output skew - grant is driven on the negative edge of sysclk
input #1step addr;
// Override the default input skew – address is sampled one step before the positive edge of sysclk
endclocking
• In the example shown, default keyword defines the default skews for inputs
(10ns) and outputs (3ns)
• Unless otherwise specified, the default input skew is 1step and the default
output skew is 0. A 1step skew is the negative time delay from the edge of a
clock when all inputs are steady and ready to be sampled
• Default skews can be overridden for any signal with what the user specifies
ASSERTIONS
Introduction
• The optional statement label (identifier and colon) creates a named block around
the assertion statement
• The pass statement is executed if the expression evaluates to true
• The statement associated with else is called a fail statement and is executed if the
expression evaluates to false
• Both pass and fail statements are optional
different forms of immediate assertion syntax
/With Pass and Fail statement; Fail verbosity //Only With Fail statement; Multiple statements in
info; Faile condition and Fail verbosity fatal;
assert(expression) assert(expression)
else
$display(“expression evaluates to true”); begin
else …….
$display(“expression evaluates to false”); …….
$fatal(“expression evaluates to false”);
//Only With Pass statement; end
assert(expression)
$display(“expression evaluates to true”); //Only With Fail statement; Fail verbosity warning;
assert(expression)
else
//With Pass and Fail statement; Fail verbosity $warning(“expression evaluates to false”);
fatal;
assert(expression) //With Label and Fail statement; Fail verbosity
$display(“expression evaluates to true”); warning;
else label: assert(expression)
$fatal(“expression evaluates to false”); else
$warning(“expression evaluates to false”);
Severity levels
• Assertion is a statement that something must be true, the failure of an assertion
shall have a severity associated with it.
• By default, the severity of an assertion failure is an error.
• Other severity levels can be specified by including one of the following severity
system tasks in the fail statement:
1. $fatal is a run-time fatal.
2. $error is a run-time error.
3. $warning is a run-time warning, which can be suppressed in a tool-
specific manner.
4. $info indicates that the assertion failure carries no specific severity.
• If an assertion fails and no else clause is specified, the tool shall, by default call
$error.
• Severity can optionally include further message information using $display
syntax
Concurrent assertions
• Concurrent assertions check the sequence of events spread over multiple
clock cycles.
• The concurrent assertion is evaluated only at the occurrence of a clock tick
• The test expression is evaluated at clock edges based on the sampled values of
the variables involved
• It can be placed in a procedural block, a module, an interface or a program
definition
Syntax: c_assert: assert property(@(posedge clk)
not(a && b));
• The Keyword differentiates the immediate assertion from the concurrent
assertion is “property”
• Sampling of variables is done in preponed region and evaluation of
expression is done in the observed region, execute pass/fail statement in
reactive region
• It is a temporal check i.,e behavior is only checked at clock signals
Concurrent assertion layers
Boolean expressions
(<expr>,<function>, ended,
matched)
Sequence
(repetition, cycle delay,and or
within, intersect, throughout)
Property
(disable iff, not, implication)
Assert property
Assert, cover,bind, procedural
instantion, declarative instantion
Boolean expressions
• The functionality is represented by the combination of multiple logical events.
• These events could be simple Boolean expressions
• Boolean Expressions are allowed to include function calls, but certain semantic
restrictions are imposed
1. Functions that appear in expressions cannot contain output or ref arguments
2. Functions should be automatic and have no side effects.
• Boolean layer can not use following Operator types shortreal, real, and realtime,
String, Event, Chandle, Class, Associative ar, rays,Dynamic arrays
• All operators other then assignment, increment and decrement operators can be
used in Boolean layer.
Example:
module assertion_boolean();
wire ce, en; 4 wire [7:0] addr;
(en && ce && addr < 100); // Boolean expression
endmodule
sequence
• Temporal properties are described using sequences
• Boolean expression events that evaluate over a period of time involving
single/multiple clock cycles
• Sequence is nothing but Series of Boolean equations, these are the building
blocks of properties
• A sequence can be declared in module, interface, program, clocking block,
package
• One sequence can call another sequence
• The list of operators that sequence are build upon ##, [* ], [= ], [-> ], throughout,
within Left, intersect, and, or
Example: Example:
sequence name_of_sequence; sequence sequence;
…@(posedge clk) a##1 b ##1c; (a##[2:3]b) or (c##[1:2]d);
endsequence endsequence
## operator
Example:
req ##1 gnt // Means gnt happens one clock cycle later of req.
req ##0 gnt //Means gnt happens on same edge as req getting asserted. Normally
this is used for merging two sequence.
req ##[0:3] gnt //Means gnt will be asserted 0 to 3 clock cycles after req is
asserted.
$ operator
Example:
req ##[1:$] gnt;
req
gnt 1 $
repetition operators
Syntax: Syntax:
signal [*n] or sequence [*n] sequence a_b;
@(posedge clk) a##1 b[*2:5];
endsequence
"n" is the number of repetitions //b[2:5]means ‘b’ must be true for min 2
consecutive cycles and max 5 consecutive cycles
b
b should be continuously high
2 to 5 clk cycles
Go to repetition operators
• This allows the user to specify that an expression will match the
number of times specified not necessarily on continuous clock
cycles.
• The matches can be intermittent.
• The main requirement of a "go to" repeat is that the last match
on the expression checked for repetition should happen in
the clock cycle before the end of the entire sequence matching.
• The simple syntax of "go to" repetition operator is shown below.
Signal [->n]
Syntax:
sequence a_b;
@(posedge clk)
(!start) ##2 (a[->3]) ##1 stop;
endsequence
Non-Consecutive repetition
• This is very similar to "go to" repetition except that it does not
require that the last match on the signal repetition happen in
the clock cycle before the end the entire sequence matching.
• The simple syntax of a non-consecutive repetition operator is
shown below. Signal [=n]
Syntax:
sequence a_b;
@(posedge clk)(!start) ##2 {a[=3]) ##1 stop ##1 !stop
endsequence
"and" construct
• The binary operator "and" can be used to combine two sequences logically.
• The final property succeeds when both the sequences succeed.
• Both sequences must have the same starting point but they can have
different ending points.
• The starting point of the check is when the first sequence succeeds and the
end point is when the other sequence succeeds, ultimately making the
property succeed
Example
sequence s1;
@(posedge clk )a##[l:2] b; //The property p1
endsequence
combines them with an
sequence s2; and operator. The property
@(posedge clk ) c##[2:3] d; succeeds when both the
endsequence sequences succeed.
property p1;
@(posedge clk ) s1 and s2;
endproperty
label: assert property(p1);
“or" construct
• The binary operator "or" can be used to combine two sequences logically.
• The final property succeeds when any one of the sequence succeeds.
• Sequence s1 and s2 are two independent sequences.
• The property p1 combines them with an or operator.
• The property succeeds when any one of the sequence succeeds
Example
sequence s1;
@(posedge clk )a##[l:2] b; //The property p1
endsequence combines them with an or
operator. The property
sequence s2; succeeds when any one of
@(posedge clk ) c##[2:3] d; the sequences succeed.
endsequence
property p1;
@(posedge clk ) s1 or s2;
endproperty
label: assert property(p1);
“intersect" construct (and with length restriction)
• The "intersect" operator is very similar to the "and" operator with one
additional requirement.
• Both the sequences need to start at the same time and complete at the
same time.
• In other words, the length of both sequences should be the same.
• Property p28 checks for the same condition as property p27. The only
difference is that it uses the intersect construct instead of the and construct.
Example
sequence s1;
@(posedge clk )a##[l:2] b; //The property p27
endsequence
combines them with an
sequence s2; and operator. The property
@(posedge clk ) c##[2:3] d; succeeds when both the
endsequence sequences succeed.
property p1;
@(posedge clk ) s1 intersect s2;
endproperty
label: assert property(p1);
first_match
• The first match operator matches only the first of possibly multiply
matches.
• Remaining matches are discarded
Example
Example
• $sampled: Returns the sampled value of the expression with respect to the last
occurrence of the clocking event
• $rose: Returns true if the least significant bit of the expression changed to 1.
Otherwise it returns false.
• $fell: Returns true if the least significant bit of the expression changed to 0.
Otherwise it returns false.
• $stable: Returns true if the value of the expression did not change. Otherwise it
returns false
"$past" construct
• SVA provides a built in system task called $past that is capable of getting values
of signals from previous clock cycles.
• By default, it provides the value of the signal from the previous clock cycle.
• The simple syntax of this construct is as follows.
$past (signal_name, number of clock cycles)
Property pl9;
©(posedge clk) b|-> ($past (a, 2) == 1'b1);
endproperty
al9: assert property (pl9);
• Property checks that, in the given positive clock edge, if the “b” is high, then 2
cycles before that, “a” was high
$past construct with clock gating
• $past construct can be used with a gating signal. on a given clock edge, the gating
signal has to be true even before checking for the consequent condition
$past (signal_name, number of clock cycles, gating signal)
Property pl9;
©(posedge clk) b|-> ($past (a, 2,c) == 1'b1);
endproperty
al9: assert property (pl9);
• Property checks that, in the given positive clock edge, if the “b” is high, then 2
cycles before that, a was high only if the gating signal “c’ is valid on any given
positive edge of the clock.
Property
• Property layer is built on top of sequence layer.
• It uses zero or more sequence to check a design assumption.
• zero assertions because, property layer can contain boolean layer directly.
• In order to use the behavior for verification, an assert, assume, or cover statement
must be used.
• A property declaration by itself does not produce any result. Result of a property
like in the case of a sequence is either true or false.
• Properties can be declared in module, interface, program, clocking block,
package
• Properties can have following kinds a sequence, Negation, Disjunction,
Conjunction, if..else, implication, Another named property
property name_of_property;
test expression or
complex sequence expressions
endproperty
Forbidding property
• The property is checking for a true condition.
• A property can also be forbidden from happening.
• In other words, we expect the property to be false always.
• If the property is true, the assertion fails.
sequence seq;
@(posedge clk) a ##2 b; //signal “a” is high on a given positive edge of the clock,
then after 2 clock cycles, signal “b” shall not be high.
endsequence
property p;
not seq;// The keyword “not” is used to specify that the property should never be true.
endproperty
a_1: assert property(p);
Another named property
• One property can call another property, this is allowed for performing operation
property p1;
req ##1 gnt;
endproperty
property nameproperty_prop;
@ (posedge clk)p1;
endproperty
nameproperty_assert : assert property (nameproperty_prop);
Negation property
• A negation property is same as logic not operator on outcome of a propery. So if
the outcome is true, then negation makes it false
property negation_prop;
@ (posedge clk) not (req ##1 gnt);
endproperty
negation_assert : assert property (negation_prop);
Implication operator
property p;
@(posedge clk) a |-> b;
//“a” is high on a given positive clock edge, then signal
“b” should also be high on the same clock edge.
endproperty
a: assert property(p);
• @(posedge clk) a |-> ##2 b; // signal “a” is high on a given positive clock
edge, then signal “b” should be high after 2 clock cycles .
Non-Overlapped Implication operator
property p;
@(posedge clk)
disable iff (reset) // disabling rst i.e 0 while execute whole property
a |-> ##1 b[->3] ##1 c; // disable iff(!reset), if reset is detected low at
any point , the checker will stop
endproperty
a: assert property(p);
$asserton(), $assertoff(), $assertkill()
• And RTL designer does not want verification engineer to modify his RTL for
the sake of adding assertion then, bind feature of SystemVerilog comes for
rescue.
• One can write all the assertion he or she wants to write in a separate file and
using bind, he or she can bind the ports of his assertion file with the
port/signals of the RTL in his testbench code.
sequence req_gnt_seq;
(~req_ip & gnt_ip) ##1 (~req_ip & ~gnt_ip);
endsequence
property req_gnt_prop;
@ (posedge clk_ip) disable iff (reset_ip) 17 req_ip |=> req_gnt_seq;
endproperty
Block coverage
• It is similar to statement coverage
• The difference is block coverage considers branched blocks of if-else, case, wait
while, for etc.
Conditional/expression coverage
• It reveals how the variables and sub-expressions in conditional statements are
evaluated. Expressions with logical operators only considered
• Conditional coverage is the ratio of no.of cases checked to the totoal no. of cases
present
• Branch/decision coverage
• It reports true or false conditions like if-else, case and ternary operator(?:)
statements
• For an if-else statement branch coverage will report whether the if-else statement is
evaluated in true or false cases
Statement coverage / line coverage
• From n lines of code and according to the applied stimulus how many statements
covered in the simulation is measured by statement coverage
• If a dut has 10 lines long and 8 lines of them are exercised then the dut has line
coverage of 80%
• Line coverage includes continuous assignment statements, procedural block
statements, conditional statements
• It considers only executable statements and statements which are not executable like
module, endmodule, comments, timescale etc are not covered
Block coverage
• It is similar to statement coverage
• The difference is block coverage considers branched blocks of if-else, case, wait
while, for etc.
Why can't I just use code coverage?
• Code coverage tracks what lines of code or expressions in the code have
been exercised.
• Code coverage cannot detect conditions that are not in the code.
• For example, in the packet bus item coverage example discussed above,
code coverage cannot determine that the required values or ranges have
occurred - unless the code contains expressions to test for each of these sizes.
• Instead, we need to write functional coverage.
• In the ALU cross coverage example above, code coverage cannot determine
whether particular register pairs have been used together, unless the code is
written this way.
• Generally each input to the ALU is selected independently of the other.
• Again, we need to write functional coverage.
Cont,,,,
• Code coverage on a partially implemented design can reach 100%.
• It cannot detect missing features (oops forgot to implement one of the timers)
and many boundary conditions (in particular those that span more than one
block).
• Hence, code coverage cannot be used exclusively to indicate we are done
testing.
• In addition, code coverage is an optimistic metric.
• In combinational logic code in an HDL, a process may be executed many
times during a given clock cycle due to delta cycle changes on input signals.
• This can result in several different branches of code being executed.
• However, only the last branch of code executed before the clock edge truly
has been covered.
What is Functional Coverage?
• In CRV all the features are generated randomly. Verification engineer needs
to know information about the verified feature of DUT
• System verilog provides a mechanism to know the untested feature using
functional coverage
• Functional coverage is important to any verification approach since it is one
of the factors used to determine when testing is done.
• Specifically, 100% functional coverage indicates that all items in the test
plan have been tested.
• Combine this with 100% code coverage and it indicates that testing is done
Contin…
Control-oriented Coverage –
• Checks whether sequences of behaviors have occurred.
• We can get assertion coverage by writing SystemVerilog Assertions
What is the difference between code coverage
and functional coverage?
• Code coverage will give information about how many lines are executed,
how many times expressions, branches executed.
• It doesn't know anything about what design supposed to do.
• This coverage is collected by the simulation tools.
• Users use this coverage to reach those corner cases which are not hit by the
random test-cases.
• Users have to write the directed test-cases to reach the missing code
coverage areas.
• Functional coverage, by the name it-self is related to the functionality of the
design and it is defined by the user.
• User will define the coverage points for the functions to be covered in DUT.
This is completely under user control.
If code coverage is 100% and functional coverage is not, then what does it
mean?
• Reason could be any one of the following,
• 1) There could be a bug in the functional coverage block which is not
recording the execute scenario User need to debug to find and fix the issue.
• 2) User did not exercise all the scenarios. User need to write test-cases to fill
the functional coverage holes.
• 3) Even if a feature is not implemented in design, code coverage can report
100% coverage, but functional does not.
If functional coverage is 100% and code coverage is not, then what does it
mean?
• 1) The functional coverage will hit due to faulty pass but some of the DUT
code may not get exercised.
• 2) If DUT is a configurable IP, it may has some use less code to support
additional functionality, due to this code coverage will not be achieved 100%.
• 3) RTL designer add a code for new feature, but due to miscommunication
between designer and verification engineer, when verification engineer did
code coverage, he didn’t get 100% code coverage.
Test Done = Test Plan Executed and All
Code Executed
• To know testing is done, we need to know that both the test plan is executed
and all of the code has been executed.
• Is 100% functional coverage enough?
• Unfortunately a test can reach 100% functional coverage without reaching
100% code coverage.
• This indicates the design contains untested code that is not part of the test
plan.
• This can come from an incomplete test plan, extra undocumented features in
the design, or case statement others branches that do not get exercised in
normal hardware operation.
• Untested features need to either be tested or removed.
• As a result, even with 100% functional coverage it is still a good idea to use
code coverage as a fail safe for the test plan.
Why You Need Functional Coverage,
even with Directed Testing
• You might think, "I have written a directed test for each item in the test plan,
I am done right?"
• As design size grows, the complexity increases. A test that completely
validates one version of the design, may not validate the design after
revisions.
• For example, if the size a of FIFO increases, the test may no longer provide
enough stimulus values to fill it completely and cause a FIFO Full condition.
• If new features are added, a test may need to change its configuration
register values to enable the appropriate mode.
• Without functional coverage, you are assuming your directed, algorithmic,
file based, or constrained random test actually hits the conditions in your test
plan.
• Whether you are using directed, algorithmic, file based, or constrained
random test methods, functional coverage provides your supporting data.
Defining the coverage model
• coverage model is defined using Covergroup construct.
• The covergroup construct is a user-defined type.
• The type definition is written once, and multiple instances of that type can
be created in different contexts.
• Similar to a class, once defined, a covergroup instance can be created via the
new()operator.
• A covergroup can be defined in a module, program, interface, or class.
Each covergroup specification can include
• A clocking event that synchronizes the sampling of coverage points
• A set of coverage points
• Cross coverage between coverage points
• Optional formal arguments
• Coverage options
Covergroup example
• In the example-1 clocking, event specifies the event at which coverage points
are sampled.
• In the example-2 coverage, sampling is triggered by calling a built-in
sample() method.
• A Cover group is defined between key words covergroup & endgroup.
• A Covergroup Instance can be created using the new() operator.
Example:1 Example:2
covergroup cov_grp @(posedge clk); covergroup cov_grp;
cov_p1: coverpoint a;
cov_p1: coverpoint a; endgroup
endgroup
cov_grp cov_inst = new(); cov_grp cov_inst = new();
@(abc) cov_inst.sample();
Defining coverage points
module cov;
logic clk;
Below are the bins, will get created automatically,
logic [7:0] addr;
logic wr_rd;
for addr: c1.auto[0] c1.auto[1] c1.auto[2] …
c1.auto[255]
covergroup cg @(posedge clk); for wr_rd: c2.auto[0]
c1: coverpoint addr;
c2: coverpoint wr_rd;
endgroup : cg
cg cover_inst = new();
...
endmodule
Explicit bins
• “bins” keyword is used to declare the bins explicitly to a variable.
• A separate bin is created for each value in the given range of variable or a
single/multiple bins for the rage of values.
• Bins are explicitly declared within curly braces { } along with the bins
keyword followed by bin name and variable value/range, immediately after
the cover point identifier.
Explicit bins example
module cov;
logic clk;
logic [7:0] addr;
logic wr_rd;
program main;
bit [0:3] y;
bit [0:2] values[$]= '{3,5,6};
covergroup cg;
cover_point_y : coverpoint y {
bins trans[] = (3,4=>5,6);
} example
endgroup bin trans creates 4 bin for covering
cg cg_inst = new(); 3=>5,4=>5,3=>6 and 4=>6.
initial
foreach(values[i])
begin
y = values[i];
cg_inst.sample();
end
endprogram
Consecutive Repetitions
• Consecutive repetitions of transitions are specified using
trans_item [* repeat_range ]
• Here, trans_item is repeated for repeat_range times.
program main;
bit [0:3] y;
bit [0:2] values[$]= '{3,3,3,4,4};
covergroup cg;
cover_point_y : coverpoint y {
bins trans_3 = (3[*5]); For example,
bins trans_4 = (4[*2]); 3 [* 5] is the same as 3=>3=>3=>3=>3
}
endgroup
cg cg_inst = new();
initial
foreach(values[i])
begin
y = values[i];
cg_inst.sample();
end
endprogram
Range Of Repetition
program main;
bit [0:3] y;
bit [0:2] values[$]= '{4,5,3,3,3,3,6
• For example,
,7};
covergroup cg;
An example of a range of repetition is:
cover_point_y : coverpoint y { 3 [* 3:5]
bins trans_3[] = (3[*3:5]); is the same as
} 3=>3=>3, 3=>3=>3=>3,
endgroup 3=>3=>3=>3=>3
cg cg_inst = new(); • In the above example, only the sequence
initial 3=>3=>3=>3 is generated. Other expected
foreach(values[i])
sequences 3=>3=>3 and
begin
y = values[i];
3=>3=>3=>3=>3 are not generated
cg_inst.sample();
end
endprogram
Goto Repetition
• goto repetition is specified using: trans_item [-> repeat_range].
• The required number of occurrences of a particular value is specified by the
repeat_range.
• Any number of sample points can occur before the first occurrence of the
specified value and any number of sample points can occur between each
occurrence of the specified value.
• The transition following the goto repetition must immediately follow the last
occurrence of the repetition.
• For example: 3 [-> 3] is the same as ...=>3...=>3...=>3 where the dots (...)
represent any transition that does not contain the value 3.
• A goto repetition followed by an additional value is represented as follows:
1 => 3 [ -> 3] => 5 is the same as 1...=>3...=>3...=>3 =>5
Go to Repetition example
program main;
bit [0:3] y;
bit [0:2] values[$]= '{1,6,3,6,3,6,3,5};
covergroup cg;
cover_point_y : coverpoint y {
bins trans_3 = (1=>3[->3]=>5); } 1 => 3 [ -> 3] => 5 is the same
as 1...=>3...=>3...=>3 =>5
endgroup
cg cg_inst = new();
initial
foreach(values[i])
begin
y = values[i];
cg_inst.sample();
end
endprogram
Non Consecutive Repetition
• The nonconsecutive repetition is specified using: trans_item [= repeat_range].
• The required number of occurrences of a particular value is specified by the
repeat_range.
• Any number of sample points can occur before the first occurrence of the
specified value and any number of sample points can occur between each
occurrence of the specified value.
• The transition following the nonconsecutive repetition may occur after any
number of sample points so long as the repetition value does not occur again.
For example:
3 [= 2] is same as ...=>3...=>3
• A nonconsecutive repetition followed by an additional value is represented as
follows:
1 => 3 [=2] => 5 is the same as 1...=>3...=>3...=>5
Non consecutive Repetition example
program main;
bit [0:3] y;
bit [0:2] values[$]= '{1,6,3,6,3,6,5};
covergroup cg;
cover_point_y : coverpoint y {
bins trans_3 = (1=>3[=2]=>5); 1 => 3 [=2] => 5
} is the same as
1...=>3...=>3...=>5
endgroup
cg cg_inst = new();
initial
foreach(values[i])
begin
y = values[i];
cg_inst.sample();
end
endprogram
Wildcard bins
• By default, a value or transition bin definition can specify 4-state values.
• When a bin definition includes an X or Z, it indicates that the bin count should
only be incremented
• when the sampled value has an X or Z in the same bit positions.
• The wildcard bins definition causes all X, Z, or ? to be treated as wildcards for 0
or 1 (similar to the ==? operator).
• For example:
wildcard bins g12_16 = { 4'b11?? };
The count of bin g12_16 is incremented when the sampled variable is between 12
and 16:
1100 1101 1110 1111
wildcard bins example
wildcard bins g12_16 = { 4'b11?? }; wildcard bins T0_3 = (2'b0x => 2'b1x);
The count of bin g12_16 is incremented The count of transition bin T0_3 is
when the sampled variable is between 12 incremented for the following transitions
and 16: (as if by (0,1=>2,3)):
1100 1101 1110 1111 00 => 10 , 00 => 11, 01 => 10 , 01 => 1
1
program main; program main;
reg [0:3] y; reg [0:1] y;
reg [0:3] values[$]= '{ 4'b1100,4'b1101,4'b1 reg [0:1] values[$]= '{ 2'b00,2'b01,2'b10,
110,4'b1111}; 2'b11};
covergroup cg; covergroup cg;
cover_point_y : coverpoint y { cover_point_y : coverpoint y {
wildcard bins g12_15 = { 4'b11?? } ; } wildcard bins trans = (2'b0X => 2'b1X ); }
endgroup endgroup
cg cg_inst = new(); cg cg_inst = new();
initial initial
foreach(values[i]) foreach(values[i])
begin begin
y = values[i]; y = values[i];
cg_inst.sample(); cg_inst.sample();
end end
endprogram endprogram
ignore bins
• A set of values or transitions associated with a coverage-point can be explicitly
excluded from coverage by specifying them as ignore_bins.
covergroup cg;
cover_point_y : coverpoint y {
ignore_bins ig = {1,2,3,4,5}; In the above program, total
} possible values for y are 0 to 7.
Ignore_bins specified to Ignored
endgroup
values between 1 to 5.
cg cg_inst = new();
So the Expected values are 0,6
initial and 7. Out of these expected
foreach(values[i]) values, only 6 and 7 are
begin generated.
y = values[i];
cg_inst.sample();
end
endprogram
illegal_bins
• A set of values or transitions associated with a coverage-point can be marked as
illegal by specifying them as illegal_bins
• All values or transitions associated with illegal bins are excluded from coverage.
If an illegal value or transition occurs, a runtime error is issued.
endgroup : cg
illegal bins example
program main;
bit [0:2] y;
bit [0:2] values[$]= '{1,6,3,7,3,4,3,5};
covergroup cg;
cover_point_y : coverpoint y {
illegal_bins ib = {7}; Result:
} ------------
** ERROR **
endgroup
Illegal state bin ib of coverpoint
cg cg_inst = new();
cover_point_y in
initial covergroup cg got hit with value
foreach(values[i]) 0x7
begin
y = values[i];
cg_inst.sample();
end
endprogram
Cross coverage
• Cross Coverage is specified between the cover points or variables. Cross
coverage is specified using the cross construct.
• Expressions cannot be used directly in a cross; a coverage point must be explicitly
defined first.
Cross coverage by cover_point name Cross coverage by the variable name
bit [3:0] a, b;
bit [3:0] a, b;
covergroup cov @(posedge clk);
covergroup cg @(posedge clk);
aXb : cross a, b;
c1: coverpoint a; endgroup
c2: coverpoint b; //cross of a and b (labeled aXb), therefore,
c1Xc2: cross c1,c2; has 256 cross products, and each cross
endgroup : cg product is a bin of aXb.
Cross coverage between variable and expression
• The coverage group cov has the same number of cross products as the previous
example
• But in this case, one of the coverage points is the expression b+c, which is labeled
BC.
program main;
bit [3:0] a, b, c;
bit [0:1] y;
covergroup cov @(posedge clk);
bit [0:1] y_values[$]= '{1,3};
BC : coverpoint b+c;
bit [0:1] z;
aXb : cross a, BC;
bit [0:1] z_values[$]= '{1,2};
endgroup.
covergroup cg;
cover_point_y : coverpoint y ;
cover_point_z : coverpoint z ;
In the program, y has can have 4 values 0,1,2 and cross_yz : cross cover_point_y,cover_point_z ;
3 and similarly z can have 4 values 0,1,2 and 3. endgroup
The cross product of the y and z will be 16 values cg cg_inst = new();
(00),(01),(02),(03),(10),(11)........(y,z)......(3,2)(3,3) initial
. foreach(y_values[i])
Only combinations (11) and (32) are generated. begin
Cross coverage report: cover points are not y = y_values[i];
shown. Covered bins z = z_values[i];
cover_point_y cover_point_z cg_inst.sample();
auto[3] auto[2] end
auto[1] auto[1] endprogram
Coverage options
• Options control the behavior of the covergroup, coverpoint, and cross.
• There are two types of options:
• those that are specific to an instance of a covergroup and
• those that specify an option for the covergroup type as a whole
• Weight
Syntax : weight= number
default value: 1
Description : If set at the covergroup syntactic level, it specifies the weight of this
covergroup instance for computing the overall instance coverage of the
simulation.
• If set at the coverpoint (or cross) syntactic level, it specifies the weight of a
coverpoint (or cross) for computing the instance coverage of the enclosing
covergroup.
• The specified weight shall be a non-negative integral value.
Coverage options
• Goal
Syntax :goal=number
default value: 100
Description :
Specifies the target goal for a covergroup instance or for a coverpoint or a
cross of an instance.
• Name
Syntax :name=string
default value:unique name
Description :
Specifies a name for the covergroup instance. If unspecified, a unique name
for each instance is automatically generated by the tool.
Coverage options
• Comment
Syntax :comment=string
default value: ""
Description : A comment that appears with a covergroup instance or with a
coverpoint or cross of the covergroup instance.
The comment is saved in the coverage database and included in the coverage
report.
• At_least
Syntax :at_least=number
default value: 1
Description : Minimum number of hits for each bin.
A bin with a hit count that is less than number is not considered covered.
Coverage options
• Detect_overlap
Syntax :detect_overlap=Boolean
default value: 0
Description : When true, a warning is issued if there is an overlap between the
range list (or transition list) of two bins of a coverpoint.
• Auto_bin_max
Syntax :auto_bin_max=number
default value: 64
Description :
Maximum number of automatically created bins when no bins are explicitly
defined for a coverpoint.
Continu….
• Cross_num_print_missing
Syntax :cross_num_print_missing=number
default value: 0
Description : Number of missing (not covered) cross product bins that shall be
saved to the coverage database and printed in the coverage report.
• Per_instance
Syntax :per_instance=Boolean
default value: 0
Description : Each instance contributes to the overall coverage information for
the covergroup type.
When true, coverage information for this covergroup instance shall be saved in
the coverage database and included in the coverage report.
When false, implementations are not required to save instance-specific
information.
Continu….
Get_inst_coverage
Syntax :get_inst_coverage=Boolean
default value: 0
Description :
Only applies when the merge_instances type option is set .
Enables the tracking of per instance coverage with the get_inst_coverage built-in
method.
When false, the value returned by get_inst_coverage shall equal the value returned
by get_coverage
Following Table summarizes the syntactical level (covergroup, coverpoint, or
cross) in which type options can be specified.
Coverage methods
• The following coverage methods are provided for the covergroup. These methods
can be invoked procedurally at any time.
• void sample():
Description : Triggers sampling of the covergroup
• real get_coverage()
real get_coverage(ref int, ref int)
Description : Calculates type coverage number (0...100)
The get_coverage() method returns the cumulative (or type) coverage, which
considers the contribution of all instances of a particular coverage item
It is a static method that is available on both types (via the :: operator) and
instances (using the "." operator).
The get_coverage() method both accept an optional set of arguments, a pair of int
values passed by reference.
When the optional arguments are specified, the get_coverage() method assign to
the first argument the value of the covered bins, and to the second argument the
number of bins for the given coverage item
These two values correspond to the numerator and the denominator used for
calculating the particular coverage number (i.e., the return value before scaling by
100).
Continu..
• real get_inst_coverage()
real get_inst_coverage(ref int, ref int)
• Description : Calculates the coverage number (0...100)
• get_inst_coverage() method returns the coverage of the specific instance on
which it is invoked, thus, it can only be invoked via the "."operator.
• The get_inst_coverage() method both accept an optional set of arguments, a pair
of int values passed by reference.
• When the optional arguments are specified, the get_inst_coverage() method
assign to the first argument the value of the covered bins, and to the second
argument the number of bins for the given coverage item.
• These two values correspond to the numerator and the denominator used for
calculating the particular coverage number (i.e., the return value before scaling by
100).
Continu..
• void set_inst_name(string)
Description : Sets the instance name to the given string
• void start()
Description : Starts collecting coverage information
• void stop()
Description : Stops collecting coverage information
System tasks
• SystemVerilog provides the following system tasks and functions to help manage
coverage data collection.
• $set_coverage_db_name ( name ) :
Sets the filename of the coverage database into which coverage information is
saved at the end of a simulation run.
• $load_coverage_db ( name ) :
Load from the given filename the cumulative coverage information for all
coverage group types.
• $get_coverage ( ) :
Returns as a real number in the range 0 to 100 the overall coverage of all
coverage group types. This number is computed as described above.
Cover property
• Cover statement can be used to monitor sequences and other behavioral aspects of
the design.
• The tools can gather information about the evaluation and report the results at the
end of simulation.
• When the property for the cover statement is successful, the pass statements can
specify a coverage function, such as monitoring all paths for a sequence.
• The pass statement shall not include any concurrent assert, assume or cover
statement.
• A cover property creates a single cover point.
• Coverage results are divided into two: coverage for properties, coverage for
sequences. For sequence coverage, the statement appears as: