Some details about generate block scoping quirks which affect implicit wire handling and other aspects of scoping.
AFAICT none of the following is discussed in the SystemVerilog-2012 standard.
Unlike any other kind of
This has implications for correctly introducing implicit wires and also for scoping in general. We want to be smart enough to prohibit things like:
module m; not(v, w); // implicit declaration of w begin wire w = 1; // illegal (redefinition of w) end endmodule
while at the same time allowing legal things like:
module m; not(v, w); // implicit declaration of w begin : myblock wire w = 1; // fine (this is a new scope) end endmodule
On both NCV and VCS, at least at the top level of a module, an unnamed block does NOT appear to introduce a new scope. Instead, wires declared inside it become visible to the rest of the module after the generate, just as if they were declared before the begin/end block.
Moreover, the following seem to be roughly(*) equivalent,
module m ; module m ; begin ... vs. ... end endmodule endmodule
(*) Exceptions we're aware of: begin/end blocks aren't allowed to have ports, specify blocks, and specparams (Section 27.3) and parameter declarations inside of begin/end blocks are supposed to be treated as localparams. Testing suggests that these restrictions still hold for unnamed top-level begin/end blocks. See especially vl-genelementlist-flatten.
We find that NCV and VCS disagree about the handling of scopes for nested begin/end generate blocks. In particular, consider something like:
module m ; begin wire [3:0] w1 = 0; begin wire [3:0] w2 = 1; end wire [3:0] w3 = w1; wire [3:0] w4 = w2; end endmodule
This code is happily accepted by NCVerilog, suggesting that the inner
begin/end block is not given its own scope. However, VCS instead produces an
error saying that
In VL we choose to follow the behavior of NCVerilog since it is seems more consistent. That is, we will universally regard any unnamed begin/end generate blocks as not introducing a scope.
Since we are going to treat unnamed begin/end blocks as not having their own scopes, there's really no reason to keep them around.
It also seems like a good idea to get rid of them. If we keep unnamed begin/end blocks around, then when building scopes for vl-scopestacks, we would need to would need to collect all the items from (say) the module, and then also dive down into the begin/end blocks and (recursively) collect up the items within them. It seems much nicer and simpler to inline the contents of these generate blocks into their surroundings. Similarly we would need to do this sort of thing for packages.
We do this inlining as part of introducing implicit wires. This seems like a reasonable place: it certainly needs to happen before or during implicit wire introduction in order to get implicit wires right. It also needs to happen before we create scopestacks for shadowchecking.