0% found this document useful (0 votes)
91 views363 pages

Basha System Verilog PPT

The document discusses design verification and the verification flow. It covers topics like the need for verification due to increasing design complexity, different phases of verification like testcase generation and coverage, and the limitations of Verilog for verification which led to the development of SystemVerilog.

Uploaded by

jerinkakkurumpil
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
91 views363 pages

Basha System Verilog PPT

The document discusses design verification and the verification flow. It covers topics like the need for verification due to increasing design complexity, different phases of verification like testcase generation and coverage, and the limitations of Verilog for verification which led to the development of SystemVerilog.

Uploaded by

jerinkakkurumpil
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 363

Presented by,

Chand Basha
What is Design Verification

 DESIGN VERIFICATION is a process of experimenting our design


with possible test scenarios

 Design verification is used where the actual design output should be


same as expected design output

 Verification contains many phases that includes Testcase generation,


coverage, monitor etc
Need for 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

To validate millions of lines of code written using different languages


1. RTL is written in VHDL, testbenches in Verilog and functional
models are coded in C
Verification flow
Verification flow

1. Design specification: Understand the design specifications properly

2. Verification Plan: Preparation of testcase scenarios and testbench


environment
 Testcase scenarios means all possible combinations to test the functionality
of DUT
 Testcase scenarios are 2 types. i. Self-checking ii. Non Self-checking

 Self-checking: Testcases are written in such a way that tests itself


 Examples are Corner, Directed , coverage testcases

 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

4. Integration: Once RTL coding is over, it is hooked up in the testbench


environment and then verification process can be started

5. Simulation: Design is simulated using the simulation tool

6. Test Suite Regression: Regression environment is developed using


Perl and Shell scripts, to automate the regression run
Introduction

 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.

 These languages are not good for verification engineers, so verification


engineers had to use languages like "e", VERA, Testbuilder.

 It was rather difficult to have two languages, one for design and other
for verification.

 System Verilog combines the Verification capabilities of HVL with ease


of Verilog to provide a single platform for both design and verification.

 System Verilog is an extension of Verilog with many features that


allows to verify the design using complex TB structures and random
stimuli in verification
Limitations of Verilog for verification

 Verilog(IEEE 1364–2005) doesn't provide race free testbenches.

 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.

 The randomization of stimulus in Verilog is very limited


Limitations of Verilog for verification

 Verilog does not allow changing the dimensions of an array once it is


declared.

 In Verilog, an array with the maximum packet size is declared. Hence,


for smaller packets some elements are unused, which is a waste of
memory

 Although 100% line coverage, path coverage, expression coverage and


toggle coverage is achieved for a design, it still does not mean that
100% functionality of the design has been covered.

 Lack of an Object Oriented Programming approach severely limits the


amount of code that can be re-used in Verilog.
Why we go for system verilog

 As design size have increased however no of RTL code lines required to


represent the design have increased dramatically the amount of
verification code required to test this very large design

 While modelling large and verification routines in RTL HDL is still


possible but coding is very large

 System Verilog adds several new features to verilog. It is used to


