Fix event triggering (#6932)

This commit is contained in:
Igor Zaworski
2026-02-11 10:35:59 -08:00
committed by GitHub
parent e41436bd4a
commit 446bec3d1a
23 changed files with 3765 additions and 1795 deletions
+76 -15
View File
@@ -421,7 +421,7 @@ void createSettle(AstNetlist* netlistp, AstCFunc* const initFuncp, SenExprBuilde
// Gather the relevant sensitivity expressions and create the trigger kit
const auto& senTreeps = getSenTreesUsedBy({&comb, &hybrid});
const TriggerKit trigKit = TriggerKit::create(netlistp, initFuncp, senExprBulider, {},
senTreeps, "stl", extraTriggers, true);
senTreeps, "stl", extraTriggers, true, false);
// Remap sensitivities (comb has none, so only do the hybrid)
remapSensitivities(hybrid, trigKit.mapVec());
@@ -446,7 +446,11 @@ void createSettle(AstNetlist* netlistp, AstCFunc* const initFuncp, SenExprBuilde
// Inner loop statements
nullptr,
// Prep statements: Compute the current 'stl' triggers
trigKit.newCompCall(),
[&trigKit] {
AstNodeStmt* const stmtp = trigKit.newCompBaseCall();
if (stmtp) stmtp->addNext(trigKit.newDumpCall(trigKit.vscp(), trigKit.name(), true));
return stmtp;
}(),
// Work statements: Invoke the 'stl' function
util::callVoidFunc(stlFuncp));
@@ -499,7 +503,8 @@ AstNode* createInputCombLoop(AstNetlist* netlistp, AstCFunc* const initFuncp,
// Gather the relevant sensitivity expressions and create the trigger kit
const auto& senTreeps = getSenTreesUsedBy({&logic});
const TriggerKit trigKit = TriggerKit::create(netlistp, initFuncp, senExprBuilder, {},
senTreeps, "ico", extraTriggers, false);
senTreeps, "ico", extraTriggers, false, false);
std::ignore = senExprBuilder.getAndClearResults();
if (dpiExportTriggerVscp) {
trigKit.addExtraTriggerAssignment(dpiExportTriggerVscp, dpiExportTriggerIndex);
@@ -549,7 +554,11 @@ AstNode* createInputCombLoop(AstNetlist* netlistp, AstCFunc* const initFuncp,
// Inner loop statements
nullptr,
// Prep statements: Compute the current 'ico' triggers
trigKit.newCompCall(),
[&trigKit] {
AstNodeStmt* const stmtp = trigKit.newCompBaseCall();
if (stmtp) stmtp->addNext(trigKit.newDumpCall(trigKit.vscp(), trigKit.name(), true));
return stmtp;
}(),
// Work statements: Invoke the 'ico' function
util::callVoidFunc(icoFuncp));
@@ -586,8 +595,8 @@ void createEval(AstNetlist* netlistp, //
) {
FileLine* const flp = netlistp->fileline();
// 'createResume' consumes the contents that 'createCommit' needs, so do the right order
AstCCall* const timingCommitp = timingKit.createCommit(netlistp);
// 'createResume' consumes the contents that 'createReady' needs, so do the right order
AstCCall* const timingReadyp = timingKit.createReady(netlistp);
AstCCall* const timingResumep = timingKit.createResume(netlistp);
// Create the active eval loop
@@ -598,9 +607,16 @@ void createEval(AstNetlist* netlistp, //
// Prep statements
[&]() {
// Compute the current 'act' triggers - the NBA triggers are the latched value
AstNodeStmt* stmtsp = trigKit.newCompCall(nbaKit.m_vscp);
// Commit trigger awaits from the previous iteration
if (timingCommitp) stmtsp = AstNode::addNext(stmtsp, timingCommitp->makeStmt());
AstNodeStmt* stmtsp = trigKit.newCompBaseCall();
AstNodeStmt* const dumpp
= stmtsp ? trigKit.newDumpCall(trigKit.vscp(), trigKit.name(), true) : nullptr;
// Mark as ready for triggered awaits
if (timingReadyp) stmtsp = AstNode::addNext(stmtsp, timingReadyp->makeStmt());
if (AstVarScope* const vscAccp = trigKit.vscAccp()) {
stmtsp = AstNode::addNext(stmtsp, trigKit.newOrIntoCall(actKit.m_vscp, vscAccp));
}
stmtsp = AstNode::addNext(stmtsp, trigKit.newCompExtCall(nbaKit.m_vscp));
stmtsp = AstNode::addNext(stmtsp, dumpp);
// Latch the 'act' triggers under the 'nba' triggers
stmtsp = AstNode::addNext(stmtsp, trigKit.newOrIntoCall(nbaKit.m_vscp, actKit.m_vscp));
//
@@ -609,8 +625,15 @@ void createEval(AstNetlist* netlistp, //
// Work statements
[&]() {
AstNodeStmt* workp = nullptr;
if (AstVarScope* const actAccp = trigKit.vscAccp()) {
AstCMethodHard* const cCallp = new AstCMethodHard{
flp, new AstVarRef{flp, actAccp, VAccess::WRITE}, VCMethod::UNPACKED_FILL,
new AstConst{flp, AstConst::Unsized64{}, 0}};
cCallp->dtypeSetVoid();
workp = AstNode::addNext(workp, cCallp->makeStmt());
}
// Resume triggered timing schedulers
if (timingResumep) workp = timingResumep->makeStmt();
if (timingResumep) workp = AstNode::addNext(workp, timingResumep->makeStmt());
// Invoke the 'act' function
workp = AstNode::addNext(workp, util::callVoidFunc(actKit.m_funcp));
//
@@ -650,7 +673,7 @@ void createEval(AstNetlist* netlistp, //
netlistp->nbaEventp(nullptr);
netlistp->nbaEventTriggerp(nullptr);
// If a dynamic NBA is pending, clear the pending flag and fire the commit event
// If a dynamic NBA is pending, clear the pending flag and fire the ready event
AstIf* const ifp = new AstIf{flp, new AstVarRef{flp, nbaEventTriggerp, VAccess::READ}};
ifp->addThensp(util::setVar(continuep, 1));
ifp->addThensp(util::setVar(nbaEventTriggerp, 0));
@@ -867,11 +890,12 @@ void schedule(AstNetlist* netlistp) {
&logicRegions.m_obs, //
&logicRegions.m_react, //
&timingKit.m_lbs});
const TriggerKit trigKit = TriggerKit::create(netlistp, staticp, senExprBuilder, preTreeps,
senTreeps, "act", extraTriggers, false);
const TriggerKit trigKit
= TriggerKit::create(netlistp, staticp, senExprBuilder, preTreeps, senTreeps, "act",
extraTriggers, false, v3Global.usesTiming());
// Add post updates from the timing kit
if (timingKit.m_postUpdates) trigKit.compp()->addStmtsp(timingKit.m_postUpdates);
if (timingKit.m_postUpdates) trigKit.compBasep()->addStmtsp(timingKit.m_postUpdates);
if (dpiExportTriggerVscp) {
trigKit.addExtraTriggerAssignment(dpiExportTriggerVscp, dpiExportTriggerIndex);
@@ -996,7 +1020,44 @@ void schedule(AstNetlist* netlistp) {
createEval(netlistp, icoLoopp, trigKit, actKit, nbaKit, obsKit, reactKit, postponedFuncp,
timingKit);
// Step 15: Clean up
// Step 15: Add neccessary evaluation before awaits
if (AstCCall* const readyp = timingKit.createReady(netlistp)) {
staticp->addStmtsp(readyp->makeStmt());
beforeTrigVisitor(netlistp, senExprBuilder, trigKit);
} else {
// beforeTrigVisitor clears Sentree pointers in AstCAwaits (as these sentrees will get
// deleted later) if there was no need to call it, SenTrees have to be cleaned manually
netlistp->foreach([](AstCAwait* const cAwaitp) { cAwaitp->clearSentreep(); });
}
if (AstVarScope* const trigAccp = trigKit.vscAccp()) {
// Copy trigger vector to accumulator at the end of static initialziation so,
// triggers fired during initialization persist to the first resume.
const AstUnpackArrayDType* const trigAccDTypep
= VN_AS(trigAccp->dtypep(), UnpackArrayDType);
UASSERT_OBJ(
trigAccDTypep->right() == 0, trigAccp,
"Expected that trigger vector and accumulator start elements enumeration from 0");
UASSERT_OBJ(trigAccDTypep->left() >= 0, trigAccp,
"Expected that trigger vector and accumulator has no negative indexes");
FileLine* const flp = trigAccp->fileline();
AstVarScope* const vscp = netlistp->topScopep()->scopep()->createTemp("__Vi", 32);
AstLoop* const loopp = new AstLoop{flp};
loopp->addStmtsp(
new AstAssign{flp,
new AstArraySel{flp, new AstVarRef{flp, trigAccp, VAccess::WRITE},
new AstVarRef{flp, vscp, VAccess::READ}},
new AstArraySel{flp, new AstVarRef{flp, actKit.m_vscp, VAccess::READ},
new AstVarRef{flp, vscp, VAccess::READ}}});
loopp->addStmtsp(util::incrementVar(vscp));
loopp->addStmtsp(new AstLoopTest{
flp, loopp,
new AstLte{flp, new AstVarRef{flp, vscp, VAccess::READ},
new AstConst{flp, AstConst::WidthedValue{}, 32,
static_cast<uint32_t>(trigAccDTypep->left())}}});
staticp->addStmtsp(loopp);
}
// Step 16: Clean up
netlistp->clearStlFirstIterationp();
// Haven't split static initializer yet