diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 0e91f5fca..c07b28c47 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -3232,7 +3232,8 @@ AstAlways* AstAssignW::convertToAlways() { if (hasTimingControl) { // If there's a timing control, put the assignment in a fork..join_none. This process won't // get marked as suspendable and thus will be scheduled normally - AstFork* forkp = new AstFork{flp, "", bodysp}; + AstBegin* const beginp = new AstBegin{flp, "", bodysp}; + AstFork* const forkp = new AstFork{flp, "", beginp}; forkp->joinType(VJoinType::JOIN_NONE); bodysp = forkp; } diff --git a/src/V3Fork.cpp b/src/V3Fork.cpp index 4f9e7d1da..b05ea6776 100644 --- a/src/V3Fork.cpp +++ b/src/V3Fork.cpp @@ -459,10 +459,11 @@ class DynScopeVisitor final : public VNVisitor { })) { nodep->user2(true); // Put it in a fork to prevent lifetime issues with the local - AstFork* const forkp = new AstFork{nodep->fileline(), "", nullptr}; + AstBegin* const beginp = new AstBegin{nodep->fileline(), "", nullptr}; + AstFork* const forkp = new AstFork{nodep->fileline(), "", beginp}; forkp->joinType(VJoinType::JOIN_NONE); nodep->replaceWith(forkp); - forkp->addStmtsp(nodep); + beginp->addStmtsp(nodep); UINFO(9, "assign new fork " << forkp); } else { visit(static_cast(nodep)); diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index d25a40346..e0cac0507 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -1030,7 +1030,10 @@ class TimingControlVisitor final : public VNVisitor { if (!controlp) controlp = nbaEventControlp; } controlp->replaceWith(forkp); - forkp->addStmtsp(controlp); + AstBegin* beginp = VN_CAST(controlp, Begin); + if (!beginp) beginp = new AstBegin{nodep->fileline(), "", controlp}; + forkp->addStmtsp(beginp); + controlp = forkp; } UASSERT_OBJ(nodep, controlp, "Assignment should have timing control"); addCLocalScope(flp, insertBeforep); @@ -1225,14 +1228,9 @@ class TimingControlVisitor final : public VNVisitor { AstNode* stmtp = nodep->stmtsp(); // Put each statement in a begin while (stmtp) { - if (!VN_IS(stmtp, Begin)) { - auto* const beginp = new AstBegin{stmtp->fileline(), "", nullptr}; - if (hasFlags(stmtp, T_HAS_PROC)) addFlags(beginp, T_HAS_PROC); - stmtp->replaceWith(beginp); - beginp->addStmtsp(stmtp); - stmtp = beginp; - } - auto* const beginp = VN_AS(stmtp, Begin); + UASSERT_OBJ(VN_IS(stmtp, Begin), nodep, + "All statements under forks must be begins at this point"); + AstBegin* const beginp = VN_AS(stmtp, Begin); stmtp = beginp->nextp(); iterate(beginp); // Even if we do not find any awaits, we cannot simply inline the process here, as new diff --git a/test_regress/t/t_timing_intra_assign_func.py b/test_regress/t/t_timing_intra_assign_func.py new file mode 100755 index 000000000..c6e56559a --- /dev/null +++ b/test_regress/t/t_timing_intra_assign_func.py @@ -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=["--binary"]) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_timing_intra_assign_func.v b/test_regress/t/t_timing_intra_assign_func.v new file mode 100644 index 000000000..30cd53d87 --- /dev/null +++ b/test_regress/t/t_timing_intra_assign_func.v @@ -0,0 +1,26 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; + reg [3:0] ia = 4'd1; + wire signed [3:0] iufunc; + + // verilator lint_off WIDTH + assign #1 iufunc = int_func(ia); + // verilator lint_on WIDTH + + function [31:0] int_func; + input [31:0] in; + int_func = in * 2; + endfunction + + initial begin + #1 + if (iufunc != 4'd2) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule