verilog: fix multiple AST_PREFIX scope resolution issues
authorZachary Snow <zach@zachjs.com>
Tue, 3 Aug 2021 00:42:34 +0000 (18:42 -0600)
committerZachary Snow <zachary.j.snow@gmail.com>
Tue, 21 Sep 2021 16:10:59 +0000 (12:10 -0400)
- Root AST_PREFIX nodes are now subject to genblk expansion to allow
  them to refer to a locally-visible generate block
- Part selects on AST_PREFIX member leafs can now refer to generate
  block items (previously would not resolve and raise an error)
- Add source location information to AST_PREFIX nodes

frontends/ast/simplify.cc
frontends/verilog/verilog_parser.y
tests/verilog/prefix.sv [new file with mode: 0644]
tests/verilog/prefix.ys [new file with mode: 0644]

index f713cf8e119d53b39edd7bbdd27d9180c3e8c27b..607ca9a8b7392be4ef6b886f21ad77264faacd6d 100644 (file)
@@ -4045,7 +4045,7 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m
 // prefix is carried forward, but resolution of their children is deferred
 void AstNode::expand_genblock(const std::string &prefix)
 {
-       if (type == AST_IDENTIFIER || type == AST_FCALL || type == AST_TCALL || type == AST_WIRETYPE) {
+       if (type == AST_IDENTIFIER || type == AST_FCALL || type == AST_TCALL || type == AST_WIRETYPE || type == AST_PREFIX) {
                log_assert(!str.empty());
 
                // search starting in the innermost scope and then stepping outward
@@ -4131,10 +4131,15 @@ void AstNode::expand_genblock(const std::string &prefix)
 
        for (size_t i = 0; i < children.size(); i++) {
                AstNode *child = children[i];
-               // AST_PREFIX member names should not be prefixed; a nested AST_PREFIX
-               // still needs to recursed-into
-               if (type == AST_PREFIX && i == 1 && child->type == AST_IDENTIFIER)
+               // AST_PREFIX member names should not be prefixed; we recurse into them
+               // as normal to ensure indices and ranges are properly resolved, and
+               // then restore the previous string
+               if (type == AST_PREFIX && i == 1) {
+                       std::string backup_scope_name = child->str;
+                       child->expand_genblock(prefix);
+                       child->str = backup_scope_name;
                        continue;
+               }
                // functions/tasks may reference wires, constants, etc. in this scope
                if (child->type == AST_FUNCTION || child->type == AST_TASK)
                        continue;
index 8d0ba4cf67a9dd1e2f7d751df8375ce63c76df59..91b1140e9e273fecdbcd58421152898ee080113b 100644 (file)
@@ -2973,6 +2973,7 @@ rvalue:
        hierarchical_id '[' expr ']' '.' rvalue {
                $$ = new AstNode(AST_PREFIX, $3, $6);
                $$->str = *$1;
+               SET_AST_NODE_LOC($$, @1, @6);
                delete $1;
        } |
        hierarchical_id range {
diff --git a/tests/verilog/prefix.sv b/tests/verilog/prefix.sv
new file mode 100644 (file)
index 0000000..2d7fbb1
--- /dev/null
@@ -0,0 +1,95 @@
+module top;
+    genvar i, j;
+    if (1) begin : blk1
+        integer a = 1;
+        for (i = 0; i < 2; i = i + 1) begin : blk2
+            integer b = i;
+            for (j = 0; j < 2; j = j + 1) begin : blk3
+                integer c = j;
+                localparam x = i;
+                localparam y = j;
+                always @* begin
+                    assert (1 == a);
+                    assert (1 == blk1.a);
+                    assert (1 == top.blk1.a);
+                    assert (i == b);
+                    assert (i == blk2[i].b);
+                    assert (i == blk1.blk2[i].b);
+                    assert (i == top.blk1.blk2[i].b);
+                    assert (i == blk2[x].b);
+                    assert (i == blk1.blk2[x].b);
+                    assert (i == top.blk1.blk2[x].b);
+                    assert (j == c);
+                    assert (j == blk3[j].c);
+                    assert (j == blk2[x].blk3[j].c);
+                    assert (j == blk1.blk2[x].blk3[j].c);
+                    assert (j == top.blk1.blk2[x].blk3[j].c);
+                    assert (j == c);
+                    assert (j == blk3[y].c);
+                    assert (j == blk2[x].blk3[y].c);
+                    assert (j == blk1.blk2[x].blk3[y].c);
+                    assert (j == top.blk1.blk2[x].blk3[y].c);
+                    assert (j == top.blk1.blk2[x].blk3[y].c[0]);
+                    assert (0 == top.blk1.blk2[x].blk3[y].c[1]);
+                    assert (0 == top.blk1.blk2[x].blk3[y].c[j]);
+                end
+            end
+            always @* begin
+                assert (1 == a);
+                assert (1 == blk1.a);
+                assert (1 == top.blk1.a);
+                assert (i == b);
+                assert (i == blk2[i].b);
+                assert (i == blk1.blk2[i].b);
+                assert (i == top.blk1.blk2[i].b);
+                assert (0 == blk3[0].c);
+                assert (0 == blk2[i].blk3[0].c);
+                assert (0 == blk1.blk2[i].blk3[0].c);
+                assert (0 == top.blk1.blk2[i].blk3[0].c);
+                assert (1 == blk3[1].c);
+                assert (1 == blk2[i].blk3[1].c);
+                assert (1 == blk1.blk2[i].blk3[1].c);
+                assert (1 == top.blk1.blk2[i].blk3[1].c);
+            end
+        end
+        always @* begin
+            assert (1 == a);
+            assert (1 == blk1.a);
+            assert (1 == top.blk1.a);
+            assert (0 == blk2[0].b);
+            assert (0 == blk1.blk2[0].b);
+            assert (0 == top.blk1.blk2[0].b);
+            assert (1 == blk2[1].b);
+            assert (1 == blk1.blk2[1].b);
+            assert (1 == top.blk1.blk2[1].b);
+            assert (0 == blk2[0].blk3[0].c);
+            assert (0 == blk1.blk2[0].blk3[0].c);
+            assert (0 == top.blk1.blk2[0].blk3[0].c);
+            assert (1 == blk2[0].blk3[1].c);
+            assert (1 == blk1.blk2[0].blk3[1].c);
+            assert (1 == top.blk1.blk2[0].blk3[1].c);
+            assert (0 == blk2[1].blk3[0].c);
+            assert (0 == blk1.blk2[1].blk3[0].c);
+            assert (0 == top.blk1.blk2[1].blk3[0].c);
+            assert (1 == blk2[1].blk3[1].c);
+            assert (1 == blk1.blk2[1].blk3[1].c);
+            assert (1 == top.blk1.blk2[1].blk3[1].c);
+        end
+    end
+    always @* begin
+        assert (1 == blk1.a);
+        assert (1 == top.blk1.a);
+        assert (0 == blk1.blk2[0].b);
+        assert (0 == top.blk1.blk2[0].b);
+        assert (1 == blk1.blk2[1].b);
+        assert (1 == top.blk1.blk2[1].b);
+        assert (0 == blk1.blk2[0].blk3[0].c);
+        assert (0 == top.blk1.blk2[0].blk3[0].c);
+        assert (1 == blk1.blk2[0].blk3[1].c);
+        assert (1 == top.blk1.blk2[0].blk3[1].c);
+        assert (0 == blk1.blk2[1].blk3[0].c);
+        assert (0 == top.blk1.blk2[1].blk3[0].c);
+        assert (1 == blk1.blk2[1].blk3[1].c);
+        assert (1 == top.blk1.blk2[1].blk3[1].c);
+    end
+endmodule
diff --git a/tests/verilog/prefix.ys b/tests/verilog/prefix.ys
new file mode 100644 (file)
index 0000000..ed3b3a1
--- /dev/null
@@ -0,0 +1,5 @@
+read_verilog -sv prefix.sv
+hierarchy
+proc
+select -module top
+sat -verify -seq 1 -prove-asserts -show-all