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

Comments

6 thoughts about “SystemVerilog Parameterized Classes
  • You can easily extend parameterized classes. There are two cases I can think of.

    If the base class is a utility, such as a the stack example, provide a default type. That way the derived class can build on the base functionality, and does not have to give a value for every parameter. An example is uvm_driver:
    class uvm_driver #(type REQ=uvm_sequence_item,
    type RSP=REQ) extends uvm_component;
    You don’t have to give a sequence item type when you define your own driver, and the driver will then work with uvm_sequence_item types. (Not a perfect example as you would have to change the sequencer type too.)

    Other base classes are parameterized with types to allow new functionality. For example, the UVM Framework includes many classes that are type parameterized. For example, the uvmf_parameterized_agent class has parameters for the monitor and driver type. This base class automatically declares and builds the driver and monitor for you so you don’t have to. As a result, your derived class is much smaller, and less code means less bugs.

  • Give it a try. You can easily write an example in less than 20 lines. Why wait for my answer?

    Also, check if your company has a IEEE library subscription. You can then get a free copy of the language reference manual. See page 120 of the 2017 standard. (Note – I spent more time looking this up than I would have writing an example.)

    Enjoy your SystemVerilog journey,
    Chris

  • Hi Scott,

    Accellera created the original SV and UVM standards made them freely available, and finally handed them to the IEEE. The issue is that there are now multiple documents that all say “Standard” and if you go by an old one, your code might not work on a current simulator. Just this morning I saw an issue where the Accellera 3.1 SystemVerilog standard had a C routine svLength and it was replaced with svSize in the IEEE P1800 standard. There are things in my book which worked in the 2005 standard, but not later ones. (How embarrassing!)

    Enjoy your SystemVerilog journey,
    Chris

Leave a Reply

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/