SystemVerilog introduces classes as the foundation of the testbench automation language. Classes are used to model data, whose values can be created as part of the constrained random methodology.
A class is a user-defined data type. Classes consist of data (called properties) and tasks and functions to access the data (called methods). Classes are used in object-oriented programming. In SystemVerilog, classes support the following aspects of object-orientation – encapsulation, data hiding, inheritance and polymorphism.
Here is a simple class declaration:
task set (int i);
x = i;
function int get;
This class has a single data member, x, and two methods, set() and get(). To use the class, an object must be created:
c1 = new;
The first of these statements declares c1 to be a C. In other words, the variable c1 can contain a handle to an object (i.e. an instance) of the class C. The second statement creates an object and assigns its handle to c1. The two statements could be replaced by the following statement, which declares a variable, creates a class object and initialises the variable:
C c1 = new;
Having created a class object, we can use the class methods to assign and look at the data value, x:
$display("c1.x is %d", c1.get());
Although the task set() and the function get() were intended to be the means by which the class’s member variable x was assigned and retrieved, it would be possible to do this directly:
c1.x = 3;
$display("c1.x is %d", c1.x);
This is because all class members are, by default, publicly visible. To hide x, it must be declared local:
local int x;
It is now illegal to access c1.x outside the class, except using the class methods.
Classes may be parameterized in the same way that modules may.
class Register #(parameter int N = 1);
bit [N-1:0] data;
The default parameter value can be overridden when the class is instantiated.
Register #(4) R4; // data is bit [3:0]
Register #(.N(8)) R8 // data is bit [7:0]
Register R; // data is bit [0:0]
It is also possible to pass a data type to a class:
class Register #(parameter type T = int);
Register Rint; // data is int
Register #(bit [7:0]) Rint; // data is bit [7:0]
Extending Classes – Inheritance
One of the key features of object-oriented programming is the ability to create new classes that are based on existing classes. A derived class by default inherits the properties and methods of its parent or base class. However, the derived class may add new properties and methods, or modify the inherited properties and methods. In other words, the new class is a more specialised version of the original class.
In SystemVerilog the syntax for deriving or inheriting one class from another is this:
class Derived extends BaseClass;
// New and overridden property and method declarations.
Consider the example of the class Register, which was used earlier. This could represent a general-purpose data register, which stores a value. We could derive a new class, ShiftRegister, from this that represents a specialised type of a register.
class ShiftRegister extends Register;
task shiftleft; data = data << 1; endtask
task shiftright; data = data >> 1; endtask
Objects of the class ShiftRegister can be manipulated using the original set() and get() methods, as well as the shiftleft and shiftright methods. However, there is a problem if the data property in Register was declared as local – it would not be visible in the extended class! So instead, it would need to be declared protected:
protected int data;
A protected member is one that is not visible outside the class, but is visible in derived classes; local members are not visible, except in the class in which they are declared.
Virtual Classes and Methods
Sometimes, it is useful to create a class without intending to create any objects of the class. The class exists simply as a base class from which other classes can be derived. In SystemVerilog this is called an abstract class and is declared by using the word virtual:
virtual class Register;
Methods, too, may be declared virtual. This means that if the method is overridden in a derived class, the signature (the return type, the number and types of its arguments) must be the same as that of the virtual method. This provides a mechanism for saying, “I want all derived classes to have a method that looks exactly like this.” A virtual method in an abstract class need not have a body – this will have to be defined in a non-abstract derived class.
Note that methods in a virtual class need not be virtual and that virtual methods may be declared in non-abstract classes.
Other Features of Classes
This tutorial has provided an introductory overview of classes in SystemVerilog. Refer to the SystemVerilog LRM for more details.
Classes can include random variables and constraints. The tutorial on Constrained-Random Testing
explains these features and contains further examples of classes.