From b9fd4a13893e9d95fdd23cd94589f9c85dcd5918 Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Tue, 14 Nov 2023 13:45:03 +0100 Subject: [PATCH] Fix dynamic assigns to automatic vars Signed-off-by: Krzysztof Bieganski --- src/V3Fork.cpp | 19 ++++++++++++++----- src/V3SchedTiming.cpp | 3 ++- src/V3Timing.cpp | 8 ++++++-- test_regress/t/t_assigndly_dynamic.v | 18 ++++++++++++++++++ 4 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/V3Fork.cpp b/src/V3Fork.cpp index 133e4352ff4..6d08aa153e1 100644 --- a/src/V3Fork.cpp +++ b/src/V3Fork.cpp @@ -313,11 +313,8 @@ class DynScopeVisitor final : public VNVisitor { } static bool hasAsyncFork(AstNode* nodep) { - bool afork = false; - nodep->foreach([&](AstFork* forkp) { - if (!forkp->joinType().join()) afork = true; - }); - return afork; + return nodep->exists([](AstFork* forkp) { return !forkp->joinType().join(); }) + || nodep->exists([](AstAssignDly*) { return true; }); } void bindNodeToDynScope(AstNode* nodep, ForkDynScopeFrame* frame) { @@ -415,6 +412,18 @@ class DynScopeVisitor final : public VNVisitor { } visit(static_cast(nodep)); } + void visit(AstAssignDly* nodep) override { + if (m_procp && !VN_IS(nodep->backp(), Fork) && nodep->lhsp()->exists([](AstVarRef* refp) { + return refp->varp()->isFuncLocal(); + })) { + auto* forkp = new AstFork{nodep->fileline(), "", nullptr}; + forkp->joinType(VJoinType::JOIN_NONE); + nodep->replaceWith(forkp); + forkp->addStmtsp(nodep); + } else { + iterateChildren(nodep); + } + } void visit(AstNode* nodep) override { if (nodep->isTimingControl()) m_afterTimingControl = true; iterateChildren(nodep); diff --git a/src/V3SchedTiming.cpp b/src/V3SchedTiming.cpp index 368201f0552..75b5a67d778 100644 --- a/src/V3SchedTiming.cpp +++ b/src/V3SchedTiming.cpp @@ -288,7 +288,8 @@ void transformForks(AstNetlist* const netlistp) { funcp->foreach([&](AstNodeVarRef* refp) { AstVar* const varp = refp->varp(); AstBasicDType* const dtypep = varp->dtypep()->basicp(); - bool passByValue = false; + // If not a fork..join, copy. All write refs should've been handled by V3Fork + bool passByValue = !m_forkp->joinType().join(); if (!varp->isFuncLocal()) { if (VString::startsWith(varp->name(), "__Vintra")) { // Pass it by value to the new function, as otherwise there are issues with diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index 6484a724752..f9b59ca813c 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -1029,8 +1029,12 @@ class TimingControlVisitor final : public VNVisitor { // Special case for NBA if (inAssignDly) { // Put it in a fork so it doesn't block - auto* const forkp = new AstFork{flp, "", nullptr}; - forkp->joinType(VJoinType::JOIN_NONE); + // Could already be the only thing directly under a fork, reuse that if possible + AstFork* forkp = !nodep->nextp() ? VN_CAST(nodep->backp(), Fork) : nullptr; + if (!forkp) { + forkp = new AstFork{flp, "", nullptr}; + forkp->joinType(VJoinType::JOIN_NONE); + } if (!m_underProcedure) { // If it's in a function, it won't be handled by V3Delayed // Put it behind an additional named event that gets triggered in the NBA region diff --git a/test_regress/t/t_assigndly_dynamic.v b/test_regress/t/t_assigndly_dynamic.v index 9183eb767ff..f1fcc046d52 100644 --- a/test_regress/t/t_assigndly_dynamic.v +++ b/test_regress/t/t_assigndly_dynamic.v @@ -25,8 +25,23 @@ class nba_waiter; endtask endclass +class Foo; + task bar(logic b); + int x; + if (b) x <= 'hDEAD; + #2 + if (x != 'hDEAD) $stop; + endtask + + task qux(); + int x[] = new[1]; + x[0] <= `DELAY 'hBEEF; // Segfault check + endtask +endclass + module t; nba_waiter waiter = new; + Foo foo = new; event e; int cnt = 0; @@ -42,6 +57,9 @@ module t; waiter.wait_for_nba_region; if (cnt != 4) $stop; if ($time != `TIME_AFTER_SECOND_WAIT) $stop; + foo.bar(1); + foo.qux(); + #2 $write("*-* All Finished *-*\n"); $finish; end