A Verilog parameter infers its type from its value — the myth that there is a default signed integer parameter type in Verilog

Because it’s so common to assign a signed integer constant to a Verilog parameter

parameter SIZE = 8;

a myth has arisen that there is a default signed integer parameter type in Verilog.

But there is no default parameter type in Verilog. The type of a parameter (or a local parameter) is the type of whatever value is eventually assigned to it during elaboration. Override SIZE above with "four score and seven years ago" and its type becomes an unsigned vector of width 240.

Verilog 2001 (IEEE Std 1364-2001) added the ability to write

parameter integer SIZE = 8;

so that the right-hand side would instead be evaluated in the context of an assignment to a parameter of type integer. But that never caught on, because apparently it’s considered too painful to write integer after every parameter.

(An extra complication is that Verilog also has some half-way specifications you can add to parameters. For the horrible details, see the bottom of p. 694 in IEEE Std 1800-2012.)

When SystemVerilog extended the Verilog type system, it allowed any of those new types to be used after parameter. Most importantly here, it added an int type that is a 2-state version of integer.

If you are confident it’s only going to be a simple signed integer parameter value, such as #(.N(8)), then I guess even in SystemVerilog you could go ahead and still omit the explicit type from the parameter declaration, because it’s too painful to write the three extra characters int after every parameter.

But if I personally were defining a SystemVerilog coding guideline, I would insist on parameter int N = … or some other explicit type, instead of letting it depend on the type of the value.

parameter int SIZE = 8;


  1. module test
    parameter s_rev = "im1_14nm5",
    //string t_die = to_die_name( s_rev);
    localparam string t_die = to_die_name( s_rev);

    initial begin
    $display("Input:: s_rev=%s", s_rev);
    $display("Output:: t_die=%s", t_die);

    function string to_die_name(input string s_rev);
    // to_die_name = s_rev;
    if (silicon_rev == "im1_14nm5") to_die_name = s_rev;

    endmodule // test

    Consider this piece of code above.
    When t_die is declared as a “string” only, the function returns “im1_14nm5” onto t_die. Which is nothing but a string output from the function being assigned to another signal of same datatype (string t_die). So this should be fine. Is there anything different?
    There are two issues:
    1. The function returns an empty string when t_die datatype is “localparam string t_die”. So basically the above program output is “t_die=”. Why is this the case?
    2. The function returns the correct value when I change the module parameter “parameter s_rev” to “parameter string s_rev”. How/why should this change the way the “localparam string” value?

    Please help.


    • Did you mean

      if (s_rev == "im1_14nm5")

      instead of

      if (silicon_rev == "im1_14nm5")



  2. Is there a way to have a parameter as an array? I want to have an array of integer as a parameter and use it in a generate loop (different parameter to different instantiations).

    I tried:

    parameter [31:0] SIZE [4:0] = {32'd8, 32'd16, 32'd8, 32'd32, 32'd128};

    Get an “illegal assignment” in SpyGlass…


    • That’s legal, but only in SystemVerilog-2009 or later. It’s called an “unpacked array concatenation” and is discussed in 10.10 of IEEE Std 1800-2012.

      If you instead use an assignment pattern, by adding an apostrophe, then it would even be legal in SystemVerilog-2005. That’s discussed in 10.9 of IEEE Std 1800-2012.

      parameter [31:0] SIZE [4:0] = '{32'd8, 32'd16, 32'd8, 32'd32, 32'd128};

      I would recommend

      parameter int SIZE [4:0] = '{32'd8, 32'd16, 32'd8, 32'd32, 32'd128};


  3. I find these kinds of design decisions in the language to be really bad. Why do there have to be 1000 hidden rules that you have to remember. I also would have preferred it if the language would have required you to specify the type of the parameter.


    • And there’s rarely an opportunity to clean up early design decisions in these language standards after the lessons of experience, because the demand for backward compatibility is so strong. The only counter-example I can think of in Verilog, where something was actually changed backward incompatibly, instead of just adding more, is “generate”. Unfortunately, there they also dropped the requirement for a generate scope name, because SV had already done so, leading to the painful “External names for unnamed generate blocks”.


  4. Unless you want them to be dependent on the value type…
    I don’t much like the idea of writing one type in the instantiation, only to find that the parameter actually gets a different type…


    • Do you have an SV example in mind? The parameter type itself can be a parameter, as in “parameter T = …” where the T is passed in from the instantiation. If it’s strongly typed, such as an unpacked struct, then a mismatched parameter value will even provoke an elaboration-time error.

      The 6.16 example

      parameter string default_name = “John Smith”;”

      should also yield an elaboration-time error if default_name is overridden with an integer?


Tell me (anonymous OK)

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s