SystemVerilog allows you to create modules and classes that are parameterized. This makes them more flexible, and able to work on a range of data types instead of just a single one. This concept is widely used in UVM, especially the uvm_config_db configuration database. Try these examples yourself.
Parameterized by value
Let’s start with a simple class with a bit vector. The class has a parameter for the width of the vector. (Good programming practice is to always have a default for your parameters.)
class Vector #(parameter WIDTH=1); bit [WIDTH-1:0] data; endclass
You can now declare handles for classes with vectors of various widths.
Vector v1; // Default: data width=1 Vector #(8) v8; // 8-bit data Vector #(.WIDTH(16)) v16; // 16-bit data initial begin v1 = new(); $display("v1 ", $typename(v1.data)); // v1 bit[0:0] v8 = new(); $display("v8 ", $typename(v8.data)); // v8 bit[7:0] end
Every time you specify a value, you are essentially creating a new class. So you can imagine that the v8 line above creates the following class declaration.
class Vector__8; bit [8-1:0] data; endclass
The handles v1, v8, and v16 are not type compatible as each is for a separate class, Vector__1, Vector__8, and Vector__16. You can’t assign between these handles, even with $cast().
Parameterized by type
Say your boss asked you to write a utility class for a stack in SystemVerilog. You might come up with something like this.
class Stack; int items, idx=0; function void push(input int val); items[idx++] = val; endfunction function int pop(); return items[idx--]; endfunction endclass
Your class was so popular that other people on your project asked for a stack of bytes, a stack of real values and more. Rather than write dozens of new classes, just modify your old one. The code for push() and pop() remains the same, it just works on a different type.
class Stack #(parameter type T=int); T items, idx=0; function void push(input T val); … function T pop(); … endclass Stack int_stack; // Default: Stack of ints Stack #(bit[7:0]) byte_stack; // Stack of 8-bit values Stack #(real) real_stack; // Stack of real values
Once again, these three declarations essentially create three new classes. As a result, these handles are not type compatible.
Of course you could have just told your boss to use the SystemVerilog queue data type, but what’s the fun of doing that?
The keyword “parameter” in the class header is optional.
Make the parameter name upper case to show it is not a variable.
Enjoy your verification journey!