[Edit of Image1]
Hey it's a me again @drifter1!
Today we continue with the Logic Design series on SystemVerilog in order to cover more about Classes. This is part 3 and also the final part! I highly suggest checking out part 1 and part 2 before getting into this one.
So, without further ado, let's get straight into it!
SystemVerilog's parameter system can of course also be used with Classes. Using it it's thus possible to write so called Generic Classes, where each instantiation can specify different data types, array sizes etc. So, through parameterization a single class can be used for the creation of different objects.
Parameters are added in-between #() after the class name, both in the declaration of the class and the instantiation of the object.
class className #();
...
endclass
className #() instance;
For example, let's suppose that we add an integer parameter of the name size, which specifies the bit length of some data or address bus, and has a default value of 32 bits. An object can override that value with 16 quite easily, as shown below.
class className #(int size = 32);
...
endclass
className #(.size(16)) instance;
Overriding a type is also quite easy. A type parameter has to be specified that can then be overridden in the same way as any other parameter.
class className #(type T = real);
...
endclass
className #(.T(int)) instance;
Of course, any type can be passed as the parameter, even user-defined classes, structs, arrays etc.
Because Classes can easily become quite long, SystemVerilog allows the definition of methods to exist outside of the class block. The extern keyword has to be added in front of such methods.
extern function funcName();
extern task taskName();
Of course, the method implementations can also exist in completely different files. In that case, the include compiler directive has to be used so that the header (class definition) is "included" in the corresponding implementation file.
If the class definition is located in file "className.sv" and the class is called className, the corresponding out-of-block declaration would have to be of the sort:
`include "className.sv"
function className::funcName();
...
endfunction
task className::taskName();
...
endtask
In the "main" module only this final file will have to be included.
Be default, any class member is accessible from outside the class. If some members (properties or methods) shouldn't be assessible they have to be marked as local. Even classes that extend the class can't access such members. If local members should be accessible by subclasses, the protected keyword has to be used instead.
For example:
class className;
int p1;
local int p2;
protected int p3;
endclass
In this class:
p1 is accessible from anywherep2 only within the classp3 from within the class and any subclass that extends this classLast time, we showed that methods can be marked as virtual, which allows for different implementations in the subclasses that inherit from that base class.
Additionally, SystemVerilog also allows for the creation of Virtual Classes marked by the virtual keyword. Such Classes contain only virtual methods, that provide the prototype that the extending classes need to follow exactly when overriding them.
The implementation can also be left completely blank in the virtual method by adding the pure keyword.
Block diagrams and other visualizations were made using draw.io
And this is actually it for today's post!
I'm not too sure about the next one. Maybe we will make a small post about the program block. Either way, there are still many enormous topics to discuss...
See Ya!

Keep on drifting!