From 724a42e31d56516bae66d6c4c6a1f3a4536027c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Alberto=20L=C3=B3pez=20Soto?= <110079630+Pointgamer2001@users.noreply.github.com> Date: Fri, 18 Sep 2026 13:41:01 -0600 Subject: [PATCH] Fix reevaluation of method calls in wait conditions (#8391) --- docs/CONTRIBUTORS | 1 + src/V3LiftExpr.cpp | 11 ++++ test_regress/t/t_wait_method_recheck.py | 18 ++++++ test_regress/t/t_wait_method_recheck.v | 80 +++++++++++++++++++++++++ 4 files changed, 110 insertions(+) create mode 100755 test_regress/t/t_wait_method_recheck.py create mode 100644 test_regress/t/t_wait_method_recheck.v diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 1f5d4d8f9..6e61d54b8 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -148,6 +148,7 @@ jeffrey.song Jens Yuechao Liu Jeremy Bennett Jesse Taube +Jesús Alberto López Soto Jevin Sweval Jiacheng Qian Jiamin Zhu diff --git a/src/V3LiftExpr.cpp b/src/V3LiftExpr.cpp index 94c927206..96075e8a0 100644 --- a/src/V3LiftExpr.cpp +++ b/src/V3LiftExpr.cpp @@ -229,6 +229,17 @@ class LiftExprVisitor final : public VNVisitor { } // VISITORS - statements + void visit(AstWait* nodep) override { + if (nodep->user1SetOnce()) return; + VL_RESTORER(m_doNotLiftp); + m_doNotLiftp = nullptr; + // Keep lifted statements inside the repeatedly evaluated condition. + if (AstNode* const newStmtps = lift(nodep->condp())) { + AstNodeExpr* const condp = nodep->condp()->unlinkFrBack(); + nodep->condp(new AstExprStmt{nodep->fileline(), newStmtps, condp}); + } + iterateAndNextNull(nodep->stmtsp()); + } void visit(AstNodeStmt* nodep) override { if (nodep->user1SetOnce()) return; VL_RESTORER(m_doNotLiftp); diff --git a/test_regress/t/t_wait_method_recheck.py b/test_regress/t/t_wait_method_recheck.py new file mode 100755 index 000000000..6fe7d000c --- /dev/null +++ b/test_regress/t/t_wait_method_recheck.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of either the GNU Lesser General Public License Version 3 +# or the Perl Artistic License Version 2.0. +# SPDX-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile(verilator_flags2=["--binary"]) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_wait_method_recheck.v b/test_regress/t/t_wait_method_recheck.v new file mode 100644 index 000000000..3dada4640 --- /dev/null +++ b/test_regress/t/t_wait_method_recheck.v @@ -0,0 +1,80 @@ +// DESCRIPTION: Verilator: Reevaluate function and method calls in wait conditions +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Wilson Snyder +// SPDX-License-Identifier: CC0-1.0 + +// verilog_format: off +`define stop $stop +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0); +// verilog_format: on + +class State; + int value; + function bit ready(); + return value == 3; + endfunction +endclass + +module t; + State state; + process child; + process killed; + bit completed; + bit kill_seen; + + initial begin + state = new; + fork + begin + fork + begin + child = process::self(); + #5; + state.value = 3; + #3; + end + begin + #20; + `checkd(completed, 1) + end + join + end + begin + #1; + wait (state.ready()) begin + `checkd($time, 5) + child.await(); + `checkd($time, 8) + `checkd(child.status(), process::FINISHED) + completed = 1; + end + end + join + fork + begin + killed = process::self(); + #100; + `stop; + end + begin + #2; + killed.kill(); + end + begin + #1; + killed.await(); + `checkd($time, 22) + `checkd(killed.status(), process::KILLED) + kill_seen = 1; + end + join + `checkd(kill_seen, 1) + $write("*-* All Finished *-*\n"); + $finish; + end + initial begin + #150; + `stop; + end +endmodule