1
\$\begingroup\$

I have a SystemVerilog module that calculates a constant. How can I make this constant available to an enclosing module?

Parameters are good for passing constants into a submodule, but they don't seem appropriate for passing constants out of a submodule, because the enclosing module is allowed to set the parameter to whatever it wants (which is what I'm trying to avoid).

For example, suppose the submodule calculates a constant called LATENCY. The enclosing module needs to use this value to align its pipeline stages with the submodule's stages.

module sub#( parameter LATENCY=3 )( input clock, input in, output out );
    ...
endmodule

module enclosing( input clock, input in, output out );

sub i1( .clock, .in, .out );

// can I access i1.LATENCY here at compile time?

sub#( .LATENCY(1) ) i2( .clock, .in, .out );

// but, can I prevent LATENCY from being changed?

endmodule

Does such a mechanism exist?

Or, if only parameters are available, is the submodule supposed to call $error() if the parameter is not correct?

Thanks

\$\endgroup\$
2
  • \$\begingroup\$ Constant is a overloaded, ambiguous term. There are compile time constants, and run-time constants. Parameters are definitely calculated at compile time, but its unclear if you really mean to define a function instead of a module. \$\endgroup\$
    – dave_59
    Mar 13 at 0:43
  • \$\begingroup\$ Regarding how LATENCY is declared, I was trying to ask how to declare LATENCY such that it could not be changed by the enclosing (ie instantiating) module. \$\endgroup\$
    – Spices
    Mar 13 at 1:05

2 Answers 2

2
\$\begingroup\$

I have a SystemVerilog module that calculates a constant.
How can I make this constant available to an enclosing module?

You are able to use a hierarchical name reference to a parameter, localparam (constants), or variables in a child module.
Ref IEEE 1800 2017 SystemVerilog section 23.6 Hierarchical names

The ability to access objects using a hierarchical naming is not limited to just the testbench. Modules anywhere in the hierarchy can access other modules by using a hierarchical name.

The ability to access objects using a hierarchical naming is not limited to compile time/elaboration time. Objects that change at run time can be referenced also.

Here is a relevant quote from the spec section I referenced
"Any named SystemVerilog object or hierarchical name reference can be referenced uniquely in its full form by concatenating the names of the modules, module instance names, generate blocks, tasks, functions, assertion labels, named assertion action blocks, or named blocks that contain it. The period character shall be used to separate each of the names in the hierarchy, except for escaped identifiers embedded in the hierarchical name reference, which are followed by separators composed of white space and a periodcharacter."

Example

module tb ();
  
  enclosing dut();
 
endmodule

Enclosing

module enclosing();

  sub u1();

  // accessing a variable in the child module using a hierarchical name
  initial 
    $display(u1.FOO);

endmodule

Child module

module sub();

  // calculate a constant
  // the parent can't change this, its not passed in
  localparam FOO = 7 * 7;

endmodule

Produces

xcelium> run
          49

The ability to access a child module is not limited to simulation. Xilinx states that hierarchical names are supported for synthesis Vivado UG901 Synthesis Guide 2023 p288

enter image description here

It seems reasonable that not all synthesis tools support hierarchical names (I don't know). Maybe check your vendor if its not Xilinx.

If you don't trust the idea of hierarchical names, then create a small design which uses hierarchical names to do what you want then run it thru synthesis and examine the synthesis results as a verification step in your process. Or, deploy it to the lab and verify the behavior on hardware.


Parameters are good for passing constants into a submodule, but they don't seem appropriate for passing constants out of a submodule, because the enclosing module is allowed to set the parameter to whatever it wants (which is what I'm trying to avoid).

If you don't want to use a parameter, then use localparam in the child module.
See Difference between localparam and parameter

Or just use a parameter which is not part of the module header, so that the parent can't change it.
Like this

module sub();

  parameter FOO = 7 * 7;

endmodule

...the enclosing module is allowed to set the parameter to whatever it wants

There is no requirement for any parameter to be part of a module header. If you don't want the parent module to change them, then don't put the parameter in question on the child module header. This seems to be a point of confusion in the question.


Hierarchical referencing works fine from a coding and tools perspective. However, some engineers prefer not to use it in RTL code. One reason is that when a module is blindly probed from somewhere else, the module itself is no longer completely specifies its own interface signals in its module header. It can be difficult to understand & maintaining a design, if its not clear how modules are connected. Consider the difficulty debugging a large design (hundreds of thousands of unique modules) that you don't know and many of the modules obtain their input not from the module ports but from sneak paths using hierarchal referencing.

Hierarchical referencing is often used for monitoring in testbenches.

\$\endgroup\$
1
  • \$\begingroup\$ Ah, I wasn't aware that the enclosing module could access a submodule's localparam. At least within Vivado. Thanks. \$\endgroup\$
    – Spices
    Mar 13 at 20:01
2
\$\begingroup\$

No direct approach exist, they way you desire it to exist.

Does such a mechanism exist?

parameters defined within a submodule are not directly accessible (read) by the top module or as you say it the enclosing module. Here is the thing about parameters, they are static values and cannot be modified or accessed directly outside the module they are defined in.

However if you still insist on getting the parameters value out of the submodule then you have to develop a mechanisms. One way is, you can declare an output port in the submodule to convey the parameter value to the top module. But this will limit the use of parameter. You will not be able to declare the width of wire or reg but you will be able to only use the value as a constant to assign to a register or in a computation (I believe this is your desired case).

module sub#( parameter LATENCY=3 )( input clock, input in, output out, output [31:0] my_parameter );
    assign my_parameter = LATENCY;
    ...
endmodule

module enclosing( input clock, input in, output out );

sub i1( .clock, .in, .out, .my_parameter );//Here my_parameter will be 3


sub#( .LATENCY(1) ) i2( .clock, .in, .out, .my_parameter  );//Here my_parameter will be 1


endmodule

Secondly, if you want the top module to not change the parameters of the submodule then you better not instantiate that specific parameter and that will leave the parameter to its default value.

Regarding how LATENCY is declared, I was trying to ask how to declare LATENCY such that it could not be changed by the enclosing (i.e. instantiating) module.

About the // can I access i1.LATENCY here at compile time?, You can access it if it is in the testbench but if its part of the design then you cannot access it. In the synthesized design every connection is made through physical wires.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Hmm, it seems that you and Mikef are saying different things. Maybe the difference is runtime vs compile time? (I was always thinking compile time.) I can confirm that the Xilinx tools allow me to reference a submodule's localparams at compile time. \$\endgroup\$
    – Spices
    Mar 13 at 20:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.