verifying the very large designs more easily with less coding
Features of System verilog
The IEEE Standard for System Verilog is 1800. The features in system
Verilog is:
• Supports object oriented programming.
• C type data types like int, typedef, struct, union, enum.
• Dynamic data types : struct, classes, dynamic queues, dynamic arrays.
• New operators and built in methods.
• Casting and Interface, program and clocking blocks
• Enhanced flow control like, foreach, return, break, continue.
• Semaphores, mailboxes, event extensions.
• Constrained Random Verification
• Assertions.
• Coverage.
Time unit and Time precision in system verilog
The `timescale compiler directive is used to tell Verilog compilers how we want them
to process certain delay (#) statements in our code
The `timescale compiler directive has the following syntax:
`timescale time_unit / time_precision

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

The time_precision argument


The syntax of the time_precision argument is exactly the same as that of
the time_unit argument, except there is one additional restriction placed upon
the time_precision argument.
That restriction is: The time specified by the time_precision argument must be at
least as short as that specified by the time_unit argument.
Time precision
For example, if the time_unit value were 10ns, then the
following time_precision values (and some others) would be
valid: 10ns, 1ns, 100ps because they each specify an amount of time as short as, or
shorter than, the amount of time specified by the time_unit argument (i.e. 10
nanoseconds).
Here are some time_precision values that would be invalid: 100ns, 1us, 10us. Each
of these is invalid because it specifies an amount of time longer than 10
nanoseconds. Get it?
Watch what happens when I try to compile a testbench file that contains
a time_precision value that's longer than the time_unit value.
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-state datatypes are automatically converted to a 2-state value, X and Z will be


converted to zeros
Data Types
S.No TYPE 2 State datatypes/ Signed/ No. of bits/ Verilog/
4 State datatypes Unsigned Size System
Verilog
1. reg 4 Unsigned User specific Verilog

2. Wire 4 Unsigned User specific Verilog

3. Integer 4 Signed >=32 Verilog

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

9. short int 2 signed 16bit SystemVerilog

10. int 2 signed 32bit SystemVerilog

11. long int 2 signed 64bit SystemVerilog

12. logic 4 Unsigned User SystemVerilog


specific
13. Short - - - SystemVerilog
real
Data Types

S.No TYPE Verilog/System verilog

14. Typedef System verilog

15. enum System verilog


16. String System verilog
17. Class System verilog
18. void System verilog
19. Structure System verilog
20. Union System verilog
21. Chandle System verilog
Data Types

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;

• longint: It is a signed 2-statedata type with a size of 64-bits. Example: longint a;


.

Applications of Two-State data types:


• These data types are mostly used only in testbenches.

• Care must be taken to connect 2- state variables in a testbench with 4-state


variables in the DUV.

• ‘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

 Logic data type doesn't permit multiple driver

 It has a last assignment wins behavior in case of multiple assignment

Example:
logic a;
assign a = b ^ c;
always (c or d) a = c + d;
.

Characteristics:

• By default this is an unsigned data type and its initial value is x


• Cannot be driven by multiple drivers. The net data type ‘wire’ is to be used in
case of multiple drivers.
• In addition to being a variable, it can be driven by continuous assignments and
gates
• If all signals are declared using the logic type, SystemVerilog infers a variable or
net based on context

Applications of the Logic data type:


• The logic data type can have only one driver and hence can be used to find
netlist bugs
• If all the signals in a design are declared as logic rather than wires and regs, then
a compilation error will occur for cases where multiple drivers for a signal are
present.
• It makes the code simpler and readable in most cases.
.

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
.

 It is a collection of various data types that stored in different memory locations


 The limitation in Verilog is the lack of a data type that can group a collection
of different data types together
 SystemVerilog introduces the concept of structures to alleviate this limitation

Syntax : struct packed(optional)


{<data_type> <range(optional)> element1,element2,…;
<data_type> <range(optional)> element1,element2,…;

} structure_name;

 By default, structures are unpacked


 A structure is just a collection of data and hence it can be synthesized
 Separate-separate memory allocated for the stored data type values
.
Stucture example
 A packet can declared as a struct with its constituent elements like packet
length, header, footer etc. as fields of the packet
PACKET
data_in-8bits
Address-32bits
struct {byte data_in;
logic [31:0] address; data_out-8bits
bit [7:0] data_out;} packet; // structure data type, packet containing a collection of
byte, logic and bit data types respectively
packet ETH; // Defining a variable ETH of the packet structure type
ETH.data_in = 10; // Access of the data_in element using the ETH variable

struct packed {int a;


shortint b;
longint c, d;
bit [7:0] e, f;
byte g;} pack2state; // 2-state variable collection as a packed structure
Union
.

 It is a collection of different datatypes that stored in same memory location


 Unions are therefore more memory efficient than structures and that is why
they were introduced in SV
Syntax : : union packed(optional)
{<data_type> <range(optional)> element1,element2,…;
<data_type> <range(optional)> element1,element2,…;

} union_name;
 The size of an object of the union data type is the size of its largest field.
 A union can store only one value – the size of the largest data field in it.
Hence the memory usage is reduced
 Unions are useful when frequent reads and writes are done to a register in
several different formats – the largest format determines the storage size.
 By default, a union is unpacked
 It can be synthesized
.

Union
32bit size memory
because largest datatype
data_in size here is 32-bit,
Address different datatypes are
Data_out stored in single location

union {byte data_in;


logic [31:0] address;
bit [7:0] data_out;} packet; //union data type, packet containing a collection of
byte, logic and bit data types respectively
String
.

 It is a variable-length ordered collection of characters. The length of a string


is the number of characters in the collection.
Syntax : string variable_name = initial_value(optional);

 Verilog 2001 supports only string literals.


 SystemVerilog adds support for string as a built-in data type. Also added are
a lots of operators and functions for string manipulation
 The memory space for strings is dynamically allocated
 The indices of string variables shall be numbered from 0 to N–1 (where N is
the length of the string)
 so that index 0 is the first (leftmost) character of the string and index N–1 is
the last (rightmost) character of the string
String
.

 An un-initialized or empty string is represented with the special value “”. An


empty string has 0 length
 An individual character is of type ‘byte’
 Unlike the ‘C’ programming language, there is no “null” character at the end
of a SystemVerilog string
 Used to report the status of verification, to trace how far along in its
execution a test case is, and most importantly to display error messages that
helps in debug
String Operators
.

 SystemVerilog provides a set of operators that can be used to manipulate


combinations of string variables and string literals
Operators Description
Str1 == Str2 Equality Operation: Checks whether the two string operands are
equal. Result is 1 if both strings are composed of the same character
sequence and 0 if not

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

{multiplier{Str}} Replication Operation: Str is a string literal or a string expression


and the multiplier is an integer ‘N’. The result of this operation is a
string containing ‘N’ concatenated copies of Str

Str[index] Indexing Operation: Str is a string literal or a string expression and


index is an integer from 0 to ‘N-1’, where ‘N’ is the number of
characters in the string. The result returned is a byte, which is nothing
but the character at the given index
String Methods
.

• 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
.

• Used to assign a new name for another data type

Syntax : typedef <base_data_type><user_defined_type_name>;

• 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
.

• It defines a set of named values. It assigns a symbolic name to each legal


value taken by the data type
Syntax :enum enum_base_type(optional) {
<enum_name_declaration> = constant_expr(optional),
<enum_name_declaration> = constant_expr(optional),
:
<enum_name_declaration> = constant_expr(optional)
} <enum_type_identifier>;

• An enumerated type is stored as type ‘int’ unless specified as something else


• This type automatically gives a unique value to every name in the list
• Values default to the ‘int’ type starting at 0 and then incrementing by 1
• If a value is not specified for a name, it gets the value of the previous name
in the list incremented by 1
The enumeration index values for
INIT, START, STOP, FINAL and ABORT
are 0,1, 2, 3 and 4 respectively –
anonymous int types

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

If a value is not specified for a name, it gets the value of


the previous name in the list incremented by 1. The
value of W is 1. X is not specified and hence it is 1+1,
i.e., 2. Similarly Y is 8 and Z is not specified. Hence its
value is 8+1, i.e., 9
Enumerated Type Methods
• SystemVerilog provides a set of specialized methods to iterate over and manipulate the
values of enumerated types

• 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 int num():Returns the number of elements in the given enumeration

• 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

Example of Enumerated Data Type Methods:

enum {init,start,stop} fsm_states;


fsm_states ctrl;
int total;
total = ctrl.num(); // total gets the value 3
ctrl = ctrl.first();
$display("%s",ctrl.name); // Displays ‘init’
ctrl = ctrl.next();
$display("%s",ctrl.name); // Displays ‘start’
ctrl = ctrl.last();
$display("%s",ctrl.name); // Displays ‘stop’
ctrl = ctrl.prev();
$display("%s",ctrl.name); // Displays ‘start’
SV ARRAYS
.
Arrays

• 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

• Arrays can be classified as fixed-sized arrays (sometimes known as static arrays)


whose size cannot change once their declaration is done, or dynamic arrays,
which can be resized.
.
Difference between Struct and Array

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’.

Single-dimension array declaration


// Verilog 2001 verbose declaration style – 0 and 15 are the lower and higher array limits
int sdarr [0:15];
// Same example as above, but using System Verilog’s compact declaration style – only the array size
int sdarr [16]; (16) is given

Multi-dimension array declaration

int mdarr [0:7][0:7]; // Verilog 2001 verbose declaration style

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>;

• In packed array data stored as a contiguous set of bits


• In this all the data elements are stored in packet format
• In this memory is not wasted, there is no unused space

logic [3:0][7:0] //Array format is [high : low]

parr[3] parr[2] parr[1] parr[0]


logic [3:0][7:0]parr [7:0] [7:0] [7:0] [7:0]

pack[3] pack[2] pack[1] pack[0]


bit[3:0][7:0]pack[1] [7:0] [7:0] [7:0] [7:0] Pack[0]
pack[3] pack[2] pack[1] pack[0]
2rows- 0,1 [7:0] [7:0] [7:0] [7:0] Pack[1]
4coloumns
Each element size-8bit
Unpacked
. Array
• An unpacked array is one where the dimensions of the array is declared after the
array object name
Syntax :<data_type> <array_name> <range>+;
• The unpacked dimensions can be arranged in memory in any way that the
simulator chooses – does not have to be contiguous
• They could be fixed-size arrays, dynamic arrays, associative arrays or queues
• SystemVerilog simulators store each element on a 32-bit word boundary.
• An unpacked array, such as the one shown in following example, stores the values
in the lower 8-bits of the 32-bit word boundary, while the upper 24 bits are unused
bit upkd_arr[0:2][0:7]; //Array format is [low: high]
7 6 5 4 3 2 1 0 [0]
bit upkd_arr[0:2][0:7]; 7 6 5 4 3 2 1 0 [1]
pack[3] pack[2] pack[1] 7 6 5 4 3 2 1 0 [2]
[7:0] [7:0] [7:0]
3rows- 0,1,2
32 23 15 7 0
unused space -
upper 24-bits
32-bit word boundary
• Used to model Random Access Memories (RAMs), Read Only Memories (ROMs)
.
Operations on Arrays

 SystemVerilog allows the following operations to be performed on all


arrays, packed or unpacked

• Reading and writing the entire array. E.g., X = Y


• Reading and writing a slice of the array. E.g., X[0:7] = Y[8:15]
• Reading and writing an element of the array. E.g., X[10] = Y[20]
• Equality operations on the array or slice of the array.
E.g., (1) if (X==Y)……(2) while (X[0:7] != Y[8:15])…..
.
Multi-Dimensional Array

 Combination of both packed and unpacked array

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

logic [2:0][9:0] mymix_array [0:3] [0:5] [2];

mymix_array [0] [4] [1] [2] [7] = 1’b1;


0row
2packet 7bit
4column frame-1
.
Example-1 bit [0:2]mix_arr1[0:1][0:3];

3rows-0,1,2 2frames-0,1 4columns-0,1,2,3

03 2 1 0
1
2 2frames

Example-2
bit [3:0][7:0]mix_arr[0:2]; mix_arr[0][0],

4 packets 8-bits 3rows-0,1,2

mix_arr[0][3] mix_arr[2][2] mix_arr[0][1][6] mix_arr[0][0]


mix_arr[0]
mix_arr[1]
mix_arr2[1][0] mix_arr[2]

mix_arr[1][3][4]
mix_arr[2][0]
.
Dynamic Array

 A dynamic array is an unpacked array whose size can be set or changed at


run time
 The space for a dynamic array does not exist until the array is explicitly
created at run-time

Syntax : <data_type> array_name [];

 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
.

 It is declared with empty square brackets []

 This means that the array size is not specified at compile time, rather it will be
given later at run time

 The default size of an un-initialized dynamic array is 0

 An out-of-bound access in a dynamic array leads to a run-time error

 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

 An associative array is an unpacked array data-type in SV


 It does not have any storage allocated until it is used, and the index type used
to access elements is not restricted to integers

Syntax : <data_type> array_name [index_type];


where, index_type is the data_type to be used or can be the wildcard “*”

 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] );

// Display statement is executed to show “Last entry is : map[data] = 3”


. next():
 Finds the smallest index whose value is greater than the given index
argument.
 If there is a next entry, the index variable is assigned the index of the
next 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.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.

Syntax : <data_type> queue_name [$];

 The queue data type was introduced in SystemVerilog to combine the


dynamic storage property and fast access of elements.
 The main advantage is that one can add or remove elements anywhere in a
queue
 Any element in the queue can be accessed directly using an index without
any need for accessing elements before it.

Example1: string ctrl_names[$] = { “control", “enable"}; // 2string elements


Example2: integer Q[$] = { 4, 2, 7 }; // 3 integer elements
Characteristics of Queue

 The empty array literal {} is used to denote an empty queue


 If known, an upper limit index ‘N’ of the queue can be set.
 This is known as a bounded queue and shall be limited to have indices not
greater than ‘N’ (its size shall not exceed N+1)
 For e.g.: bit limitq[$:255];// A bounded queue whose maximum size is 256 bits
 SystemVerilog automatically allocates space if the queue runs out of memory
when adding additional elements.
 Hence, the new[] constructor used in allocating memory for arrays, is never used
for queues
 Queues are commonly used in various testbench components like scoreboard,
monitor, driver
Characteristics of Queue

 A queue is similar to a one-dimensional unpacked array, except that it grows


and shrinks automatically
 Therefore, like arrays, queues can be manipulated using the indexing,
concatenation, slicing and equality operators
 Elements of a queue are stored in contiguous locations in memory
 Adding an element to the front of the queue or deleting an element from the
back of the queue therefore takes a fixed amount of time
 Adding or deleting an element from the middle of the queue requires shifting
the data already present in the queue
 The time to do this depends on the size of the queue
 They are used to model Last In First Out (LIFO) and First In First Out (FIFO)
behavior, typically buffers
Queue Operations

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 queue_type pop_back(): Removes and returns the last element of


the queue
e = Q.pop_back () is equivalent to e = Q[$]; Q = Q[0:$-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

Array Type Examples Applications


Associative Array bit [3:0] array_a[int]; // Such arrays could be used to model
Un- initialized CAMs.
associative array of a 4- Random read or write tests for
bit vector, indexed by verification of memories could use
int associative arrays for storing data
only for addresses which have been
written
Queue integer Q[$] = { 4, 2, 7 }; Such arrays could be used to model
// An initialized integer Last In First Out (LIFO) and First In
queue called “Q” First Out (FIFO) behavior, typically
containing three buffers
integers
Array Locator Methods
These methods or functions are called after the array object name with a period “.”
between the object name and the function name

The ‘with’ clause is mandatory in the following methods:

find() with (filter_expr):


• Returns all the elements satisfying the given expression
find_index() with (filter_expr):
• Returns the indices of all the elements satisfying the given expression
find_first() with (filter_expr):
• Returns the first element satisfying the given expression
find_first_index() with (filter_expr):
• Returns the index of the first element satisfying the given expression
find_last() with (filter_expr):
• Returns the last element satisfying the given expression
find_last_index() with (filter_expr):
• Returns the index of the last element satisfying the given expression
• The ‘with’ clause can be omitted if the relational operators (<, >, ==) are
defined for the element type of the given array.
• If the ‘with’ clause is specified, the relational operators shall be defined for
the type of the expression.
min():
• Returns the element with the minimum value or whose expression evaluates
to a minimum
max():
• Returns the element with the maximum value or whose expression evaluates
to a maximum
unique():
• Returns all elements with unique values or whose expression evaluates to a
unique value
unique_index():
• Returns the indices of all elements with unique values or whose expression
evaluates to a unique value
Examples of Array Locator Methods:

string SA[10], qs[$];


int IA[*], qi[$];

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

Next, the input stimuli needs to be given


Consider an array consisting of a in a reverse order to test a particular
packet of elements used as input corner case during the verification.So
stimuli in the verification of a design the reverse() method is used

int da[] = ‘{10,2,7,3,4,4};


da.reverse(); // output is {4,4,3,7,2,10}
da.sort(); // output is {2,3,4,4,7,10}
da.rsort(); // output is {10,7,4,4,3,2}
da.shuffle();// output is {4,2,4,3,10,7}

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.

Say the contents of the array needs


to be randomized after an interrupt.
Then the shuffle() method is used to
randomize the array
Array Reduction Methods

• These methods are used to reduce the array to a single value


1. sum():Returns the sum of all the array elements.
2. product(): Returns the product of all the array elements.
3. and(): Returns the bit-wise AND ( & ) of all the array elements.
4. or(): Returns the bit-wise OR ( | ) of all the array elements.
5. xor(): Returns the bit-wise XOR ( ^ ) of all the array elements.

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

6. Introduces multiple Inheritance and composition concept where a single child


class can inherit the properties of more than one class at the same time which
helps in tremendous reduction of code and minimises debugging effort within
a code

7. Introduces concept of observer pattern so that if a particular object within a


class got modified then extended data member which is dependent on that
object gets updated without any further modification of the code

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

class <name_of_class> #(<parameters>); // Declare parameterized class


// Override class parameter
class Trans #(addr = 32); <name_of_class> #(<parameters>) <name_of_inst>;
Trans #(.addr(16)) obj;
Example:
// A class is parameterized by #(<parameters>)
// Here, we define a parameter called "size" and gives it a default value of 8. The "size" parameter is
used to define the size of the "out" variable
class something #(int size = 8);
bit [size-1:0] out;
endclass

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

• A typedef is used to provide a forward declaration of the class.


• In some cases, the class needs to be instantiated before the class
declaration.
• In these kinds of situations, the typedef is used to provide a forward
declaration of the class.

Syntax:
typedef class class_name;
With out typedef With typedef

Class c1; typedef class c2;


C2 c; //class-1
endclass class c1;
c2 c; //using class c2 handle before
Class c2; declaring it.
C1 c; endclass
endclass
//class-2
module typedef_class; class c2;
initial begin c1 c;
c1 class1; endclass
c2 class2;
$display("Inside typedef_class"); module typedef_class;
end initial begin
endmodule c1 class1;
c2 class2;
$display("Inside typedef_class");
Output end
Syntax error endmodule
Following verilog source has syntax error :
token 'c2' should be a valid type.
Please declare it virtual if it is an Interface. Output
"testbench.sv", 6: token is ';' c2 c;
Inside typedef_clas
Nested class

• A nested class is a class whose definition appears inside the definition


of another class, as if it were a member of the other class.
• The SystemVerilog programming language allows you to define a class
within another class.
• Nesting allows hiding of local names and local allocation of resources.
• This is often desirable when a new type is needed as part of the
implementation of a class.
• Declaring types within a class helps prevent name collisions and the
cluttering of the outer scope with symbols that are used only by that
class.
• Type declarations nested inside a class scope are public and can be
accessed outside the class
Nested class example

EXAMPLE
class StringList;

class Node; // Nested class for a node in a linked list.


string name;
Node link;
endclass

endclass

class StringTree;

class Node; // Nested class for a node in a binary tree.


string name;
Node left, right;
endclass

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.

Increased encapsulation : Consider two top-level classes, A and B, where B


needs access to members of A that would otherwise be declared private. By
hiding class B within class A, A's members can be declared private and B can
access them. In addition, B itself can be hidden from the outside world.

More readable, maintainable code: Nesting small classes within top-level


classes places the code closer to where it is used.
Static Properties
• A static property is a class variable that is associated with the class, rather than with
an instance of the class (a.k.a., an object)
• By default, all instances (objects) of a class have their own copies of the data
variables or properties
• This means that when it is changed, its change is reflected in all instances of the
class
• Static properties are declared with the static keyword
• When it is required that all instances of a class have only one shared copy of some
property, then that property has to be declared as static.
Features and Characteristics:
• These class properties are created by first specifying the keyword ‘static’
• A static property is a variable of the class that is associated with the class definition,
and not with an object (instance) of the class
Continu..
• This variable is shared by all objects of the class - when its value is changed,
the change is reflected in all instances of the class

• These properties can be used without creating an object

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

program main ; program main ; program main ; program main ;


A obj_1; A obj_1; A obj_1; A obj_1;
A obj_2; initial A obj_2;
initial begin initial
begin obj_1 = new(); initial begin
obj_1 = new(); obj_1.i = 123; begin obj_1.i = 123;
obj_2 = new(); $display(A::i); obj_1.i = 123; $display(A::i);
obj_1.i = 123; end $display(obj_2.i); end
$display(obj_2.i); endprogram end endprogram
end endprogram
endprogram
RESULT RESULT
RESULT 123 RESULT 123
123 123
Static Methods

 Methods can be declared as static.


 A static method is subject to all the class scoping and access rules, but behaves
like a regular subroutine that can be called outside the class
 A static method behaves like a regular task or function that can be called outside
the class, even with no class instantiation
 They have an important restriction in that they can only access static class
properties or static methods of their own class
 A static method has no access to nonstatic members (class properties or methods),
but it can directly access static class properties or call static methods of the same
class.
 Access to nonstatic members or to the special this handle within the body of a
static method is illegal and results in a compiler error.
class test_id;
static int val = 0;// Static Property
int delay; // Non-static Property
static function int inc_val(string objname);// Static Method (function)
inc_val = ++val;// Accessing the static class property val is OK
$display(“%s’s val = %0d”, objname, val);//Illegal to access non-static class property delay
endfunction
endclass
module sample();
test_id handle1, handle2;// 2 handles of the class test_id int v1, v2;
Initial
begin
v1 = handle1.inc_val("handle1");// calling the static function inc_val without actually
v2 = handle2.inc_val("handle2");// creating an object (class instance) here. Its legal !
end
endmodule
class test_id; Since the ‘gen_id’ task is defined as static, all
static int id = 0; // Static Property invocations of it will see the same value for ‘val’.
static task gen_id(string objname); // Static Method (task) This means that changing ‘val’ in one invocation will
int val; make all the others also see the change.
val = ($urandom() % 100); id = val + 100; If ‘gen_id’ was a normal task in the class, i.e., an
$display("%s's id = %0d, val = %0d",objname,id,val); automatic task, then each invocation of it would have
endtask its own local copy of ‘val’, totally independent of the
endclass others. This means that changing ’val’ in one
test_id handle1, handle2; // 2 handles of the class test_id invocation won't affect any of the other invocations
initial begin
handle1.gen_id("handle1"); // calling the static task gen_id here without actually
// creating an object (class instance) here. Its legal !
handle2 = new();
handle2.gen_id("handle2"); // calling the static task gen_id here after creating the object
end
‘this’ Keyword
 Both the properties and arguments in function are same then this keyword is
used. Both have same names then the values will not be assigned properly

 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

Class packet; Class packet;


bit[31:0]addr; //Properties bit[31:0]addr; //Properties
bit[31:0]data; bit[31:0]data;
bit write; bit write;
string pkt_type; string pkt_type;

function new(bit[31:0]addr, data; // Arguments function new(bit[31:0]addr, data; // Arguments


bit write, string pkt_type); bit write, string pkt_type);
this.addr=addr; addr=addr;
this.data=data; data=data;
this.write=write; write=write;
this.pkt_type=pkt_type; pkt_type=pkt_type;
endfunction endfunction
endclass endclass

module sv(); module sv(); Output:


packet pkt; Output: packet pkt; addr=0
initial begin addr=32’hff initial begin data=0
pkt=new(32’hff,32’h1f,1’b0,SK); data=32’h1f pkt=new(32’hff,32’h1f,1’b0,SK); bit=0
end bit=0 end string=null
endmodule string=SK endmodule
‘super’ Keyword

 It is used to access parent class properties into child class

 Parent class properties are overridden by derived class by using super


keyword

 When using the super keyword within the new function, super.new shall be
the first statement executed in the constructor

 This is because the parent-class must be initialized before the sub-class

 If the user code doesn’t provide an initialization, the compiler will


automatically insert a call to super.new
‘super’ keyword
//without superkeyword cant access //with super keyword calling methods
baseclass properties
class parent_class;
class parnt_class; bit [31:0] addr;
bit [31:0] addr;
function sk();
function display(); //with super keyword calling $display("Addr = %0d",addr);
$display("Addr = %0d",addr); properties endfunction
endfunction endclass
endclass
Class packet; class child_class extends parent_class;
class child_class extends parnt_class; Integer A; bit [31:0] data;
bit [31:0] data;
function integer X(); function display();
function display(); Y=A*A; super.sk();//calling base class
$display("Data = %0d",data); endfunction properties
endfunction endclass $display("Data = %0d",data);
endclass endfunction
Class Ethernet extends packet(); endclass
module inheritence; bit[31:0] B;
initial begin
child_class c=new(); function int Z(); module inheritence;
c.addr = 10; Y=super.X+B*super.A; initial begin
c.data = 20; endfunction child_class c=new();
c.display(); c.addr = 10;
end endclass c.data = 20;
Output Output
endmodule Addr=0 c.display(); Addr=10
Data = 20 end Data = 20
endmodule
Scope Resolution Operator ::
 Scope operator :: is used to refer an identifier within the scope of a class
 Classes and other scopes can have the same identifiers
 The scope resolution operator uniquely identifies a member of a particular class
 Class Resolution operator allows access to static members (class properties and
methods) from outside the class, as well as access to public or protected
elements of super classes from within the derived classes
 Accessing methods from outside the class by using the extern keyword
 A static member of the class is accessed outside the class by using class
resolution operator ::
Example
module sro_class;
class packet; int id=10; Output:
bit [31:0] addr; initial begin
static bit [31:0] id; packet p;
id=10
p = new(); Id=20
function display(bit [31:0] a,b); packet::id = 20;
$display("Values are %0d %0d",a,b); p.display(packet::id,id);
endfunction end
endclass endmodule
 Scope identifiers on the left side of the :: scope resolution operator can be class
names, package names or typedef names
 The scope resolution operator applies to all static elements of a class - static
class properties, static methods, typedefs, enumerations, structures, unions, and
nested class declarations
 It can be used to access members of a parent-class from within the sub-class
 Such class scope resolved member identifiers can be
 Read in expressions
 Written in assignments or subroutine calls
 Triggered in event expressions

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

 Using extern qualifier in method declaration indicates that implementation is


done outside the body of this class

 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

module extern_method; module extern_method;


initial begin initial begin
packet p; packet p;
p = new(); p = new();
p.addr = 10; Addr = 10 p.addr = 10; Addr = 10
p.data = 20; Data = 20 p.data = 20; Data = 20
p.display(); p.display();
end end
endmodule endmodule
Arguments Mismatch
Arguments Match
class packet;
//function declaration - extern indicates class packet;
out-of-body declaration //function declaration - extern indicates out-of-body
extern virtual function void display(bit [31:0] declaration
addr, data ); extern virtual function void display(bit [31:0] addr, d
endclass ata );
//function implementation outside class endclass
body //function implementation outside class body
function void packet::display(bit [31:0] add function void packet::display(bit [31:0] addr, data);
r_t, data_t); $display("Addr = %0d Data = %0d",addr,data);
$display("Addr = %0d Data = endfunction
%0d",addr_t,data_t);
endfunction module extern_method;
initial begin
module extern_method; packet p;
p = new(); Output:
initial begin
p.display(20,30); Addr = 20
packet p;
end Data = 30
p = new();
p.display(20,30); endmodule
end
endmodule
OUTPUT:
Error-[ECMDSMPD] Mismatched method testbench.sv, 11
External class method should match prototype declaration.
Argument names do not match.
The signature of function 'packet::display' should match the
corresponding prototype declaration at: "testbench.sv", 7.
Inheritance
 It allows to extend a class to create another class and have access to all the
properties and methods of original base class from the handle of new class
object
 It allows to make modifications without touching the base class at all
 Base class and child class having same method names i.e., same prototype
1. if this methods are called by Child class handle then child class methods are executed
2. if this methods are called by Base class handle then Base class methods are executed

 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

Features and Characteristics:


• No ‘extends’ keyword here.
• A handle of the parent-class is declared in the sub-class to accomplish the
manual extension
• The methods of the parent-class cannot be overridden by methods using the
same name in the sub-class
COMPOSITION EXAMPLE
class Packet;
int payload;
int checksum;
endclass

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

• NetworkPacket is a manual extension of Packet and hence is a sub-class.

• It contains a handle of Packet called intranet_packet, integer properties header,


trailer and a function called linkpackets

• The handle intranet_packet declared in the class NetworkPacket is used to access


properties or methods of class Packet from NetworkPacket.

• 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

• SystemVerilog limits inheritance to • Composition allows for extension


only one level of hierarchy – the across multiple levels of hierarchy
parent-class and its sub-class
• Functionality is acquired dynamically
• The implemented functionality at run- time by objects referring to
inherited from a parent-class cannot the methods. Its implementation can
be changed at run-time, as be replaced at run-time, with one
inheritance is defined at compile-time object just replaced by another, as
long as they have the same type
Abstract Classes (Virtual Classes)
Definition:
• Abstract or virtual classes are a way of creating a template for a common base-
class that is never instantiated, but extended to derive useful sub-classes

Features and Characteristics:

• 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:

virtual class BasePacket;


bit [1:0] frame_delimiter;
virtual function integer send_pkt(bit[63:0]
payload_data); // No implementation –
just function declaration A common base-class of type BasePacket
endclass that defines the structure of packets and
methods to work on it, is incomplete and is
class InternetPacket extends BasePacket; never going to be instantiated.
virtual function integer send_pkt(bit[63:0]
payload_data); However, from this base-class, a number of
// Internal implementation details here in useful sub-classes can be derived, such as
the body of the function ethernet packets, internet packets, and
... satellite packets to name a few.
endfunction
endclass Each of these packets might look very
similar, all needing the same set of
methods, but they could vary significantly in
terms of
their internal implementation details.
Pure virtual method
• A virtual method may or may not be overridden in the derived lasses. It means,
it is not necessary for a derived class to override a virtual method.
• But there are times when a base class is not able to define anything meaningful
for the virtual method in that case every derived class must provide its own
definition of the that method.
• A pure virtual method is a virtual method that you want to force derived classes
to override. If a class has any unoverridden pure virtuals, it is an "abstract
class" and you can't create objects of that type.
• " pure virtual function " or " pure virtual task " declaration is supposed to
represent the fact that the method has no implementation.
• There are two major differences between a virtual and a pure virtual function,
these are below:

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

Error: pure virtual task disp(); must be overridden in


derived class
Polymorphism
• Polymorphism allows the use of a variable of the superclass type to hold
subclass objects and to reference the methods of those subclasses directly from
the superclass variable

• So, you can say Polymorphism = Virtual Methods + Inheritance

• Virtual method overrides in subclasses shall have matching argument types,


identical argument names, identical qualifiers, and identical directions to the
prototype

• The virtual qualifier is optional in the derived class method declarations

• 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:

• Polymorphism allows the use of a variable of the parent-class type to


hold sub-class objects and to reference the methods of those sub-
classes directly from the parent-class variable
• To achieve polymorphism the 'virtual' identifier must be used when
defining the base class and methods within that class
• Similar to the concept found in the C++ programming language
• Different data types for e.g., integers, bits, and strings, cannot be
stored in a single array.
• However, with polymorphism this can be done
class Animal; a_handle = d_handle;
virtual function eat(); a_handle.eat();
$display("Animal eat"); d_handle.eat();
endfunction p_handle.eat();
endclass
class Dog extends Animal; a_handle = p_handle;
function eat(); a_handle.eat();
$display("Dog eat"); d_handle.eat();
endfunction p_handle.eat();
endclass
class Puppy extends Dog; d_handle = p_handle;
function eat(); a_handle.eat();
$display("Puppy eat"); d_handle.eat();
endfunction p_handle.eat();
endclass end
endmodule
module sample();
initial begin
Animal a_handle; Output:
Dog d_handle; 1.Animal eat 3.Puppy eat
Puppy p_handle; Dog eat Dog eat
Puppy eat Puppy eat
a_handle = new();
d_handle= new(); 2.Dog eat 4.Puppy eat
p_handle= new(); Dog eat Puppy eat
Puppy eat Puppy eat
a_handle.eat();
d_handle.eat();
p_handle.eat();
Virtual Methods

• 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

virtual function function_name; virtual task task_name;


//Function definition //task definition
endfunction endtask
Without Virtual With Virtual
class A ; class A ;
task disp (); virtual task disp ();
$display(" This is class A "); $display(" This is class A ");
endtask endtask
endclass endclass

class EA extends A ; class EA extends A ;


task disp (); task disp ();
$display(" This is Extended class A "); $display(" This is Extended class A ");
endtask endtask
endclass endclass

program main ; program main ;


EA my_ea; EA my_ea;
A my_a; A my_a;
initial
begin initial
my_a = new(); begin
my_a.disp(); Output: my_a = new(); Output:
This is class A my_a.disp(); This is class A
my_ea = new(); This is class A This is Extended
my_a = my_ea; my_ea = new(); class A
my_a.disp(); my_a = my_ea;
end my_a.disp();
endprogram end
endprogram
Encapsulation or Datahiding

• Encapsulation is an act of enclosing in a capsule.


• In systemverilog, more likely to say, in OOPS, encapsulation is a process of
hiding a class members (properties/methods) from being accessed outside of
class.
• By default, members of class are public, so it can be accessible outside of class
directly using class handle and dot operator.
• But OOPS provides a feature to protect or hide properties/methods of class
from outside world.
• In systemverilog, two keywords are specified to hide a class member.
Local keyword
 Class members declared as local are available to methods inside the class. They
are not visible within sub-classes and cannot be inherited

local varible access from local varible access using


outside
class base; method
class base; local varible access from
local int i; local int i; child
classclass
base;
endclass local int i;
task set(int j); endclass
program main; i = j;
initial $display(i); class ext extends base;
begin endtask function new();
base b = new(); endclass i = 10;
b.i = 123; program main; endfunction
end initial endclass
endprogram begin
base b = new(); Output
Output b.set(123); Compilation error
Compilation error end //Local poperties cant
//local keyword endprogram access from child class
properties can
access from Output
outside the class i=123// i local variable doesn’t
declared outside the class
Protect keyword
• protected: Class members declared as protected that can be inherited and is
visible only to sub classes and not outside in the main module or block of code
Protect varible access from
outsideclass base; Protect varible accessing in
protected int i; child class
class base;
endclass
protected int i;
endclass
program main;
initial
class ext extends base;
begin
function new();
base b = new();
i = 10;
b.i = 123;
endfunction
end
endclass
endprogram

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

 Shallow copy creates the common memory for internal objects


 In Shallow copy, the properties of the class are copied, except objects i.e., it
only copies handles not objects
 An object will be created only after doing new to a class handle
packet pkt_1;
pkt_1 = new();

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

Syntax: <casting_type> ’ (<expression>)


Static casting Example
module casting;

real r_a;
int i_a;

initial begin

r_a = (2.1 * 3.2);

//real to integer conversion


i_a = int'(2.1 * 3.2); //or i_a = int'(r_a);

$display("real value is %f",r_a);


$display("int value is %d",i_a);
end
Endmodule

real value is 6.720000


int value is 7
Dynamic casting
• Dynamic casting is used to, safely cast a super-class pointer (reference) into a
subclass pointer (reference) in a class hierarchy
• Dynamic casting will be checked during run time, an attempt to cast an object to an
incompatible object will result in a run-time error
• Dynamic casting is done using the $cast(destination, source) method
• With $cast compatibility of the assignment will not be checked during compile
time, it will be checked during run-time
• It is always legal to assign a child class variable to a variable of a class higher in
the inheritance tree (parent class).
parent_class = child_class; //allowed
• It is never legal to directly assign a super-class (parent class) variable to a variable
of one of its subclasses (child class).

child_class = parent_class; //not-allowed


Dynamic casting
• However, it is legal to assign a super-class (parent class) handle to a subclass (child
class) variable if the super-class (parent class) handle refers to an object of the
given subclass(child class)
Parent_class = child_class ;
child_class = parent_class; //allowed because parent_class is pointing to child_class.

• Though parent_class is pointing to the child_class, we will get a compilation


error saying its not compatible type for the assignment

• This we can over come by make use of $cast method, i.e,

$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.

Syntax: $cast (destination_variable, source_expression);


assigning child class handle to parent class handle assigning parent class handle to child class handle
class parent_class; class parent_class;
bit [31:0] addr; bit [31:0] addr;
function display(); function display();
$display("Addr = %0d",addr); $display("Addr = %0d",addr);
endfunction endfunction
endclass endclass

class child_class extends parent_class; class child_class extends parent_class;


bit [31:0] data; bit [31:0] data;
function display(); function display();
super.display(); super.display();
$display("Data = %0d",data); $display("Data = %0d",data);
endfunction endfunction
endclass endclass

module inheritence; module inheritence;


initial begin initial begin
parent_class p=new(); parent_class p=new();
child_class c=new(); child_class c=new();
c.addr = 10; c.addr = 10;
c.data = 20; c.data = 20;
p = c; //assigning child class handle to parent class c = p; //assigning child class handle to parent class
handle handle
c.display(); c.display();
end end
Endmodule Endmodule
Output
Output "c = p;" Expression 'p' on rhs is not a class or a compatible
Addr = 10 Data = 20 class and hence cannot be assigned to a class handle on
lhs. Please make sure that the lhs and rhs expressions are
compatible.
assigning parent class handle to child class handle Use of $cast or casting
class parent_class; //During the compile time, as the handle of p is of parent
bit [31:0] addr; class type which leads to compile error.
function display(); // With the use of $cast(), type check during compile time
$display("Addr = %0d",addr); can be skipped.
endfunction class parent_class;
endclass bit [31:0] addr;
function display();
class child_class extends parent_class; $display("Addr = %0d",addr);
bit [31:0] data; endfunction
function display(); endclass
super.display(); class child_class extends parent_class;
$display("Data = %0d",data); bit [31:0] data;
endfunction function display();
endclass super.display();
$display("Data = %0d",data);
module inheritence; endfunction
initial begin endclass
parent_class p; Output
child_class c=new(); module inheritence; Addr = 10 Data = 20
child_class c1; initial begin
c.addr = 10; parent_class p;
c.data = 20; child_class c=new();
p = c; //p is pointing to child class handle c. child_class c1;
c1 = p; //type check fails during compile time. c.addr = 10;
c1.display(); c.data = 20;
end p = c; //p is pointing to child class handle c.
endmodule $cast(c1,p); //with the use of $cast, type chek will occur
Output during runtime
c1 = p;" Expression 'p' on rhs is not a class or a compatible class c1.display();
and hence cannot be assigned to a class handle on lhs. Please end
make sure that the lhs and rhs expressions are compatible endmodule
TASKS & FUNCTIONS
Task
• Tasks and Functions provide a means of splitting code into small parts.
• A Task can contain a declaration of parameters, input arguments, output arguments,
in-out arguments, registers, events, and zero or more behavioral statements.
• SystemVerilog task can be,
i. static ii. automatic
Static tasks
• Static tasks share the same storage space for all task calls.
Automatic tasks
• Automatic tasks allocate unique, stacked storage for each task call.
Capabilities of SV task
• Local variables are dynamically allocated at run time
• By default, the tasks and functions that are defined within a class are automatic, and
those defined within a module, interface, program, or package are static
• A return statement has been added to a task
• to declare an automatic variable in a static task
• to declare a static variable in an automatic task
• more capabilities for declaring task ports
• multiple statements within task without requiring a begin…end or fork…join block
• returning from the task before reaching the end of the task
• passing values by reference, value, names, and position
• default argument values
• the default direction of argument is input if no direction has been specified
• default arguments type is logic if no type has been specified
Formal Argument Direction and Type

• 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.

// SystemVerilog Coding Style


task mytask_sv(a,b, output bit [15:0] u,v);
… endtask
task arguments in parentheses
task arguments in declarations and
mentioning directions
module sv_task;
module sv_task;
int x;
int x;
//task to add two integer numbers.
//task to add two integer numbers.
task sum(input int a,b,output int c);
task sum;
c = a+b;
input int a,b;
endtask
output int c;
c = a+b;
initial begin
endtask
sum(10,5,x);
$display("\tValue of x = %0d",x);
initial begin
end
sum(10,5,x);
Endmodule
$display("\tValue of x = %0d",x);
end
Endmodule

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

module sv_function; module sv_function;


int x; int x;
//function to add two integer //function to add two integer
numbers. numbers.
function int sum(input int a,b); function int sum;
sum = a+b; input int a,b;
endfunction sum = a+b;
endfunction
initial begin initial begin
x=sum(10,5); x=sum(10,5);
$display("\tValue of x = %0d",x); $display("\tValue of x = %0d",x);
end end
endmodule endmodule
Output Output
Value of x=15 Value of X=15
function with return value with the return keyword
• A function’s return value can be specified in two ways, either by using a return
statement or by assigning a value to the internal variable with the same name as the
function
module sv_function;
int x;
//function to add two integer
numbers.
function int sum;
input int a,b;
return a+b;
endfunction
initial begin
x=sum(10,5);
$display("\tValue of x = %0d",x);
end
endmodule
Void function
• The example below shows usage of void function, void function,(function with no
return value)
• Functions can be declared as type void – these do not have a return value

function void printf (int a);


$display(“The value passed to the printf function is %0d”, a);
endfunction

• A non-void function (say it is called ‘nv_fn_name’) can be used as a statement and


the return value discarded without any warning from the compiler, by casting the
function call to the void type as shown below:

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

class pass_by_value; class pass_by_reference;


int x,y,z; int x,y,z;
function sum(int x,y); function sum(ref int x,y);
x=x+y; x=x+y;
z=sum(x,y); z=sum(x,y);
endfunction endfunction
module sample(); Output module sample(); Output
pass_by_value pkt; x=30 pass_by_reference pkt; x=50
initial begin y=20 initial begin y=30
pkt.x=30; pkt.y=20; z=50 pkt.x=30; pkt.y=20; z=80
pkt.z=sum(x,y); pkt.z=sum(x,y);
end end
Endmodule endmodule
Stratified Event Queue
Stratified Event Queue
1. Preponed Region
• The function of this region is to sample values that are used by concurrent
assertions.
• The Preponed region is executed only once in each time slot

2. Active Region (Simulation of design code)


• The function of this region is to evaluate and process the current active region set
event activity in any order.
• Execution of all module blocking assignments
• Evaluation of the Right-Hand-Side (RHS) expression of all nonblocking
assignments and schedule updates into the NBA region
• Execution of all the continuous assignments
• Evaluation of the inputs and updating outputs of Verilog primitives
• Execution of the $display and $finish commands
3. Inactive Region
• This is the region that holds the events to be evaluated after all the active events are
processed
• #0 blocking assignments are scheduled here
• #0 procedural assignments should be avoided as per coding guidelines and hence
ideally the inactive region should not be used

4. NBA (NonBlocking Assignment) Region


• This is the region that holds the events to be evaluated after all the inactive events
are processed
• It executes updates to the Left-Hand-Side (LHS) variables that were scheduled in
the active region for all currently executing nonblocking assignments
5. Observed Region (Assertions evaluated after design executes)
• This region is to evaluate the concurrent property assertions using the values
sampled in the Preponed region
• Assertions that execute a pass or fail action block, actually schedule a process
associated with the pass and fail code into the reactive regions and not in the
observed region.
• This is because concurrent assertions are designed to behave strictly as monitors
and are not allowed to modify the state of the design
6. Re-NBA Region
• The Re-NBA region is the set dual of the corresponding NBA region in the same
time slot
• This is the region that holds the events to be evaluated after all the Re-Inactive
events are processed
• The function of this region is to execute the updates to the Left-Hand-Side (LHS)
variables that were scheduled in the reactive region for all currently executing
nonblocking assignments that were evaluated in the reactive region
• It iterates with the reactive and re-inactive regions until all reactive/re-inactive
events have completed
7. Reactive Region (Execution of the testbench)
This is the set dual of the corresponding active region in the same time slot
• The function of this region is to evaluate and execute all current program activity in
any order. The activity includes:
• Execution of all program blocking assignments
• Execution of the pass/fail code from concurrent assertions
• Evaluation of the Right-Hand-Side (RHS) expression of all program
nonblocking assignments and schedule updates into the Re-NBA region
• Execution of all the program continuous assignments
• Execution of the $exit and implicit $exit commands
• Execution of the verification process spawned by program blocks
• The processes that execute when processing the reactive region typically drive back
stimulus into the design
8. Re-Inactive Region
• This is the set dual of the corresponding inactive region in the same time slot
• This is the region that holds the events to be evaluated after all the reactive events
are processed
• It iterates with the reactive region until all reactive/re-inactive events have
completed
• Events are scheduled in this region by executing a #0 in a program process
• Ideally the re-inactive region should not be used as per coding guideline

9. Postponed Region (Sampling signals after all design activity)


• The function of this region is to execute the $strobe and $monitor commands that
will show the final updated values for the current time slot
• This region is also used to collect functional coverage for items that use strobe
sampling
• No new value changes are allowed to happen in the current time slot once the
postponed region is reached
Regions that are designed to implement RTL functionality
• Active region set (Active, Inactive and NBA regions - but avoid
Inactive region events)

Regions that are designed to implement verification execution


• Preponed region, Reactive region set (Reactive, Re-Inactive, Re-
NBA) and Postponed region

Regions that are designed to implement concurrent assertion checking


• Preponed, Observed, and Reactive regions

Region that should be avoided


• Inactive region
PROCEDURAL
STATEMENTS & CONTROL
FLOW
Unique and priority

• SystemVerilog unique and priority modifiers are placed before an if,


case, casez, casex statement
• With the if-else statement , the unique and priority keyword is placed
only before the first if, but affects all else if and else statements
Unique if : It evaluates all the conditions parallel.
• In the following conditions simulator issue a run time error/warning,
• More than one condition is true
• No condition is true or final if doesn’t have corresponding else
Unique Case: A unique case asserts that there are no overlapping case items
and hence that it is safe for the case items to be evaluated in parallel.
Unique if

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.

module priority_if; module priority_if;


//variables declaration //variables declaration
int a,b,c; int a,b,c;
initial begin
initial begin //initialization
//initialization a=10;
a=50; b=20;
b=20; c=40;
c=40;
priority if ( a < b ) $display("\t a is less than b"); priority if ( a < b ) $display("\t a is less than b");
else if ( a < c ) $display("\t a is less than c"); else if ( a < c ) $display("\t a is less than c");
end else $display("\t a is greater than b and c");
endmodule end
endmodule

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 ?

• A loop is a piece code that keeps executing over and over


• A conditional statement is typically included in a loop, so that it can
terminate once the condition becomes true
• If the loop, runs forever then the simulation will hang indefinetly
• Different types of looping constructs in system verilog
1. forever
2. repeat
3. while
4. for
5. do while
6. foreach
repeat loop
• Used to repeat the execution of a statement or statement block a fixed
number of times
• Example below shown below will display the message 5 times and
continues with rest of code

module tb; // This initial block will execute a


repeat statement that will run 5 times and exit
initial
begin // Repeat everything within begin end 5
times and exit "repeat" block
repeat(5) Output
begin $display ("Hello World !"); Hello World !
End Hello World !
end Hello World !
endmodule Hello World !
Hello World !
forever loop
• This is infinite loop just like while(1)
• Note that simulation time will hang unless include a time delay inside
the forever block to advance simulation time

module tb; // This initial block has a Output


forever loop which will "run forever" // Hello World !
Hence this block will never finish in Hello World !
simulation initial begin Hello World !
forever begin Hello World !
#5 $display ("Hello World !"); Hello World !
end Hello World !
end Hello World !
// Because the other initial block will Hello World !
run forever, our simulation will hang! // Hello World !
To avoid that, we will explicity terminate Simulation
simulation after 50ns using $finish complete via
initial #50 $finish; $finish(1) at
endmodule time 50 NS + 0
while loop
• It will repeat the block as long as the condition is true

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("-------------------------------------------------
----------------");

for(int i=0;i<8;i++) begin


Output:
if((i > 2) && (i < 7))begin
$display("\t\tCalling continue,"); After Continue :: Value of i=0
continue; After Continue :: Value of i=1
end After Continue :: Value of i=2
$display("\t\tAfter Continue\t:: Value of i=%0d",i); Calling continue
end Calling continue
$display("-------------------------------------"); Calling continue
end Calling continue
endmodule After Continue :: Value of i=7
Named blocks

 Named blocks in Verilog are allowed for begin and fork.

begin : "MY_NAMED_BLOCK1“
Fork : “MY_NAMED_BLOCK2”

 SystemVerilog extends it and allows one to add named blocks to


reserve word end and join.
 Also SystemVerilog allows to add the LABLE or NAMED
BLOCK before begin, fork as below
"MY_NAMED_BLOCK" : begin
"MY_NAMED_BLOCK" : end
"MY_NAMED_BLOCK" : fork
"MY_NAMED_BLOCK" : join
Event control
 Verilog event control contains with @, delay with #.
 SystemVerilog improves upon this and added following

@*
@ (*)
event expression , iff

 SystemVerilog addes one more important reserve word iff, what


this does is a event is triggered only if condition after iff hold
true.
Example : always @ (posedge clk iff reset == 0 or posedge reset)

 For example: What this does is when reset is LOW, block will be
triggered
always blocks in System verilog

• In an always block which is used to model combinational logic,


forgetting an else leads to an unintended latch

• To avoid this mistake, system verilog adds specialized always_comb


and always_latch blocks, which indicate design intent to simulation,
synthesis and formal verification tools

• SystemVerilog has both static processes, introduced by always, initial


or fork, and dynamic processes, introduced by built-in fork...join_any
and fork...join_none

• Features added in system verilog always_combo, always_latch


always_ff, join_any, join_none
Diff b/w always_latch, always_comb, always_ff
always_comb always_ff always_latch
• always_comb procedure for • always_ff procedure can be • provides a special
modeling combinational logic used to model synthesizable always_latch procedure
behavior sequential logic behavior for modeling latched logic
behavior.
• There is an inferred • Represents a flip-flop (ff), the
sensitivity list that includes process is triggered (executed) • always_latch procedure
the expressions defined on every positive edge of the determines its sensitivity
clock. and executes identically
• automatically triggered once • to the always_comb
at time zero • This replaces always @(posedge procedure.
clk). This is the only type where
• variables written on the left- non-blocking (<=) assignments
hand side of assignments should be used, as this mimics
shall not be written to by any the way a flip-flop transfers
other process. data.

• Statements in • Variables on the left-hand side


an always_comb cannot of assignments within an
include those that block, always_ff procedure, including
have blocking timing or event variables from the contents of a
controls, or fork-join called function, shall not be
statements. written to by any other process.
PROCCESS
What are SystemVerilog threads or processes ?

• A thread or process is any piece of code that gets executed as a separate


entity
• Verilog groups statements for execution
Sequentially: Within a begin … end block
Parallel: Within a fork … join block
• A fork join block also creates different threads that run in parallel.
• fork-join: Finishes when all child threads are over
• fork-join_any: Finishes when any child thread gets over
• fork-join_none: Finishes soon after child threads are created
Limitation of a Verilog fork join

• 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

In sv introduced fork-join_any, fork-join_none


• fork-join_any: waits until anyone of the forked processes is complete
• fork-join_none: doesn’t wait and immediately exits the main thread
block, allowing forked process to run in background
• The main thread resumes execution of statements that follow after the
fork-join_none block
Diff b/w fork-join, fork-join_any, fork-join_none
fork-join fork-join_any fork-join_none
initial begin
initial begin initial clk = 0;
clk = 0; begin #5
#5 clk = 0; fork
fork #5 #5 a = 0;
#5 a = 0; fork
#10 b = 0; #5 a = 0; #10 b = 0;
join #10 b = 0; join_none
clk = 1; //clk becomes one join_any clk = 1; //clk becomes
at t=15 clk = 1; //clk becomes one at one at t=5
End t=10 end
end

Output Output Output


#0 clk=0 #0 clk=0 #0 clk=0
#10 a=0 #10 a=0 #5 clk=1
#20 b-=0 #20 b=0
#15 clk=1 #10 clk=1
Example
module start();
initial begin
#10 $display(“A”);
#30 $display(“B”);
fork
#20 $display(“C”);
#5 $display(“D”);
#10 $display(“E”);
#40 $display(“F”);
join or join_any or join_none
#30 $display(“G”);
#10 $display(“H”); end
endmodule
fork-join fork-join_any fork-join_none
Inside fork-join large Inside fork-join_any small large delay outside
delay added to outside delay added to outside fork-join_none is
#10
addedAto outside block
#10 A #10 A
#40 B
#40 B #40 B
#40+20=
#40+20=60 C #40+20=60 C
#40+5 =45 D #40+5 =45 D
60 C
#40+10=50 E #40+10=50 E
#40+5 =45 D
#40+40=80 F #40+40=80 F
#40+10=50 E
#80+30=110 G #45+30=75 G
#40+40=80 F
#110+10=120H #75+10=85 H
#40+30=70 G
Process control

• Verilog terminates a simulation run when there is no further activity of any


kind.
• SystemVerilog adds the ability to automatically terminate the simulation
• When all its program blocks finish executing (i.e, they reach the end of their
execute block), regardless of the status of any child processes
• SystemVerilog provides constructs that allow one process to terminate or
wait for the completion of other processes
• The wait fork construct waits for the completion of processes.
• The disable fork construct stops the execution of processes.
Without wait –fork With wait-fork
After the completion of Process-1 (i.e, after 5ns) fork- wait fork will wait for the completion of the second thread in
join_any will get unblocked, the $finish will get called and it the fork-join_any.
ends the simulation. for better understanding compare the result of Example-1
The simulation will get ended in the middle of the execution and Example-2
of process-2, this can be avoided with the use of wait-fork.
module wait_fork;
module wait_fork; initial begin
initial begin $display("----------------------------------------------");
$display("---------------------------------------"); fork
fork //Process-1
//Process-1 begin
$display($time,"\tProcess-1 Started");
begin
#5;
$display($time,"\tProcess-1 Started");
$display($time,"\tProcess-1 Finished");
#5;
end
$display($time,"\tProcess-1 Finished");
end //Process-2
//Process-2 begin
begin $display($time,"\tProcess-2 Started");
$display($time,"\tProcess-2 Started"); #20;
#20; $display($time,"\tProcess-2 Finished");
$display($time,"\tProcess-2 Finished"); end
end join_any
join_any Output wait fork; //waiting for the completion of active fork
$display("----------"); 0 Process-1 Started threads
$finish; //ends the simulation 0 Process-2 Started $display("------------------------");
Output
end 5 Process-1 Finished $finish; //ends the simulation 0 Process-1 Started 0
endmodule end Process-2 Started 5
endmodule Process-1 Finished 20
Process-2 Finished
Example for disable fork
module disable_fork;
initial begin
$display("-----------------------------------------------------------------");
fork
//Process-1
begin
$display($time,"\tProcess-1 of fork-1 Started");
#5;
$display($time,"\tProcess-1 of fork-1 Finished");
end
//Process-2
begin
sub_process();
end
join_any
disable fork;
$display("-----------------------------------------------------------------");
$display($time,"\tAfter disable-fork");
$display("-----------------------------------------------------------------");
end
//Sub-Process
Output
task sub_process;
$display($time,"\tSub-Process Started"); #0 Process-1 of fork-1 Started
#10; #0 Sub-Process Started
$display($time,"\tSub-Process Finished"); #5 Process-1 of fork-1 Finished
endtask -----------
endmodule #5 After disable-fork
RANDOMISATION
Randomisation
• Randomization is the process of making something random
• SystemVerilog randomization is the process of generating random values
to a variable
• Verilog has a $random method for generating the random integer values
• This is good for randomizing the variables alone, but it is hard to use in
case of class object randomization
• For easy randomization of class properties, SystemVerilog provides rand
keyword and randomize() method
• We can ensure that randomisation is succeeded by using assert()
function.
• This will avoid running simulations junk values that we may not figure
until we look closer
Why do we need Randomisation
• Direct stimuli take a long time, to develop all possible scenarios, to
verify different features
• In direct stimuli we can miss some kind of corner cases
• A corner case in verification normally refers to a scenario that is very
hard to be simulated/tested
• Random testing is used to find the unexpected bugs

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

• The rand_mode() method is used to disable the randomization of a


variable declared with the rand/randc keyword.
• rand_mode(1) means randomization enabled
• rand_mode(0) means randomization disabled
• The default value of rand_mode is 1, i.e enabled
• Once the randomization is disabled, it is required to make rand_mode(1)
enable back the randomization
• rand_mode can be called as SystemVerilog method, the randomization
enables/disable status of a variable can be obtained by calling
vairble.rand_mode().
• the rand_mode method returns 1 if randomization is enabled else returns
0
//without randomization //randomization disable for //randomization disable for
disable a class variable all class variable

class packet; class packet; class packet;


rand byte addr; rand byte addr; rand byte addr;
rand byte data; rand byte data; rand byte data;
endclass endclass endclass

module rand_methods; module rand_methods; module rand_methods;


initial begin initial begin initial begin
packet pkt; packet pkt; packet pkt;
pkt = new(); pkt = new(); pkt = new();
//disable rand_mode of addr //disable rand_mode of object
variable of pkt pkt.rand_mode(0);
//calling randomize method
pkt.addr.rand_mode(0); //calling randomize method
pkt.randomize();
//calling randomize method pkt.randomize();
pkt.randomize(); $display("\taddr = %0d \t data =
$display("\taddr = %0d \t data $display("\taddr = %0d \t data = %0d",pkt.addr,pkt.data);
= %0d",pkt.addr,pkt.data); %0d",pkt.addr,pkt.data); $display("\taddr.rand_mode() = %0d
end $display("\taddr.rand_mode() = %0d \t data.rand_mode() =
endmodule \t data.rand_mode() = %0d",pkt.addr.rand_mode(),pkt.data.r
%0d",pkt.addr.rand_mode(),pkt.data.r and_mode());
and_mode()); end
Output Output
end endmodule Output
addr = 110 addr.rand_mode() = 1 addr.rand_mode() = 0
data = 116
endmodule
data.rand_mode() = 0 data.rand_mode() = 0
addr = 0 data = 110 addr = 0 data = 0
randomisation methods

• SystemVerilog randomization provides a built-in method randomize.


• The randomize() method generates random values for all the active
random variables of an object, subject to the active constraints.
• Variables declared with the rand keyword will get random values on the
object.randomize() method call.
• The randomize() method returns 1 if the randomization is successful i.e
on randomization it’s able to assign random values to all the random
variables, otherwise, it returns 0.
randomize method associated with below callbacks,
• pre_randomize
• post_randomize
pre-randomize and post-randomize methods
• On calling randomize(), pre_randomize() and post_randomize() functions
will get called before and after the randomize call respectively
• Users can override the pre_randomize() and post_randomize() functions
pre_randomize
1. the pre_randomize function can be used to set pre-conditions before the
object randomization.
2. For example, Users can implement randomization control logic in
pre_randomize function. i.e randomization enable or disable by using
rand_mode() method.
post_randomize
1. the post_randomization function can be used to check and perform post-
conditions after the object randomization.
2. For example, Users can override the randomized values or can print the
randomized values of variables.
pre and post randomized methods are implemented in the class, on calling
obj.randomize() pre and post will get called.
//Implementing pre and post randomize methods

class packet;
rand bit [7:0] addr;
randc bit wr_rd;
bit tmp_wr_rd;

//pre randomization function - disabling randomization of addr,


//if the prevoius operation is write.
function void pre_randomize();
if(tmp_wr_rd==1) addr.rand_mode(0);
else addr.rand_mode(1);
endfunction

//post randomization function - store the wr_rd value to tmp_wr_rd


//and display randomized values of addr and wr_rd
function void post_randomize();
tmp_wr_rd = wr_rd;
$display("POST_RANDOMIZATION:: Addr = %0h,wr_rd = %0h",addr,wr_rd);
endfunction
endclass
Output:
module rand_methods;
initial begin POST_RANDOMIZATION:: Addr = 6e,wr_rd = 1
packet pkt; POST_RANDOMIZATION:: Addr = 6e,wr_rd = 0
pkt = new(); POST_RANDOMIZATION:: Addr = 88,wr_rd = 1
POST_RANDOMIZATION:: Addr = 88,wr_rd = 0
repeat(4) pkt.randomize();
end
endmodule
Constraint randomisation

• 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 <constraint_block_name> { <condition/expression>;


...
<condition/expression>; }
Constraint block inside the class Constraint block outside the class

class packet; class packet;


rand bit [3:0] addr; rand bit [3:0] addr;
constraint addr_range { addr > 5; } constraint addr_range; //constraint block
endclass declaration
endclass
module constr_blocks;
initial begin //constraint implementation outside class body
packet pkt; constraint packet::addr_range { addr > 5; }
pkt = new();
repeat(10) begin module extern_constr;
pkt.randomize(); initial begin
$display("\taddr = %0d",pkt.addr); packet pkt;
end pkt = new();
end repeat(10) begin
endmodule pkt.randomize();
$display("\taddr = %0d",pkt.addr);
Output end
end Output
addr = 14 addr = 10 addr = 14 addr = 10
addr = 9 addr = 8 endmodule
addr = 9 addr = 8
addr = 9 addr = 6 addr = 9 addr = 6
addr = 10 addr = 14 addr = 10 addr = 14
addr = 12 addr = 8 addr = 12 addr = 8
Constraint inheritance
class packet;
rand bit [3:0] addr;
constraint addr_range { addr > 5; }
endclass

class packet2 extends packet;


constraint addr_range { addr < 5; } //overriding constraint of parent class
endclass

module const_inhe; C Like class members, constraints also will get


initial begin inherited from parent class to child class.
packet pkt1;
packet2 pkt2; Constraint blocks can be overridden by writing
pkt1 = new(); constraint block with the same name as in parent
pkt2 = new(); class.
$display("------------------------------------");
repeat(5) begin
Output:
pkt1.randomize();
pkt1:: addr = 14 pkt2:: addr = 0
$display("\tpkt1:: addr = %0d",pkt1.addr);
pkt1:: addr = 10 pkt2:: addr = 1
end
pkt1:: addr = 9 pkt2:: addr = 2
$display("------------------------------------");
pkt1:: addr = 8 pkt2:: addr = 0
repeat(5) begin
pkt1:: addr = 9 pkt2:: addr =2
pkt2.randomize();
$display("\tpkt2:: addr = %0d",pkt2.addr);
end
$display("------------------------------------");
end
endmodule
Constraint inside
In SystemVerilog inside operator, random variables will get values specified
within the inside block.
• values within the inside block can be variable, constant or range
• the inside block is written with an inside keyword followed by curly braces {}
Syntax: constraint addr_range { addr inside { ... };
the range is specified by [ ]
constraint addr_range { addr inside { [5:10]}; }

set of values are specified by ‘comma’,


constraint addr_range { addr inside { [5:10]}; }
it is allowed to mix range and set of values
constraint addr_range { addr inside {1,3,[5:10],12,[13:15]}; }

Other random variables can be used in inside block


rand bit [3:0] start_addr;
rand bit [3:0] end_addr;
rand bit [3:0] addr;
constraint addr_range { addr inside {[start_addr:end_addr]}; }
Constraint inside Constraint inverted inside
class packet; class packet;
rand bit [3:0] addr; rand bit [3:0] addr;
rand bit [3:0] start_addr; rand bit [3:0] start_addr;
rand bit [3:0] end_addr; rand bit [3:0] end_addr;

constraint addr_1_range { addr inside {[start_ad constraint addr_1_range { !(addr inside {[start_addr:end
dr:end_addr]}; } _addr]}); }
endclass endclass

module constr_inside; module constr_inside;


initial begin initial begin
packet pkt; packet pkt;
pkt = new(); pkt = new();
$display("------------------------------------"); $display("------------------------------------");
repeat(3) begin repeat(3) begin
pkt.randomize(); pkt.randomize();
$display("\tstart_addr = %0d,end_addr = $display("\tstart_addr = %0d,end_addr =
%0d",pkt.start_addr,pkt.end_addr); %0d",pkt.start_addr,pkt.end_addr);
$display("\taddr = %0d",pkt.addr); $display("\taddr = %0d",pkt.addr);
$display("------------------------------------"); $display("------------------------------------");
end end
end end
endmodule endmodule Output
start_addr = 12,end_addr = 4 addr = 0
Output
start_addr = 6,end_addr = 7 addr = 13
start_addr = 12,end_addr = 13 addr = 12
start_addr = 5,end_addr = 9 addr = 11
start_addr = 3,end_addr = 7 addr = 7
start_addr = 5,end_addr = 11 addr = 9
dist Constraint
• To control the occurrence or repetition of the same value on randomization.
• It is possible, with dist operator, some values can be allocated more often to
a random variable.
• This is called a weighted distribution. dist is an operator, it takes a list of
values and weights, separated by := or :/ operator
• in weighted distribution weight will be specified to the values inside the
constraint block.
• Value with the more weight will get allocated more often to a random
variable

value := weight or value :/ weight

value – desired value to a random variable


weight – indicates how often the value needs to be considered on randomization
• The values and weights can be constants or variables
• value can be single or a range
• the default weight of an unspecified value is := 1
• the sum of weights need not be a 100

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;

constraint addr_1_range { addr_1 dist { 2 := 5, constraint addr_2_range { addr_2 dist { 2 :/ 5, [10:12] :/


[10:12] := 8 }; } 8 }; }
endclass endclass

module constr_dist; module constr_dist;


initial begin initial begin
packet pkt; packet pkt;
pkt = new(); pkt = new();
$display("------------------------------------"); $display("------------------------------------");
repeat(10) begin repeat(10) begin
pkt.randomize(); pkt.randomize();
$display("\taddr_1 = %0d",pkt.addr_1); $display("\taddr_2 =
end %0d",pkt.addr_2);
$display("-----------------------"); Output end Output
$display("---------------------"); addr_1 = 2 $display("----------"); addr_2 = 10
end addr_1 = 12 end addr_2 = 12
endmodule addr_1 = 12 endmodule addr_2 = 2
addr_1 = 12 addr_2 = 2
addr_1 = 11 addr_2 = 10
addr_1 = 10 addr_2 = 10
addr_1 = 11 addr_2 = 2
addr_1 = 2 addr_2 = 11
addr_1 = 11 addr_2 = 11
addr_1 = 12 addr_2 = 12
Implication constraint

• The implication operator can be used to declaring conditional relations


between two variables.
• Implication operator is denoted by the symbol ->.
• The implication operator is placed between the expression and constraint.
• If the expression on the LHS of implication operator (->) is true, then the
only constraint on the RHS will be considered.

expression -> constraint

• 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

• if else block allows conditional executions of constraints.


• If the expression is true, all the constraints in the first constraint/constraint-
block must be satisfied, otherwise all the constraints in the optional else
constraint/constraint-block must be satisfied.

constraint address_range { if(addr_range == "small")


addr < 8;
else
addr > 8;
}
if else constraint
class packet;
rand bit [3:0] addr;
string addr_range;
constraint address_range { if(addr_range == "small")
addr < 8;
else
addr > 8; Output:
} addr_range = small addr = 1
endclass addr_range = small addr = 4
module constr_if_else;
initial begin addr_range = small addr = 6
packet pkt; addr_range = high addr = 12
pkt = new(); addr_range = high addr = 15
pkt.addr_range = "small";
repeat(3) begin
addr_range = high addr = 9
pkt.randomize();
$display("\taddr_range = %s addr = %0d",pkt.addr_range,pkt.addr);
end
pkt.addr_range = "high";
repeat(3) begin
pkt.randomize();
$display("\taddr_range = %s addr = %0d",pkt.addr_range,pkt.addr);
end
$display("------------------------------------");
end
endmodule
foreach constraint
• SystemVerilog supports using the foreach loop inside a constraint block.
using the foreach loop within the constraint block will make easy to
constrain an array.
• The foreach loop iterates over the elements of an array, so constraints with
the foreach loop are called Iterative constraints.
• The foreach constraint will be applicable to an array with one or more than
one element.
• So it’s required to specify or constrain the size of the dynamic array.

constraint constraint_name { foreach ( variable[iterator] )


variable[iterator]<..conditions..> }
foreach constraint
class packet;
rand byte addr [];
rand byte data [];

constraint avalues { foreach( addr[i] ) addr[i] inside {4,8,12,16}; }


constraint dvalues { foreach( data[j] ) data[j] > 4 * j; }
constraint asize { addr.size < 4; }
constraint dsize { data.size == addr.size; } Output:
endclass addr-size = 2 data-size = 2
addr = 4 data = 101
module constr_iteration;
initial begin addr = 16 data = 21
packet pkt; addr-size = 3 datasize = 3
pkt = new(); addr = 16 data = 89 addr = 4
$display("------------------------------------"); data = 19 addr = 16 data = 13
repeat(2) begin
pkt.randomize();
$display("\taddr-size = %0d data-size = %0d",pkt.addr.size(),pkt.data.size());
foreach(pkt.addr[i])
$display("\taddr = %0d data = %0d",pkt.addr[i],pkt.data[i]);
end
end
endmodule
Disable Constraints
• Constraints in a class can be disabled using the constraint_mode method call.
• By default all the constraints will be enabled, during the randomization constraint
solver will not consider the disabled constraints.
• the constraint disables method is similar to rand_mode() method.
The constraint_mode() method can be used to disable any particular constraint block.
• constraint_mode(1) means constraint block is enabled
• constraint_mode(0) means constraint block is disabled
• default value of constraint_mode is 1, i.e enabled
• once the constraint block is disabled, it is required to make constraint_mode(1)
enable back the constraint block
• constraint_mode can be called as like SystemVerilog method, which returns the
enable/disable status of a constraint block
<object_hanlde>.<constraint_block_name>.constraint_mode(enable);
//enable == 1, constraint block enable
//enable == 0, constraint block disable
calling constraint_mode method
class packet;
rand bit [3:0] addr;

constraint addr_range { addr inside {5,10,15}; }


endclass

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

• Static constraints are similar to static class properties.


• A constraint block can be defined as static by including the static keyword in
its definition. constraint block with the static keyword followed by
constraint keyword is called as a static constraint.
• The static constraint is shared across all the class instances.
• Only the mode change of static constraint will get affected in all the
instances of a class
• Mode change is enable or disable of a constraint by constrain_mode()
method
• A static class can be enabled or disabled by any object handle of its class,
mode change with one object handle will reflect all other objects of same
class type
static constraint constraint_name { ....; }
//turn off non-static constraint //turn off static constraint
class packet; class packet;
rand bit [7:0] addr; rand bit [7:0] addr;

constraint addr_range { addr == 5; } static constraint addr_range { addr == 5; }


endclass endclass

module static_constr; module static_constr; // constraint is static


//As constraint is
initial begin initial begin in nature, the
packet pkt1; non-static only for
packet pkt1; constraint will get
packet pkt2; pkt2 constraint will packet pkt2; disabled for both the
pkt1 = new(); get disabled. pkt1 = new(); objects.
pkt2 = new(); pkt2 = new();
$display("Before disabling constraint"); $display("Before disabling constraint");
pkt1.randomize(); pkt1.randomize();
$display("\tpkt1.addr = %0d",pkt1.addr); $display("\tpkt1.addr = %0d",pkt1.addr);
pkt2.randomize(); pkt2.randomize();
$display("\tpkt2.addr = %0d",pkt2.addr); $display("\tpkt2.addr = %0d",pkt2.addr);
pkt2.addr_range.constraint_mode(0); pkt2.addr_range.constraint_mode(0);
$display("After disabling constraint"); $display("After disabling constraint");
pkt1.randomize(); pkt1.randomize();
$display("\tpkt1.addr = %0d",pkt1.addr); $display("\tpkt1.addr = %0d",pkt1.addr);
pkt2.randomize(); pkt2.randomize();
$display("\tpkt2.addr = %0d",pkt2.addr); $display("\tpkt2.addr = %0d",pkt2.addr);
end end
Endmodule Endmodule Output
Output
Before disabling constraint Before disabling constraint
pkt1.addr = 5 pkt2.addr = 5 pkt1.addr = 5 pkt2.addr = 5
After disabling constraint After disabling constraint
pkt1.addr = 5 pkt2.addr = 134 pkt1.addr = 22 pkt2.addr = 134
Inline Constraints

• 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

object.randomize() with { .... };


//Only inline constraint //Constraint inside the class and inline
constraint
class packet;
rand bit [3:0] addr; class packet;
endclass rand bit [3:0] addr;
rand bit [3:0] data;
module inline_constr;
initial begin constraint data_range { data > 0;
packet pkt; data < 10; }
pkt = new(); endclass

repeat(2) begin module inline_constr;


pkt.randomize() with { addr == 8;}; initial begin
$display("\taddr = %0d",pkt.addr); packet pkt;
end pkt = new();
end repeat(2) begin
Endmodule pkt.randomize() with { addr == 8;};
$display("\taddr = %0d data =
%0d",pkt.addr,pkt.data);
Output end
addr = 8 addr = 8 end Output
Endmodule addr = 8 data = 2
addr = 8 data = 5
Conflict with inline constraint Class and inline constraints for the same
random variable
class packet;
rand bit [3:0] addr; class packet;
rand bit [3:0] addr;
constraint addr_range {addr < 5;};
endclass constraint addr_range {addr inside {[6:12]};};
endclass
module inline_constr;
initial begin module inline_constr;
packet pkt; initial begin
pkt = new(); packet pkt;
repeat(2) begin pkt = new();
pkt.randomize() with { addr > 5;}; repeat(2) begin
$display("\taddr = %0d",pkt.addr); pkt.randomize() with { addr == 8;};
end $display("\taddr = %0d",pkt.addr);
end end
endmodule end
Endmodule Output
Output addr = 8
Error-[CNST-CIF] Constraints addr = 8
inconsistency failure
Functions in Constraints

• In some cases constraint can’t be expressed in a single line, in such cases


function call can be used to constrain a random variable. calling the function
inside the constraint is referred to as function in constraints.
• The function will be written outside the constraint block
• Constraint logic shall be written inside the function as function definition
and function call shall be placed inside the constraint block
• Functions shall be called before constraints are solved, and their return
values shall be treated as state variables.

constraint constraint_name { var = function_call(); };


// function is called inside the constraint
class packet;
rand bit [3:0] start_addr;
rand bit [3:0] end_addr;

constraint start_addr_c { start_addr == s_addr(end_addr); }

function bit [3:0] s_addr(bit [3:0] e_addr);


if(e_addr < 4)
s_addr = 0;
Output
else start_addr = 9 end_addr =13
s_addr = e_addr - 4; start_addr = 2 end_addr = 6
endfunction start_addr = 0 end_addr = 1
endclass

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

• SystemVerilog constraints declared with the keyword soft is called as soft


constraints.
• Any conflict between class constraint and inline constraint leads to a
randomization failure, from this it is clear that it is not possible to override
the class constraint by inline constraint.
• Some test scenarios demand to override the constraints, this can be done by
writing a soft keyword in class constraint.
• A soft constraint is a constraint on a random variable, which allows
overriding the constraint.

constraint c_name { soft variable { condition }; }


real-time use of soft constraint
• This is one of the situations where soft constraints are useful.
• Lets Consider, In a verification testbench transaction class constraint is
written to generate normal stimulus.
• For error stimulus generation, error testcase need to have an inline
constraint that may conflict with the constraint defined inside the class.
• In this situation, we have only the option to change the constraint defined
inside the transaction class, but changing the constraint in the transaction
class will reflect in all other test cases.
• so this kind of problem can be avoided using soft constraints.
Conflict with inline constraint Using soft constraint
class packet;
class packet;
rand bit [3:0] addr;
rand bit [3:0] addr;
constraint addr_range { soft addr > 6; }
constraint addr_range {addr < 5;}; endclass
endclass
module soft_constr;
initial begin
module inline_constr;
packet pkt;
initial begin pkt = new();
packet pkt;
pkt = new(); repeat(2) begin
repeat(2) begin pkt.randomize() with { addr < 6;};
$display("\taddr = %0d",pkt.addr);
pkt.randomize() with { addr > 5;};
end
$display("\taddr = %0d",pkt.addr);
end
end
Endmodule
end
endmodule
Output
Output addr = 1
Error-[CNST-CIF] Constraints addr = 3
inconsistency failure
Unique Constraint

• SystemVerilog constraint defined with the keyword unique is called as a


unique constraint.
• On randomization, unique values to set of variables or unique elements to an
array can be generated by using unique constraints.
• Unique constraint allows us to,
• Generate unique values across the variables
• Generate unique elements in an array (Fixed Size Array, Dynamic Array,
Associative array and Queue)

constraint c_name { unique {variable's/array}; }


unique elements example unique array of elements example
class unique_elements;
class unique_elements;
rand bit [3:0] var_1,var_2,var_3;
rand bit [31:0] array[10];
rand bit [7:0] array[6];
constraint varis_c {unique {var_1,var_2,var_3};} constraint array_c {unique {array};
constraint array_c {unique {array};} foreach(array[i]) array[i] < 10;}
function void display();
function void display();
$display("array = %p",array);
$display("var_1 = %p",var_1);
endfunction
$display("var_2 = %p",var_2);
endclass
$display("var_3 = %p",var_3);
program unique_elements_randomization;
$display("array = %p",array);
unique_elements pkt;
endfunction
initial begin
endclass
pkt = new();
program unique_elements_randomization; pkt.randomize();
unique_elements pkt; pkt.display();
initial begin pkt = new(); end
pkt.randomize(); endprogram
pkt.display();
Output
end array = '{'h5, 'h7, 'h8, 'h1, 'h6, 'h9, 'h2, 'h3, 'h4, 'h0}
Endprogram
Output
Without unique---repeated the values
var_1 = 8
array = '{'h8, 'h4, 'h3, 'h2, 'h3, 'h0, 'h4, 'h8, 'h6,
var_2 = 14
'h2}
var_3 = 11
array = '{'h81, 'h7b, 'h4, 'h47, 'he1, 'h17}
Bidirectional Constraints

• SystemVerilog constraints are solved bidirectionally, which means


constraints on all random variables will be solved parallel.

constraint c_name { if(a == 0) b == 1;


else b == 0; }

• We see that ‘b’ is dependent on ‘a’.


but constraint solver see’s it as ‘a’ is dependent on ‘b’ and ‘b’ is dependent
on ‘a’.
i.e if ‘b’ is inline constrained as ‘1’, in order to satisfy, ‘a’ should take the
value ‘0’.
• As constraints are considered from all the aspects, SystemVerilog constraints
are called as bidirectional constraints.
Bidirectional 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;

constraint a_b { (a == 1) -> b == 0; } constraint sab { solve a before b;}


endclass constraint a_b { (a == 1) -> b == 0;}
endclass
module inline_constr; module inline_constr;
initial begin initial begin
packet pkt; packet pkt;
pkt = new(); pkt = new();
repeat(10) begin repeat(10) begin
pkt.randomize(); pkt.randomize();
$display("\tValue of a = %0d, b = $display("\tValue of a = %0d, b =
%0d",pkt.a,pkt.b); Output %0d",pkt.a,pkt.b); Output
end Value of a = 0, b = 6 end Value of a = 0, b = 9
end Value of a = 0, b = 3 end Value of a = 0, b = 14
Endmodule Value of a = 1, b = 0 Endmodule Value of a = 0, b = 3
Value of a = 0, b = 15 Value of a = 0, b = 13
Value of a = 0, b = 7 Value of a = 1, b = 0
Value of a = 0, b = 2 Value of a = 1, b = 0
Value of a = 0, b = 15 Value of a = 1, b = 0
Value of a = 0, b = 4 Value of a = 0, b = 5
Value of a = 0, b = 7 Value of a = 0, b = 3
Value of a = 0, b = 11 Value of a = 0, b = 4
Random System Functions
1. $urandom( )
• The system function $urandom provides a mechanism for generating
pseudorandom numbers.
• The function returns a new 32-bit random number each time it is called.
• The number shall be unsigned.
Syntax: variable = $urandom(seed);
• The seed is an optional argument that determines the sequence of random
numbers generated.
• The seed can be an integral expression. for a particular seed, the same value
will get generated.

bit [31:0] addr1; addr1 = $urandom();


bit [31:0] addr2; addr2 = $urandom(89);
bit [64:0] addr3; addr3 = {$urandom(),$urandom()};
bit [31:0] data; data = $urandom * 6;
2. $random( )
• $random() is same as $urandom() but it generates signed numbers

3. $urandom_range( )
• The $urandom_range() function returns an unsigned integer within a
specified range.

$urandom_range( int unsigned maxval, int unsigned minval = 0 );


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‘
//EXAMPLE FOR RANDOM SYSTEM FUNCTIONS
module system_funcations;
bit [31:0] addr1;
bit [31:0] addr2;
bit [64:0] addr3;
bit [31:0] data; Output
initial begin addr1=303379748,
addr1 = $urandom(); addr2=2153631232,
addr2 = $urandom(89); addr3=423959822444962108,
addr3 = {$urandom(),$urandom()}; data=546103870
data = $urandom * 6; addr1=27,
addr2=6,
addr3=25
$display("addr1=%0d, addr2=%0d, addr3=%0d,
data=%0d",addr1,addr2,addr3,data);

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.

Syntax: semaphore semaphore_name;


Semaphore methods
• Semaphore is a built-in class that provides the following methods,
• new(); Create a semaphore with a specified number of keys
• get(); Obtain one or more keys from the bucket
• put(); Return one or more keys into the bucket
• try_get(); Try to obtain one or more keys without blocking
new( );
• The new() method is used to create the Semaphore.

Syntax: semaphore_name = new(numbers_of_keys);

• 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

Generic Mailbox (type-less mailbox)


• The default mailbox is type-less. that is, a single mailbox can send and
receive data of any type.

Syntax: mailbox mailbox_name;

Parameterized mailbox (mailbox with particular type)


• Parameterized mailbox is used to transfer a data of particular type

Syntax: mailbox #(type) mailbox_name;


Mailbox methods
• new(bound): Creates a mailbox with a capacity of the specified ‘bound’
number of messages. bound has to be apositive value or 0.
• num(): Returns the number of messages in a mailbox
• put(): Places a message in the mailbox. If the mailbox is full, the process
suspends and blocks until there is enough place in the queue to place the
message.
• try_put(): Attempts to place a message in the mailbox. The process does not
block if the mailbox is full.
• get(): Retrieves and removes a message from the mailbox, if available. If the
mailbox is empty, then the current process blocks until a message is placed in
the mailbox.
• try_get(): Retrieves and removes a message from the mailbox. The process
does not block if the mailbox is empty.
• peek(): Copies a message from a mailbox, if available. If not, block. It does
not remove the message from the mailbox queue.
• try_peek(): Copies a message from a mailbox without blocking
Difference b/w mailbox & queue
Mailbox Queue

• 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

• Mailboxes can be • If you have only one process reading


bounded or unbounded size. and writing to the data structure, there
is no need to use a mailbox we can
• Mailboxes/semaphores guarantee use queue
that the order that the threads
suspend is the same as the order they • multiple threads waiting on the size of
wake up (FIFO order First In/First Out). the queue to change, there is no
guaranteed ordering which thread will
wake up and proceed when the
condition is satisfied.
Events

• 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.

2. Waiting for event trigger


i. @ operator
• wait for an event to be triggered is via the event control operator, @.
• The @ operator blocks the calling process until the given event is triggered.
• For a trigger to unblock a process waiting on an event, the waiting process
must execute the @ statement before the triggering process executes the
trigger operator, ->
• Note: If the trigger executes first, then the waiting process remains blocked.
ii. wait operator
• If the event triggering and waiting for event trigger with @ operator happens
at the same time, @ operator may miss detecting the event trigger.
• Whereas wait(); construct will detect the event triggering.
wait(event_name.triggered);

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

• Executed in active region • Executed in reactive region

• Used for RTL verification • Used for RTL design

• Module block inside it can • Program block inside it doesn't


contains always ,interface and contains any initial ,always
program blocks ,interface and program blocks

• In module block it can contain • In program block it doesn't contain


both blocking & non-blocking any non-blocking assignments
assignments
• Inside the program block we can
• Module block cannot call call other functions and tasks
functions and tasks which is which is declared in module and
declared in program block program blocks
Interface
• In Verilog, the communication between blocks is specified using module ports.
• SystemVerilog adds the interface construct which encapsulates the
communication between blocks.
• An interface is a bundle of signals or nets through which a testbench
communicates with a design.
• A virtual interface is a variable that represents an interface instance
• Also specifies the,
• directional information, i.e modports
• timing information, i.e clocking blocks
• An interface can have parameters, constants, variables, functions, and tasks.
• An interface can be instantiated hierarchically like a module, with or without
ports. interface interface_name;
...
interface_items
...
endinterface
Advantages of the interface
• In order to overcome the following disadvantages of standard Verilog module
port connections, SystemVerilog adds a powerful new port type called an
interface
• Same declarations have to be repeated in multiple modules
• Any change in design specification resulting in ports being added or removed,
will require a modification to the port list of multiple modules and also
changes in the names in the port list of the connecting modules
• Risk of mismatched positional or named port maps due to pilot or scripting
errors
• The interface construct captures connectivity and synchronization between
various design blocks, and also between design and verification blocks of code
• allows the number of signals to be grouped together and represented as a
single port, the single port handle is passed instead of multiple signal/ports.
• interface declaration is made once and the handle is passed across the
modules/components.
• addition and deletion of signals are easy.
Virtual interface
• A virtual interface is a pointer to an actual physical interface instance.
• Interfaces are static in nature, while classes and objects are dynamic.
• Virtual interfaces help bridge the dynamic world of objects with the static
world of modules and interfaces.

Syntax: virtual interface_name interface_identifier;

• Only the following operations are directly allowed on virtual interface


variables,
• Assignment ( = ) to and Equality ( == ), inequality ( != ) with,
1. another virtual interface of the same type
2. an interface instance of the same type
3. the special constant null
Features and Characteristics:
• It is most often used in classes to provide a connection point to allow classes to
access the signals in the interface through the virtual interface
• Virtual interfaces can be declared as class properties, which can be initialized
procedurally or by an argument to new().
• This allows the same virtual interface to be used in different classes
• Instead of referring directly to the actual set of signals, users can manipulate a
set of virtual signals using virtual interfaces
• Like any other data type, virtual interfaces can be passed to tasks or functions
• A virtual interface must be initialized before it can be used.
• By default, it points to null. Attempting to use an uninitialized virtual interface
will result in a run-time error
//virtual interface
virtual intf vif; //Virtual Interface declaration

Connecting virtual interface with interface


//constructor
function new(virtual intf vif);
//get the interface from test
this.vif = vif;
endfunction

//Accessing interface signal using a virtual interface handle


vif.a = 6;
vif.b = 4;
$display("Value of a = %0d, b = %0d",vif.a,vif.b);
#5;
$display("Sum of a and b, c = %0d",vif.c);
Modport

• Modport is used define different directions for the interface


signal, i.e., whether the connecting module sees the signal
direction as input, output or bidirectional.
• These are accomplished using corresponding modport lists
• Modport is an abbreviation for “module port”.
• It indicates that the directions are declared as if inside the module
• An interface can have any number of modport definitions
• Modports are declared inside the interface with the keyword
modport
Modport

• Modport wire declared with input is not allowed to drive or


assign, any attempt to drive leads to a compilation error
• The Interface can have any number of modports, the wire
declared in the interface can be grouped in many modports
• Modpports can have, input, inout, output, and ref

Syntax: modport dut(input a,b, output y);


Example:
interface arb_interface(input bit clk, reset);
logic [1:0] gnt, req;
modport FOR_TB(input reset, gnt, clk, output req);
modport FOR_DUV(input req, reset, clk, output gnt);
modport FOR_MONITOR(input reset, clk, req, gnt);
endinterface

There are 2 ways to specify modport names in a design


1. In the modules that connect to the interface signals
• The syntax of interface_name.modport_name reference_name gives a
hierarchical reference to a local name
module duv (arb_interface.FOR_DUV arbif); module tb (arb_interface.FOR_TB arbif);
// same code as before – no changes // same code as before – no changes
endmodule endmodule

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

• The timing between a design and its testbench should be synchronized in


order to avoid race conditions.
• Clocking blocks have been introduced in SV to provides a means for
grouping signals that are synchronous to a particular clock and making
their timing explicit
• They can only be declared within a module, interface or a program block
(explained later)
• A testbench can contain one or more clocking blocks, each containing its
own clock along with an arbitrary number of signals
• Each clocking block must have at least one clock associated with it
• The clocking block separates the timing and synchronization details from the
structural, functional, and procedural details of a testbench
• Signals in a clocking block are driven or sampled synchronously, ensuring
that the testbench interacts with the signals at the right time
• Clocking blocks cannot be synthesized
• The clocking_skew determines how many time units away from the clock
event a signal is to be sampled or driven.
• Input skews are implicitly negative, that is, they always refer to a time before
the clock edge, whereas output skews always refer to a time after the clock
edge
• Clocking block signals must always be driven using nonblocking assignments
Clocking event
• The event specification used to synchronize the clocking block, @(posedge
clk) is the clocking event.

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

• Assertions are primarily used to validate the behavior of a design.


• An assertion is a check embedded in design or bound to a design unit
during the simulation.
• It’s a verification technique that is embedded in the language
• Warnings or errors are generated on the failure of a specific condition or
sequence of events.
Assertions are used to,
• Check the occurrence of a specific condition or sequence of events.
• Provide functional coverage.
There are two kinds of assertions:
• Immediate Assertions
• Concurrent Assertions
• Assertions increase the observability and the controllability of a design
1. Observability: ability to observe the effects of a specific, internal,
stimulate point within the design(observe the bug at initially without
propagating to the output)
2. Controllability: ability to activate, stimulate or sensitize a specific point
within the design

• Assertion based verification flows provides


1. Find bug faster with assertions
2. Find more bugs with verification hotspots
3. Reduce simulation cycles
Immediate assertions
• Immediate assertions check for a condition at the current simulation time.
• An immediate assertion is the same as an if..else statement with assertion control.
• Immediate assertions have to be placed in a procedural block definition.
• No temporal checks( behavior doesnt check on clock signal)
Syntax: label: assert(expression)
pass_statement;
else
fail_statement;

• 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

• A ## followed by a number or range specifies the delay from the current


clock tick to the beginning of the sequence that follows.
• The delay ##1 indicates that the beginning of the sequence that follows is
one clock tick later than the current clock tick.
• The delay ##0 indicates that the beginning of the sequence that follows is
at the same clock tick as the current clock tick.

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

• $ Operator is used when something needs to be checked till end of


simulation.
• $ denoted till end of simulation. It like saying, something will happen
eventually before end of simulation. It specifies infinite no .of cycles
• its better to use a know upper limit then putting bound less value.

Example:
req ##[1:$] gnt;

req

gnt 1 $
repetition operators

• Sequence of events can be repeated for a repeated count using [*n]


• “n” must be >=0
• “n” cannot be equal to $

• They are 3 types of repetition operators


1. Consecutive repetition operator[*]
2. Non-consecutive repetition operator[=]
3. Goto repetition operator[->]
Consecutive repetition

• Consecutive repetition operator is used to specify that a signal or a sequence


will match continuously for the number of clocks specified.
• Sequence of events can be repeated for a range of repeated count
using[*m:n]

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

sequence s1; //first match only


first_match(te1 ## [2:5]te2); considered remaining will
endsequence discarded.

te1 ## te2, te1 ## te3, te1## te4, te1 ##te5


throughout
• To make certain condition holds true, during the evaluation of entire
sequence, throughout operator should be used
• The simple syntax of a throughout operator is shown below.
(expression) throughout {sequence definition)
Example
sequence burst_rule1;
@(posedge mclk)
$fell(burst_mode) ##0 (!burst_mode) throughout (##2 ((trdy==0)&&(irdy==0)) [*7]);
endsequence
Condition
Burst mode signal should be 0 throughout the sequence evaluation
within
• The "within" construct allows the definition of a sequence contained within
another sequence
• Syntax: seql within seq2.
• This means that seql happens within the start and completion of seq2.
• The starting matching point of seq2 must happen before the starting
matching point of seql.
• The ending matching point of seql must happen before the ending matching
point of seq2

Example

sequence my_seq1; //my_seq1 start with rdy


read[=8] within (rdy##[9:15]done); end with done must have 8
endsequence reads
Built-in system functions
• SVA provides several built-in functions to check for some of the most common
design conditions.
• $onehot(expression) - checks that the expression is one-hot, in other words,
only one bit of the expression can be high on any given clock edge.
• $onehotO(expression) - checks that the expression is zero one-hot, in other
words, only one bit of the expression can be high or none of the bits can be
high on any given clock edge.
• $isunknown(expresslon) - checks if any bit of the expression is X or Z.
• $countones(expression) - counts the number of bits that are high in a vector.
Both a33a and a33b fail in clock
cycles 5, 6, 7 and 8 wherein more
than one bit is high.
Sampled value functions or sequence with
edge definitions

• $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

• Implication is equivalent to an if - then structure


• The lhs of implication is called the antecedent and the rhs is called the
consequent
• The antecedent is the gating condition. If the antecedent(lhs) succeeds,
then the consequent is evaluated
• The implication construct can be used only with property definitions.
• It cannot be used in sequences
• There are 2 types of implication
1. Overlapped implication(->)
2. Non-overlapped implication(=>)
Overlapped Implication operator
• The overlapped implication is denoted by the symbol |->.
• If there is a match on the antecedent, then the consequent expression is
evaluated in the same clock cycle.
• Below property checks that, if signal “a” is high on a given positive clock
edge, then signal “b” should also be high on the same clock edge.

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

• The non-overlapped implication is denoted by the symbol |=>.


• If there is a match on the antecedent, then the consequent expression is
evaluated in the next clock cycle.
• Below property checks that, if signal “a” is high on a given positive clock
edge, then signal “b” should be high on the next clock edge.
property p;
@(posedge clk) a |=> b;
//signal “a” is high on a given positive clock edge, then signal
“b” should be high on the next clock edge.
endproperty
a: assert property(p);
"disable iff construct
• SVA provides a construct called "disable iff' that acts like an asynchronous reset for
the checker. The simple syntax for a disable iff is as follows.
disable iff (expression) < property definition>
• If the signal “a” is high on given posedge of the clock, the signal “b” should be
high for 3 clock cycles followed by “c” should be high after ”b” is high for the
third time.
• During this entire sequence, if reset is detected high at any point, the checker
will stop.

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

• This gives a global control on assertions at module or instance level


$asserton():
• it is default
• $asserton() is called after $assertoff(), $assertkill() are to restart turning on of
assertions
$assertoff():
• temporarily turnoff all executing of assertions
$assertkill():
• kills all currently executing assertions
bind
• When RTL is already written and it becomes responsibility of a verification
engineer to add assertion.

• 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.

• A Bind feature can be used in module, interface


bind keyword example
DUT File
module bind_assertion( input wire clk,req,reset, output reg gnt);
always @ (posedge clk)
gnt <= req; Separate
endmodule
assertion File
module assertion_ip(input wire clk_ip, req_ip,reset_ip,gnt_ip);

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

Binding file req_gnt_assert : assert property (req_gnt_prop)


dut and assertion else
$display("@%0dns Assertion Failed", $time);
Files are
endmodule
instantianting
module binding_module();
bind bind_assertion assertion_ip U_assert_ip ( //instantiating dut, assertions)
.clk_ip (clk), .req_ip (req), .reset_ip (reset), .gnt_ip (gnt));
endmodule
COVERAGE
Introduction
• Coverage is used to measure tested and untested portions of the design.
• Coverage is defined as the percentage of verification objectives that have
been met.
• There are two types of coverage metrics,
• Code Coverage
• Functional Coverage
Code Coverage
• Code coverage measures how much of the “design Code” is exercised.
• This includes the execution of design blocks, Number of Lines, Conditions,
FSM, Toggle and Path.
• The simulator tool will automatically extract the code coverage from the
design code.
Types of code coverage
1. Statement coverage / line coverage
2. Block/segment coverage
3. Conditional/expression coverage
4. Branch coverage
5. Toggle coverage
6. Path coverage
7. FSM coverage
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.
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…

• There are two types of functional coverage,


Data-oriented Coverage –
• Checks combinations of data values have occurred.
• We can get Data-oriented coverage by writing Coverage groups, coverage
points and also by cross coverage

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

• A covergroup can contain one or more coverage points.


• A coverage point can be an integral variable or an integral expression.
• Each coverage point is associated with “bin”.
• On each sample clock simulator will increment the associated bin value.
• The bins will automatically be created or can be explicitly defined
Automatic Bins or Implicit Bins
• An automatically single bin will be created for each value of the coverpoint
variable range.
• These are called automatic, or implicit, bins.
• For an “n” bit integral coverpoint variable, a 2^n number of automatic bins
will get created.

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;

covergroup cg @(posedge clk);


c1: coverpoint addr { bins b1 = {0,2,7};
bins b2[3] = {11:20};
bins b3 = {[30:40],[50:60],77};
bins b4[] = {[79:99],[110:130],140};
bins b5[] = {160,170,180};
bins b6 = {200:$};
bins b7 = default;}
c2: coverpoint wr_rd {bins wrrd};
endgroup : cg
cg cover_inst = new()...
endmodule

bins b1 = {0,2,7 }; //bin “b1” increments for addr = 0,2 or 7


bins b2[3] = {11:20};//creates three bins b2[0],b2[1] and b2[3].and The 11 possible values are
distributed as follows: (11,12,13),(14,15,16) and (17,18,19,20) respectively.
bins b3 = {[30:40],[50:60],77}; //bin “b3” increments for addr = 30-40 or 50-60 or 77
bins b4[] = {[79:99],[110:130],140};//creates three bins b4[0],b4[1] and b4[3] with values 79-99,50-60
and 77 respectively
bins b5[] = {160,170,180} //creates three bins b5[0],b5[1] and b5[3] with values 160,170 and 180
respectively
bins b6 = {200:$}; //bin “b6” increments for addr = 200 to max value i.e, 255.
default bin; // catches the values of the coverage point that do not lie within any of the defined bins.
Transition bins
• Transitional functional point bin is used to examine the legal transitions of a
value.
• SystemVerilog allows to specifies one or more sets of ordered value transitions
of the coverage point.
Type of Transitions:
• Single Value Transition
Sequence Of Transitions
Set Of Transitions
Consecutive Repetitions
Range Of Repetition
Goto Repetition
Non Consecutive Repetition
Single Value Transition
• Single value transition is specified as: value1 => value2
program main;
bit [0:3] y;
bit [0:2] values[$]= '{3,5,6};
covergroup cg; example
cover_point_y : coverpoint y { • 2 bins are created for covering the
bins tran_34 = (3=>4); transition of point "y" from 3 to 4 and
bins tran_56 = (5=>6); other for 5 to 6.
}
endgroup
• The variable y is given the values
cg cg_inst = new();
initial and only the transition 5 to 6 is
foreach(values[i]) occurring.
begin
y = values[i];
cg_inst.sample();
end
endprogram
Sequence Of Transitions
• A sequence of transitions is represented as:
value1 => value3 => value4 => value5
• In this case, value1 is followed by value3, followed by value4 and followed by
value5. A sequence can be of any arbitrary length
program main;
bit [0:3] y; example
bit [0:2] values[$]= '{3,5,6}; • 2 bins re created for covering the
covergroup cg; transition of point "y" from 3 to 4 to 5
cover_point_y : coverpoint y { and other for 3 to 5 to 6.
bins tran_345 = (3=>4>=5);
• The variable y is given the values
bins tran_356 = (3=>5=>6);
} and only the transition 3 to 5 to 6 is
endgroup occurring.
cg cg_inst = new();
initial
foreach(values[i])
begin
y = values[i];
cg_inst.sample();
end
endprogram
Set Of Transitions
• A set of transitions can be specified as:
range_list1 => range_list2

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 @(posedge clk);


c1: coverpoint addr{ ignore_bins b1 = {6,60,66};
ignore_bins b2 = (30=>20=>10); }
endgroup : cg
Ignore 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 {
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.

covergroup cg @(posedge clk);


c1: coverpoint addr{ illegal_bins b1 = {7,70,77};
ignore_bins b2 = (7=>70=>77);}

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:

Cover property ( sequence_expr ) statement_or_null


• Coverage property can be declared in A design or a separate
module, Packages, Interfaces, Program block , Cover properties are not allowed
in class.
Covergroup vs coverproperty
covergroup coverproperty
• Cover groups can reference data sets where as cover • Cover property dont have this
property references a temporal expression. option.
• Cover group can be triggered using .sample method () • Cover property has only one bin.
• Cover group has multiple bins options. • Cover properties can cover complex
• Cover group cannot handle complex temporal temporal expressions
relationships. • Cover properties cannot do crosses
• Cover group automatically handles the crosses. • Cover property has no specific
• Cover group has lot of filtering options. filtering constructs but it can be
• Cover groups can be used in classes. So, cover groups can filtered.
reference the variables in class.
• Cover groups are most useful at a higher level of
abstractions where as cover property makes sense to use
when we want to work at low level signals.
• We can mix cover group and cover property to gain the
OO and temporal advantages. .
• Using properties for temporal expressions and trigger the
cover group

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy