diff --git a/docs/internals.rst b/docs/internals.rst index 12cbd720c..c78e0197b 100644 --- a/docs/internals.rst +++ b/docs/internals.rst @@ -628,16 +628,12 @@ coroutines ``co_await`` its ``join`` function, and forked ones call ``done`` when they're finished. Once the required number of coroutines (set using ``setCounter``) finish execution, the forking coroutine is resumed. -Awaitable Utilities -~~~~~~~~~~~~~~~~~~~ +``VlForever`` +~~~~~~~~~~~~~ -There are also two small utility awaitable types: - -* ``VlNow`` is an awaitable that suspends and immediately resumes coroutines. - It is used for forcing a coroutine to be moved onto the heap. See the `Forks` - section for more detail. -* ``VlForever`` is used for blocking a coroutine forever. See the `Timing pass` - section for more detail. +A small utility awaitable type. It allows for blocking a coroutine forever. It +is currently only used for ``wait`` statements that await a constant false +condition. See the `Timing Pass` section for more details. Timing Pass ~~~~~~~~~~~ @@ -749,9 +745,7 @@ doesn't suspend the forking process. In forked processes, references to local variables are only allowed in ``fork..join``, as this is the only case that ensures the lifetime of these -locals are at least as long as the execution of the forked processes. This is -where ``VlNow`` is used, to ensure the locals are moved to the heap before they -are passed by reference to the forked processes. +locals are at least as long as the execution of the forked processes. Multithreaded Mode diff --git a/include/verilated_timing.h b/include/verilated_timing.h index 535839389..019573185 100644 --- a/include/verilated_timing.h +++ b/include/verilated_timing.h @@ -312,16 +312,6 @@ public: } }; -//============================================================================= -// VlNow is a helper awaitable type that always suspends, and then immediately resumes a coroutine. -// Allows forcing the move of coroutine locals to the heap. - -struct VlNow { - bool await_ready() const { return false; } // Always suspend - bool await_suspend(std::coroutine_handle<>) const { return false; } // Resume immediately - void await_resume() const {} -}; - //============================================================================= // VlForever is a helper awaitable type for suspending coroutines forever. Used for constant // wait statements. diff --git a/src/V3SchedTiming.cpp b/src/V3SchedTiming.cpp index e772d1bcb..0b3da2451 100644 --- a/src/V3SchedTiming.cpp +++ b/src/V3SchedTiming.cpp @@ -272,22 +272,20 @@ void transformForks(AstNetlist* const netlistp) { // If it a fork sync or an intra-assignment variable, pass it by value const bool passByValue = (dtypep && dtypep->isForkSync()) || VString::startsWith(varp->name(), "__Vintra"); - // Only handle vars passed by value or locals declared before the fork - if (!passByValue && (!varp->user1() || !varp->isFuncLocal())) return; if (passByValue) { // We can just pass it to the new function + } else if (!varp->user1() || !varp->isFuncLocal()) { + // Not func local, or not declared before the fork. Their lifetime is longer + // than the forked process. Skip + return; } else if (m_forkp->joinType().join()) { // If it's fork..join, we can refer to variables from the parent process - if (!m_funcp->user1SetOnce()) { // Only do this once per function - // Move all locals to the heap before the fork - AstCExpr* const nowp - = new AstCExpr{m_forkp->fileline(), "VlNow{}", 0, true}; - nowp->dtypeSetVoid(); // TODO: this is sloppy but harmless - AstCAwait* const awaitp = new AstCAwait{m_forkp->fileline(), nowp}; - awaitp->dtypeSetVoid(); - m_forkp->addHereThisAsNext(awaitp->makeStmt()); - } } else { + // TODO: It is possible to relax this by allowing the use of such variables up + // until the first await. Also, variables defined within a forked process + // (inside a begin) are extracted out by V3Begin, so they also trigger this + // error. Preventing this (or detecting such cases and moving the vars back) + // would also allow for using them freely. refp->v3warn(E_UNSUPPORTED, "Unsupported: variable local to a forking process " "accessed in a fork..join_any or fork..join_none"); return; @@ -305,7 +303,8 @@ void transformForks(AstNetlist* const netlistp) { = new AstVarScope{newvarp->fileline(), funcp->scopep(), newvarp}; funcp->scopep()->addVarsp(newvscp); vscp->user2p(newvscp); - callp->addArgsp(new AstVarRef{refp->fileline(), vscp, VAccess::READ}); + callp->addArgsp(new AstVarRef{ + refp->fileline(), vscp, passByValue ? VAccess::READ : VAccess::READWRITE}); } AstVarScope* const newvscp = VN_AS(vscp->user2p(), VarScope); refp->varScopep(newvscp);