User Tools

Site Tools



This shows you the differences between two versions of the page.

Link to this comparison view

geda:icarus_ieee1364 [2012/02/20 15:14]
geda:icarus_ieee1364 [2012/02/20 15:14] (current)
Line 1: Line 1:
 +====== Icarus Verilog vs. IEEE1364 ======
 +<​code> ​               Icarus Verilog vs. IEEE1364
 +                Copyright 2000 Stephen Williams
 +The IEEE1364 standard is the bible that defines the correctness of the
 +Icarus Verilog implementation and behavior of the compiled
 +program. The IEEE1364.1 is also referenced for matters of
 +synthesis. So the ultimate definition of right and wrong comes from
 +those documents.
 +That does not mean that a Verilog implementation is fully
 +constrained. The standard document allows for implementation specific
 +behavior that, when properly accounted for, does not effect the
 +intended semantics of the specified language. It is therefore possible
 +and common to write programs that produce different results when run
 +by different Verilog implementations.
 +These are some issues where the IEEE1364 left unclear, unspecified or
 +simply wrong. I'll try to be precise as I can, and reference the
 +standard as needed. I've made implementation decisions for Icarus
 +Verilog, and I will make clear what those decisions are and how they
 +affect the language.
 +Consider this module:
 +    module sample1;
 +        initial foo = 1;
 + reg foo;
 + wire tmp = bar;
 + initial #1 $display("​foo = %b, bar = %b", foo, tmp);
 +    endmodule
 +Notice that the ``reg foo;''​ declaration is placed after the first
 +initial statement. It turns out that this is a perfectly legal module
 +according to the -1995 and -2000 versions of the standard. The
 +statement ``reg foo;''​ is a module_item_declaration which is in turn a
 +module_item. The BNF in the appendix of IEEE1364-1995 treats all
 +module_item statements equally, so no order is imposed.
 +Furthermore,​ there is no text (that I can find) elsewhere in the
 +standard that imposes any ordering restriction. The sorts of
 +restrictions I would look for are "​module_item_declarations must
 +appear before all other module_items"​ or "​variables must be declared
 +textually before they are referenced."​ Such statements simply do not
 +exist. (Personally,​ I think it is fine that they don'​t.)
 +The closest is the rules for implicit declarations of variables that
 +are otherwise undeclared. In the above example, ``bar''​ is implicitly
 +declared and is therefore a wire. However, although ``initial foo = 1;''​
 +is written before foo is declared, foo *is* declared within the
 +module, and declared legally by the BNF of the standard.
 +Here is another example:
 +    module sample2;
 + initial = 1;
 +        test x;
 + initial #1 $display("​foo = %b",;
 +    endmodule
 +    module test;
 +        reg foo;
 +    endmodule;
 +From this example one can clearly see that foo is once again declared
 +after its use in behavioral code. One also sees a forward reference of
 +an entire module. Once again, the standard places no restriction on
 +the order of module declarations in a source file, so this program is,
 +according to the standard, perfectly well formed.
 +Icarus Verilog interprets both of these examples according to "The
 +Standard As I Understand It." However, commercial tools in general
 +break down with these programs. In particular, the first example
 +may generate different errors depending on the tool. The most common
 +error is to claim that ``foo''​ is declared twice, once (implicitly) as
 +a wire and once as a reg.
 +So the question now becomes, "Is the standard broken, or are the tools
 +limited?"​ Coverage of the standard seems to vary widely from tool to
 +tool so it is not clear that the standard really is at fault. It is
 +clear, however, that somebody goofed somewhere.
 +My personal opinion is that there is no logical need to require that
 +all module_item_declarations precede any other module items. I
 +personally would oppose such a restriction. It may make sense to
 +require that declarations of variables within a module be preceded by
 +their use, although even that is not necessary for the implementation
 +of efficient compilers.
 +However, the existence hierarchical naming syntax as demonstrated in
 +sample2 can have implications that affect any declaration order
 +rules. When reaching into a module with a hierarchical name, the
 +module being referenced is already completely declared (or not
 +declared at all, as in sample2) so module_item order is completely
 +irrelevant. But a "​declare before use" rule would infect module
 +ordering, by requiring that modules that are used be first defined.
 +Consider a function negate that wants to take a signed integer value
 +and return its negative:
 + function integer negate;
 +     input [15:0] val;
 +     negate = -val;
 + endfunction
 +This is not quite right, because the input is implicitly a reg type,
 +which is unsigned. The result, then, will always be a negative value,
 +even if a negative val is passed in.
 +It is possible to fix up this specific example to work properly with
 +the bit pattern of a 16bit number, but that is not the point. What's
 +needed is clarification on whether an input can be declared in the
 +port declaration as well as in the contained block declaration.
 +As I understand the situation, this should be allowed:
 + function integer negate;
 +     input [15:0] val;
 +     reg signed [15:0] val;
 +     negate = -val;
 + endfunction
 +In the -1995 standard, the variable is already implicitly a reg if
 +declared within a function or task. However, in the -2000 standard
 +there is now (as in this example) a reason why one might want to
 +actually declare the type explicitly.
 +I think that a port *cannot* be declared as an integer or time type
 +(though the result can) because the range of the port declaration must
 +match the range of the integer/​time declaration,​ but the range of
 +integers is unspecified. This, by the way, also applies to module
 +With the above in mind, I have decided to *allow* function and task
 +ports to be declared with types, as long as the types are variable
 +types, such as reg or integer. Without this, there would be no
 +portable way to pass integers into functions/​tasks. The standard does
 +not say it is allowed, but it doesn'​t *disallow* it, and other
 +commercial tools seem to work similarly.
 +When the `timescale directive is present, the compiler is supposed to
 +round fractional times (after scaling) to the nearest integer. The
 +confusing bit here is that it is apparently conventional that if the
 +`timescale directive is *not* present, times are rounded towards zero
 +The IEEE1364-1995 standard clearly states in Table 8-1 that the x
 +symbols is allowed in input columns, but is not allowed in
 +outputs. Furthermore,​ none of the examples have an x in the output of
 +a primitive. Table 8-1 in the IEEE1364-2000 also says the same thing.
 +However, the BNF clearly states that 0, 1, x and X are valid
 +output_symbol characters. The standard is self contradictory. So I
 +take it that x is allowed, as that is what Verilog-XL does.
 +There seems to be ambiguity in how code like this should be parsed:
 + repeat (5) @(posedge clk) <​statement>;​
 +There are two valid interpretations of this code, from the
 +IEEE1364-1995 standard. One looks like this:
 +    procedural_timing_control_statement ::=
 +          delay_or_event_control ​ statement_or_null
 +    delay_or_event_control ::=
 +          event_control
 +          | repeat ( expression ) event_control
 +If this interpretation is used, then the statement <​statement>​ should
 +be executed after the 5th posedge of clk. However, there is also this
 +    loop_statement ::=
 +         ​repeat ( expression ) statement
 +If *this* interpretation is used, then <​statement>​ should be executed
 +5 times on the posedge of clk. The way the -1995 standard is written,
 +these are both equally valid interpretations of the example, yet they
 +produce very different results. The standard offers no guidance on how
 +to resolve this conflict, and the IEEE1364-2000 DRAFT does not improve
 +the situation.
 +Practice suggests that a repeat followed by an event control should be
 +interpreted as a loop head, and this is what Icarus Verilog does, as
 +well as all the other major Verilog tools, but the standard does not
 +say this.
 +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.
 +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 then 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_00_00_00_00}
 + {'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.
 +A module declaration like this declares a module that takes three ports:
 + module three (a, b, c);
 +   input a, b, c;
 +   reg x;
 + endmodule
 +This is fine and obvious. It is also clear from the standard that
 +these are legal instantiations of this module:
 + three u1 (x,y,z);
 + three u2 ( ,y, );
 + three u3 ( , , );
 + three u4 (.b(y));
 +In some of the above examples, there are unconnected ports. In the
 +case of u4, the pass by name connects only port b, and leaves a and c
 +unconnected. u2 and u4 are the same thing, in fact, but using
 +positional or by-name syntax. The next example is a little less
 + three u4 ();
 +The trick here is that strictly speaking, the parser cannot tell
 +whether this is a list of no pass by name ports (that is, all
 +unconnected) or an empty positional list. If this were an empty
 +positional list, then the wrong number of ports is given, but if it is
 +an empty by-name list, it is an obviously valid instantiation. So it
 +is fine to accept this case as valid.
 +These are more doubtful:
 + three u5(x,y);
 + three u6(,);
 +These are definitely positional port lists, and they are definitely
 +the wrong length. In this case, the standard is not explicit about
 +what to do about positional port lists in module instantiations,​
 +except that the first is connected to the first, second to second,
 +etc. It does not say that the list must be the right length, but every
 +example of unconnected ports used by-name syntax, and every example of
 +ordered list has the right size list.
 +Icarus Verilog takes the (very weak) hint that ordered lists should be
 +the right length, and will therefore flag instances u5 and u6 as
 +errors. The IEEE1364 standard should be more specific one way or the
 +Consider this example:
 + reg [7:0] vec;
 + wire [4:0] idx = <​expr>;​
 + [...]
 + vec[idx] = 1;
 +So long as the value of idx is a valid bit select address, the
 +behavior of this assignment is obvious. However, there is no explicit
 +word in the standard as to what happens if the value is out of
 +range. The standard clearly states the value of an expression when the
 +bit-select or part select is out of range (the value is x) but does
 +not address the behavior when the expression is an l-value.
 +Icarus Verilog will take the position that bit select expressions in
 +the l-value will select oblivion if it is out of range. That is, if
 +idx has a value that is not a valid bit select of vec, then the
 +assignment will have no effect.
 +The interaction between blocking assignments in procedural code and
 +logic gates in gate-level code and expressions is poorly defined in
 +Verilog. Consider this example:
 +   reg a;
 +   reg b;
 +   wire q = a & b;
 +   ​initial begin
 +      a = 1;
 +      b = 0;
 +      #1 b = 1;
 +      if (q !== 0) begin
 + $display("​FAILED -- q changed too soon? %b", q);
 + $finish;
 +      end
 +   end
 +This is a confusing situation. It is clear from the Verilog standard
 +that an assignment to a variable using a blocking assign causes the
 +l-value to receive the value before the assignment completes. This
 +means that a subsequent read of the assigned variable *must* read back
 +what was blocking-assigned.
 +However, in the example above, the "wire q = a & b" expresses some
 +gate logic between a/b and q. The standard does not say whether a read
 +out of logic should read the value computed from previous assigns to
 +the input from the same thread. Specifically,​ when "​a"​ and "​b"​ are
 +assigned by blocking assignments,​ will a read of "​q"​ get the computed
 +value or the existing value?
 +In fact, existing commercial tools do it both ways. Some tools print
 +the FAILED message in the above example, and some do not. Icarus
 +Verilog does not print the FAILED message in the above example,
 +because the gate value change is *scheduled* when inputs are assigned,
 +but not propagated until the thread gives up the processor.
 +Icarus Verilog chooses this behavior in order to filter out zero-width
 +pulses as early as possible. The implication of this is that a read of
 +the output of combinational logic will most likely *not* reflect the
 +changes in inputs until the thread that changed the inputs yields
 +Bit and part selects are supposed to only be supported on vector nets
 +and variables (wires, regs, etc.) However, it is common for Verilog
 +compilers to also support bit and part select on parameters. Icarus
 +Verilog also chooses to support bit and part selects on parameter
 +names, but we need to define what that means.
 +A bit or a part select on a parameter expression returns an unsigned
 +value with a defined size. The parameter value is considered be a
 +constant vector of bits foo[X:0]. That is, zero based. The bit and
 +part selects operate from that assumption.
 +Verilog 2001 adds syntax to allow the user to explicitly declare the
 +parameter range (i.e. parameter [5:0] foo = 9;) so Icarus Verilog will
 +(or should) use the explicitly declared vector dimensions to interpret
 +bit and part selects.
 +Consider this example:
 +   reg [ 5:0] clock;
 +   ​always @(posedge clock) [do stuff]
 +The IEEE1364 standard clearly states that the @(posedge clock) looks
 +only at the bit clock[0] (the least significant bit) to search for
 +edges. It has been pointed out by some that Verilog XL instead
 +implements it as "​@(posedge |clock)":​ it looks for a rise in the
 +reduction or of the vector. Cadence Design Systems technical support
 +has been rumored to claim that the IEEE1364 specification is wrong,
 +but NC-Verilog behaves according to the specification,​ and thus
 +different from XL.
 +Icarus Verilog, therefore, takes the position that the specification
 +is clear and correct, and it behaves as does NC-Verilog in this
 +The IEEE1364 standard clearly states that in VCD files, the $dumpoff
 +section checkpoints all the dumped variables as X values. For reg and
 +wire bits/​vectors,​ this obviously means 'bx values. Icarus Verilog
 +does this, for example:
 +    $dumpoff
 +    x!
 +    x"
 +    $end
 +Real variables can also be included in VCD dumps, but it is not at
 +all obvious what is supposed to be dumped into the $dumpoff-$end
 +section of the VCD file. Verilog-XL dumps "r0 !" to set the real
 +variables to the dead-zone value of 0.0, whereas other tools, such as
 +ModelTech, ignore real variables in this section.
 +For example (from XL):
 +    $dumpoff
 +    r0 !
 +    r0 "
 +    $end
 +Icarus Verilog dumps NaN values for real variables in the
 +$dumpoff-$end section of the VCD file. The NaN value is the IEEE754
 +equivalent of an unknown value, and so better reflects the unknown
 +(during the dead zone) status of the variable, like this:
 +    $dumpoff
 +    rNaN !
 +    rNaN "
 +    $end
 +It turns out that NaN is conventionally accepted by scanf functions,
 +and viewers that support real variables support NaN values. So while
 +the IEEE1364 doesn'​t require this behavior, and given the variety that
 +already seems to exist amongst VCD viewers in the wild, this behavior
 +seems to be acceptable according to the standard, is a better mirror
 +of 4-value behavior in the dead zone, and appears more user friendly
 +when viewed by reasonable viewers.
 +$Id: ieee1364-notes.txt,​v 1.17 2003/07/15 03:49:22 steve Exp $
 +$Log: ieee1364-notes.txt,​v $
 +Revision 1.17  2003/07/15 03:​49:​22 ​ steve
 + ​Spelling fixes.
 +Revision 1.16  2003/04/14 03:​40:​21 ​ steve
 + Make some effort to preserve bits while
 + ​operating on constant values.
 +Revision 1.15  2003/02/16 23:​39:​08 ​ steve
 + NaN in dead zones of VCD dumps.
 +Revision 1.14  2003/02/06 17:​51:​36 ​ steve
 + Edge of vectors notes.
 +Revision 1.13  2002/08/20 04:​11:​53 ​ steve
 + ​Support parameters with defined ranges.
 +Revision 1.12  2002/06/11 03:​34:​33 ​ steve
 + ​Spelling patch (Larry Doolittle)
 +Revision 1.11  2002/04/27 02:​38:​04 ​ steve
 + ​Support selecting bits from parameters.
 +Revision 1.10  2002/03/31 01:​54:​13 ​ steve
 + Notes about scheduling
 +Revision 1.9  2002/01/26 02:​08:​07 ​ steve
 + ​Handle x in l-value of set/x
 +Revision 1.8  2001/08/01 05:​17:​31 ​ steve
 + ​Accept empty port lists to module instantiation.
 +Revision 1.7  2001/02/17 05:​27:​31 ​ steve
 + I allow function ports to have types.
 +Revision 1.6  2001/02/12 16:​48:​04 ​ steve
 + Rant about bit widths.
 +Revision 1.5  2001/01/02 17:​28:​08 ​ steve
 + ​Resolve repeat ambiguity in favor of loop.
 +Revision 1.4  2001/01/01 19:​12:​35 ​ steve
 + ​repeat loops ambiguity.
 +Revision 1.3  2000/12/15 00:​21:​46 ​ steve
 + ​rounding of time and x in primitives.
 +Revision 1.2  2000/11/19 22:​03:​04 ​ steve
 + ​Integer parameter comments.
 +Revision 1.1  2000/07/23 18:​06:​31 ​ steve
 + ​Document ieee1364 issues.</​code>​
geda/icarus_ieee1364.txt ยท Last modified: 2012/02/20 15:14 (external edit)