Recently Adiel Khan of Synopsys wrote a weblog on the virtues of using parameterized classes for implementing reusable VMM VIP's. It seems support for parameterized classes has matured up quite a bit in the latest release of SV compilers.
In his blog, Adiel concludes that `define macros should be preferred over using parameterized classes. In this blog entry, I will try to focus on some of the virtues of parameterized classes.
Take for example an AMBA AHB Master VIP, that I recently had an opportunity to work on. To make the VIP reusable, the data bus-width and the address bus-width need to be made configurable. There are two approaches ....
The `define method
When you code using `define, you don't hardcode the configurable parameters (eg DATAWIDTH and ADDRWIDTH). Instead you use `define constants. The following SV code snippet shows an attempt to code an AHB master transaction this way.
`define AHB_ADDRWIDTH 32
`define AHB_DATAWIDTH 32
class ahbm_xactn extends vmm_data;
static vmm_log log = new("ahbm_xactn", "class");
rand ahb::trans_kind_e kind;
rand bit [`AHB_ADDRWIDTH-1:0] haddr;
rand bit [`AHB_DATAWIDTH-1:0] hwdata;
rand bit [`AHB_DATAWIDTH-1:0] hrdata;
....
endclass: ahbm_xactn
Note that the `define macro constants are scoped globally - and that is primarily the reason I have given them a longish name (in an attempt to make them really unique).
Also note that we are really defining a single transaction descriptor class, just that it happens to be configurable.
Using parameterized classes
The following SV code snippet illustrates another attempt to implement the AHB transaction descriptor class — this time using parameterized classes.
class ahbm_xactn #(int DW=32, int AW=32) extends vmm_data;
static vmm_log log = new("ahbm_xactn", "class");
rand ahb::trans_kind_e kind;
rand bit [AW-1:0] haddr;
rand bit [DW-1:0] hwdata;
rand bit [DW-1:0] hrdata;
....
endclass: ahbm_xactn
Note that the parameters DW and AW are scoped locally — and therefor it is perfectly fine to give them smaller names. When using C++ templates too, it is a standard practice to use small — often single character — names to represent classes and parameterized constants.
Now something that really makes parameterized classes more powerful. When you code a parameterized class, you are really coding a set of classes. A class is in fact an instance of a parameterized class and you could create a multitude of such classes.
Why is that important? When modeling complex systems, there are places where you have multiple subsystems, each having its own AHB bus. And you need to have independent parameters for the address and data widths of these subsystems. If you used `define to implement an AHB bus transaction, you will find yourself in a fix.
In fact there are multiple dimensions to reusability. When you code a reusable VIP, it should be reusable across multiple projects. It is equally important to make it reusable within the same system — meaning thereby, it should be possible to instantiate the same VIP multiple times within the same system. And it should be simultaneously possible to configure each VIP instance in a different way. When you use the `define method, you can still have multiple instances of the VIP, but the `define parameters (being globally scoped) are common for all the VIP instances, and hence not independently configurable.
Support for parameterized classes does open up a lot of coding options. And I will try to explore some of these in my upcoming blog entries. My focus is going to be on how to code efficient VIPs that are really reusable.
3 Responses to “Exploring SystemVerilog Parameterized Classes”
[...] achieving that — parameters and pre-processor tick-defines. While, tick-defines are not elegant, earlier we also saw why tick-defines do not provide a viable solution all the [...]
Hi Punnet, I think you misread my blog.
I conclude that parameterized classes are useful however there are pitfalls.
For maximizing reuse with multiple-widths transactions its more reusable to use constructor arguments than class-parameters.
The `define I state is NOT reusable on its own. Here is quote from the BLOG:
“the first thing that comes to my mind is that a `define is a global namespace macro with a single value, whereas I am using my VIP with 2 different bus architectures. Therefore, the `define alone is not enough: you also need a local constant to be able to exclude unwanted bits when you have a VIP instantiated for various bus widths.”
`define & const-inst allow for easier reuse when you only have one width-type transactions.
Class parameterization has its uses but for transactions it can lead to $cast() issues and several SV users have already hit the $cast() problem when they didn’t really need to parameterize the transaction in the first place.
-Adiel.
Thanks Adiel, for your illuminating comment. I have made updates to the blog entry.