3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-08-09 20:50:51 +00:00

verilog: significant block scoping improvements

This change set contains a number of bug fixes and improvements related to
scoping and resolution in generate and procedural blocks. While many of the
frontend changes are interdependent, it may be possible bring the techmap
changes in under a separate PR.

Declarations within unnamed generate blocks previously encountered issues
because the data declarations were left un-prefixed, breaking proper scoping.
The LRM outlines behavior for generating names for unnamed generate blocks. The
original goal was to add this implicit labelling, but doing so exposed a number
of issues downstream. Additional testing highlighted other closely related scope
resolution issues, which have been fixed. This change also adds support for
block item declarations within unnamed blocks in SystemVerilog mode.

1. Unlabled generate blocks are now implicitly named according to the LRM in
   `label_genblks`, which is invoked at the beginning of module elaboration
2. The Verilog parser no longer wraps explicitly named generate blocks in a
   synthetic unnamed generate block to avoid creating extra hierarchy levels
   where they should not exist
3. The techmap phase now allows special control identifiers to be used outside
   of the topmost scope, which is necessary because such wires and cells often
   appear in unlabeled generate blocks, which now prefix the declarations within
4. Some techlibs required modifications because they relied on the previous
   invalid scope resolution behavior
5. `expand_genblock` has been simplified, now only expanding the outermost
   scope, completely deferring the inspection and elaboration of nested scopes;
   names are now resolved by looking in the innermost scope and stepping outward
6. Loop variables now always become localparams during unrolling, allowing them
   to be resolved and shadowed like any other identifier
7. Identifiers in synthetic function call scopes are now prefixed and resolved
   in largely the same manner as other blocks
     before: `$func$\func_01$tests/simple/scopes.blk.v:60$5$\blk\x`
      after: `\func_01$func$tests/simple/scopes.v:60$5.blk.x`
8. Support identifiers referencing a local generate scope nested more
   than 1 level deep, i.e. `B.C.x` while within generate scope `A`, or using a
   prefix of a current or parent scope, i.e. `B.C.D.x` while in `A.B`, `A.B.C`,
   or `A.B.C.D`
9. Variables can now be declared within unnamed blocks in SystemVerilog mode

Addresses the following issues: 656, 2423, 2493
This commit is contained in:
Zachary Snow 2021-01-27 13:30:22 -05:00
parent 98afe2b758
commit fe74b0cd95
33 changed files with 783 additions and 262 deletions

33
tests/simple/func_block.v Normal file
View file

@ -0,0 +1,33 @@
`default_nettype none
module top(inp, out1, out2, out3);
input wire [31:0] inp;
function automatic [31:0] func1;
input [31:0] inp;
reg [31:0] idx;
for (idx = 0; idx < 32; idx = idx + 1) begin : blk
func1[idx] = (idx & 1'b1) ^ inp[idx];
end
endfunction
function automatic [31:0] func2;
input [31:0] inp;
reg [31:0] idx;
for (idx = 0; idx < 32; idx = idx + 1) begin : blk
func2[idx] = (idx & 1'b1) ^ inp[idx];
end
endfunction
function automatic [31:0] func3;
localparam A = 32 - 1;
parameter B = 1 - 0;
input [31:0] inp;
func3[A:B] = inp[A:B];
endfunction
output wire [31:0] out1, out2, out3;
assign out1 = func1(inp);
assign out2 = func2(inp);
assign out3 = func3(inp);
endmodule

View file

@ -0,0 +1,25 @@
module top(
input wire [3:0] inp,
output wire [3:0] out1, out2
);
function automatic [3:0] pow_a;
input [3:0] base, exp;
begin
pow_a = 1;
if (exp > 0)
pow_a = base * pow_a(base, exp - 1);
end
endfunction
function automatic [3:0] pow_b;
input [3:0] base, exp;
begin
pow_b = 1;
if (exp > 0)
pow_b = base * pow_b(base, exp - 1);
end
endfunction
assign out1 = pow_a(inp, 3);
assign out2 = pow_b(2, 2);
endmodule

View file

@ -0,0 +1,41 @@
module top(inp, out1, out2);
input wire signed inp;
localparam WIDTH_A = 5;
function automatic [WIDTH_A-1:0] func1;
input reg [WIDTH_A-1:0] inp;
func1 = ~inp;
endfunction
wire [func1(0)-1:0] xc;
assign xc = 1'sb1;
wire [WIDTH_A-1:0] xn;
assign xn = func1(inp);
generate
if (1) begin : blk
localparam WIDTH_A = 6;
function automatic [WIDTH_A-1:0] func2;
input reg [WIDTH_A-1:0] inp;
func2 = ~inp;
endfunction
wire [func2(0)-1:0] yc;
assign yc = 1'sb1;
wire [WIDTH_A-1:0] yn;
assign yn = func2(inp);
localparam WIDTH_B = 7;
function automatic [WIDTH_B-1:0] func3;
input reg [WIDTH_B-1:0] inp;
func3 = ~inp;
endfunction
wire [func3(0)-1:0] zc;
assign zc = 1'sb1;
wire [WIDTH_B-1:0] zn;
assign zn = func3(inp);
end
endgenerate
output wire [1023:0] out1, out2;
assign out1 = {xc, 1'b0, blk.yc, 1'b0, blk.zc};
assign out2 = {xn, 1'b0, blk.yn, 1'b0, blk.zn};
endmodule

View file

@ -0,0 +1,27 @@
`default_nettype none
module top1;
generate
if (1) begin : foo
if (1) begin : bar
wire x;
end
assign bar.x = 1;
wire y;
end
endgenerate
endmodule
module top2;
genvar i;
generate
if (1) begin : foo
wire x;
for (i = 0; i < 1; i = i + 1) begin : foo
if (1) begin : foo
assign x = 1;
end
end
end
endgenerate
endmodule

