mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-23 00:55:32 +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:
parent
98afe2b758
commit
fe74b0cd95
33 changed files with 783 additions and 262 deletions
33
tests/simple/func_block.v
Normal file
33
tests/simple/func_block.v
Normal 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
|
25
tests/simple/func_recurse.v
Normal file
25
tests/simple/func_recurse.v
Normal 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
|
41
tests/simple/func_width_scope.v
Normal file
41
tests/simple/func_width_scope.v
Normal 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
|
27
tests/simple/genblk_collide.v
Normal file
27
tests/simple/genblk_collide.v
Normal 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
|
21
tests/simple/genblk_dive.v
Normal file
21
tests/simple/genblk_dive.v
Normal 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
|
18
tests/simple/genblk_order.v
Normal file
18
tests/simple/genblk_order.v
Normal 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
|
|
@ -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
|
||||
|
|
11
tests/simple/local_loop_var.sv
Normal file
11
tests/simple/local_loop_var.sv
Normal 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
|
15
tests/simple/loop_var_shadow.v
Normal file
15
tests/simple/loop_var_shadow.v
Normal 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
|
27
tests/simple/named_genblk.v
Normal file
27
tests/simple/named_genblk.v
Normal 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
|
14
tests/simple/nested_genblk_resolve.v
Normal file
14
tests/simple/nested_genblk_resolve.v
Normal 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
|
17
tests/simple/unnamed_block_decl.sv
Normal file
17
tests/simple/unnamed_block_decl.sv
Normal 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
|
|
@ -1,13 +1,17 @@
|
|||
module test(x, y, z);
|
||||
`default_nettype none
|
||||
module test;
|
||||
localparam OFF = 0;
|
||||
generate
|
||||
if (OFF) ;
|
||||
else input x;
|
||||
if (!OFF) input y;
|
||||
else wire x;
|
||||
if (!OFF) wire y;
|
||||
else ;
|
||||
if (OFF) ;
|
||||
else ;
|
||||
if (OFF) ;
|
||||
input z;
|
||||
wire z;
|
||||
endgenerate
|
||||
assign genblk1.x = 0;
|
||||
assign genblk2.y = 0;
|
||||
assign z = 0;
|
||||
endmodule
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
read_verilog gen_if_null.v
|
||||
select -assert-count 1 test/x
|
||||
select -assert-count 1 test/y
|
||||
select -assert-count 1 test/genblk1.x
|
||||
select -assert-count 1 test/genblk2.y
|
||||
select -assert-count 1 test/z
|
||||
|
|
12
tests/verilog/bug2493.ys
Normal file
12
tests/verilog/bug2493.ys
Normal file
|
@ -0,0 +1,12 @@
|
|||
logger -expect error "Failed to detect width for identifier \\genblk1\.y!" 1
|
||||
read_verilog <<EOT
|
||||
module top1;
|
||||
wire x;
|
||||
generate
|
||||
if (1) begin
|
||||
mod y();
|
||||
assign x = y;
|
||||
end
|
||||
endgenerate
|
||||
endmodule
|
||||
EOT
|
21
tests/verilog/bug656.v
Normal file
21
tests/verilog/bug656.v
Normal file
|
@ -0,0 +1,21 @@
|
|||
module top #(
|
||||
parameter WIDTH = 6
|
||||
) (
|
||||
input [WIDTH-1:0] a_i,
|
||||
input [WIDTH-1:0] b_i,
|
||||
output [WIDTH-1:0] z_o
|
||||
);
|
||||
genvar g;
|
||||
generate
|
||||
for (g = 0; g < WIDTH; g = g + 1) begin
|
||||
if (g > 2) begin
|
||||
wire tmp;
|
||||
assign tmp = a_i[g] || b_i[g];
|
||||
assign z_o[g] = tmp;
|
||||
end
|
||||
else begin
|
||||
assign z_o[g] = a_i[g] && b_i[g];
|
||||
end
|
||||
end
|
||||
endgenerate
|
||||
endmodule
|
13
tests/verilog/bug656.ys
Normal file
13
tests/verilog/bug656.ys
Normal file
|
@ -0,0 +1,13 @@
|
|||
read_verilog bug656.v
|
||||
|
||||
select -assert-count 1 top/a_i
|
||||
select -assert-count 1 top/b_i
|
||||
select -assert-count 1 top/z_o
|
||||
|
||||
select -assert-none top/genblk1[0].genblk1.tmp
|
||||
select -assert-none top/genblk1[1].genblk1.tmp
|
||||
select -assert-none top/genblk1[2].genblk1.tmp
|
||||
|
||||
select -assert-count 1 top/genblk1[3].genblk1.tmp
|
||||
select -assert-count 1 top/genblk1[4].genblk1.tmp
|
||||
select -assert-count 1 top/genblk1[5].genblk1.tmp
|
26
tests/verilog/genblk_case.v
Normal file
26
tests/verilog/genblk_case.v
Normal file
|
@ -0,0 +1,26 @@
|
|||
module top;
|
||||
parameter YES = 1;
|
||||
generate
|
||||
if (YES) wire y;
|
||||
else wire n;
|
||||
|
||||
if (!YES) wire n;
|
||||
else wire y;
|
||||
|
||||
case (YES)
|
||||
1: wire y;
|
||||
0: wire n;
|
||||
endcase
|
||||
|
||||
case (!YES)
|
||||
0: wire y;
|
||||
1: wire n;
|
||||
endcase
|
||||
|
||||
if (YES) wire y;
|
||||
else wire n;
|
||||
|
||||
if (!YES) wire n;
|
||||
else wire y;
|
||||
endgenerate
|
||||
endmodule
|
15
tests/verilog/genblk_case.ys
Normal file
15
tests/verilog/genblk_case.ys
Normal file
|
@ -0,0 +1,15 @@
|
|||
read_verilog genblk_case.v
|
||||
|
||||
select -assert-count 0 top/genblk1.n
|
||||
select -assert-count 0 top/genblk2.n
|
||||
select -assert-count 0 top/genblk3.n
|
||||
select -assert-count 0 top/genblk4.n
|
||||
select -assert-count 0 top/genblk5.n
|
||||
select -assert-count 0 top/genblk6.n
|
||||
|
||||
select -assert-count 1 top/genblk1.y
|
||||
select -assert-count 1 top/genblk2.y
|
||||
select -assert-count 1 top/genblk3.y
|
||||
select -assert-count 1 top/genblk4.y
|
||||
select -assert-count 1 top/genblk5.y
|
||||
select -assert-count 1 top/genblk6.y
|
11
tests/verilog/hidden_decl.ys
Normal file
11
tests/verilog/hidden_decl.ys
Normal file
|
@ -0,0 +1,11 @@
|
|||
logger -expect error "Identifier `\\y' is implicitly declared and `default_nettype is set to none" 1
|
||||
read_verilog <<EOT
|
||||
`default_nettype none
|
||||
module top1;
|
||||
wire x;
|
||||
generate
|
||||
if (1) wire y;
|
||||
endgenerate
|
||||
assign x = y;
|
||||
endmodule
|
||||
EOT
|
28
tests/verilog/unnamed_block.ys
Normal file
28
tests/verilog/unnamed_block.ys
Normal file
|
@ -0,0 +1,28 @@
|
|||
read_verilog <<EOT
|
||||
module top;
|
||||
initial begin : blk
|
||||
integer x;
|
||||
end
|
||||
endmodule
|
||||
EOT
|
||||
|
||||
delete
|
||||
|
||||
read_verilog -sv <<EOT
|
||||
module top;
|
||||
initial begin
|
||||
integer x;
|
||||
end
|
||||
endmodule
|
||||
EOT
|
||||
|
||||
delete
|
||||
|
||||
logger -expect error "Local declaration in unnamed block is only supported in SystemVerilog mode!" 1
|
||||
read_verilog <<EOT
|
||||
module top;
|
||||
initial begin
|
||||
integer x;
|
||||
end
|
||||
endmodule
|
||||
EOT
|
39
tests/verilog/unnamed_genblk.sv
Normal file
39
tests/verilog/unnamed_genblk.sv
Normal file
|
@ -0,0 +1,39 @@
|
|||
// This test is taken directly from Section 27.6 of IEEE 1800-2017
|
||||
|
||||
module top;
|
||||
parameter genblk2 = 0;
|
||||
genvar i;
|
||||
|
||||
// The following generate block is implicitly named genblk1
|
||||
|
||||
if (genblk2) logic a; // top.genblk1.a
|
||||
else logic b; // top.genblk1.b
|
||||
|
||||
// The following generate block is implicitly named genblk02
|
||||
// as genblk2 is already a declared identifier
|
||||
|
||||
if (genblk2) logic a; // top.genblk02.a
|
||||
else logic b; // top.genblk02.b
|
||||
|
||||
// The following generate block would have been named genblk3
|
||||
// but is explicitly named g1
|
||||
|
||||
for (i = 0; i < 1; i = i + 1) begin : g1 // block name
|
||||
// The following generate block is implicitly named genblk1
|
||||
// as the first nested scope inside g1
|
||||
if (1) logic a; // top.g1[0].genblk1.a
|
||||
end
|
||||
|
||||
// The following generate block is implicitly named genblk4 since
|
||||
// it belongs to the fourth generate construct in scope "top".
|
||||
// The previous generate block would have been
|
||||
// named genblk3 if it had not been explicitly named g1
|
||||
|
||||
for (i = 0; i < 1; i = i + 1)
|
||||
// The following generate block is implicitly named genblk1
|
||||
// as the first nested generate block in genblk4
|
||||
if (1) logic a; // top.genblk4[0].genblk1.a
|
||||
|
||||
// The following generate block is implicitly named genblk5
|
||||
if (1) logic a; // top.genblk5.a
|
||||
endmodule
|
8
tests/verilog/unnamed_genblk.ys
Normal file
8
tests/verilog/unnamed_genblk.ys
Normal file
|
@ -0,0 +1,8 @@
|
|||
read_verilog -sv unnamed_genblk.sv
|
||||
select -assert-count 0 top/genblk1.a
|
||||
select -assert-count 1 top/genblk02.b
|
||||
select -assert-count 0 top/genblk1.a
|
||||
select -assert-count 1 top/genblk02.b
|
||||
select -assert-count 1 top/g1[0].genblk1.a
|
||||
select -assert-count 1 top/genblk4[0].genblk1.a
|
||||
select -assert-count 1 top/genblk5.a
|
Loading…
Add table
Add a link
Reference in a new issue