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?