Fix $finish inside fork blocks (#6555)

Signed-off-by: Bartłomiej Chmiel <bchmiel@antmicro.com>
This commit is contained in:
Bartłomiej Chmiel 2025-10-20 10:16:05 -04:00 committed by GitHub
parent 61c64e4a3b
commit 9bd30baba4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 72 additions and 1 deletions

View File

@ -619,6 +619,20 @@ public:
int instrCount() const override { return 0; } // Rarely executes
bool sameNode(const AstNode* samep) const override { return fileline() == samep->fileline(); }
};
class AstFinishFork final : public AstNodeStmt {
// $finish in fork
public:
explicit AstFinishFork(FileLine* fl)
: ASTGEN_SUPER_FinishFork(fl) {}
ASTGEN_MEMBERS_AstFinishFork;
bool isGateOptimizable() const override { return false; }
bool isPredictOptimizable() const override { return false; }
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
bool isOutputter() override { return true; } // SPECIAL: $display makes output
bool isUnlikely() const override { return true; }
int instrCount() const override { return 0; } // Rarely executes
bool sameNode(const AstNode* samep) const override { return fileline() == samep->fileline(); }
};
class AstFireEvent final : public AstNodeStmt {
// '-> _' and '->> _' event trigger statements
// @astgen op1 := operandp : AstNodeExpr

View File

@ -90,6 +90,7 @@ class CfgBuilder final : public VNVisitorConst {
void visit(AstComment*) override {} // ignore entirely
void visit(AstDisplay* nodep) override { simpleStatement(nodep); }
void visit(AstFinish* nodep) override { simpleStatement(nodep); }
void visit(AstFinishFork* nodep) override { simpleStatement(nodep); }
void visit(AstStmtExpr* nodep) override { simpleStatement(nodep); }
void visit(AstStop* nodep) override { simpleStatement(nodep); }

View File

@ -165,6 +165,7 @@ class CfgLiveVariables final : VNVisitorConst {
void visit(AstAssignW* nodep) override { single(nodep); }
void visit(AstDisplay* nodep) override { single(nodep); }
void visit(AstFinish* nodep) override { single(nodep); }
void visit(AstFinishFork* nodep) override { single(nodep); }
void visit(AstStmtExpr* nodep) override { single(nodep); }
void visit(AstStop* nodep) override { single(nodep); }

View File

@ -1253,6 +1253,18 @@ public:
puts(cvtToStr(nodep->fileline()->lineno()));
puts(", \"\");\n");
}
void visit(AstFinishFork* nodep) override {
putns(nodep, "VL_FINISH_MT(");
putsQuoted(protect(nodep->fileline()->filename()));
puts(", ");
puts(cvtToStr(nodep->fileline()->lineno()));
puts(", \"\");\n");
if (m_cfuncp->isCoroutine()) {
putns(nodep, "co_return;\n");
} else {
putns(nodep, "return;\n");
}
}
void visit(AstPrintTimeScale* nodep) override {
putns(nodep, "VL_PRINTTIMESCALE(");
putsQuoted(protect(nodep->prettyName()));

View File

@ -556,6 +556,7 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
puts(";\n");
}
void visit(AstFinish* nodep) override { putfs(nodep, "$finish;\n"); }
void visit(AstFinishFork* nodep) override { putfs(nodep, "$finish;\n"); }
void visit(AstStmtExpr* nodep) override {
iterateConst(nodep->exprp());
puts(";\n");

View File

@ -441,7 +441,10 @@ class LinkJumpVisitor final : public VNVisitor {
void visit(AstFinish* nodep) override {
if (nodep->user1SetOnce()) return; // Process once
iterateChildren(nodep);
if (m_loopp) {
if (m_inFork) {
nodep->replaceWith(new AstFinishFork{nodep->fileline()});
VL_DO_DANGLING(nodep->deleteTree(), nodep);
} else if (m_loopp) {
// Jump to the end of the loop (post-finish)
AstJumpBlock* const blockp = getJumpBlock(m_loopp, false);
nodep->addNextHere(new AstJumpGo{nodep->fileline(), blockp});

18
test_regress/t/t_fork_finish.py Executable file
View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2025 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
import vltest_bootstrap
test.scenarios('simulator')
test.compile(verilator_flags2=["--timing"])
test.execute()
test.passes()

View File

@ -0,0 +1,21 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2025 by Antmicro.
// SPDX-License-Identifier: CC0-1.0
module t;
initial begin
forever begin
fork
begin
assert ($c(1)) begin
$write("*-* All Finished *-*\n");
$finish;
end
wait ($c(1));
end
join_any
end
end
endmodule