sv: fix always_comb auto nosync for nested and function blocks
authorZachary Snow <zach@zachjs.com>
Tue, 22 Feb 2022 15:57:08 +0000 (16:57 +0100)
committerZachary Snow <zachary.j.snow@gmail.com>
Tue, 5 Apr 2022 20:43:48 +0000 (14:43 -0600)
CHANGELOG
frontends/ast/simplify.cc
tests/verilog/always_comb_nolatch_5.ys [new file with mode: 0644]
tests/verilog/always_comb_nolatch_6.ys [new file with mode: 0644]

index bec9f8321b8a476357736c987475e490267c4fdb..a27adc5bff0333995c6e6da133c9f27d2bbc40e0 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -5,6 +5,10 @@ List of major changes and improvements between releases
 Yosys 0.16 .. Yosys 0.16-dev
 --------------------------
 
+ * SystemVerilog
+    - Fixed automatic `nosync` inference for local variables in `always_comb`
+      procedures not applying to nested blocks and blocks in functions
+
 Yosys 0.15 .. Yosys 0.16
 --------------------------
  * Various
index 565025d3a063d710f851b021f4cbcddf2086b487..bd3e09c4b9cc09633d3193bf38f348b38a93303e 100644 (file)
@@ -744,6 +744,16 @@ static void mark_auto_nosync(AstNode *block, const AstNode *wire)
                        false);
 }
 
+// block names can be prefixed with an explicit scope during elaboration
+static bool is_autonamed_block(const std::string &str) {
+       size_t last_dot = str.rfind('.');
+       // unprefixed names: autonamed if the first char is a dollar sign
+       if (last_dot == std::string::npos)
+               return str.at(0) == '$'; // e.g., `$fordecl_block$1`
+       // prefixed names: autonamed if the final chunk begins with a dollar sign
+       return str.rfind(".$") == last_dot; // e.g., `\foo.bar.$fordecl_block$1`
+}
+
 // check a procedural block for auto-nosync markings, remove them, and add
 // nosync to local variables as necessary
 static void check_auto_nosync(AstNode *node)
@@ -2355,7 +2365,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
 
                // if this is an autonamed block is in an always_comb
                if (current_always && current_always->attributes.count(ID::always_comb)
-                               && str.at(0) == '$')
+                               && is_autonamed_block(str))
                        // track local variables in this block so we can consider adding
                        // nosync once the block has been fully elaborated
                        for (AstNode *child : children)
diff --git a/tests/verilog/always_comb_nolatch_5.ys b/tests/verilog/always_comb_nolatch_5.ys
new file mode 100644 (file)
index 0000000..1328786
--- /dev/null
@@ -0,0 +1,15 @@
+read_verilog -sv <<EOF
+module top;
+logic [4:0] x;
+logic z;
+assign z = 1'b1;
+always_comb begin : foo
+    x = '0;
+    if (z) begin : bar
+        for (int i = 0; i < 5; i++)
+            x[i] = 1'b1;
+    end
+end
+endmodule
+EOF
+proc
diff --git a/tests/verilog/always_comb_nolatch_6.ys b/tests/verilog/always_comb_nolatch_6.ys
new file mode 100644 (file)
index 0000000..90ee78a
--- /dev/null
@@ -0,0 +1,15 @@
+read_verilog -sv <<EOF
+module top(input wire x, y, output reg z);
+function automatic f;
+    input inp;
+    for (int i = 0; i < 1; i++)
+        f = inp + 0;
+endfunction
+always_comb
+    if (y)
+        z = f(x);
+    else
+        z = 0;
+endmodule
+EOF
+proc