Electronic – How to calculate constant values across several modules at compile time in Verilog

system-verilogverilog

I have a Verilog module that uses three instances of the same low-level module, called 'pole'. The instances are identical, except for a constant offset value, which is provided by the top level. There are other constant values within 'pole' as well.

Here's a rough pseudo-code concept:
(please forgive any syntax typos, I'm just trying to illustrate the idea)

module toplevel{
    localparam offset0 = 0;
    localparam offset120 = 120;
    localparam offset240 = 240;

    pole myPole0(offset0, variable);
    pole myPole120(offset120, variable);
    pole myPole240(offset240, variable);
}

module pole{
   input offset;
   input variable;

   localparam x = 1;
   localparam y = 2;
   localparam z = 3;
   localparam transitionConst = x + y + z + offset;
   reg transitionPoint = transitionConst + variable;
}

'variable' is dynamically updated during operation, but is consistent across each instance of pole. 'offset' is statically set at compile time, but there is a different offset value for each pole.

I want to calculate the total of the constant values (transitionConst) for reg transitionPoint at compile time. How do I do this?

I tried using a localparam as shown above, but this gives me compilation errors at the 'pole' level because offset is not a constant. Obviously, I know that I will be providing offset as a different constant for each instance of pole, but
the compiler doesn't know that. Is there an easy way to add constants across multiple modules at compile time?

Best Answer

With variable as an input, the compiler can't assign a constant value to transitionConst, as you've discovered.

You should declare your module like this, and then override the OFFSET parameter as a parameter to each invocation of the module. localparam variables may not be overriden, but parameter can be as shown. You can also supply a default value to the parameter, so you don't need to override it if it's not necessary. I chose variable to be 32 bits wide, but that's arbitrary*.

module pole #(parameter OFFSET = 0) (input logic [31:0] variable);
    localparam x = 1;
    localparam y = 1;
    localparam z = 1;

    localparam transitionConst = x + y + z + OFFSET;
    reg [31:0] transitionPoint = transitionConst + variable;
endmodule : pole

You can then invoke this in your top module like this:

module toplevel();
    localparam offset0 = 0;
    localparam offset120 = 120;
    localparam offset240 = 240;

    logic [31:0] variable;

    pole mypole0(.variable(variable));  // no need to use offset0
    pole #(.OFFSET(offset120)) mypole120(.variable(variable));
    pole #(.OFFSET(offset240)) mypole240(.variable(variable));
endmodule : toplevel

*: As declared, the localparams will be 32 bits wide