3

Assume you have a module at a low-level in your hierarchy that has a fairly complex parameter calculation. This parameter calculation can not be conveniently replicated in a higher-level module, because it uses information from other parameters at the low-level. Now assume you also have a module at a higher level in the hierarchy that requires referring to that parameter to calculate a different parameter.

Is there a way in (System)Verilog to read a parameter from a lower-level module's instantiation in the calculation of a higher-level module's parameter?

Of course, you could attempt to use an 'interface' here...

interface interface_low ();                                                                         

        localparam VERY_COMPLEX_PARAM = 1 + 1;                                                           

endinterface;                                                                                       

interface interface_high (interface_low if_low);                                                    

        localparam OTHER_PARAM = if_low.VERY_COMPLEX_PARAM + 1;                                          

endinterface

... but attempting to compile this snippet for simulation with Riviera-PRO will return the error "Parameter initial value cannot contain external references: if_low.COMPLEX_PARAM+1.". Alternatively, you can try something like...

module low_level #(parameter SOME_NUM = 1, localparam VERY_COMPLEX_PARAM = SOME_NUM + 1) (output logic [31 : 0] out);

        always_comb                                                                                 
        begin                                                                                       
                out = VERY_COMPLEX_PARAM;                                                           
        end                                                                                         

endmodule                                                                                           


module high_level (output logic [31:0] out);                                                        

        logic [31:0] low_out;                                                                       

        low_level #(.SOME_NUM (4)) ll (low_out);                                                    


        localparam OTHER_PARAM = ll.VERY_COMPLEX_PARAM + 1;                                         

        always_comb                                                                                 
        begin                                                                                       
                out = OTHER_PARAM;                                                                  
        end                                                                                         

endmodule  

... but again it leads to the error "Parameter initial value cannot contain external references: ll.VERY_COMPLEX_PARAM+1."

It is always possible to simply re-organize the implementation so that constant parameters are strictly passed downwards, but I feel this is a lackluster solution. In that case, the higher level modules are now calculating constants that refer to implementation details much lower in the hierarchy. It seems silly to add dependencies in low-level modules to higher-level modules simply to satisfy restrictions regarding the calculation of constants.

So, is there a better way?

A. Name
  • 33
  • 4

1 Answers1

1

Parameter evaluation must flow top to bottom. Your interface example should have worked as an interface port is not considered a hierarchical reference (it does work on two other tools I tried).

For your particular example, you could have used

const int OTHER_PARAM = ll.VERY_COMPLEX_PARAM + 1;  

As long as OTHER_PARAM is not being used in a place where a constant is required. You might have the same problem with synthesis tool support.

Another option is to put the parameters in a package and have both lower and upper modules import the same package.

dave_59
  • 39,096
  • 3
  • 24
  • 63