• Top
    • Documentation
    • Books
    • Boolean-reasoning
    • Projects
    • Debugging
    • Std
    • Proof-automation
    • Macro-libraries
    • ACL2
    • Interfacing-tools
    • Hardware-verification
      • Gl
      • Esim
      • Vl2014
      • Sv
      • Fgl
      • Vwsim
      • Vl
        • Syntax
        • Loader
        • Warnings
        • Getting-started
        • Utilities
        • Printer
        • Kit
        • Mlib
        • Transforms
          • Unparameterization
          • Elaborate
          • Addnames
          • Annotate
            • Increment-elim
            • Make-implicit-wires
              • Shadowcheck
              • Implicit-wires-minutia
                • Implicit-wires-generate-scoping
                • Vl-genbase-make-implicit-wires
                • Vl-expr-names-for-implicit
                • Vl-make-implicit-wires-main
                • Vl-implicitst
                • Vl-make-port-implicit-wires
                • Vl-import-update-implicit
                • Vl-blockitemlist-update-implicit
                • Vl-blockitem-update-implicit
                • Vl-make-ordinary-implicit-wires
                • Vl-remove-declared-wires
                • Vl-implicitsts-restore-fast-alists
                • Vl-genblock-under-cond-make-implicit-wires
                • Vl-collect-exprs-for-implicit-wires-from-namedargs
                • Vl-genblock-make-implicit-wires
                • Vl-collect-exprs-for-implicit-wires-from-portargs
                • Vl-collect-exprs-for-implicit-wires-from-namedarg
                • Vl-gateinst-exprs-for-implicit-wires
                • Vl-modinst-exprs-for-implicit-wires
                • Vl-genelementlist-make-implicit-wires
                • Vl-packagemap-find-name
              • Basic-bind-elim
              • Argresolve
              • Basicsanity
              • Portdecl-sign
              • Enum-names
              • Port-resolve
              • Udp-elim
              • Vl-annotate-design
              • Vl-annotate-module
            • Clean-warnings
            • Eliminitial
            • Custom-transform-hooks
            • Problem-modules
        • X86isa
        • Svl
        • Rtl
      • Software-verification
      • Math
      • Testing-utilities
    • Make-implicit-wires

    Implicit-wires-minutia

    Some details about implicit wires.

    Adding implicit wires turns out to be surprisingly subtle. Here are some notes about implicit wires in Verilog-2005.

    When a wire is implicitly declared, its type is controlled by the `default_nettype compiler directive (Section 19.2). But VL's preprocessor does not yet support this directive and will cause an error if it is used, so for now we can safely assume any implicit wires should just have type wire. (We can probably add support default_nettype without too much work, since our new approach of going through the module elements sequentially means that we have easy access to location information. On the other hand, this is a really subtle directive to be using and we hope nobody tries to use it.)

    We think wires need to be declared, explicitly or implicitly, before being used. The Verilog-2005 standard seems not to explicitly say whether or not this is the case, and the language at the start of Section 4.5 is somewhat vague: we are supposed to assume implicit nets in the absence of an explicit declaration in certain situations. But later in 4.5 we find some language that pretty strongly suggests we are only to consider whether or not there is an explicit declaration before the use of the net: "and that identifier has not been declared previously in the scope...."

    Section 4.5 outlines the conditions under which an implicit wire declaration is supposed to be made. In each case, the implicit declaration is to be added to the nearest scope. It seems like this mostly only matters in the case of generate blocks. You might think that it would matter for functions, tasks, and named blocks as well, but it doesn't seem possible to use implicit wires in these contexts, see bullet #4 below for details.

    Note: I think that throughout Section 4.5, the words port expression declaration are a typo that should be port declaration; nowhere else in the Verilog-2005 standard do the words port expression declaration occur, at least according to Acrobat's find function.

    Case 1

    If there is a port declaration like input [3:0] i; that has no corresponding wire declaration, then we are supposed to infer an implicit net with the vector width of the "port expression declaration," which I think means the [3:0] part. This seems basically reasonable when you just read it, but there are a lot of subtle issues that arise; see #7 below for some experiments.

    Note that per 12.3.3, a port declaration like input wire [3:0] i; is treated as both an input declaration and an explicit wire declaration. We don't have to do anything special to handle this, because the parser automatically builds both a vl-portdecl-p and a vl-vardecl-p for such declarations; see vl-parse-port-declaration-noatts.

    Case 2

    If there is an undeclared identifier in the terminal list of a primitive or module instance, or in the left-hand side of a continuous assignment statement, then we are supposed to infer an implicit, scalar net.

    I think a "primitive instance" is supposed to mean either a gate instance or a user-defined primitive instance. See for instance Section 7.1.6, which talks about "primitive instance connection lists" in reference to gates, and 11.6.6 where primitive terminals are distinguished from module ports. So, this means we should infer implicit wires in the ports/terminals of any instance, regardless of whether it's a gate/udp/module.

    Implicit Wires in Verilog Tools

    We developed some tests (see test/test-implicit.v) to see how Verilog-XL and NCVerilog handle implicit wires. Here are our findings.

    #1. As expected, both allow implicit wires to be inferred from the arguments of gate and module instances. This seems to be the intent of Case 2.

    #2. As expected, both complain about undeclared wires on the right-hand side of an assign statement. This seems to agree with Case 2.

    #3. As expected, NCVerilog allows us to infer implicit nets from the left-hand sides of assign elements. Unfortunately, Verilog-XL complains about such wires, which seems to contradict the Verilog-2005 standard. We choose to mimick NCVerilog and infer the implicit net. Historically we also issued warnings that other tools like Verilog-XL may not allow the construct, but these warnings seemed to be noise and we eventually decided that it would be better not to issue them.

    A subtle case is, what if #2 and #3 overlap, i.e., an undeclared wire occurs on both the left-hand and right-hand sides? This isn't entirely contrived; someone might occasionally write things like assign {a, abar} = {foo, ~a}. NCVerilog seems to process the left-hand side first, and hence it allows us to infer an implicit wire for w when we give it an assignment like assign w = w.

    #4. Mostly as expected, neither tool allows undeclared wires on either side of an assignment in an always block. The tools even reject implicit wires in procedural continuous assignments, e.g., always @(b) assign w = a;.

    This seems arguably incorrect: is not a procedural continuous assignment also a continuous assignment, whose LHS should therefore be able to contain implicit wires? But we mimick these tools and disallow the implicit net, even thought the spec might perhaps be interpreted as allowing it.

    A nice consequence of disallowing implicit wires here is that it allows us to avoid certain scoping questions. In particular, suppose we see a procedural continuous assignment statement, assign w = ..., where w is not already declared. If this statement occurs in a task or a named block within an initial/always statement, should the declaration for w be added to the module or to this more local scope? I'm not sure. So, the good thing about not inferring implicit nets for these assignments is that I don't have to be able to answer the question, because I'm not going to infer a net anyway.

    #5. As expected, neither implementation tolerates undeclared wires on either side of assignments in function bodies. This seems perfectly reasonable since functions aren't allowed to have procedural continuous assignments (10.4.4 E).

    #6 As expected, both Verilog-XL and NCVerilog require that all wires be declared (either explicitly or implicitly) before they are used. For instance, they if a is declared but w is not, then they reject code fragments such as:

    assign a = w;   // error here, saying w is undeclared
    wire w;

    And also for code like this:

    not(a, w);
    wire w;         // error here, saying w is implicitly declared above

    #7 The whole declare-before-use thing is pretty strange for ports. Suppose c is a port of the module. Then, both NCVerilog and Verilog-XL will complain if you try to write:

    wire c2 = c;    // error here, saying c is not declared.
    input c;

    Verilog-XL seems to require the port declaration to come before the wire declaration, if any. That is, it considers the following an error, whereas NCVerilog allows it:

    wire c;
    input c;

    This seems to hold for implicit declarations, too. For instance, Verilog-XL rejects the following, but NCVerilog allows it:

    buf(c, c2);     // implicit declaration of wire c here
    input c;

    But both Verilog-XL and NCVerilog allow the following, even though you might think the buf gate would introduce an implicit declaration of c that would conflict with the explicit declaration.

    input c;
    buf(c, c2);
    wire c;

    We try to be permissive and mimick NCVerilog, but add a (non-fatal) warning if a wire's net declaration comes before its port declaration to explain that some other tools do not permit this.

    Other Notes

    In previous versions of VL, we allowed declarations to come in any order, and inferred an implicit wire whenever a wire was used in a context that permitted it. We now try to be more faithful to other Verilog systems and require that wires be declared before their first uses, since this seems like the right way to interpret the Verilog-2005 standard.

    With regard to Case 1, we add a net declaration for each port declaration that is missing a corresponding wire declaration. In the process, we make sure that at least some declaration (be it a wire or port declaration) of each port occurs before every use of the port. If only a wire declaration occurs before some use of the port wire, we issue a non-fatal warning saying that Verilog-XL does not tolerate this ordering.

    When we add implicit wires for ports, we use the range of the port declaration, which seems to be correct with respect to the "vector width of the port declaration expression," described above. We also keep the signedness of the port, which isn't discussed above, but appears to be the correct thing to do; see portdecl-sign for details. We place the implicit wire declaration at the same location as the corresponding port declaration, which seems like the easiest place to put it. We also mark each implicit wire declaration with the VL_PORT_IMPLICIT attribute. This attribute is used by the printer to avoid printing any net declarations that were implicit.

    With regard to Case 2, we add one-bit wire declarations for any undeclared wires that occur within the port arguments of gate and module instances, and which occur in the left-hand sides of continuous assignments. For assignments, we always issue a non-fatal warning that says Verilog-XL doesn't add implicit nets here, and we always process the left-hand side first (like NCVerilog). We add the wire declarations at the locations in which they are implicitly declared, and mark them with the VL_IMPLICIT attribute. Historically this attribute was used in a ``typo detection'' vl-lint check, which has become defunct but can probably be easily revived.