diff --git a/src/V3SchedTiming.cpp b/src/V3SchedTiming.cpp index 2fcc691b6..d6d763c56 100644 --- a/src/V3SchedTiming.cpp +++ b/src/V3SchedTiming.cpp @@ -283,6 +283,7 @@ void transformForks(AstNetlist* const netlistp) { // STATE bool m_inClass = false; // Are we in a class? bool m_beginHasAwaits = false; // Does the current begin have awaits? + bool m_awaitMoved = false; // Has the current function lost awaits? AstFork* m_forkp = nullptr; // Current fork AstCFunc* m_funcp = nullptr; // Current function @@ -344,7 +345,13 @@ void transformForks(AstNetlist* const netlistp) { } void visit(AstCFunc* nodep) override { m_funcp = nodep; + m_awaitMoved = false; iterateChildren(nodep); + if (nodep->isCoroutine() && m_awaitMoved + && !nodep->stmtsp()->exists([](AstCAwait*) { return true; })) { + // co_return at the end (either that or a co_await is required in a coroutine + nodep->addStmtsp(new AstCStmt{nodep->fileline(), "co_return;\n"}); + } m_funcp = nullptr; } void visit(AstVar* nodep) override { @@ -399,6 +406,8 @@ void transformForks(AstNetlist* const netlistp) { if (!m_beginHasAwaits) { // co_return at the end (either that or a co_await is required in a coroutine newfuncp->addStmtsp(new AstCStmt{nodep->fileline(), "co_return;\n"}); + } else { + m_awaitMoved = true; } remapLocals(newfuncp, callp); } else { diff --git a/test_regress/t/t_fork_join_none_virtual.pl b/test_regress/t/t_fork_join_none_virtual.pl new file mode 100755 index 000000000..929ae897c --- /dev/null +++ b/test_regress/t/t_fork_join_none_virtual.pl @@ -0,0 +1,22 @@ +#!/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(simulator => 1); + +compile( + verilator_flags2 => ["--exe --main --timing"], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_fork_join_none_virtual.v b/test_regress/t/t_fork_join_none_virtual.v new file mode 100644 index 000000000..717f7707c --- /dev/null +++ b/test_regress/t/t_fork_join_none_virtual.v @@ -0,0 +1,62 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +event evt1; + +typedef enum {ENUM_VALUE} enum_t; + +class Foo; + int m_member; + enum_t m_en; + + virtual task do_something(); + fork + #20 begin + m_member++; + $display("this's m_member: %0d m_en: %s", m_member, m_en.name()); + if (m_member != 3) + $stop; + ->evt1; + end + #10 begin + m_member++; + bar(this); + end + join_none + endtask + + static task bar(Foo foo); + fork + begin + foo.m_member++; + $display("foo's m_member: %0d m_en: %s", foo.m_member, foo.m_en.name()); + if (foo.m_member != 2) + $stop; + end + join_none + endtask +endclass + +class Subfoo extends Foo; + virtual task do_something();#5;endtask +endclass + +module t(); + initial begin + Subfoo subfoo; + Foo foo; + subfoo = new; + subfoo.do_something(); + foo = new; + foo.m_member = 0; + foo.do_something(); + end + + always @(evt1) begin + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule