mirror of
https://github.com/verilator/verilator.git
synced 2026-10-07 18:42:58 +02:00
Fix nonblocking event trigger never firing in suspendable processes (#8485)
This commit is contained in:
+38
-12
@@ -300,6 +300,7 @@ class DelayedVisitor final : public VNVisitor {
|
||||
bool m_ignoreBlkAndNBlk = false; // Suppress delayed assignment BLKANDNBLK
|
||||
bool m_inNonCombLogic = false; // We are in non-combinational logic
|
||||
bool m_needsInitialTrigger = false; // Whether a NodeProcedure needs a initial trigger
|
||||
std::vector<AstSenTree*> m_nbaEventSenTreeps; // Sensitivities of '->>' in the process
|
||||
AstVarRef* m_currNbaLhsRefp = nullptr; // Current NBA LHS variable reference
|
||||
|
||||
// STATE - during NBA conversion (after visit)
|
||||
@@ -1190,6 +1191,7 @@ class DelayedVisitor final : public VNVisitor {
|
||||
}
|
||||
void visit(AstNodeProcedure* nodep) override {
|
||||
VL_RESTORER(m_needsInitialTrigger);
|
||||
VL_RESTORER_CLEAR(m_nbaEventSenTreeps);
|
||||
const size_t firstNBAAddedIndex = m_nbas.size();
|
||||
{
|
||||
VL_RESTORER(m_inSuspendableOrFork);
|
||||
@@ -1241,6 +1243,8 @@ class DelayedVisitor final : public VNVisitor {
|
||||
for (size_t i = firstNBAAddedIndex; i < m_nbas.size(); ++i) {
|
||||
m_vscpInfo(m_nbas[i].vscp).addSensitivity(senItemp);
|
||||
}
|
||||
for (AstSenTree* const senTreep : m_nbaEventSenTreeps)
|
||||
senTreep->addSensesp(senItemp->cloneTree(true));
|
||||
// Done with these
|
||||
VL_DO_DANGLING(senItemp->deleteTree(), senItemp);
|
||||
}
|
||||
@@ -1266,8 +1270,15 @@ class DelayedVisitor final : public VNVisitor {
|
||||
cstmtp->add(");");
|
||||
|
||||
AstNode* newp = cstmtp;
|
||||
if (nodep->isDelayed()) {
|
||||
const AstVarRef* const vrefp = VN_AS(eventp, VarRef);
|
||||
const AstVarRef* const vrefp = VN_CAST(eventp, VarRef);
|
||||
if (nodep->isDelayed() && (m_cfuncp || !vrefp)) {
|
||||
// V3Timing converts these with --timing
|
||||
nodep->v3warn(E_NOTIMING, "Nonblocking event trigger "
|
||||
<< (m_cfuncp ? "in a non-inlined function/task"
|
||||
: "of a class or interface member or "
|
||||
"array element")
|
||||
<< " requires --timing");
|
||||
} else if (nodep->isDelayed()) {
|
||||
const std::string newvarname = "__Vdly__" + vrefp->varp()->shortName();
|
||||
AstVarScope* const dlyvscp
|
||||
= createTemp(flp, vrefp->varScopep()->scopep(), newvarname, 1);
|
||||
@@ -1276,20 +1287,35 @@ class DelayedVisitor final : public VNVisitor {
|
||||
return new AstVarRef{flp, dlyvscp, access};
|
||||
};
|
||||
|
||||
AstAlwaysPre* const prep = new AstAlwaysPre{flp};
|
||||
prep->addStmtsp(new AstAssign{flp, dlyRef(VAccess::WRITE),
|
||||
new AstConst{flp, AstConst::BitFalse{}}});
|
||||
AstAlwaysPost* const postp = new AstAlwaysPost{flp};
|
||||
{
|
||||
AstIf* const ifp = new AstIf{flp, dlyRef(VAccess::READ)};
|
||||
postp->addStmtsp(ifp);
|
||||
ifp->addThensp(newp);
|
||||
}
|
||||
AstIf* const ifp = new AstIf{flp, dlyRef(VAccess::READ)};
|
||||
postp->addStmtsp(ifp);
|
||||
|
||||
UASSERT_OBJ(m_activep, nodep, "No active to handle FireEvent");
|
||||
AstActive* const activep = new AstActive{flp, "nba-event", m_activep->sentreep()};
|
||||
AstSenTree* senTreep = m_activep->sentreep();
|
||||
AstActive* activep = nullptr;
|
||||
if (m_inSuspendableOrFork && (senTreep->hasInitial() || senTreep->hasClocked())) {
|
||||
// Suspendable code can trigger whenever it resumes, so fire when its NBAs are
|
||||
// committed (see visit(AstNodeProcedure*)), clearing the flag like
|
||||
// Scheme::FlagUnique
|
||||
senTreep = new AstSenTree{
|
||||
flp, senTreep->hasClocked() ? senTreep->sensesp()->cloneTree(true) : nullptr};
|
||||
m_nbaEventSenTreeps.push_back(senTreep);
|
||||
m_needsInitialTrigger |= m_timingDomains.empty();
|
||||
dlyvscp->varp()->setIgnorePostWrite();
|
||||
ifp->addThensp(new AstAssign{flp, dlyRef(VAccess::WRITE),
|
||||
new AstConst{flp, AstConst::BitFalse{}}});
|
||||
activep = new AstActive{flp, "nba-event", senTreep};
|
||||
activep->senTreeStorep(senTreep);
|
||||
} else {
|
||||
activep = new AstActive{flp, "nba-event", senTreep};
|
||||
AstAlwaysPre* const prep = new AstAlwaysPre{flp};
|
||||
prep->addStmtsp(new AstAssign{flp, dlyRef(VAccess::WRITE),
|
||||
new AstConst{flp, AstConst::BitFalse{}}});
|
||||
activep->addStmtsp(prep);
|
||||
}
|
||||
ifp->addThensp(newp);
|
||||
m_activep->addNextHere(activep);
|
||||
activep->addStmtsp(prep);
|
||||
activep->addStmtsp(postp);
|
||||
|
||||
newp = new AstAssign{flp, dlyRef(VAccess::WRITE),
|
||||
|
||||
Reference in New Issue
Block a user