Support randsequence production function ports (#7522)

This commit is contained in:
Yilou Wang
2026-05-04 11:28:17 -04:00
committed by GitHub
parent 4e349971d3
commit fc49811fd7
9 changed files with 164 additions and 28 deletions
+29 -10
View File
@@ -141,26 +141,32 @@ class RandSequenceVisitor final : public VNVisitor {
taskp->addStmtsp(breakVarp);
// Call the start production's task
taskp->addStmtsp(newProdFuncRef(nodep, m_startProdp, breakVarp));
taskp->addStmtsp(newProdFuncRef(nodep, m_startProdp, breakVarp, nullptr));
UINFOTREE(9, taskp, "newStart", "");
return taskp;
}
AstNode* newProdFuncRef(AstNode* nodep, AstRSProd* prodp, AstVar* breakVarp) {
AstNode* newProdFuncRef(AstNode* nodep, AstRSProd* prodp, AstVar* breakVarp,
AstArg* userArgsp) {
auto it = m_prodFuncps.find(prodp);
UASSERT_OBJ(it != m_prodFuncps.end(), nodep, "No production function made");
AstNodeFTask* const prodFuncp = it->second;
FileLine* const fl = nodep->fileline();
AstArg* const argsp
= new AstArg{fl, breakVarp->name(), new AstVarRef{fl, breakVarp, VAccess::WRITE}};
// V3Width already ran before V3RandSequence, so VarRefs we create here
// need dtype set explicitly, V3Broken later checks width == widthMin.
AstVarRef* const breakRefp = new AstVarRef{fl, breakVarp, VAccess::WRITE};
breakRefp->dtypeFrom(breakVarp);
AstArg* const argsp = new AstArg{fl, breakVarp->name(), breakRefp};
for (const auto& itr : m_localizeNames) {
const AstVar* const lvarp = itr.second;
AstVar* const iovarp = m_localizeRemaps[lvarp];
UASSERT_OBJ(iovarp, nodep, "No new port variable for local variable" << lvarp);
argsp->addNext(new AstArg{nodep->fileline(), "__Vrsarg_" + lvarp->name(),
new AstVarRef{fl, iovarp, VAccess::READWRITE}});
AstVarRef* const refp = new AstVarRef{fl, iovarp, VAccess::READWRITE};
refp->dtypeFrom(iovarp);
argsp->addNext(new AstArg{nodep->fileline(), "__Vrsarg_" + lvarp->name(), refp});
}
if (userArgsp) argsp->addNext(userArgsp);
AstNode* const newp
= new AstStmtExpr{fl, new AstTaskRef{fl, VN_AS(prodFuncp, Task), argsp}};
return newp;
@@ -480,6 +486,19 @@ class RandSequenceVisitor final : public VNVisitor {
m_breakVarp = newBreakVar(nodep->fileline(), true);
m_prodFuncp->addStmtsp(m_breakVarp);
// Production formal ports become real input ports on the generated task.
// Must be added after m_breakVarp / localize ports so positional argument
// order in newProdFuncRef stays consistent: [break, localize..., user...].
if (AstNode* const portsp = nodep->portsp()) {
portsp->unlinkFrBackWithNext();
m_prodFuncp->addStmtsp(portsp);
for (AstNode* itp = portsp; itp; itp = itp->nextp()) {
AstVar* const portVarp = VN_AS(itp, Var);
portVarp->funcLocal(true);
portVarp->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
}
}
// Put JumpBlock immediately under the new function to support
// a future break/return. V3Const will rip it out if unneeded.
VL_RESTORER(m_jumpBlockp);
@@ -489,9 +508,6 @@ class RandSequenceVisitor final : public VNVisitor {
if (nodep->fvarp())
nodep->fvarp()->v3warn(E_UNSUPPORTED,
"Unsupported: randsequence production function variable");
if (nodep->portsp())
nodep->portsp()->v3warn(E_UNSUPPORTED,
"Unsupported: randsequence production function ports");
// Move children into m_prodFuncp, and iterate there
if (!nodep->rulesp()) { // Nothing to do
@@ -579,8 +595,11 @@ class RandSequenceVisitor final : public VNVisitor {
UASSERT_OBJ(m_prodFuncp, nodep, "RSProdItem not under production");
AstRSProd* const foundp = nodep->prodp();
UASSERT_OBJ(foundp, nodep, "Unlinked production reference");
// Pass through caller-side argument list (IEEE 1800-2023 18.17.7).
AstArg* const userArgsp
= nodep->argsp() ? nodep->argsp()->unlinkFrBackWithNext() : nullptr;
// Convert to task call
AstNode* const newp = newProdFuncRef(nodep, foundp, m_breakVarp);
AstNode* const newp = newProdFuncRef(nodep, foundp, m_breakVarp, userArgsp);
// The production might have done a "break;", skip other steps if so
newp->addNext(new AstIf{nodep->fileline(),
new AstVarRef{nodep->fileline(), m_breakVarp, VAccess::READ},