Thought Leadership

SystemVerilog Parameterized Classes

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[64], 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[64], 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?

More tips

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!
Chris Spear

Keep learning at mentor.com/training
Questions or ideas? verificationacademy.com/ask-chris-spear
View my recent webinar on UVM Coding Guidelines and the Questions and Answers

Chris Spear

Chris brings over forty years of EDA expertise to Siemens customers. Holding a degree in electrical engineering from Cornell University, Chris has developed deep roots in the EDA industry, including as a Principal Application Consultant. Chris is also an industry author, writing the 2012 best-selling “SystemVerilog for Verification” and developing the IEEE standard for random seeding and File I/O PLI package that is part of SystemVerilog. Having taught thousands of engineers around the world, Chris is driven by a passion for learning new techniques and then helping others learn best practices for hardware verification. Outside of work, you may see Chris bicycling over 12,000-foot mountain passes.

More from this author

This article first appeared on the Siemens Digital Industries Software blog at https://blogs.stage.sw.siemens.com/verificationhorizons/2020/04/16/systemverilog-parameterized-classes/