sv: support declaration in procedural for initialization
authorZachary Snow <zach@zachjs.com>
Mon, 30 Aug 2021 17:35:36 +0000 (11:35 -0600)
committerZachary Snow <zachary.j.snow@gmail.com>
Mon, 30 Aug 2021 21:19:21 +0000 (15:19 -0600)
In line with other tools, this adds an extra wrapping block around such
for loops to appropriately scope the variable.

frontends/verilog/verilog_parser.y
tests/verilog/for_decl_no_init.ys [new file with mode: 0644]
tests/verilog/for_decl_no_sv.ys [new file with mode: 0644]
tests/verilog/for_decl_shadow.sv [new file with mode: 0644]
tests/verilog/for_decl_shadow.ys [new file with mode: 0644]

index b0c16c0f44ff9ea994ce8bd22a0c28f40c07b6a9..23404f844b2d7c1d97cc7b925360321971f22814 100644 (file)
@@ -2607,6 +2607,53 @@ asgn_binop:
        TOK_SSHL_ASSIGN { $$ = AST_SHIFT_SLEFT; } |
        TOK_SSHR_ASSIGN { $$ = AST_SHIFT_SRIGHT; } ;
 
+for_initialization:
+       TOK_ID '=' expr {
+               AstNode *ident = new AstNode(AST_IDENTIFIER);
+               ident->str = *$1;
+               AstNode *node = new AstNode(AST_ASSIGN_EQ, ident, $3);
+               ast_stack.back()->children.push_back(node);
+               SET_AST_NODE_LOC(node, @1, @3);
+       } |
+       non_io_wire_type range TOK_ID {
+               frontend_verilog_yyerror("For loop variable declaration is missing initialization!");
+       } |
+       non_io_wire_type range TOK_ID '=' expr {
+               if (!sv_mode)
+                       frontend_verilog_yyerror("For loop inline variable declaration is only supported in SystemVerilog mode!");
+
+               // loop variable declaration
+               AstNode *wire = $1;
+               AstNode *range = checkRange(wire, $2);
+               if (range != nullptr)
+                       wire->children.push_back(range);
+               SET_AST_NODE_LOC(wire, @1, @3);
+               SET_AST_NODE_LOC(range, @2, @2);
+
+               AstNode *ident = new AstNode(AST_IDENTIFIER);
+               ident->str = *$3;
+               wire->str = *$3;
+               delete $3;
+
+               AstNode *loop = ast_stack.back();
+               AstNode *parent = ast_stack.at(ast_stack.size() - 2);
+               log_assert(parent->children.back() == loop);
+
+               // loop variable initialization
+               AstNode *asgn = new AstNode(AST_ASSIGN_EQ, ident, $5);
+               loop->children.push_back(asgn);
+               SET_AST_NODE_LOC(asgn, @3, @5);
+               SET_AST_NODE_LOC(ident, @3, @3);
+
+               // inject a wrapping block to declare the loop variable and
+               // contain the current loop
+               AstNode *wrapper = new AstNode(AST_BLOCK);
+               wrapper->str = "$fordecl_block$" + std::to_string(autoidx++);
+               wrapper->children.push_back(wire);
+               wrapper->children.push_back(loop);
+               parent->children.back() = wrapper; // replaces `loop`
+       };
+
 // this production creates the obligatory if-else shift/reduce conflict
 behavioral_stmt:
        defattr | assert | wire_decl | param_decl | localparam_decl | typedef_decl |
@@ -2667,7 +2714,7 @@ behavioral_stmt:
                ast_stack.back()->children.push_back(node);
                ast_stack.push_back(node);
                append_attr(node, $1);
-       } simple_behavioral_stmt ';' expr {
+       } for_initialization ';' expr {
                ast_stack.back()->children.push_back($7);
        } ';' simple_behavioral_stmt ')' {
                AstNode *block = new AstNode(AST_BLOCK);
diff --git a/tests/verilog/for_decl_no_init.ys b/tests/verilog/for_decl_no_init.ys
new file mode 100644 (file)
index 0000000..68c1584
--- /dev/null
@@ -0,0 +1,9 @@
+logger -expect error "For loop variable declaration is missing initialization!" 1
+read_verilog -sv <<EOT
+module top;
+    integer z;
+    initial
+        for (integer i; i < 10; i = i + 1)
+            z = i;
+endmodule
+EOT
diff --git a/tests/verilog/for_decl_no_sv.ys b/tests/verilog/for_decl_no_sv.ys
new file mode 100644 (file)
index 0000000..34edddf
--- /dev/null
@@ -0,0 +1,9 @@
+logger -expect error "For loop inline variable declaration is only supported in SystemVerilog mode!" 1
+read_verilog <<EOT
+module top;
+    integer z;
+    initial
+        for (integer i = 1; i < 10; i = i + 1)
+            z = i;
+endmodule
+EOT
diff --git a/tests/verilog/for_decl_shadow.sv b/tests/verilog/for_decl_shadow.sv
new file mode 100644 (file)
index 0000000..f6948f9
--- /dev/null
@@ -0,0 +1,32 @@
+module gate(x);
+       output reg [15:0] x;
+       if (1) begin : gen
+               integer x;
+               initial begin
+                       for (integer x = 5; x < 10; x++)
+                               if (x == 5)
+                                       gen.x = 0;
+                               else
+                                       gen.x += 2 ** x;
+                       x = x * 2;
+               end
+       end
+       initial x = gen.x;
+endmodule
+
+module gold(x);
+       output reg [15:0] x;
+       if (1) begin : gen
+               integer x;
+               integer z;
+               initial begin
+                       for (z = 5; z < 10; z++)
+                               if (z == 5)
+                                       x = 0;
+                               else
+                                       x += 2 ** z;
+                       x = x * 2;
+               end
+       end
+       initial x = gen.x;
+endmodule
diff --git a/tests/verilog/for_decl_shadow.ys b/tests/verilog/for_decl_shadow.ys
new file mode 100644 (file)
index 0000000..d2dca71
--- /dev/null
@@ -0,0 +1,6 @@
+read_verilog -sv for_decl_shadow.sv
+hierarchy
+proc
+equiv_make gold gate equiv
+equiv_simple
+equiv_status -assert