View file

@ -0,0 +1,21 @@
`default_nettype none
module top(output wire x);
generate
if (1) begin : Z
if (1) begin : A
wire x;
if (1) begin : B
wire x;
if (1) begin : C
wire x;
assign B.x = 0;
wire z = A.B.C.x;
end
assign A.x = A.B.C.x;
end
assign B.C.x = B.x;
end
end
endgenerate
assign x = Z.A.x;
endmodule

View file

@ -0,0 +1,18 @@
`default_nettype none
module top(
output wire out1,
output wire out2
);
generate
if (1) begin : outer
if (1) begin : foo
wire x = 0;
if (1) begin : foo
wire x = 1;
assign out1 = foo.x;
end
assign out2 = foo.x;
end
end
endgenerate
endmodule

View file

@ -260,3 +260,66 @@ module gen_test8;
`ASSERT(gen_test8.A.C.x == 1)
`ASSERT(gen_test8.A.B.x == 0)
endmodule
// ------------------------------------------
module gen_test9;
// `define VERIFY
`ifdef VERIFY
`define ASSERT(expr) assert property (expr);
`else
`define ASSERT(expr)
`endif
wire [1:0] w = 2'b11;
generate
begin : A
wire [1:0] x;
begin : B
wire [1:0] y = 2'b00;
`ASSERT(w == 3)
`ASSERT(x == 2)
`ASSERT(y == 0)
`ASSERT(A.x == 2)
`ASSERT(A.C.z == 1)
`ASSERT(A.B.y == 0)
`ASSERT(gen_test9.w == 3)
`ASSERT(gen_test9.A.x == 2)
`ASSERT(gen_test9.A.C.z == 1)
`ASSERT(gen_test9.A.B.y == 0)
end
begin : C
wire [1:0] z = 2'b01;
`ASSERT(w == 3)
`ASSERT(x == 2)
`ASSERT(z == 1)
`ASSERT(A.x == 2)
`ASSERT(A.C.z == 1)
`ASSERT(A.B.y == 0)
`ASSERT(gen_test9.w == 3)
`ASSERT(gen_test9.A.x == 2)
`ASSERT(gen_test9.A.C.z == 1)
`ASSERT(gen_test9.A.B.y == 0)
end
assign x = B.y ^ 2'b11 ^ C.z;
`ASSERT(x == 2)
`ASSERT(A.x == 2)
`ASSERT(A.C.z == 1)
`ASSERT(A.B.y == 0)
`ASSERT(gen_test9.w == 3)
`ASSERT(gen_test9.A.x == 2)
`ASSERT(gen_test9.A.C.z == 1)
`ASSERT(gen_test9.A.B.y == 0)
end
endgenerate
`ASSERT(w == 3)
`ASSERT(A.x == 2)
`ASSERT(A.C.z == 1)
`ASSERT(A.B.y == 0)
`ASSERT(gen_test9.w == 3)
`ASSERT(gen_test9.A.x == 2)
`ASSERT(gen_test9.A.C.z == 1)
`ASSERT(gen_test9.A.B.y == 0)
endmodule

View file

@ -0,0 +1,11 @@
module top(out);
output integer out;
initial begin
integer i;
for (i = 0; i < 5; i = i + 1)
if (i == 0)
out = 1;
else
out += 2 ** i;
end
endmodule

View file

@ -0,0 +1,15 @@
module top(out);
genvar i;
generate
for (i = 0; i < 2; i = i + 1) begin : loop
localparam j = i + 1;
if (1) begin : blk
localparam i = j + 1;
wire [i:0] x;
assign x = 1'sb1;
end
end
endgenerate
output wire [63:0] out;
assign out = {loop[0].blk.x, loop[1].blk.x};
endmodule

View file

@ -0,0 +1,27 @@
`default_nettype none
module top;
generate
if (1) begin
wire t;
begin : foo
wire x;
end
wire u;
end
begin : bar
wire x;
wire y;
begin : baz
wire x;
wire z;
end
end
endgenerate
assign genblk1.t = 1;
assign genblk1.foo.x = 1;
assign genblk1.u = 1;
assign bar.x = 1;
assign bar.y = 1;
assign bar.baz.x = 1;
assign bar.baz.z = 1;
endmodule

View file

@ -0,0 +1,14 @@
`default_nettype none
module top;
generate
if (1) begin
wire x;
genvar i;
for (i = 0; i < 1; i = i + 1) begin
if (1) begin
assign x = 1;
end
end
end
endgenerate
endmodule

View file

@ -0,0 +1,17 @@
module top(z);
output integer z;
initial begin
integer x;
x = 1;
begin
integer y;
y = x + 1;
begin
integer z;
z = y + 1;
y = z + 1;
end
z = y + 1;
end
end
endmodule