When developing SystemVerilog code, writing a generic class that can be instantiated in multiple ways can save you a lot of time. By using parameterized classes, you can avoid rewriting code for different array sizes or data types. This approach allows you to define one class that can be used with different types of data or sizes without repeating code. In this article, we will explore how to use SystemVerilog parameterized classes effectively.

What Are SystemVerilog Parameterized Classes?

A parameterized class in SystemVerilog allows you to create a class that is flexible and can be customized during instantiation. Parameters in SystemVerilog are like constants within the class, and they can have default values. However, you can override these default values when you instantiate the class.

The basic syntax to declare a parameterized class looks like this:

class <class_name> #( <parameter_list> );

For example, a parameterized class can be declared with the following syntax:

class Trans #(addr = 32);

Overriding Class Parameters During Instantiation

You can easily override class parameters when you create an instance of the class. Here’s how it works:

Trans #(.addr(16)) obj;

In this case, the addr parameter is set to 16 when the class Trans is instantiated. This allows for great flexibility in your design.

Example of a Parameterized Class: Array Size

Let’s take a look at an example where a class is parameterized by size. The size parameter can be changed during class instantiation, making the class adaptable to different scenarios.

class Something #(int size = 8);
    bit [size-1:0] out;
endclass

In this example, the Something class has a parameter size with a default value of 8. The size of the out variable is based on the value of this parameter.

Instantiating the Class with Different Parameters

You can override the default parameter values during instantiation like this:

module tb;

    // Override default value of size
    Something #(16) sth1;  // size = 16
    Something #(.size(8)) sth2;  // size = 8
    typedef Something #(4) td_nibble;  // Define an alias with size = 4
    td_nibble nibble;

    initial begin
        // Instantiate class objects
        sth1 = new;
        sth2 = new;
        nibble = new;

        // Print the size of the "out" variable
        $display("sth1.out   = %0d bits", $bits(sth1.out));
        $display("sth2.out   = %0d bits", $bits(sth2.out));
        $display("nibble.out = %0d bits", $bits(nibble.out));
    end
endmodule

Simulation Log:

When you run the simulation, the output will show the size of the out variable for each instantiation:

sth1.out   = 16 bits
sth2.out   = 8 bits
nibble.out = 4 bits

This demonstrates how you can change the size dynamically at the time of instantiation using parameters.

Example of Parameterized Classes with Data Types

You can also parameterize the data type of a class. This allows you to specify different data types for different instances of the class. Let’s look at an example where the data type is parameterized.

class Stack #(type T = int);
    T item;

    function T add_a(T a);
        return item + a;
    endfunction
endclass

In this example, T is a parameter that has a default value of int. You can override this parameter to use different data types when instantiating the class.

Instantiating Classes with Different Data Types

You can instantiate the Stack class with different data types:

module tb;
    Stack st;  // item is of type int by default
    Stack #(bit[3:0]) bs;  // item is a 4-bit vector
    Stack #(real) rs;  // item is of type real

    initial begin
        st = new;
        bs = new;
        rs = new;

        // Assign different values and perform operations
        st.item = -456;
        $display("st.item = %0d", st.add_a(10));

        bs.item = 8'hA1;
        $display("bs.item = %0d", bs.add_a(10));

        rs.item = 3.14;
        $display("rs.item = %0.2f", rs.add_a(10));
    end
endmodule

Simulation Log:

When you run the simulation, the output will reflect the different data types for each class instance:

st.item = -446
bs.item = 11
rs.item = 13.14

As you can see, the data type of item affects the output of the add_a function.

Key Takeaways

  • Parameterized classes in SystemVerilog allow you to create flexible and reusable code by defining parameters that can be customized during instantiation.
  • You can parameterize the size of variables and the data types in a class.
  • This approach allows you to avoid redundant code and makes your classes adaptable to different use cases.
  • You can override parameters during instantiation to suit specific requirements for size, data type, or other characteristics.

Conclusion

By using SystemVerilog parameterized classes, you can make your code more flexible and reusable. Parameterized classes allow you to customize array sizes, data types, and other features without rewriting code. This method is a great way to write clean, maintainable, and efficient SystemVerilog code.


Comparison of Default and Custom Parameterized Classes

ParameterDefault ValueCustom ValueExample Usage
Size816Something #(16) sth1;
Data Type (T)intbit[3:0]Stack #(bit[3:0]) bs;

This table summarizes how default and custom parameter values affect the class behavior.

Scroll to Top