Create explicit declarations for implicit wires. This is generally
the first step after parsing a design.
Verilog allows wires to be implicitly declared in certain cases.
For instance, even if w has not yet been declared, you can write things
assign w = ∈
and we are to assume that w is a one-bit wire. This is mostly
straightforward but there are some subtleties; see implicit-wires-minutia for more discussion.
Our general approach to handling these wires in VL is to add explicit
declarations for them. Having explicit declarations seems like a generally
good idea. For instance, it allows us to easily check for conflicting
declarations with the same name, and to generally assume that when we look
something up we should get a real declaration for it.
Historically, VL added explicit declarations for these wires as part of the
loader, even before a proper vl-module-p structures were
generated, which allowed us to easily consider the order of module elements.
But when we added support for SystemVerilog import statements, we found
this approach to be tricky. In particular, to decide whether we need to add a
declaration for some particular wire foo, we now need to consider whether
foo is defined by any imported package. For this to work, we really want
to be able to inspect the whole vl-design while making implicit wires.
We therefore decided to split making implicit wires out of the parser and into
a separate transform.
Note: Special Transform!
This transform is unique and we generally expect to run it as a very early
step after parsing. Normally it is invoked as part of annotate. It is
also closely related to shadowcheck—indeed, it invokes
shadowcheck— and the two should generally be regarded as a single,
unified transition from just-parsed modules to a more canonical form.
The special thing about make-implicit-wires and shadowcheck is
that these transforms we need to process module elements in parse order, i.e.,
the order that things occur in the source files. In contrast, throughout the
rest of VL we pay no attention to the parse order and just treat modules as if
they contain various sets of elements (e.g., assignments, gates, etc.).
The elements are available in parse order in the special parse-temps
field of the vl-module. Other transforms should never look at
parse-temps, but should refer to these typed fields, instead.
- Sanity check to detect undeclared identifiers, name clashes, and
tricky kinds of global name shadowing that we don't support.
- Some details about implicit wires.
- Some details about generate block scoping quirks which affect
implicit wire handling and other aspects of scoping.
- Make implicit wires for a single modelement.
- Collect up wire names that might need to be implicitly declared.
- Top level routine for adding implicit wires to a module's load items.
- State for the make-implicit-wires transform.
- Generate variable declarations for ports that don't have
corresponding variable declarations.
- Generate net declarations for one-bit implicit wires.
- Filter names to remove wires that are already declared. We remove
the names of any port declarations, ordinary declarations, global
names, and imported names.
- Assuming new-st is a modified version of st, restores any changed
fast alists in st and frees them in new-st. Side effects only.
- Only for genblocks that are found in conditional contexts, i.e.,
the then/else branches of if statements, or the bodies of case
statements. (Scoping is tricky here).
- Only for genblocks that definitely introduce their own scope, e.g.,
named begin/end blocks or generate loops. (Not for conditional
generate blocks because scoping is trickier there.)
- Gets the expressions from a gate instance, for making implicit wires.
- Main loop for introducing implicit wires.