From 04febb194437e8b982e3c14c25d9d4298f11ec1d Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 26 Nov 2020 15:03:55 -0500 Subject: [PATCH] Internals: Move V3Param code. No functional change. --- src/V3Param.cpp | 409 ++++++++++++++++++++++++------------------------ 1 file changed, 205 insertions(+), 204 deletions(-) diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 91def7f9f..fbdf6bc67 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -65,6 +65,7 @@ //###################################################################### // Hierarchical block and parameter db (modules without parameter is also handled) + class ParameterizedHierBlocks final { typedef std::multimap HierBlockOptsByOrigName; typedef HierBlockOptsByOrigName::const_iterator HierMapIt; @@ -195,10 +196,9 @@ public: }; //###################################################################### -// Param state, as a visitor of each AstNode +// Process parameter visitor class ParamVisitor final : public AstNVisitor { -private: // NODE STATE // AstNodeModule::user5() // bool True if processed // AstGenFor::user5() // bool True if processed @@ -531,7 +531,209 @@ private: } return newmodp; } - void visitCellDeparam(AstCell* nodep, const string& hierName); + void visitCellDeparam(AstCell* nodep, const string& hierName) { + // Cell: Check for parameters in the instantiation. + iterateChildren(nodep); + UASSERT_OBJ(nodep->modp(), nodep, "Not linked?"); + // We always run this, even if no parameters, as need to look for interfaces, + // and remove any recursive references + { + UINFO(4, "De-parameterize: " << nodep << endl); + // Create new module name with _'s between the constants + if (debug() >= 10) nodep->dumpTree(cout, "-cell: "); + // Evaluate all module constants + V3Const::constifyParamsEdit(nodep); + AstNodeModule* srcModp = nodep->modp(); + srcModp->hierName(hierName + "." + nodep->name()); + + // Make sure constification worked + // Must be a separate loop, as constant conversion may have changed some pointers. + // if (debug()) nodep->dumpTree(cout, "-cel2: "); + string longname = srcModp->name(); + bool any_overrides = false; + // Must always clone __Vrcm (recursive modules) + if (nodep->recursive()) any_overrides = true; + longname += "_"; + if (debug() > 8) nodep->paramsp()->dumpTreeAndNext(cout, "-cellparams: "); + for (AstPin* pinp = nodep->paramsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) { + if (!pinp->exprp()) continue; // No-connect + if (AstVar* modvarp = pinp->modVarp()) { + if (!modvarp->isGParam()) { + pinp->v3error("Attempted parameter setting of non-parameter: Param " + << pinp->prettyNameQ() << " of " << nodep->prettyNameQ()); + } else if (VN_IS(pinp->exprp(), InitArray) + && arraySubDTypep(modvarp->subDTypep())) { + // Array assigned to array + AstNode* exprp = pinp->exprp(); + longname + += "_" + paramSmallName(srcModp, modvarp) + paramValueNumber(exprp); + any_overrides = true; + } else { + AstConst* exprp = VN_CAST(pinp->exprp(), Const); + AstConst* origp = VN_CAST(modvarp->valuep(), Const); + if (!exprp) { + // if (debug()) pinp->dumpTree(cout, "error:"); + pinp->v3error("Can't convert defparam value to constant: Param " + << pinp->prettyNameQ() << " of " + << nodep->prettyNameQ()); + pinp->exprp()->replaceWith(new AstConst( + pinp->fileline(), AstConst::WidthedValue(), modvarp->width(), 0)); + } else if (origp && exprp->sameTree(origp)) { + // Setting parameter to its default value. Just ignore it. + // This prevents making additional modules, and makes coverage more + // obvious as it won't show up under a unique module page name. + } else if (exprp->num().isDouble() || exprp->num().isString() + || exprp->num().isFourState() || exprp->num().width() != 32) { + longname += ("_" + paramSmallName(srcModp, modvarp) + + paramValueNumber(exprp)); + any_overrides = true; + } else { + longname += ("_" + paramSmallName(srcModp, modvarp) + + exprp->num().ascii(false)); + any_overrides = true; + } + } + } else if (AstParamTypeDType* modvarp = pinp->modPTypep()) { + AstNodeDType* exprp = VN_CAST(pinp->exprp(), NodeDType); + AstNodeDType* origp = modvarp->subDTypep(); + if (!exprp) { + pinp->v3error("Parameter type pin value isn't a type: Param " + << pinp->prettyNameQ() << " of " << nodep->prettyNameQ()); + } else if (!origp) { + pinp->v3error("Parameter type variable isn't a type: Param " + << modvarp->prettyNameQ()); + } else { + UINFO(9, "Parameter type assignment expr=" << exprp << " to " << origp + << endl); + if (exprp->sameTree(origp)) { + // Setting parameter to its default value. Just ignore it. + // This prevents making additional modules, and makes coverage more + // obvious as it won't show up under a unique module page name. + } else { + V3Const::constifyParamsEdit(exprp); + longname += "_" + paramSmallName(srcModp, modvarp) + + paramValueNumber(exprp); + any_overrides = true; + } + } + } else { + pinp->v3error("Parameter not found in sub-module: Param " + << pinp->prettyNameQ() << " of " << nodep->prettyNameQ()); + } + } + IfaceRefRefs ifaceRefRefs; + for (AstPin* pinp = nodep->pinsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) { + AstVar* modvarp = pinp->modVarp(); + if (modvarp->isIfaceRef()) { + AstIfaceRefDType* portIrefp = VN_CAST(modvarp->subDTypep(), IfaceRefDType); + if (!portIrefp && arraySubDTypep(modvarp->subDTypep())) { + portIrefp = VN_CAST(arraySubDTypep(modvarp->subDTypep()), IfaceRefDType); + } + AstIfaceRefDType* pinIrefp = nullptr; + AstNode* exprp = pinp->exprp(); + AstVar* varp = (exprp && VN_IS(exprp, VarRef)) ? VN_CAST(exprp, VarRef)->varp() + : nullptr; + if (varp && varp->subDTypep() && VN_IS(varp->subDTypep(), IfaceRefDType)) { + pinIrefp = VN_CAST(varp->subDTypep(), IfaceRefDType); + } else if (varp && varp->subDTypep() && arraySubDTypep(varp->subDTypep()) + && VN_CAST(arraySubDTypep(varp->subDTypep()), IfaceRefDType)) { + pinIrefp = VN_CAST(arraySubDTypep(varp->subDTypep()), IfaceRefDType); + } else if (exprp && exprp->op1p() && VN_IS(exprp->op1p(), VarRef) + && VN_CAST(exprp->op1p(), VarRef)->varp() + && VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep() + && arraySubDTypep( + VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep()) + && VN_CAST(arraySubDTypep( + VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep()), + IfaceRefDType)) { + pinIrefp = VN_CAST( + arraySubDTypep(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep()), + IfaceRefDType); + } + + UINFO(9, " portIfaceRef " << portIrefp << endl); + + if (!portIrefp) { + pinp->v3error("Interface port " << modvarp->prettyNameQ() + << " is not an interface " << modvarp); + } else if (!pinIrefp) { + pinp->v3error("Interface port " + << modvarp->prettyNameQ() + << " is not connected to interface/modport pin expression"); + } else { + UINFO(9, " pinIfaceRef " << pinIrefp << endl); + if (portIrefp->ifaceViaCellp() != pinIrefp->ifaceViaCellp()) { + UINFO(9, " IfaceRefDType needs reconnect " << pinIrefp << endl); + longname += ("_" + paramSmallName(srcModp, pinp->modVarp()) + + paramValueNumber(pinIrefp)); + any_overrides = true; + ifaceRefRefs.push_back(make_pair(portIrefp, pinIrefp)); + if (portIrefp->ifacep() != pinIrefp->ifacep() + // Might be different only due to param cloning, so check names too + && portIrefp->ifaceName() != pinIrefp->ifaceName()) { + pinp->v3error("Port " + << pinp->prettyNameQ() << " expects " + << AstNode::prettyNameQ(portIrefp->ifaceName()) + << " interface but pin connects " + << AstNode::prettyNameQ(pinIrefp->ifaceName()) + << " interface"); + } + } + } + } + } + + if (!any_overrides) { + UINFO(8, "Cell parameters all match original values, skipping expansion.\n"); + } else if (AstNodeModule* modp + = m_hierBlocks.findByParams(srcModp->name(), nodep->paramsp(), m_modp)) { + nodep->modp(modp); + nodep->modName(modp->name()); + modp->dead(false); + // We need to relink the pins to the new module + relinkPinsByName(nodep->pinsp(), modp); + } else { + // If the name is very long, we don't want to overwhelm the filename limit + // We don't do this always, as it aids debugability to have intuitive naming. + // TODO can use new V3Name hash replacement instead of this + // Shorter name is convenient for hierarchical block + string newname = moduleCalcName(srcModp, nodep, longname); + UINFO(4, + "Name: " << srcModp->name() << "->" << longname << "->" << newname << endl); + // + // Already made this flavor? + AstNodeModule* cellmodp = nullptr; + auto iter = m_modNameMap.find(newname); + if (iter != m_modNameMap.end()) cellmodp = iter->second.m_modp; + if (!cellmodp) { + cellmodp = deepCloneModule(srcModp, nodep, newname, ifaceRefRefs); + iter = m_modNameMap.find(newname); + UASSERT(iter != m_modNameMap.end(), "should find just-made module"); + } else { + UINFO(4, " De-parameterize to old: " << cellmodp << endl); + } + // Have child use this module instead. + nodep->modp(cellmodp); + nodep->modName(newname); + // We need to relink the pins to the new module + CloneMap* clonemapp = &(iter->second.m_cloneMap); + relinkPins(clonemapp, nodep->pinsp()); + UINFO(8, " Done with " << cellmodp << endl); + } // if any_overrides + + nodep->recursive(false); + + // Delete the parameters from the cell; they're not relevant any longer. + if (nodep->paramsp()) nodep->paramsp()->unlinkFrBackWithNext()->deleteTree(); + UINFO(8, " Done with " << nodep << endl); + // if (debug() >= 10) + // v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("param-out.tree")); + } + + // Now remember to process the child module at the end of the module + m_todoModps.insert(make_pair(nodep->modp()->level(), nodep->modp())); + } + void visitModules() { // Loop on all modules left to process // Hitting a cell adds to the appropriate level of this level-sorted list, @@ -877,207 +1079,6 @@ public: virtual ~ParamVisitor() override = default; }; -//---------------------------------------------------------------------- -// VISITs - -void ParamVisitor::visitCellDeparam(AstCell* nodep, const string& hierName) { - // Cell: Check for parameters in the instantiation. - iterateChildren(nodep); - UASSERT_OBJ(nodep->modp(), nodep, "Not linked?"); - // We always run this, even if no parameters, as need to look for interfaces, - // and remove any recursive references - { - UINFO(4, "De-parameterize: " << nodep << endl); - // Create new module name with _'s between the constants - if (debug() >= 10) nodep->dumpTree(cout, "-cell: "); - // Evaluate all module constants - V3Const::constifyParamsEdit(nodep); - AstNodeModule* srcModp = nodep->modp(); - srcModp->hierName(hierName + "." + nodep->name()); - - // Make sure constification worked - // Must be a separate loop, as constant conversion may have changed some pointers. - // if (debug()) nodep->dumpTree(cout, "-cel2: "); - string longname = srcModp->name(); - bool any_overrides = false; - // Must always clone __Vrcm (recursive modules) - if (nodep->recursive()) any_overrides = true; - longname += "_"; - if (debug() > 8) nodep->paramsp()->dumpTreeAndNext(cout, "-cellparams: "); - for (AstPin* pinp = nodep->paramsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) { - if (!pinp->exprp()) continue; // No-connect - if (AstVar* modvarp = pinp->modVarp()) { - if (!modvarp->isGParam()) { - pinp->v3error("Attempted parameter setting of non-parameter: Param " - << pinp->prettyNameQ() << " of " << nodep->prettyNameQ()); - } else if (VN_IS(pinp->exprp(), InitArray) - && arraySubDTypep(modvarp->subDTypep())) { - // Array assigned to array - AstNode* exprp = pinp->exprp(); - longname += "_" + paramSmallName(srcModp, modvarp) + paramValueNumber(exprp); - any_overrides = true; - } else { - AstConst* exprp = VN_CAST(pinp->exprp(), Const); - AstConst* origp = VN_CAST(modvarp->valuep(), Const); - if (!exprp) { - // if (debug()) pinp->dumpTree(cout, "error:"); - pinp->v3error("Can't convert defparam value to constant: Param " - << pinp->prettyNameQ() << " of " << nodep->prettyNameQ()); - pinp->exprp()->replaceWith(new AstConst( - pinp->fileline(), AstConst::WidthedValue(), modvarp->width(), 0)); - } else if (origp && exprp->sameTree(origp)) { - // Setting parameter to its default value. Just ignore it. - // This prevents making additional modules, and makes coverage more - // obvious as it won't show up under a unique module page name. - } else if (exprp->num().isDouble() || exprp->num().isString() - || exprp->num().isFourState() || exprp->num().width() != 32) { - longname - += ("_" + paramSmallName(srcModp, modvarp) + paramValueNumber(exprp)); - any_overrides = true; - } else { - longname += ("_" + paramSmallName(srcModp, modvarp) - + exprp->num().ascii(false)); - any_overrides = true; - } - } - } else if (AstParamTypeDType* modvarp = pinp->modPTypep()) { - AstNodeDType* exprp = VN_CAST(pinp->exprp(), NodeDType); - AstNodeDType* origp = modvarp->subDTypep(); - if (!exprp) { - pinp->v3error("Parameter type pin value isn't a type: Param " - << pinp->prettyNameQ() << " of " << nodep->prettyNameQ()); - } else if (!origp) { - pinp->v3error("Parameter type variable isn't a type: Param " - << modvarp->prettyNameQ()); - } else { - UINFO(9, - "Parameter type assignment expr=" << exprp << " to " << origp << endl); - if (exprp->sameTree(origp)) { - // Setting parameter to its default value. Just ignore it. - // This prevents making additional modules, and makes coverage more - // obvious as it won't show up under a unique module page name. - } else { - V3Const::constifyParamsEdit(exprp); - longname - += "_" + paramSmallName(srcModp, modvarp) + paramValueNumber(exprp); - any_overrides = true; - } - } - } else { - pinp->v3error("Parameter not found in sub-module: Param " - << pinp->prettyNameQ() << " of " << nodep->prettyNameQ()); - } - } - IfaceRefRefs ifaceRefRefs; - for (AstPin* pinp = nodep->pinsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) { - AstVar* modvarp = pinp->modVarp(); - if (modvarp->isIfaceRef()) { - AstIfaceRefDType* portIrefp = VN_CAST(modvarp->subDTypep(), IfaceRefDType); - if (!portIrefp && arraySubDTypep(modvarp->subDTypep())) { - portIrefp = VN_CAST(arraySubDTypep(modvarp->subDTypep()), IfaceRefDType); - } - AstIfaceRefDType* pinIrefp = nullptr; - AstNode* exprp = pinp->exprp(); - AstVar* varp - = (exprp && VN_IS(exprp, VarRef)) ? VN_CAST(exprp, VarRef)->varp() : nullptr; - if (varp && varp->subDTypep() && VN_IS(varp->subDTypep(), IfaceRefDType)) { - pinIrefp = VN_CAST(varp->subDTypep(), IfaceRefDType); - } else if (varp && varp->subDTypep() && arraySubDTypep(varp->subDTypep()) - && VN_CAST(arraySubDTypep(varp->subDTypep()), IfaceRefDType)) { - pinIrefp = VN_CAST(arraySubDTypep(varp->subDTypep()), IfaceRefDType); - } else if (exprp && exprp->op1p() && VN_IS(exprp->op1p(), VarRef) - && VN_CAST(exprp->op1p(), VarRef)->varp() - && VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep() - && arraySubDTypep(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep()) - && VN_CAST( - arraySubDTypep(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep()), - IfaceRefDType)) { - pinIrefp = VN_CAST( - arraySubDTypep(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep()), - IfaceRefDType); - } - - UINFO(9, " portIfaceRef " << portIrefp << endl); - - if (!portIrefp) { - pinp->v3error("Interface port " << modvarp->prettyNameQ() - << " is not an interface " << modvarp); - } else if (!pinIrefp) { - pinp->v3error("Interface port " - << modvarp->prettyNameQ() - << " is not connected to interface/modport pin expression"); - } else { - UINFO(9, " pinIfaceRef " << pinIrefp << endl); - if (portIrefp->ifaceViaCellp() != pinIrefp->ifaceViaCellp()) { - UINFO(9, " IfaceRefDType needs reconnect " << pinIrefp << endl); - longname += ("_" + paramSmallName(srcModp, pinp->modVarp()) - + paramValueNumber(pinIrefp)); - any_overrides = true; - ifaceRefRefs.push_back(make_pair(portIrefp, pinIrefp)); - if (portIrefp->ifacep() != pinIrefp->ifacep() - // Might be different only due to param cloning, so check names too - && portIrefp->ifaceName() != pinIrefp->ifaceName()) { - pinp->v3error("Port " << pinp->prettyNameQ() << " expects " - << AstNode::prettyNameQ(portIrefp->ifaceName()) - << " interface but pin connects " - << AstNode::prettyNameQ(pinIrefp->ifaceName()) - << " interface"); - } - } - } - } - } - - if (!any_overrides) { - UINFO(8, "Cell parameters all match original values, skipping expansion.\n"); - } else if (AstNodeModule* modp - = m_hierBlocks.findByParams(srcModp->name(), nodep->paramsp(), m_modp)) { - nodep->modp(modp); - nodep->modName(modp->name()); - modp->dead(false); - // We need to relink the pins to the new module - relinkPinsByName(nodep->pinsp(), modp); - } else { - // If the name is very long, we don't want to overwhelm the filename limit - // We don't do this always, as it aids debugability to have intuitive naming. - // TODO can use new V3Name hash replacement instead of this - // Shorter name is convenient for hierarchical block - string newname = moduleCalcName(srcModp, nodep, longname); - UINFO(4, "Name: " << srcModp->name() << "->" << longname << "->" << newname << endl); - // - // Already made this flavor? - AstNodeModule* cellmodp = nullptr; - auto iter = m_modNameMap.find(newname); - if (iter != m_modNameMap.end()) cellmodp = iter->second.m_modp; - if (!cellmodp) { - cellmodp = deepCloneModule(srcModp, nodep, newname, ifaceRefRefs); - iter = m_modNameMap.find(newname); - UASSERT(iter != m_modNameMap.end(), "should find just-made module"); - } else { - UINFO(4, " De-parameterize to old: " << cellmodp << endl); - } - // Have child use this module instead. - nodep->modp(cellmodp); - nodep->modName(newname); - // We need to relink the pins to the new module - CloneMap* clonemapp = &(iter->second.m_cloneMap); - relinkPins(clonemapp, nodep->pinsp()); - UINFO(8, " Done with " << cellmodp << endl); - } // if any_overrides - - nodep->recursive(false); - - // Delete the parameters from the cell; they're not relevant any longer. - if (nodep->paramsp()) nodep->paramsp()->unlinkFrBackWithNext()->deleteTree(); - UINFO(8, " Done with " << nodep << endl); - // if (debug() >= 10) - // v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("param-out.tree")); - } - - // Now remember to process the child module at the end of the module - m_todoModps.insert(make_pair(nodep->modp()->level(), nodep->modp())); -} - //###################################################################### // Param class functions