diff --git a/Changes b/Changes index 31faa4155..7bfa604da 100644 --- a/Changes +++ b/Changes @@ -67,6 +67,7 @@ Verilator 5.051 devel * Fix variable scope in unique on dynamic array (#7981). [Kornel Uriasz, Antmicro Ltd.] * Fix table optimization causing not contextually convertible to bool error (#7983). [Jakub Michalski] * Fix $fgets being mis-optimized away (#7976). [G-A. Kamendje] +* Fix SYNCASYNCNET false positive with changed non-edge logic (#7980). [Oron Port] Verilator 5.050 2026-07-01 diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index e41b61daf..b58b6a1f2 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -199,6 +199,7 @@ class GateBuildVisitor final : public VNVisitorConst { const AstScope* m_scopep = nullptr; // Current scope being processed AstActive* m_activep = nullptr; // Current active bool m_inClockedActive = false; // Underneath clocked active + bool m_inEdgeActive = false; // Underneath edge active bool m_inStaticActive = false; // Underneath static active bool m_inSenItem = false; // Underneath AstSenItem; any varrefs are clocks @@ -248,9 +249,11 @@ class GateBuildVisitor final : public VNVisitorConst { UASSERT_OBJ(!m_activep, nodep, "Should not nest"); VL_RESTORER(m_activep); VL_RESTORER(m_inClockedActive); + VL_RESTORER(m_inEdgeActive); VL_RESTORER(m_inStaticActive); m_activep = nodep; m_inClockedActive = nodep->hasClocked(); + m_inEdgeActive = nodep->sentreep() && nodep->sentreep()->hasEdge(); m_inStaticActive = nodep->hasStatic(); // AstVarScope::user2 -> bool: Signal used in SenItem in *this* active block @@ -286,7 +289,7 @@ class GateBuildVisitor final : public VNVisitorConst { if (m_inSenItem) { vVtxp->setIsClock(); vscp->user2(true); - } else if (m_inClockedActive && nodep->access().isReadOnly()) { + } else if (m_inEdgeActive && nodep->access().isReadOnly()) { // For SYNCASYNCNET if (vscp->user2()) { if (!vVtxp->rstAsyncNodep()) vVtxp->rstAsyncNodep(nodep); diff --git a/test_regress/t/t_lint_syncasyncnet_bad.out b/test_regress/t/t_lint_syncasyncnet_bad.out index 4f9c0d75d..3d2e4d52f 100644 --- a/test_regress/t/t_lint_syncasyncnet_bad.out +++ b/test_regress/t/t_lint_syncasyncnet_bad.out @@ -1,9 +1,9 @@ -%Warning-SYNCASYNCNET: t/t_lint_syncasyncnet_bad.v:14:9: Signal flopped as both synchronous and async: 'rst_both_l' - t/t_lint_syncasyncnet_bad.v:52:13: ... Location of async usage - 52 | q4 <= (~rst_both_l) ? 1'b0 : d; +%Warning-SYNCASYNCNET: t/t_lint_syncasyncnet_bad.v:9:11: Signal flopped as both synchronous and async: 'rst_both_l' + t/t_lint_syncasyncnet_bad.v:50:13: ... Location of async usage + 50 | q4 <= (~rst_both_l) ? 1'b0 : d; | ^~~~~~~~~~ - t/t_lint_syncasyncnet_bad.v:34:12: ... Location of sync usage - 34 | q2 <= (rst_both_l) ? d : 1'b0; + t/t_lint_syncasyncnet_bad.v:31:12: ... Location of sync usage + 31 | q2 <= (rst_both_l) ? d : 1'b0; | ^~~~~~~~~~ ... For warning description see https://verilator.org/warn/SYNCASYNCNET?v=latest ... Use "/* verilator lint_off SYNCASYNCNET */" and lint_on around source to disable this message. diff --git a/test_regress/t/t_lint_syncasyncnet_bad.v b/test_regress/t/t_lint_syncasyncnet_bad.v index 4e254627d..48557c84e 100644 --- a/test_regress/t/t_lint_syncasyncnet_bad.v +++ b/test_regress/t/t_lint_syncasyncnet_bad.v @@ -4,18 +4,14 @@ // SPDX-FileCopyrightText: 2010 Wilson Snyder // SPDX-License-Identifier: CC0-1.0 -module t (/*AUTOARG*/ - // Inputs - clk, rst_both_l, rst_sync_l, rst_async_l, d - ); - /*AUTOINPUT*/ +module t ( + input clk, + input rst_both_l, + input rst_sync_l, + input rst_async_l, + input d +); - input clk; - input rst_both_l; - input rst_sync_l; - input rst_async_l; - - input d; reg q1; reg q2; @@ -25,24 +21,26 @@ module t (/*AUTOARG*/ // Beginning of autoreset for uninitialized flops q1 <= 1'h0; // End of automatics - end else begin + end + else begin q1 <= d; end end always @(posedge clk) begin q2 <= (rst_both_l) ? d : 1'b0; - if (0 && q1 && q2) ; + if (0 && q1 && q2); end - reg q3; + reg q3; always @(posedge clk or negedge rst_async_l) begin if (~rst_async_l) begin /*AUTORESET*/ // Beginning of autoreset for uninitialized flops q3 <= 1'h0; // End of automatics - end else begin + end + else begin q3 <= d; end end @@ -55,7 +53,17 @@ module t (/*AUTOARG*/ reg q5; always @(posedge clk or negedge rst_both_l) begin q5 <= (~rst_both_l) ? 1'b0 : d; - if (0 && q3 && q4 && q5) ; + if (0 && q3 && q4 && q5); + end + + // Issue #7980 - should not cause a warning + logic mirror; + logic [15:0] settle; + // Level-sensitive block (NO posedge/negedge): a plain combinational observer of `value`. + always @(mirror) $display("%0d", mirror); + always_ff @(posedge clk) begin + mirror <= d; + if (mirror != 1'd0) settle <= settle + 16'd1; end endmodule