Since the Parameter lists of my classes grow and grow, I would like to replace this list by a struct or class Definition like this:
// collection of all class parameters
class abc_config;
localparam int ADDRWIDTH = 10;
localparam int DATAWIDTH = 8;
endclass
// class depending on a collection of parameters
class abc#(type CONF = int) extends abc_base#(CONF::ADDRWIDTH);
bit [CONF::DATAWIDTH-1:0] d;
covergroup abc_cov;
Option.per_instance = 0;
endgroup
endclass
program
abc#(abc_config) a;
It seems, that my Simulator has issues with such an Approach.
One issue is, that it does not like the usage of CONF::ADDRWIDTH in the Parameter list of the base class. I do not get that compiled.
The other issue is a bit more hidden. I wanted to use this construction in the context of coverage. And my Intention was to have one covergroup for all instantiations of abc (per_instance = 0). But my Simulator did not honor this per_instance Setting and always gave me a individual covergroup per instance. After removing the configuration class from the Parameter list, the per_instance Setting works fine.
My questions now are:
It is kind of strange that the compiler complains, since CONF::ADDRWIDTH should only be “dereferenced” once an actual specialization of your abc class was declared. At that point, CONF would contain a field called ADDRWIDTH.
Maybe you’d be better off using a struct parameter:
typedef struct {
int unsigned addr_width;
int unsigned data_width;
} config_t;
I’d guess you have a mixture of classes, some that only take on integral parameter and some that need more of them bundled up:
class some_base #(int width);
bit [width-1:0] some_field;
endclass
class some_class #(config_t cfg) extends some_base #(cfg.addr_width);
bit [cfg.data_width-1:0] some_other_field;
endclass
You could create different parameterizations of these classes by having two parameters of type config_t:
module top;
parameter config_t cfg = '{ 32, 64 };
parameter config_t other_cfg = '{ 16, 32 };
some_class #(cfg) obj1 = new();
some_class #(other_cfg) obj2 = new();
initial begin
$display("obj1.some_field = %x", obj1.some_field);
$display("obj1.some_other_field = %x", obj1.some_other_field);
$display("obj2.some_field = %x", obj2.some_field);
$display("obj2.some_other_field = %x", obj2.some_other_field);
end
endmodule
The $display(…) calls are there so that you can see the widths of each field in the log file (count the number of 0s). You can find the full example at http://www.edaplayground.com/x/KX3
The other thing you describe with per_instance not being honored is most likely a tool bug.
Thanks so far, this is exactly what was needed! I Extended your Version a bit to be more General, i.e. the base class has a different Parameter struct:
// Code your testbench here
// or browse Examples
typedef struct {
int unsigned addr_width;
int unsigned data_width;
} config_t;
typedef struct {
int unsigned data_width;
} config_base_t;
class some_base #(config_base_t cfg);
bit [cfg.data_width-1:0] some_field;
endclass
class some_class #(config_t cfg) extends some_base #('{cfg.data_width});
bit [cfg.data_width-1:0] some_other_field;
endclass
module top;
parameter config_t cfg = '{ 32, 64 };
parameter config_t other_cfg = '{ 16, 32 };
some_class #(cfg) obj1 = new();
some_class #(other_cfg) obj2 = new();
initial begin
$display("obj1.some_field = %x", obj1.some_field);
$display("obj1.some_other_field = %x", obj1.some_other_field);
$display("obj2.some_field = %x", obj2.some_field);
$display("obj2.some_other_field = %x", obj2.some_other_field);
end
endmodule
I tried this on EDAplayground with VCS and it worked fine. Riviera gave an internal error. BTW: Do you know what happened to Questasim on EDAplayground?
One more Thing: as an Extension to this pattern is it possible to include type definitions as well somehow, so that I can use such definitions for type Parameters?
Kind of:
typedef struct#(type T = int) {
int unsigned addr_width;
int unsigned data_width;
} config_t;
...
class some_base #(type T = int);
T some_field;
endclass
...
class some_class #(config_t cfg) extends some_base #(cfg::T);
bit [cfg.data_width-1:0] some_other_field;
endclass
parameter config_t#(real) cfg = '{ 32, 64 };
...
some_class #(cfg) obj1 = new();
I know that this does not work like that, but it is supposed to give you an idea of what I mean.
In reply to jknaeblein:
I don’t think you can. The only thing you can parameterize like that is a class, but then I don’t think you can use the class as a parameter further down. You could try it out, but on EDAPlayground it doesn’t work (feature not implemented). Maybe you’re luckier with your simulator.