diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index 6484a7247..11ad083e4 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -279,6 +279,28 @@ private: visit(static_cast(nodep)); addFlags(m_procp, T_FORCES_PROC | T_NEEDS_PROC); } + void visit(AstWait* nodep) override { + AstNodeExpr* const condp = V3Const::constifyEdit(nodep->condp()); + if (AstConst* const constp = VN_CAST(condp, Const)) { + if (!nodep->fileline()->warnIsOff(V3ErrorCode::WAITCONST)) { + condp->v3warn(WAITCONST, "Wait statement condition is constant"); + } + if (!constp->isZero()) { + // Remove AstWait before we track process as T_SUSPENDER + if (AstNode* const stmtsp = nodep->stmtsp()) { + stmtsp->unlinkFrBackWithNext(); + nodep->replaceWith(stmtsp); + } else { + nodep->unlinkFrBack(); + } + VL_DO_DANGLING(pushDeletep(nodep), nodep); + return; + } + } + v3Global.setUsesTiming(); + if (m_procp) addFlags(m_procp, T_SUSPENDEE | T_SUSPENDER | T_NEEDS_PROC); + iterateChildren(nodep); + } void visit(AstCFunc* nodep) override { VL_RESTORER(m_procp); m_procp = nodep; @@ -1123,9 +1145,6 @@ private: AstNodeExpr* const condp = V3Const::constifyEdit(nodep->condp()->unlinkFrBack()); auto* const constp = VN_CAST(condp, Const); if (constp) { - if (!nodep->fileline()->warnIsOff(V3ErrorCode::WAITCONST)) { - condp->v3warn(WAITCONST, "Wait statement condition is constant"); - } if (constp->isZero()) { // We have to await forever instead of simply returning in case we're deep in a // callstack @@ -1136,11 +1155,9 @@ private: nodep->replaceWith(awaitp->makeStmt()); if (stmtsp) VL_DO_DANGLING(stmtsp->deleteTree(), stmtsp); VL_DO_DANGLING(condp->deleteTree(), condp); - } else if (stmtsp) { - // Just put the statements there - nodep->replaceWith(stmtsp); } else { - nodep->unlinkFrBack(); + nodep->v3fatalSrc("constant wait should have been removed in " + "TimingSuspendableVisitor::visit(AstWait)"); } } else if (needDynamicTrigger(condp)) { // No point in making a sentree, just use the expression as sensitivity diff --git a/test_regress/t/t_wait_const.pl b/test_regress/t/t_wait_const.pl new file mode 100755 index 000000000..b2d31c26d --- /dev/null +++ b/test_regress/t/t_wait_const.pl @@ -0,0 +1,25 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +compile( + verilator_flags2 => ["--binary"], + verilator_make_cmake => 0, + verilator_make_gmake => 0, + make_main => 0, + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_wait_const.v b/test_regress/t/t_wait_const.v new file mode 100644 index 000000000..69e5de16e --- /dev/null +++ b/test_regress/t/t_wait_const.v @@ -0,0 +1,19 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + + initial begin + // This test is separate from t_wait.v because we needed a process with + // just one wait of a non-zero to see a bug where GCC gave "return value + // not used" + // verilator lint_off WAITCONST + wait (1); + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule