Here we document Verilog language details that may be different from common Verilog tools, or standard, baseline Verilog. These are issues that may effect portability with other Verilog compilers, or may just be clarifications where the LRM allows some latitude.

Unsized Numeric Constants are Not Limited to 32 Bits[edit | edit source]

The Verilog standard allows Verilog implementations to limit the size of unsized constants to a bit width of at least 32. That means that a constant 17179869183 (36'h3_ffff_ffff) may overflow some compilers. In fact, it is common to limit these values to 32bits. However, a compiler may just as easily choose another width limit, for example 64bits. That value is equally good.

However, it is not required that an implementation truncate at 32 bits, and in fact Icarus Verilog does not truncate at all. It will make the unsized constant as big as it needs to be to hold the value accurately. This is especially useful in situations like this;

reg [width-1:0] foo = 17179869183;

The programmer wants the constant to take on the width of the reg, which in this example is parameterized. Since constant sizes cannot be parameterized, the programmer ideally gives an unsized constant, which the compiler then expands/contracts to match the l-value.

Also, by choosing to not ever truncate, Icarus Verilog can handle code written for a 64bit compiler as easily as for a 32bit compiler. In particular, any constants that the user does not expect to be arbitrarily truncated by his compiler will also not be truncated by Icarus Verilog, no matter what that other compiler chooses as a truncation point.

Unsized Expressions[edit | edit source]

Icarus Verilog classes any expression containing an unsized numeric constant or unsized parameter value that is not part of a self-determined operand as an unsized expression. When calculating the bit width of an unsized expression, it extends the width of the expression to avoid arithmetic overflow or underflow; in other words, the expression width will be made large enough to represent any possible arithmetic result of the expression. If the expression contains operations that do not follow the normal rules of arithmetic (e.g. an explicit or implicit cast between signed and unsigned values), the expression width will be extended to at least the width of an integer.

An exception to the above is made if the expression contains a shift or power operator with a right hand operand that is a non-constant unsized expression. In this case any expansion of the expression width due to that operation is limited to the width of an integer, to avoid excessive expression widths (without this, an expression such as 2**(i-1), where i is an integer, would be expanded to 2**33 bits).

The above behaviour is a deviation from the Verilog standard, which states that when calculating an expression width, the width of an unsized constant number is the same as the width of an integer. If you need strict standard compliance (for compatibility with other EDA tools), then, starting with v0.10 (currently in development), the compiler has a command line option, -gstrict-expr-width, which disables the special treatment of unsized expressions. With this option, the compiler will output a warning message if an unsized numeric constant is encountered that cannot be represented in integer-width bits and will truncate the value.

If you are simulating synthesisable code, it is recommended that the -gstrict-expr-width option is used, as this eliminates a potential source of synthesis vs. simulation mismatches.

Unsized Parameters[edit | edit source]

Icarus Verilog classes any parameter declaration that has no explicit or implicit range specification as an unsized parameter declaration. When calculating the bit width of the final value expression for the parameter, it follows the same rules as it does for unsized expressions, regardless of whether or not the expression contains any unsized numeric constants.

If the final value expression for an unsized parameter is an unsized expression (i.e. does contain unsized numeric constants), any subsequent use of that parameter will be treated as if it was an unsized numeric constant. If not, it will be treated as if it was a numeric constant of the appropriate size. For example, with the declarations:

localparam Value1 =  'd3 +  'd2;
localparam Value2 = 2'd3 + 2'd2;

any subsequent use of Value1 will be treated as if the programmer had written 'd5, and any subsequent use of Value2 will be treated as if the programmer had written 3'd5. In particular, note that Value2 can be used as a concatenation operand, but Value1 cannot.

The above behaviour is a deviation from the Verilog standard. As for unsized expressions, if you need strict standard compliance. use the -gstrict-expr-width compiler option.

Unsized Expressions as Arguments to Concatenation[edit | edit source]

The Verilog standard clearly states in 4.1.14:

"Unsized constant numbers shall not be allowed in
concatenations. This is because the size of each
operand in the concatenation is needed to calculate
the complete size of the concatenation."

So for example the expression {1'b0, 16} is clearly illegal. It also stands to reason that {1'b0, 15+1} is illegal, for exactly the same justification. What is the size of the expression (15+1)? Furthermore, it is reasonable to expect that (16) and (15+1) are exactly the same so far as the compiler is concerned.

Unfortunately, Cadence seems to feel otherwise. In particular, it has been reported that although {1'b0, 16} causes an error, {1'b0, 15+1} is accepted. Further testing shows that any expression other than a simple unsized constant is accepted there, even if all the operands of all the operators that make up the expression are unsized integers.

This is a semantic problem. Icarus Verilog doesn't limit the size of integer constants. This is valid as stated in 2.5.1 Note 3:

"The number of bits that make up an unsized number (which is a simple decimal number or a number without the size specification) shall be at least 32." [emphasis added]

Icarus Verilog will hold any integer constant, so the size will be as large as it needs to be, whether that is 64bits, 128bits, or more. With this in mind, what is the value of these expressions?

{'h1 << 32}
{'h0_00_00_00_01 << 32}
{'h5_00_00_00_00 + 1}

These examples show that the standard is justified in requiring that the operands of concatenation have size. The dispute is what it takes to cause an expression to have a size, and what that size is. Verilog-XL claims that (16) does not have a size, but (15+1) does. The size of the expression (15+1) is the size of the adder that is created, but how wide is the adder when adding unsized constants?

One might note that the quote from section 4.1.14 says "Unsized constant numbers shall not be allowed." It does not say "Unsized expressions...", so arguably accepting (15+1) or even (16+0) as an operand to a concatenation is not a violation of the letter of the law. However, the very next sentence of the quote expresses the intent, and accepting (15+1) as having a more defined size then (16) seems to be a violation of that intent.

Whatever a compiler decides the size is, the user has no way to predict it, and the compiler should not have the right to treat (15+1) any differently then (16). Therefore, Icarus Verilog takes the position that such expressions are unsized and are not allowed as operands to concatenations. Icarus Verilog will in general assume that operations on unsized numbers produce unsized results. There are exceptions when the operator itself does define a size, such as the comparison operators or the reduction operators. Icarus Verilog will generate appropriate error messages.

Scope of macro defines doesn't extend into libraries[edit | edit source]

Icarus Verilog does preprocess modules that are loaded from libraries via the -y mechanism to substitute macros and load includes. However, the only macros defined during compilation of an automatically loaded library module file are those that it defines itself (or includes) or that are defined on the command line or in the command file.

Specifically, macros defined in the non-library source files are not remembered when the library module is loaded, and macros defined in a library module do not escape into the rest of the design. This is intentional. If it were otherwise, then compilation results might vary depending on the order that libraries are loaded, and that is unacceptable.

For example, given sample library module "a.v":

`define MACRO_A 1
module a(input x);
    always @(x) $display("x=",x);

and sample library module "b.v":

module b(input y);
`ifdef MACRO_A
    always @(y) $display("MACRO_A is defined",,y);
    always @(y) $display("MACRO_A is NOT defined",,y);

If a program instantiates both of these modules, there is no way to know which will be loaded first by the compiler, so if the definition of MACRO_A in "a.v" were to escape, then there is no way to predict or control whether MACRO_A is defined when "b.v" is processed. So the preprocessor processes automatic library module files as if they are in their own compilation unit, and you can know that MACRO_A will not be defined in "b.v" unless it is defined on the command line (a "-D" flag) or in the command file (a "+define+" record.)

Of course if "a.v" and "b.v" were listed in the command file or on the command line, then the situation is different; the order is clear. The files are processed as if they were concatenated in the order that they are listed on the command line. The non-library modules are all together in a main compilation unit, and they are all processed before any library modules are loaded.

It is said that some commercial compilers do allow macro definitions to span library modules. That's just plain weird. However, as of 31 December 2007, there is a special case that Icarus Verilog does handle.

Preprocessor definitions that are made in files explicitly listed on the command line or in the command file, do pass into implicitly loaded library files. For example, given the source file "x.v":

module main;
    reg foo;
    b dut(foo);
`define MACRO_A

And the library module file "b.v" described above, the situation is well defined; assuming the "x.v" file is listed on the command line or in the command file. The library module will receive the MACRO_A definition from the last explicitly loaded source file. The position of the define of MACRO_A in the explicitly loaded source files does not matter, as all explicitly loaded source files are preprocessed before any library files are loaded.

Continuous assign l-values can implicit-define wires[edit | edit source]

The IEEE1364-2001 standard, Section 3.5, lists the cases where nets may be implicitly created. These include:

  • identifier is a module port, or
  • identifier is passed as a port to a primitive or module.

This does not seem to include continuous assignment l-values (or r-values) so the standard does not justify allowing implicit declarations of nets by continuous assignment.

However, it has been reported that many Verilog compilers, including the big name tools, do allow this. So, Icarus Verilog will allow it as well, as an extension. If -g2x (the default) is used, this extension is enabled. To turn off this behavior, use the -g2 flag.

Dumping array words ($dumpvars)[edit | edit source]

Icarus has the ability to dump individual array words. They are only dumped when explicitly passed to $dumpvars. They are not dumped by default. For example given the following:

 module top;
   reg [7:0] array [2:0];
   initial begin
     $dumpvars(0, array[0], array[1]);

array[0] and array[1] will be dumped whenever they change value. They will be displayed as an escaped identifier and GTKWave fully supports this. Note that this is an implicitly created escaped identifier that could conflict with an explicitly created escaped identifier. You can automate adding the array word by adding an index definition

 integer idx;

and replacing the previous $dumpvars statement with

 for (idx = 0; idx < 2; idx = idx + 1) $dumpvars(0, array[idx]);

This will produce the same results as the previous example, but it is much easier to specify/change which elements are to be dumped. One important note regarding this syntax. Most system tasks/functions keep the variable selection (for this case it is a variable array word selection) context. If $dumpvars() did this then all callback created would point to this element and would use the same index which for the example above would have the value 2. This is certainly not what is desired and for this special case when $dumpvars() executes it uses the current index value to create a constant array selection and that is monitored instead of the original variable selection.

%g/%G Format Specifiers[edit | edit source]

In the 1364-2001 standard there is a general statement that the real number format specifiers will use the full formatting capabilities of C. This is then followed by an example that describes %10.3g. The example description would be correct for the e format specifier which should always have three fractional digits, but the g format specifier does not work that way. For it the .3 specifies that there will be three significant digits. What this means is that %g will always produce one less significant digit than %e and will only match the output from %f for certain values. For Example:

module top_level;
  real rval;
  initial begin
    rval = 1234567890;
    $display("This is g and e: %10.3g, %10.3e.", rval, rval);
    rval = 0.1234567890;
    $display("This is g and f: %10.3g, %10.3f.", rval, rval);
    rval = 1.234567890;
    $display("This is more g and f: %10.3g, %10.3f.", rval, rval);
endmodule // top_level

Will produce the following output:

This is g and e:   1.23e+09,  1.235e+09.
This is g and f:      0.123,      0.123.
This is more g and f:       1.23,      1.235.

Referencing declarations within an unnamed generate block[edit | edit source]

The IEEE1364-2005 standard permits generate blocks to be unnamed, but states:

"If the generate block selected for instantiation is not named, it still creates a scope; but the declarations within it cannot be referenced using hierarchical names other than from within the hierarchy instantiated by the generate block itself."

The standard later defines a scheme for automatically naming the unnamed scopes for use with external interfaces.

Icarus Verilog implements the defined automatic naming scheme, but does not prevent the automatically generated names being used in a hierarchical reference. This behaviour is harmless - the automatically generated names are guaranteed to be unique within the enclosing scope, so there is no possibility of confusion with explicit scope names. However, to maintain code portability, it is recommended that this behavior is not exploited.

%v format specifier can display vectors[edit | edit source]

The IEEE1364-2005 standard limits the %v specifier in display strings to work only with a single bit. Icarus Verilog extends that to support displaying the strength of vectors. The output is a strength specifier for each bit of the vector, with underscore characters separating each bit, a la "St0_St1_Pu1_HiZ". Most other tools will just print the strength of the least significant bit of a vector, so this may give different output results for code that otherwise works fine.

assign/deassign and force/release of bit/part selects[edit | edit source]

Icarus Verilog allows as an extension the assign/deassign and force/release of variable bit and part selects in certain cases. This allows the Verilog test bench writer to assign/deassign for example single bits of a variable (register, etc.). Other tools will report this as an error.

repeat statement is sign aware[edit | edit source]

The standard does not specify what to do for this case, but it does say what a repeat event control should do. In Icarus the repeat statement is consistent with the repeat event control definition. If the argument is signed and is a negative value this will be treated the same as an argument value of 0.

Icarus Verilog specific system tasks[edit | edit source]

Icarus Verilog defines some additional system tasks that may not be present in other implementations. There are probably more than one, but right now we can document one of them here:

  • This function operates the same as the $finish system task, but adds the feature of specifying an exit code for the interpreter. This can be useful in automated test environments to indicate whether the simulation finished with or without errors.
Community content is available under CC-BY-SA unless otherwise noted.