What to know about polymorphism in SystemVerilog
Polymorphism is one of very crucial concepts of any OOP languages. Since SystemVerilog is an OOP, it is important for us to understand this.
Basic knowledge about variables
Three properties of a variable in Systemverilog
A variable in general has several properties. However let’s just focus on three important things below for this post.
- Name: The name of the variable.
- Object that variable points to: The memory which holds the data of the variable.
- Type: The data type of the variable. This will define the structure of the variable and how it is stored in the memory.
- Systemverilog is the static typed programming language, which means in the same scope, after the variable is defined, the type cannot be changed, similar to C or Java. There are several programming languages those have dynamic typed such as Python, JavaScript, …
- For example: if the type of the variable is a class, then when the compiler read the memory pointed by the variable, it will handle the data based on this type.
Typecasting and upcasting
- Typecasting is also called type conversion. This is the act of parsing the data in memory in the other way. It is important to understand that the structure of the data in the memory will not be changed. Instead, the data is only read in a different manner.
- For class-typed variable, upcasting means reading the Child object in the memory and point that object to the Parent class variable. (a Child object is typecasted to Parent class variable). Remember, as above explanation, the object still has the structure defined by Child class, but read/parse using the Parent class.
Which function can be called?
Let’s take an example:
- There is
base_sequence
class, which hasbase_write()
function. aes_sequence
class is extended from thebase_sequence
and add new functionaes_write()
.- Now, Parent class is
base_sequence
, Child class isaes_sequence
, we create a variable as below:
base_sequence m_base_seq;
aes_sequence m_aes_seq = new(); // Construct an object of aes_sequence class (Child class)
m_base_seq = m_aes_seq; // Upcasting
// m_base_seq and m_aes_seq point to the same obj of aes_sequence (Child class)
...
m_aes_seq.base_write(); // Legal
m_aes_seq.aes_write(); // Legal
m_base_seq.base_write(); // Legal
m_base_seq.aes_write(); // Illegal, compilation error.
...
- After upcasting, we now have the
m_base_seq
points to an object of a child classaes_sequence
, but has the type of a parent classbase_sequence
. - The statement
m_base_seq.aes_write()
will generate compilation error. As discussed earlier, the obj will have the data structure ofaes_sequence
Child class but will be read and handled usingbase_sequence
Parent class, and in thebase_sequence
, there is noaes_write()
function, that’s why compilation error occurs. - A simple way to remember this is:
The type of the variable will decide which function can be called, and the object that variable points to will decide which data to return.
Some cases when upcasting occur
- Passing object as function/task argument.
aes_sequence m_aes_seq = new(); // Construct an object of aes_sequence class (Child class)
...
// Upcasting, cast any Child obj to Parent base_sequence variable m_obj
virtual function void obj_write(base_sequence m_obj);
m_obj.base_write();
endfunction
...
obj_write(m_aes_seq); // Upcasting, cast the Child aes_sequence obj to Parent base_sequence variable
- Adding object to an array/queue of parent class type of that object
base_sequence m_seq[$]; // a queue of handle of base_sequence obj
aes_sequence m_aes_seq = new(); // Construct an object of aes_sequence class (Child class)
...
// Upcasting, adding the Child obj's handle to a queue of Parent class base_sequence
m_seq.push_back(m_aes_seq);
...
Polymorphism in SystemVerilog
What does it mean?
Simply speaking, polymorphism means many possible ways. This means that we can have many different ways of execution but using the same piece of code. Take this example below:
base_sequence m_seq[$]; // a queue of handle of base_sequence obj has base_write() function
aes_sequence m_aes_seq = new(); // Where aes_sequence is extended from base_sequence
rsa_sequence m_rsa_seq = new(); // Where rsa_sequence is extended from base_sequence
sha_sequence m_sha_seq = new(); // Where sha_sequence is extended from base_sequence
...
m_seq.push_back(m_aes_seq);
m_seq.push_back(m_rsa_seq);
m_seq.push_back(m_sha_seq);
...
foreach (m_seq[i]) begin
m_seq[i].base_write(); // using the same line of code, we can call 3 different functions.
// the result will depend on the object that m_seq[i] point to.
end
...
- In above example, using only 1 line of code, we can have up to three ways of execution, based on the object that
m_seq[i]
point to. This is the most common example of polymorphism in Systemverilog. - Actually, when talking about polymorphism, there are even 3 major classes as below.
Three major classes of polymorphism
As wikipedia, polymorphism has three major classes:
- Ad hoc polymorphism: Function overloading/Operator overloading.
- Function overloading means we can define many functions with the same name, but different sets of arguments. This is not supported in Systemverilog. You may find this very common in other languages such as Java.
- Parametric polymorphism:
- Also known as Generic Programming. Systemverilog supports this as Parameterized classes.
- This is also considered as Compile-time polymorphism.
- Subtype polymorphism:
- The most well known kind of polymorphism in Sytemverilog. This whole post including the variable type explanation and the example above are actually to explain this type. However, in Systemverilog, to achieve this kind of polymorphism, we must define methods as
virtual
. - This is belong to Run-time polymorphism.
- The most well known kind of polymorphism in Sytemverilog. This whole post including the variable type explanation and the example above are actually to explain this type. However, in Systemverilog, to achieve this kind of polymorphism, we must define methods as
Virtual vs non-virtual methods
Let try the code example below:
base_sequence m_base_seq; // base_sequence class has a function called base_write()
aes_sequence m_aes_seq = new(); // aes_sequence will override the base_write() function in base_sequence
m_base_seq = m_aes_seq; // m_base_seq now points to an object of a Child class (aes_sequence)
...
// If base_write() is a VIRTUAL method
m_base_seq.base_write(); // will call the method in aes_sequence class
// because the obj is aes_sequence class obj, and the function is virtual
// If base_write() is a NON-VIRTUAL method
m_base_seq.base_write(); // will call the method in base_sequence class
// even though m_base_seq point to a aes_sequence obj,
// the function in base_sequence is called
...
- Simply put, we must define method as
virtual
to have polymorphism in Systemverilog. - Once the method is defined virtual, it will remain virtual in any child class that overrides it.
- The virtual method can override non-virtual method.
Finding more information
To have more understanding as well as more examples, you can check the IEEE Standard for SystemVerilog, Chapter.8 Classes.
[Tags
systemverilog
]