system-verilog

passing SV package as parameter


I've consulted the LRM, and I think what I'm trying to do may just not be possible, but I wanted to see if the community has any insight on this.

I have a module, call it common_module, which takes a bunch of parameters. Say the number of parameters is on the order of 10's, so it's a bit verbose to declare all these in each instantiation. What I'd love to do is bundle all the relevant params in a package, and pass the entire package as part of the instantiation.

I can't import the package within common_module, because there will be different design targets, each of which instantiates common_module with a different bundle of params. If I use a macro to define the import differently within each project, then I can't co-sim the different designs together. To describe it with pseudo-code, it would be something like this

//top_0.sv
module top_0
...
...
common_module common_0(.*); //uses some large set of params
endmodule

//top_1.sv
module top_1
..
..
common_module common_1(.*); //uses some other large set of params, different than common_0
endmodule

//TB.sv
module TB;
top_0 A(.*);
top_1 B(.*);
...
...
endmodule

Basically, I think my options are down to

  1. just deal with the giant param list in every instantiation (verbose, feels like a code-smell)
  2. maintain different versions of common_module, which are identical with the exception of different package imports.

But what I'd love to do is something in the spirit of this (obviously this is invalid syntax)

common_module 
#( .param_bundle(my_package_0))
common_0 (.*);

where my_package_0 is a package, and param_bundle is declared like this

module common_module
#( parameter package param_bundle)
...
...

And to be clear, whatever solution used isn't solely for TB code. It should be synthesizable.


Solution

  • The proper way of doing this in SystemVerilog is with parameterized classes. Some synthesis tools support classes as long as they are never constructed (Used for parameterized static functions)

    class bundle #(
      parameter A=6,
      parameter B=6);
    endclass
    
    module common_module#(type T);
      bit [T::A:0] x;
      bit [T::B:0] y;
      initial $display("%m %d %d",$bits(x), $bits(y));
    endmodule
    
    module top;
      common_module #(bundle#(8,9))cm1();
      common_module #(bundle#(16,18)) cm2();
      typedef bundle#(16,23) xyz_t; // better to use a typedef
      common_module #(xyz_t) cm2();
    endmodule
    

    But since not all synthesis tools support classes, you could use an interface as a bundle of parameters.

    interface bundle;
      parameter A=6;
      parameter B=6;
    endinterface
    
    module common_module(bundle p);
      bit [p.A:0] x;
      bit [p.B:0] y;
      initial $display("%m %d %d",$bits(x), $bits(y));
    endmodule
    
    module top;
      bundle #(8,9) b1();
      bundle #(16,18) b2();
      common_module cm1(b1);
      common_module cm2(b2);
    endmodule