System Verilog Basics Part 2
System Verilog Basics Part 2
Basics
Part II
Daniyal Tahsildar
Disclaimer:
Welcome to this educational document! Here, you'll find a comprehensive
overview of various SystemVerilog concepts, accompanied by example code. Each
topic is conveniently linked to its corresponding code repository on GitHub. Look
for a symbol! Babu’s symbol
Please note that this document is designed solely for educational purposes, aiming
to provide foundational knowledge of SystemVerilog concepts.
All code snippets included have been thoroughly tested using tools such as Mentor
Questa 2021.3 and Synopsys VCS 2021.03, available on EDA Playground.
If you seek a deeper understanding of the topics covered in this document, please
refer the SystemVerilog reference manual. This document primarily serves to
provide a foundational understanding of these concepts.
Your feedback, input, and critique are highly valued! Feel free to connect with me
on LinkedIn or via Email to share your thoughts.
Page | 1
Contents
Object Oriented Programming .............................................................................................. 4
1. Inheritance....................................................................................................................... 4
2. Polymorphism ................................................................................................................. 4
3. Encapsulation .................................................................................................................. 5
4. Abstraction ...................................................................................................................... 5
Introduction to Classes and Methods I ................................................................................. 6
1. Defining a Class .............................................................................................................. 6
2. Creating Class Instances (Objects) ................................................................................. 6
3. Properties ........................................................................................................................ 7
4. Class Inheritance ............................................................................................................. 8
5. Methods........................................................................................................................... 8
5.1. Task .......................................................................................................................... 8
5.2. Function ................................................................................................................... 9
5.3. Static Methods and Properties ............................................................................... 10
6. New Constructor ........................................................................................................... 10
6.1. Default Definition .................................................................................................. 11
6.2. Field Initialization .................................................................................................. 11
6.3. Initialization Using new Arguments ...................................................................... 11
6.4. Initialization with Default Values .......................................................................... 11
7. Polymorphism of Classes.............................................................................................. 12
7.1. Virtual Methods...................................................................................................... 12
8. this, super ...................................................................................................................... 13
9. Class Randomization .................................................................................................... 14
9.1. Rand Mode ............................................................................................................. 15
9.2. Assert for Randomization ...................................................................................... 15
10. Array of Class ............................................................................................................ 16
11. Null Check on Object Handle ................................................................................... 16
12. Variable Scope ........................................................................................................... 16
Introduction to Classes and Methods II .............................................................................. 18
Page | 2
1. Forward Declaration of Classes .................................................................................... 18
2. extern Method ............................................................................................................... 18
3. Constant Class Property ................................................................................................ 19
4. pure virtual Methods ..................................................................................................... 20
5. Abstract Class ............................................................................................................... 20
6. Parameterized Classes................................................................................................... 21
6.1. Parameterized Classes Specialization .................................................................... 22
6.2. Parameterized Classes with Inheritance ................................................................ 23
7. Interface Class............................................................................................................... 24
8. Nested Class .................................................................................................................. 24
9. Object Copying ............................................................................................................. 25
9.1. Copy by Handle ......................................................................................................... 25
9.2. Shallow Copy ............................................................................................................ 26
9.3. Deep Copy ................................................................................................................. 26
9.4. Casting ....................................................................................................................... 28
Page | 3
Object Oriented Programming
1. Inheritance
Inheritance is a fundamental concept in programming where a derived class can inherit
properties, methods, and constraints from a base class. This means that all the attributes and
functions defined in the base class are automatically accessible in the derived class when it's
created. In SV, this inheritance relationship is established using the extends keyword.
For example:
2. Polymorphism
Polymorphism in programming is where the behaviour of objects can vary depending
on the specific instance at runtime. It allows a derived class to modify or redefine a method
declared in its base class to suit its particular needs. For polymorphism to work, the method
prototype must remain consistent across both the base class and the derived class.
In SV, the virtual keyword is required to enable polymorphism. When applied to a
method in the base class, it indicates that this method can be overridden by a method with the
same prototype in a derived class.
It's considered a good practice to declare all base class methods as virtual if
polymorphism is desired. Methods that lack the virtual keyword in the base class cannot be
overwritten, thus limiting the flexibility and adaptability of the derived classes. Note that
polymorphism cannot happen without inheritance.
For example:
Page | 4
3. Encapsulation
Encapsulation involves bundling together properties (data) and methods (functions or
tasks) into a cohesive unit known as a class. This means that the data and the operations that
manipulate that data are encapsulated within the same entity.
In essence, encapsulation allows for the organization of data and functionality related to a
specific concept or entity into a single container (class). This container is self-contained and
responsible for managing its own properties and methods.
4. Abstraction
Abstraction involves hiding the complex inner workings of a class and presenting only
the essential features to the outside world. It allows programmers to focus on what an object
does, rather than how it achieves its functionality.
In the context of OOP, abstraction is achieved through data hiding, where the internal
implementation details of a class are concealed from external users. This is done by restricting
access to certain variables or methods of a class, ensuring that they can only be accessed or
modified in specific ways defined by the class itself.
Keywords such as local or protected are often used to control the visibility and accessibility
of class elements, limiting their exposure to the outside world.
Note:
This section offers a brief overview of fundamental OOP concepts. For a deeper
understanding, each concept is explored in detail in the subsequent section of classes and
methods.
Page | 5
Introduction to Classes and Methods I
1. Defining a Class
Classes are dynamic constructs that facilitate the creation and deletion of objects (class
instances) dynamically. These objects can be passed around using object handles (pointers to
the class instances). The process of defining a class data type typically includes:
1. Identifying the properties needed for the class.
2. Listing down the required methods, determining whether
they should be tasks or functions.
3. Considering if any constraints are necessary for the
properties.
Classes consist of three main elements: properties (data variables/signals), methods (tasks or
functions), and constraints. Objects, or instances of a class, are fundamental to all SV
testbenches.
Methods within a class can be categorized into two types:
Built-in methods: A class inherently possesses four built-in methods: new, randomize, pre-
randomize, and post-randomize.
User-defined methods: These methods are defined by the user to suit specific requirements.
Once an object is created, its methods can be accessed using the dot operator (`.`).
3. Properties
Properties, also known as fields or signals, are essential components of a testbench,
representing data required by both the Design Under Test (DUT) and the test environment.
Typically, properties are of integral, real, or string types, although they can encompass any SV
data type.
Properties can be categorized as follows:
Local: These properties are accessible only within the methods
and constraints of the same class.
Protected: Accessible within the methods and constraints of the
same class and any inherited classes. Properties marked as
protected cannot be accessed by other classes or modules.
Public: These properties, which are neither local nor protected, are accessible throughout the
test environment or testbench.
Additionally, properties can have the following characteristics:
Static: Memory allocation for these properties occurs at a single location shared by all
instances of the class. This allows for the creation of a commonly shared database for the entire
environment. Static variables can be accessed
using the scope resolution operator (::).
Automatic: Each class instance has dedicated
memory allocation for automatic properties.
Properties can be declared as automatic only
inside procedural blocks. Once the block is
executed, the automatic property memory is
deallocated.
For randomization purposes, properties can be declared as rand or randc. The randomize
method is built-in and can randomize any property declared as rand or
randc. When using randc, cyclic randomization occurs in a specific
order, ensuring that all possible values are generated before repetition
starts. It's important to note that randc should not be used in conjunction
Page | 7
with new() inside loops in the initial block. This is because new() resets the memory used for
previous values, disrupting the cyclic order.
As a best practice, it's advisable to declare every property as protected by default unless
there's a specific need for it to be public. If external access to a protected property is necessary,
it's recommended to declare separate functions to access and modify the property.
4. Class Inheritance
Class inheritance allows for the extension of a base class into a new subclass using the
extends keyword. This process grants the subclass access to all the properties and methods of
the base class. Additionally, the derived class can implement its own unique properties and
methods while retaining access to those inherited from the base class.
5. Methods
A method refers to a procedural block of code that is associated with a class. Methods
encapsulate behaviour and can manipulate the data (properties) of the class. They are similar
to functions or procedures in other programming languages.
SV defines two main types of methods:
5.1. Task
A task represents a procedural block of code that can have zero or more input/output
arguments. It does not return a value. Tasks can execute in zero or more simulation time units.
If an operation needs to take time to execute, using a task is recommended.
The prototype for a task is: task task_name(arguments);
For example: The following code snippet demonstrates how a task is capable of executing in
0 or more simulation time.
Page | 8
5.2. Function
A function is also a procedural block of code that can have zero or more input/output
arguments. Unlike a task, a function returns a value. Functions execute instantaneously,
without consuming simulation time.
The prototype for a function is:
function return_type function_name(arguments);
In SV, all function arguments are considered as input by default. To specify an argument as an
output, it must be explicitly declared.
Example: function void add (a, b, output c);
Following is an example of a function that returns a class instance (object).
A function can also accept the class itself as an input/output argument or return type.
For example, let's consider implementing a compare function within a sample_pkt class:
Page | 9
In this example, the compare function takes another sample_pkt object pkt as an argument. It
compares the properties of the current object (this) with the properties of the provided pkt
object.
6. New Constructor
The new constructor is inherent to every class and is responsible for object initialization,
allocating memory for object fields, and assigning default values to them. Users can either
Page | 10
utilize the default definition provided by the language or define their own implementation of
the new constructor. Fields can be accessed using the dot (‘.’) operator.
There are various coding styles for implementing the new constructor:
The example illustrates two distinct approaches to initializing the new() with input arguments.
this.sync refers to the size field defined within the class, while sync represents the input
argument passed to the constructor.
Page | 11
Example:
Any data type, including bit, byte, int, arrays, mailbox, events, interfaces, etc., can be passed
as arguments to the new constructor.
7. Polymorphism of Classes
Polymorphism in classes refers to the ability of a derived class to modify the
functionality of a method that has been declared in the base class. However, this feature is only
applicable to methods declared as virtual in the base class.
Multiple derived classes from this base class can provide different implementations for
the fix_len function. This flexibility allows each derived class to tailor the behaviour of the
Page | 12
method to its specific requirements. It's considered good practice to declare methods in the
base class as virtual, leaving them empty, to enable customization by derived classes.
In SV, polymorphism is dynamic in nature. It enables the use of a variable of the base class
(superclass) type to hold objects of derived classes (subclasses) and to directly access the
methods of these subclasses using the superclass variable.
8. this, super
In scenarios where both a base class and a derived class contain a property with the
same name, accessing that property directly in the derived class might lead to ambiguity. For
instance, if both classes have a property named count, accessing count in the derived class
would refer to the one defined within the derived class itself. However, if we specifically want
to access the count property from the base class, we can use the super keyword.
super allows users to refer to properties or methods with the same name in both the base
and derived classes as needed. this keyword is utilized to reference class properties or methods
of the current instance, specifically those inherited from the base class. It becomes necessary
to use super when accessing members of a base class that have been overridden in the derived
Page | 13
class. In case of multiple levels of inheritance, super refers to the immediate parent (one level
above class).
From the perspective of the derived class, the syntax would be as follows:
this.count: Refers to the count property in
the derived class (optional to use this here)
super.count: Refers to the count property
in the base class
The choice between super and this
depends on the specific context and
requirements.
9. Class Randomization
Class randomization differs between objects and non-objects.
Non-objects:
For non-objects, such as integers, bytes, and logic, the randomize() function cannot be utilized.
Instead, $random, $urandom_range, and $urandom functions are used.
Objects:
Page | 14
On the other hand, for objects, which are instances of a class, the randomize() function is used.
The randomize() function returns 0 if randomization fails and 1 if it succeeds.
This function comes with two callback methods:
pre_randomize() and post_randomize(). These callback
methods are automatically invoked when the main
randomize() method is called. Further details on
callbacks will be covered in a separate section.
While inline constraints can accomplish tasks that are performed using
pre_randomize(), users cannot override the randomize() function. However, SV offers users
the option to modify the randomization behaviour by utilizing pre_randomize() and
post_randomize().
Page | 15
10. Array of Class
For arrays containing dynamic elements, such as a class, the allocation process involves
two steps: first, allocating memory for the array itself if it’s a dynamic array, and second,
allocating memory for each dynamic element within the array.
Consider the example of a packet class declared as packet pkt_array[]:
pkt_array is allocated memory by doing:
However, this only allocates memory for the array, not the individual packet elements. To
allocate memory for each packet, a loop is used:
Page | 16
For accessing variables in hierarchies beyond the global scope, use the syntax
$root.module_or_class_name.variable. Here, $root signifies the top-level instance of the
design or test environment.
In referencing a variable or method, precedence is given to the closest declared variable or
method.
Page | 17
Introduction to Classes and Methods II
2. extern Method
An extern method refers to a function (or task) prototype specified within a class, with
the actual implementation residing outside the class. They are also called as out-of-block
declarations. The declaration of such
a method outside the class involves
indicating the class to which the
method belongs using a scope
resolution operator. Out of block
declarations using extern enhances
code readability.
For example: Consider a sample_pkt
class as shown here.
Page | 18
It is important to note that when the return type of a method is user-defined and declared
within the class, defining the method externally necessitates specifying the return type with
the class and scope resolution operator. However, since external methods have access to class
properties and declarations, method arguments do not require the use of class scope resolution.
Moreover, it's crucial to declare typedef definitions before the function prototype to prevent
unidentified type errors.
For example:
Page | 19
Example:
For each class instance, the size is specified during object
creation and remains fixed until the end of simulation or
object deletion.
5. Abstract Class
In scenarios where a group of classes share properties and methods, a common base
class can be created to encapsulate this shared functionality and structure. However, this base
class cannot be instantiated directly; rather, it serves as a blueprint to be inherited by other
Page | 20
classes. Such classes are called abstract classes. Any class declared as virtual is inherently an
abstract class.
The syntax is:
For example:
It's important to note that declaring a class as virtual doesn't directly relate to
polymorphism. Instead, an abstract class signifies a class to which memory allocation should
not be directly assigned.
Virtual classes cannot be utilized directly; they must be inherited by another class. The
subclasses derived from these virtual classes can then be instantiated if they are not marked as
virtual.
It's crucial to distinguish between virtual classes and virtual methods. While virtual
classes denote abstract classes, virtual methods refer to a different concept. As a best practice,
all tasks and functions within virtual classes should typically be declared as virtual.
6. Parameterized Classes
It's often advantageous to define a generic class that can be instantiated with varying
array sizes or data types. This concept, known as parameterization, facilitates code reuse
across different requirements, fostering flexibility and efficiency.
The syntax for parameterizing classes involves using the # symbol, similar to Verilog. Classes
can be parameterized with any data type available in SV, enabling type parameterization.
Syntax:
While Verilog only supports value parameterization, SV classes offer the flexibility of
parameterization for both data type and value.
For example:
Page | 21
Parameterization significantly enhances code reusability. Depending on specific
requirements, classes can be parameterized with either value or type parameters. For value
parameterization, any data type such as bit, byte, int, or string can be used. For type
parameterization, the keyword type is required. Parameterized classes can also be inherited
and utilized as needed.
In this example, each specialization of the class sample_class possesses its own unique
copy of the count variable. Despite sharing the same base class structure, classes with different
specializations are effectively treated as distinct entities. For instance, sample_1 and sample_2
share the same count variable since they have the same specialization while sample_3 has its
own count variable.
To illustrate shared static member variables among multiple class specializations, consider the
following non-parameterized base class:
Here, sample_4 and sample_5[3] share a common memory for the count variable, as it resides
within a non-parameterized class.
Page | 22
6.2. Parameterized Classes with Inheritance
There exist four distinct combinations for parameterization with inheritance, each serving a
specific purpose:
6.2.1. Non-parameterized class extended from a non-parameterized class
o Both the derived and base classes lack parameterization.
o Typically utilized when polymorphism isn't required.
For existing parameters, both read by name and read by position methods are applicable.
Page | 23
7. Interface Class
An interface class is a specialized class that exclusively contains pure virtual
tasks/functions and parameter/type declarations. It does not include any other properties or
methods within its definition, thereby enforcing a contract-like structure for derived classes.
Notably, constraints or properties cannot be implemented within an interface class,
distinguishing it from other class types.
Classes can implement one or more interface classes using the implements keyword
(use comma (,) to separate classes that are inherited from). This approach ensures that the
derived class must compulsorily define the pure virtual methods specified in the interface
class.
For example:
In the provided example, the fifo class implements both the push_in and pop_out
interface classes, obligating it to define the put and get methods as per the interface class
specifications. This promotes adherence to a predefined contract, enhancing code modularity.
8. Nested Class
A nested class refers to a class defined within another class. This nested structure allows
for the organization of classes into hierarchical levels, enabling the creation of multiple layers
of nesting. Much like modules, classes serve as scopes and can be nested within one another.
Page | 24
This nesting feature provides several advantages, including the ability to conceal local names
and allocate resources locally within the nested scope.
9. Object Copying
Object copying encompasses four primary techniques:
1. Copy by Handle
2. Shallow Copy
3. Deep Copy
4. $cast operations
In this example, s1 and s2 refer to the same memory location, allowing both objects to access
and modify the shared data.
Page | 26
1. Using Method Call
source_handle.copy(destination_handle);
2. Using Assignment
destination_handle = source_handle.copy();
Deep copy can also leverage shallow copy techniques. In cases where objects exist
below the class hierarchy, shallow copy is performed for those objects as well to ensure
independent memory allocation.
Example:
Page | 27
In this implementation, the copy function replicates each field (non-object) from the
source object into the destination object. Similarly, for class objects (e.g., sample_2), a shallow
copy is employed allocating memory to object instances.
9.4. Casting
Casting involves converting one variable from one data type into another format. This
process can only be applied to singular variables; arrays or other complex data structures are
not singular.
For example:
Variables subject to casting can be either objects or non-objects. Non-objects, where the
data type is fully known at compile time, are subject to static casting. On the other hand,
objects, where the data type is determined at runtime, are subject to dynamic casting. Objects
can be of any class type (including base or derived classes). Hence, this process is referred to
as dynamic casting.
9.4.1. Static Casting
Static casting involves the syntax datatype '(), allowing for the conversion of data types
at compile time. This type of casting is particularly crucial when dealing with typedef enum
type conversions.
Example:
Page | 29