Put dynamic NBA commit in eval_phase__nba

Fixes #4634
This commit is contained in:
Geza Lore 2023-12-10 13:32:24 +00:00
parent 75a44e5aa9
commit 6012ec8eb7

View File

@ -170,22 +170,25 @@ AstNodeStmt* profExecSectionPop(FileLine* flp) {
struct EvalLoop { struct EvalLoop {
// Flag set to true during the first iteration of the loop // Flag set to true during the first iteration of the loop
AstVarScope* firstIterp; AstVarScope* firstIterp;
// The loop continuation flag (set to true to loop again)
AstVarScope* continuep = nullptr;
// The loop itself and statements around it // The loop itself and statements around it
AstNodeStmt* stmtsp = nullptr; AstNodeStmt* stmtsp = nullptr;
}; };
// Create an eval loop with all the trimmings. // Create an eval loop with all the trimmings.
EvalLoop createEvalLoop(AstNetlist* netlistp, // EvalLoop createEvalLoop(
const std::string& tag, // Tag for current phase AstNetlist* netlistp, //
const string& name, // Name of current phase const std::string& tag, // Tag for current phase
bool slow, // Should create slow functions const string& name, // Name of current phase
AstVarScope* trigp, // The trigger vector bool slow, // Should create slow functions
AstCFunc* dumpFuncp, // Trigger dump function for debugging only AstVarScope* trigp, // The trigger vector
AstNodeStmt* innerp, // The inner loop, if any AstCFunc* dumpFuncp, // Trigger dump function for debugging only
AstNodeStmt* phasePrepp, // Prep statements run before checking triggers AstNodeStmt* innerp, // The inner loop, if any
AstNodeStmt* phaseWorkp // The work to do if anything triggered AstNodeStmt* phasePrepp, // Prep statements run before checking triggers
AstNodeStmt* phaseWorkp, // The work to do if anything triggered
// Extra statements to run after the work, even if no triggers fired. This function is
// passed a variable, which must be set to true if we must continue and loop again,
// and must be unmodified otherwise.
std::function<AstNodeStmt*(AstVarScope*)> phaseExtra = [](AstVarScope*) { return nullptr; } //
) { ) {
const std::string varPrefix = "__V" + tag; const std::string varPrefix = "__V" + tag;
AstScope* const scopeTopp = netlistp->topScopep()->scopep(); AstScope* const scopeTopp = netlistp->topScopep()->scopep();
@ -213,6 +216,9 @@ EvalLoop createEvalLoop(AstNetlist* netlistp, //
ifp->addThensp(phaseWorkp); ifp->addThensp(phaseWorkp);
phaseFuncp->addStmtsp(ifp); phaseFuncp->addStmtsp(ifp);
// Construct the extra statements
if (AstNodeStmt* const extrap = phaseExtra(executeFlagp)) phaseFuncp->addStmtsp(extrap);
// The function returns ture iff it did run the work // The function returns ture iff it did run the work
phaseFuncp->rtnType("bool"); phaseFuncp->rtnType("bool");
phaseFuncp->addStmtsp( phaseFuncp->addStmtsp(
@ -272,7 +278,7 @@ EvalLoop createEvalLoop(AstNetlist* netlistp, //
// Prof-exec section pop // Prof-exec section pop
if (v3Global.opt.profExec()) stmtps->addNext(profExecSectionPop(flp)); if (v3Global.opt.profExec()) stmtps->addNext(profExecSectionPop(flp));
return {firstIterFlagp, continueFlagp, stmtps}; return {firstIterFlagp, stmtps};
} }
//============================================================================ //============================================================================
@ -1011,25 +1017,27 @@ void createEval(AstNetlist* netlistp, //
workp->addNext(createTriggerClearCall(flp, nbaKit.m_vscp)); workp->addNext(createTriggerClearCall(flp, nbaKit.m_vscp));
// //
return workp; return workp;
}()); }(),
// Extra work (not conditional on having had a fired trigger)
[&](AstVarScope* continuep) -> AstNodeStmt* {
// Check if any dynamic NBAs are pending, if there are any in the design
if (!netlistp->nbaEventp()) return nullptr;
AstVarScope* const nbaEventp = netlistp->nbaEventp();
AstVarScope* const nbaEventTriggerp = netlistp->nbaEventTriggerp();
UASSERT(nbaEventTriggerp, "NBA event trigger var should exist");
netlistp->nbaEventp(nullptr);
netlistp->nbaEventTriggerp(nullptr);
// If the NBA event exists, trigger it in 'nba' // If a dynamic NBA is pending, clear the pending flag and fire the commit event
if (AstVarScope* const nbaEventp = netlistp->nbaEventp()) { AstIf* const ifp = new AstIf{flp, new AstVarRef{flp, nbaEventTriggerp, VAccess::READ}};
AstVarScope* const nbaEventTriggerp = netlistp->nbaEventTriggerp(); ifp->addThensp(setVar(continuep, 1));
UASSERT(nbaEventTriggerp, "NBA event trigger var should exist"); ifp->addThensp(setVar(nbaEventTriggerp, 0));
netlistp->nbaEventp(nullptr); AstCMethodHard* const firep
netlistp->nbaEventTriggerp(nullptr); = new AstCMethodHard{flp, new AstVarRef{flp, nbaEventp, VAccess::WRITE}, "fire"};
firep->dtypeSetVoid();
AstIf* const ifp = new AstIf{flp, new AstVarRef{flp, nbaEventTriggerp, VAccess::READ}}; ifp->addThensp(firep->makeStmt());
ifp->addThensp(setVar(topLoop.continuep, 1)); return ifp;
ifp->addThensp(setVar(nbaEventTriggerp, 0)); });
AstCMethodHard* const firep
= new AstCMethodHard{flp, new AstVarRef{flp, nbaEventp, VAccess::WRITE}, "fire"};
firep->dtypeSetVoid();
ifp->addThensp(firep->makeStmt());
// actLoop.stmtsp happens to be the head of the loop body inside the NBA loop...
actLoop.stmtsp->addNext(ifp);
}
if (!obsKit.empty()) { if (!obsKit.empty()) {
// Create the Observed eval loop, which becomes the top level loop. // Create the Observed eval loop, which becomes the top level loop.