parent
2358ced061
commit
0a3a15a66e
|
|
@ -3235,8 +3235,7 @@ public:
|
||||||
AstNodeModule* classOrPackagep() const {
|
AstNodeModule* classOrPackagep() const {
|
||||||
AstNode* foundp = m_classOrPackageNodep;
|
AstNode* foundp = m_classOrPackageNodep;
|
||||||
while (auto* const anodep = VN_CAST(foundp, Typedef)) foundp = anodep->subDTypep();
|
while (auto* const anodep = VN_CAST(foundp, Typedef)) foundp = anodep->subDTypep();
|
||||||
while (auto* const anodep = VN_CAST(foundp, ClassRefDType))
|
if (auto* const anodep = VN_CAST(foundp, ClassRefDType)) foundp = anodep->classp();
|
||||||
foundp = anodep->classOrPackagep();
|
|
||||||
return VN_CAST(foundp, NodeModule);
|
return VN_CAST(foundp, NodeModule);
|
||||||
}
|
}
|
||||||
AstPackage* packagep() const { return VN_CAST(classOrPackageNodep(), Package); }
|
AstPackage* packagep() const { return VN_CAST(classOrPackageNodep(), Package); }
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ static void makeToStringMiddle(AstClass* nodep) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nodep->extendsp() && nodep->extendsp()->classp()->user1()) {
|
if (nodep->extendsp()) {
|
||||||
string stmt = "out += ";
|
string stmt = "out += ";
|
||||||
if (!comma.empty()) stmt += "\", \"+ ";
|
if (!comma.empty()) stmt += "\", \"+ ";
|
||||||
// comma = ", "; // Nothing further so not needed
|
// comma = ", "; // Nothing further so not needed
|
||||||
|
|
|
||||||
|
|
@ -2379,6 +2379,7 @@ private:
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstClassOrPackageRef* nodep) override { iterateChildren(nodep); }
|
||||||
virtual void visit(AstPin* nodep) override { iterateChildren(nodep); }
|
virtual void visit(AstPin* nodep) override { iterateChildren(nodep); }
|
||||||
|
|
||||||
void replaceLogEq(AstLogEq* nodep) {
|
void replaceLogEq(AstLogEq* nodep) {
|
||||||
|
|
|
||||||
|
|
@ -471,9 +471,6 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accelerate the recursion
|
|
||||||
// Must do statements to support Generates, math though...
|
|
||||||
virtual void visit(AstNodeMath*) override {}
|
|
||||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
|
|
|
||||||
|
|
@ -1988,6 +1988,16 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isParamedClassRef(const AstNode* nodep) {
|
||||||
|
if (const auto* classRefp = VN_CAST(nodep, ClassOrPackageRef)) {
|
||||||
|
if (classRefp->paramsp()) return true;
|
||||||
|
const auto* classp = classRefp->classOrPackageNodep();
|
||||||
|
while (const auto* typedefp = VN_CAST(classp, Typedef)) classp = typedefp->subDTypep();
|
||||||
|
return VN_IS(classp, ClassRefDType) && VN_AS(classp, ClassRefDType)->paramsp();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// VISITs
|
// VISITs
|
||||||
virtual void visit(AstNetlist* nodep) override {
|
virtual void visit(AstNetlist* nodep) override {
|
||||||
// Recurse..., backward as must do packages before using packages
|
// Recurse..., backward as must do packages before using packages
|
||||||
|
|
@ -2172,11 +2182,17 @@ private:
|
||||||
// if (!start) { nodep->lhsp()->v3error("Package reference may not be embedded in
|
// if (!start) { nodep->lhsp()->v3error("Package reference may not be embedded in
|
||||||
// dotted reference"); m_ds.m_dotErr=true; }
|
// dotted reference"); m_ds.m_dotErr=true; }
|
||||||
m_ds.m_dotPos = DP_PACKAGE;
|
m_ds.m_dotPos = DP_PACKAGE;
|
||||||
|
iterateAndNextNull(nodep->lhsp());
|
||||||
} else {
|
} else {
|
||||||
m_ds.m_dotPos = DP_SCOPE;
|
m_ds.m_dotPos = DP_SCOPE;
|
||||||
iterateAndNextNull(nodep->lhsp());
|
iterateAndNextNull(nodep->lhsp());
|
||||||
// if (debug() >= 9) nodep->dumpTree("-dot-lho: ");
|
// if (debug() >= 9) nodep->dumpTree("-dot-lho: ");
|
||||||
}
|
}
|
||||||
|
if (m_statep->forPrimary() && isParamedClassRef(nodep->lhsp())) {
|
||||||
|
// Dots of paramed classes will be linked after deparametrization
|
||||||
|
m_ds.m_dotPos = DP_NONE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (m_ds.m_unresolved
|
if (m_ds.m_unresolved
|
||||||
&& (VN_IS(nodep->lhsp(), CellRef) || VN_IS(nodep->lhsp(), CellArrayRef))) {
|
&& (VN_IS(nodep->lhsp(), CellRef) || VN_IS(nodep->lhsp(), CellArrayRef))) {
|
||||||
m_ds.m_unlinkedScopep = nodep->lhsp();
|
m_ds.m_unlinkedScopep = nodep->lhsp();
|
||||||
|
|
@ -2517,13 +2533,24 @@ private:
|
||||||
if (start) m_ds = lastStates;
|
if (start) m_ds = lastStates;
|
||||||
}
|
}
|
||||||
virtual void visit(AstClassOrPackageRef* nodep) override {
|
virtual void visit(AstClassOrPackageRef* nodep) override {
|
||||||
UINFO(9, " linkClassOrPackageRef " << m_ds.ascii() << " n=" << nodep << endl);
|
// Class: Recurse inside or cleanup not founds
|
||||||
if (m_ds.m_dotPos == DP_PACKAGE) {
|
// checkNoDot not appropriate, can be under a dot
|
||||||
// Already under dot, so this is {ClassOrPackage} Dot {ClassOrPackage}
|
AstNode::user5ClearTree();
|
||||||
// m_ds.m_dotText communicates the cell prefix between stages
|
UASSERT_OBJ(m_statep->forPrimary() || nodep->classOrPackagep(), nodep,
|
||||||
m_ds.m_dotPos = DP_PACKAGE;
|
"ClassRef has unlinked class");
|
||||||
|
UASSERT_OBJ(m_statep->forPrimary() || !nodep->paramsp(), nodep,
|
||||||
|
"class reference parameter not removed by V3Param");
|
||||||
|
VL_RESTORER(m_ds);
|
||||||
|
VL_RESTORER(m_pinSymp);
|
||||||
|
{
|
||||||
|
// ClassRef's have pins, so track
|
||||||
|
if (nodep->classOrPackagep()) {
|
||||||
|
m_pinSymp = m_statep->getNodeSym(nodep->classOrPackagep());
|
||||||
|
}
|
||||||
|
m_ds.init(m_curSymp);
|
||||||
|
UINFO(4, "(Backto) Link ClassOrPackageRef: " << nodep << endl);
|
||||||
|
iterateChildren(nodep);
|
||||||
}
|
}
|
||||||
// TODO we don't iterate pins yet, as class parameters are not supported
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void visit(AstVarRef* nodep) override {
|
virtual void visit(AstVarRef* nodep) override {
|
||||||
|
|
|
||||||
202
src/V3Param.cpp
202
src/V3Param.cpp
|
|
@ -557,15 +557,16 @@ class ParamProcessor final {
|
||||||
if ((newmodp->level() - srcModp->level()) >= (v3Global.opt.moduleRecursionDepth() - 2)) {
|
if ((newmodp->level() - srcModp->level()) >= (v3Global.opt.moduleRecursionDepth() - 2)) {
|
||||||
cellp->v3error("Exceeded maximum --module-recursion-depth of "
|
cellp->v3error("Exceeded maximum --module-recursion-depth of "
|
||||||
<< v3Global.opt.moduleRecursionDepth());
|
<< v3Global.opt.moduleRecursionDepth());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
// Keep tree sorted by level. Note: Different parametrizations of the same recursive module
|
// Keep tree sorted by level. Note: Different parametrizations of the same recursive module
|
||||||
// end up with the same level, which we will need to fix up at the end, as we do not know
|
// end up with the same level, which we will need to fix up at the end, as we do not know
|
||||||
// up front how recursive modules are expanded, and a later expansion might re-use an
|
// up front how recursive modules are expanded, and a later expansion might re-use an
|
||||||
// earlier expansion (see t_recursive_module_bug_2).
|
// earlier expansion (see t_recursive_module_bug_2).
|
||||||
AstNodeModule* insertp = srcModp;
|
AstNode* insertp = srcModp;
|
||||||
while (insertp->nextp()
|
while (VN_IS(insertp->nextp(), NodeModule)
|
||||||
&& VN_AS(insertp->nextp(), NodeModule)->level() <= newmodp->level()) {
|
&& VN_AS(insertp->nextp(), NodeModule)->level() <= newmodp->level()) {
|
||||||
insertp = VN_AS(insertp->nextp(), NodeModule);
|
insertp = insertp->nextp();
|
||||||
}
|
}
|
||||||
insertp->addNextHere(newmodp);
|
insertp->addNextHere(newmodp);
|
||||||
|
|
||||||
|
|
@ -699,9 +700,9 @@ class ParamProcessor final {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cellInterfaceCleanup(AstCell* nodep, AstNodeModule* srcModp, string& longnamer,
|
void cellInterfaceCleanup(AstPin* pinsp, AstNodeModule* srcModp, string& longnamer,
|
||||||
bool& any_overridesr, IfaceRefRefs& ifaceRefRefs) {
|
bool& any_overridesr, IfaceRefRefs& ifaceRefRefs) {
|
||||||
for (AstPin* pinp = nodep->pinsp(); pinp; pinp = VN_AS(pinp->nextp(), Pin)) {
|
for (AstPin* pinp = pinsp; pinp; pinp = VN_AS(pinp->nextp(), Pin)) {
|
||||||
const AstVar* const modvarp = pinp->modVarp();
|
const AstVar* const modvarp = pinp->modVarp();
|
||||||
if (modvarp->isIfaceRef()) {
|
if (modvarp->isIfaceRef()) {
|
||||||
AstIfaceRefDType* portIrefp = VN_CAST(modvarp->subDTypep(), IfaceRefDType);
|
AstIfaceRefDType* portIrefp = VN_CAST(modvarp->subDTypep(), IfaceRefDType);
|
||||||
|
|
@ -761,8 +762,73 @@ class ParamProcessor final {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool nodeDeparamCommon(AstNode* nodep, AstNodeModule*& srcModpr, AstPin* paramsp,
|
||||||
|
AstPin* pinsp, bool any_overrides) {
|
||||||
|
// 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 = srcModpr->name() + "_";
|
||||||
|
if (debug() > 8 && paramsp) paramsp->dumpTreeAndNext(cout, "-cellparams: ");
|
||||||
|
|
||||||
|
if (srcModpr->hierBlock()) {
|
||||||
|
longname = parameterizedHierBlockName(srcModpr, paramsp);
|
||||||
|
any_overrides = longname != srcModpr->name();
|
||||||
|
} else {
|
||||||
|
for (AstPin* pinp = paramsp; pinp; pinp = VN_AS(pinp->nextp(), Pin)) {
|
||||||
|
cellPinCleanup(nodep, pinp, srcModpr, longname /*ref*/, any_overrides /*ref*/);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IfaceRefRefs ifaceRefRefs;
|
||||||
|
cellInterfaceCleanup(pinsp, srcModpr, longname /*ref*/, any_overrides /*ref*/,
|
||||||
|
ifaceRefRefs /*ref*/);
|
||||||
|
|
||||||
|
if (!any_overrides) {
|
||||||
|
UINFO(8, "Cell parameters all match original values, skipping expansion.\n");
|
||||||
|
} else if (AstNodeModule* const paramedModp
|
||||||
|
= m_hierBlocks.findByParams(srcModpr->name(), paramsp, m_modp)) {
|
||||||
|
paramedModp->dead(false);
|
||||||
|
// We need to relink the pins to the new module
|
||||||
|
relinkPinsByName(pinsp, paramedModp);
|
||||||
|
srcModpr = paramedModp;
|
||||||
|
} else {
|
||||||
|
const string newname
|
||||||
|
= srcModpr->hierBlock() ? longname : moduleCalcName(srcModpr, longname);
|
||||||
|
const ModInfo* const modInfop
|
||||||
|
= moduleFindOrClone(srcModpr, nodep, paramsp, newname, ifaceRefRefs);
|
||||||
|
// We need to relink the pins to the new module
|
||||||
|
relinkPinsByName(pinsp, modInfop->m_modp);
|
||||||
|
UINFO(8, " Done with " << modInfop->m_modp << endl);
|
||||||
|
srcModpr = modInfop->m_modp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the parameters from the cell; they're not relevant any longer.
|
||||||
|
if (paramsp) paramsp->unlinkFrBackWithNext()->deleteTree();
|
||||||
|
return any_overrides;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cellDeparam(AstCell* nodep, AstNodeModule*& srcModpr) {
|
||||||
|
// Must always clone __Vrcm (recursive modules)
|
||||||
|
if (nodeDeparamCommon(nodep, srcModpr, nodep->paramsp(), nodep->pinsp(),
|
||||||
|
nodep->recursive())) {
|
||||||
|
nodep->modp(srcModpr);
|
||||||
|
nodep->modName(srcModpr->name());
|
||||||
|
}
|
||||||
|
nodep->recursive(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void classRefDeparam(AstClassOrPackageRef* nodep, AstNodeModule*& srcModpr) {
|
||||||
|
if (nodeDeparamCommon(nodep, srcModpr, nodep->paramsp(), nullptr, false))
|
||||||
|
nodep->classOrPackagep(srcModpr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void classRefDeparam(AstClassRefDType* nodep, AstNodeModule*& srcModpr) {
|
||||||
|
if (nodeDeparamCommon(nodep, srcModpr, nodep->paramsp(), nullptr, false))
|
||||||
|
nodep->classp(VN_AS(srcModpr, Class));
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void cellDeparam(AstCell* nodep, AstNodeModule* modp, const string& someInstanceName) {
|
void nodeDeparam(AstNode* nodep, AstNodeModule*& srcModpr, AstNodeModule* modp,
|
||||||
|
const string& someInstanceName) {
|
||||||
m_modp = modp;
|
m_modp = modp;
|
||||||
// Cell: Check for parameters in the instantiation.
|
// Cell: Check for parameters in the instantiation.
|
||||||
// We always run this, even if no parameters, as need to look for interfaces,
|
// We always run this, even if no parameters, as need to look for interfaces,
|
||||||
|
|
@ -772,57 +838,18 @@ public:
|
||||||
if (debug() >= 10) nodep->dumpTree(cout, "-cell: ");
|
if (debug() >= 10) nodep->dumpTree(cout, "-cell: ");
|
||||||
// Evaluate all module constants
|
// Evaluate all module constants
|
||||||
V3Const::constifyParamsEdit(nodep);
|
V3Const::constifyParamsEdit(nodep);
|
||||||
AstNodeModule* const srcModp = nodep->modp();
|
srcModpr->someInstanceName(someInstanceName + "." + nodep->name());
|
||||||
srcModp->someInstanceName(someInstanceName + "." + nodep->name());
|
|
||||||
|
|
||||||
// Make sure constification worked
|
if (auto* cellp = VN_CAST(nodep, Cell)) {
|
||||||
// Must be a separate loop, as constant conversion may have changed some pointers.
|
cellDeparam(cellp, srcModpr);
|
||||||
// if (debug()) nodep->dumpTree(cout, "-cel2: ");
|
} else if (auto* classRefp = VN_CAST(nodep, ClassRefDType)) {
|
||||||
string longname = srcModp->name() + "_";
|
classRefDeparam(classRefp, srcModpr);
|
||||||
bool any_overrides = false;
|
} else if (auto* classRefp = VN_CAST(nodep, ClassOrPackageRef)) {
|
||||||
// Must always clone __Vrcm (recursive modules)
|
classRefDeparam(classRefp, srcModpr);
|
||||||
if (nodep->recursive()) any_overrides = true;
|
|
||||||
if (debug() > 8 && nodep->paramsp())
|
|
||||||
nodep->paramsp()->dumpTreeAndNext(cout, "-cellparams: ");
|
|
||||||
|
|
||||||
if (srcModp->hierBlock()) {
|
|
||||||
longname = parameterizedHierBlockName(srcModp, nodep->paramsp());
|
|
||||||
any_overrides = longname != srcModp->name();
|
|
||||||
} else {
|
} else {
|
||||||
for (AstPin* pinp = nodep->paramsp(); pinp; pinp = VN_AS(pinp->nextp(), Pin)) {
|
nodep->v3fatalSrc("Expected module parametrization");
|
||||||
cellPinCleanup(nodep, pinp, srcModp, longname /*ref*/, any_overrides /*ref*/);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
IfaceRefRefs ifaceRefRefs;
|
|
||||||
cellInterfaceCleanup(nodep, srcModp, longname /*ref*/, any_overrides /*ref*/,
|
|
||||||
ifaceRefRefs /*ref*/);
|
|
||||||
|
|
||||||
if (!any_overrides) {
|
|
||||||
UINFO(8, "Cell parameters all match original values, skipping expansion.\n");
|
|
||||||
} else if (AstNodeModule* const paramedModp
|
|
||||||
= m_hierBlocks.findByParams(srcModp->name(), nodep->paramsp(), m_modp)) {
|
|
||||||
nodep->modp(paramedModp);
|
|
||||||
nodep->modName(paramedModp->name());
|
|
||||||
paramedModp->dead(false);
|
|
||||||
// We need to relink the pins to the new module
|
|
||||||
relinkPinsByName(nodep->pinsp(), paramedModp);
|
|
||||||
} else {
|
|
||||||
const string newname
|
|
||||||
= srcModp->hierBlock() ? longname : moduleCalcName(srcModp, longname);
|
|
||||||
const ModInfo* const modInfop
|
|
||||||
= moduleFindOrClone(srcModp, nodep, nodep->paramsp(), newname, ifaceRefRefs);
|
|
||||||
// Have child use this module instead.
|
|
||||||
nodep->modp(modInfop->m_modp);
|
|
||||||
nodep->modName(newname);
|
|
||||||
// We need to relink the pins to the new module
|
|
||||||
relinkPinsByName(nodep->pinsp(), modInfop->m_modp);
|
|
||||||
UINFO(8, " Done with " << modInfop->m_modp << endl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
UINFO(8, " Done with " << nodep << endl);
|
||||||
// if (debug() >= 10)
|
// if (debug() >= 10)
|
||||||
// v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("param-out.tree"));
|
// v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("param-out.tree"));
|
||||||
|
|
@ -854,7 +881,8 @@ class ParamVisitor final : public VNVisitor {
|
||||||
bool m_iterateModule = false; // Iterating module body
|
bool m_iterateModule = false; // Iterating module body
|
||||||
string m_generateHierName; // Generate portion of hierarchy name
|
string m_generateHierName; // Generate portion of hierarchy name
|
||||||
string m_unlinkedTxt; // Text for AstUnlinkedRef
|
string m_unlinkedTxt; // Text for AstUnlinkedRef
|
||||||
std::deque<AstCell*> m_cellps; // Cells left to process (in current module)
|
std::multimap<bool, AstNode*> m_cellps; // Cells left to process (in current module)
|
||||||
|
std::multimap<int, AstNodeModule*> m_workQueue; // Modules left to process
|
||||||
|
|
||||||
// Map from AstNodeModule to set of all AstNodeModules that instantiates it.
|
// Map from AstNodeModule to set of all AstNodeModules that instantiates it.
|
||||||
std::unordered_map<AstNodeModule*, std::unordered_set<AstNodeModule*>> m_parentps;
|
std::unordered_map<AstNodeModule*, std::unordered_set<AstNodeModule*>> m_parentps;
|
||||||
|
|
@ -887,12 +915,21 @@ class ParamVisitor final : public VNVisitor {
|
||||||
|
|
||||||
// Process interface cells, then non-interface cells, which may reference an interface
|
// Process interface cells, then non-interface cells, which may reference an interface
|
||||||
// cell.
|
// cell.
|
||||||
for (bool doInterface : {true, false}) {
|
while (!m_cellps.empty()) {
|
||||||
for (AstCell* const cellp : m_cellps) {
|
const auto itm = m_cellps.cbegin();
|
||||||
if (doInterface != VN_IS(cellp->modp(), Iface)) continue;
|
AstNode* const cellp = itm->second;
|
||||||
|
m_cellps.erase(itm);
|
||||||
|
|
||||||
// Visit parameters in the instantiation.
|
AstNodeModule* srcModp = nullptr;
|
||||||
iterateChildren(cellp);
|
if (const auto* modCellp = VN_CAST(cellp, Cell)) {
|
||||||
|
srcModp = modCellp->modp();
|
||||||
|
} else if (const auto* classRefp = VN_CAST(cellp, ClassOrPackageRef)) {
|
||||||
|
srcModp = classRefp->classOrPackagep();
|
||||||
|
} else if (const auto* classRefp = VN_CAST(cellp, ClassRefDType)) {
|
||||||
|
srcModp = classRefp->classp();
|
||||||
|
} else {
|
||||||
|
cellp->v3fatalSrc("Expected module parametrization");
|
||||||
|
}
|
||||||
|
|
||||||
// Update path
|
// Update path
|
||||||
string someInstanceName(modp->someInstanceName());
|
string someInstanceName(modp->someInstanceName());
|
||||||
|
|
@ -903,16 +940,15 @@ class ParamVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply parameter specialization
|
// Apply parameter specialization
|
||||||
m_processor.cellDeparam(cellp, modp, someInstanceName);
|
m_processor.nodeDeparam(cellp, srcModp /* ref */, modp, someInstanceName);
|
||||||
|
|
||||||
// Add the (now potentially specialized) child module to the work queue
|
// Add the (now potentially specialized) child module to the work queue
|
||||||
workQueue.emplace(cellp->modp()->level(), cellp->modp());
|
workQueue.emplace(srcModp->level(), srcModp);
|
||||||
|
|
||||||
// Add to the hierarchy registry
|
// Add to the hierarchy registry
|
||||||
m_parentps[cellp->modp()].insert(modp);
|
m_parentps[srcModp].insert(modp);
|
||||||
}
|
}
|
||||||
}
|
if (workQueue.empty()) std::swap(workQueue, m_workQueue);
|
||||||
m_cellps.clear();
|
|
||||||
} while (!workQueue.empty());
|
} while (!workQueue.empty());
|
||||||
|
|
||||||
m_iterateModule = false;
|
m_iterateModule = false;
|
||||||
|
|
@ -930,25 +966,24 @@ class ParamVisitor final : public VNVisitor {
|
||||||
if (modp->level() <= maxParentLevel) modp->level(maxParentLevel + 1);
|
if (modp->level() <= maxParentLevel) modp->level(maxParentLevel + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A generic visitor for cells and class refs
|
||||||
|
void visitCellOrClassRef(AstNode* nodep, bool isIface) {
|
||||||
|
// Must do ifaces first, so push to list and do in proper order
|
||||||
|
string* const genHierNamep = new string{m_generateHierName};
|
||||||
|
nodep->user5p(genHierNamep);
|
||||||
|
// Visit parameters in the instantiation.
|
||||||
|
iterateChildren(nodep);
|
||||||
|
m_cellps.emplace(!isIface, nodep);
|
||||||
|
}
|
||||||
|
|
||||||
// VISITORS
|
// VISITORS
|
||||||
virtual void visit(AstNodeModule* nodep) override {
|
virtual void visit(AstNodeModule* nodep) override {
|
||||||
if (nodep->recursiveClone()) nodep->dead(true); // Fake, made for recursive elimination
|
if (nodep->recursiveClone()) nodep->dead(true); // Fake, made for recursive elimination
|
||||||
if (nodep->dead()) return; // Marked by LinkDot (and above)
|
if (nodep->dead()) return; // Marked by LinkDot (and above)
|
||||||
|
|
||||||
// Warn on unsupported parametrised class
|
|
||||||
if (VN_IS(nodep, Class)) {
|
|
||||||
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
|
||||||
if (const AstVar* const varp = VN_CAST(stmtp, Var)) {
|
|
||||||
if (varp->isParam()) {
|
|
||||||
varp->v3warn(E_UNSUPPORTED, "Unsupported: class parameters");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_iterateModule) { // Iterating body
|
if (m_iterateModule) { // Iterating body
|
||||||
UINFO(4, " MOD-under-MOD. " << nodep << endl);
|
UINFO(4, " MOD-under-MOD. " << nodep << endl);
|
||||||
iterateChildren(nodep);
|
m_workQueue.emplace(nodep->level(), nodep); // Delay until current module is done
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -961,19 +996,10 @@ class ParamVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void visit(AstCell* nodep) override {
|
virtual void visit(AstCell* nodep) override {
|
||||||
// Must do ifaces first, so push to list and do in proper order
|
visitCellOrClassRef(nodep, VN_IS(nodep->modp(), Iface));
|
||||||
string* const genHierNamep = new string(m_generateHierName);
|
|
||||||
nodep->user5p(genHierNamep);
|
|
||||||
m_cellps.push_back(nodep);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void visit(AstClassRefDType* nodep) override {
|
|
||||||
if (nodep->paramsp()) {
|
|
||||||
nodep->paramsp()->v3warn(E_UNSUPPORTED, "Unsupported: parameterized classes");
|
|
||||||
pushDeletep(nodep->paramsp()->unlinkFrBackWithNext());
|
|
||||||
}
|
|
||||||
iterateChildren(nodep);
|
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstClassRefDType* nodep) override { visitCellOrClassRef(nodep, false); }
|
||||||
|
virtual void visit(AstClassOrPackageRef* nodep) override { visitCellOrClassRef(nodep, false); }
|
||||||
|
|
||||||
// Make sure all parameters are constantified
|
// Make sure all parameters are constantified
|
||||||
virtual void visit(AstVar* nodep) override {
|
virtual void visit(AstVar* nodep) override {
|
||||||
|
|
|
||||||
|
|
@ -2438,6 +2438,17 @@ private:
|
||||||
// though causes problems with t_class_forward.v, so for now avoided
|
// though causes problems with t_class_forward.v, so for now avoided
|
||||||
// userIterateChildren(nodep->classp(), nullptr);
|
// userIterateChildren(nodep->classp(), nullptr);
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstClassOrPackageRef* nodep) override {
|
||||||
|
if (nodep->didWidthAndSet()) return;
|
||||||
|
userIterateChildren(nodep, nullptr);
|
||||||
|
}
|
||||||
|
virtual void visit(AstDot* nodep) override {
|
||||||
|
// We can only reach this from constify called during V3Param (so before linkDotParam)
|
||||||
|
// ... #(Cls#(...)::...) ...
|
||||||
|
// ^^~~~ this is our DOT
|
||||||
|
nodep->v3warn(E_UNSUPPORTED, "dotted expressions in parameters\n"
|
||||||
|
<< nodep->warnMore() << "... Suggest use a typedef");
|
||||||
|
}
|
||||||
virtual void visit(AstClassExtends* nodep) override {
|
virtual void visit(AstClassExtends* nodep) override {
|
||||||
if (nodep->didWidthAndSet()) return;
|
if (nodep->didWidthAndSet()) return;
|
||||||
if (VN_IS(nodep->childDTypep(), ClassRefDType)) {
|
if (VN_IS(nodep->childDTypep(), ClassRefDType)) {
|
||||||
|
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
%Error-UNSUPPORTED: t/t_class_param.v:40:11: Unsupported: parameterized classes
|
|
||||||
: ... In instance t
|
|
||||||
40 | Cls #(.PBASE(4)) c4;
|
|
||||||
| ^~~~~
|
|
||||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
|
||||||
%Error-UNSUPPORTED: t/t_class_param.v:42:12: Unsupported: parameterized classes
|
|
||||||
: ... In instance t
|
|
||||||
42 | Wrap #(.P(16)) w16;
|
|
||||||
| ^
|
|
||||||
%Error-UNSUPPORTED: t/t_class_param.v:13:24: Unsupported: class parameters
|
|
||||||
: ... In instance t
|
|
||||||
13 | class Wrap #(parameter P = 13);
|
|
||||||
| ^
|
|
||||||
%Error-UNSUPPORTED: t/t_class_param.v:21:15: Unsupported: class parameters
|
|
||||||
: ... In instance t
|
|
||||||
21 | localparam PMINUS1 = P - 1;
|
|
||||||
| ^~~~~~~
|
|
||||||
%Error-UNSUPPORTED: t/t_class_param.v:20:17: Unsupported: parameterized classes
|
|
||||||
: ... In instance t
|
|
||||||
20 | Cls#(PMINUS1 + 1) c1;
|
|
||||||
| ^
|
|
||||||
%Error-UNSUPPORTED: t/t_class_param.v:24:23: Unsupported: class parameters
|
|
||||||
: ... In instance t
|
|
||||||
24 | class Cls #(parameter PBASE = 12);
|
|
||||||
| ^~~~~
|
|
||||||
%Error-UNSUPPORTED: t/t_class_param.v:35:14: Unsupported: parameterized classes
|
|
||||||
: ... In instance t
|
|
||||||
35 | typedef Cls#(8) Cls8_t;
|
|
||||||
| ^
|
|
||||||
%Error: Exiting due to
|
|
||||||
|
|
@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||||
scenarios(simulator => 1);
|
scenarios(simulator => 1);
|
||||||
|
|
||||||
compile(
|
compile(
|
||||||
fails => $Self->{vlt_all},
|
|
||||||
expect_filename => $Self->{golden_filename},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
check_finished => 1,
|
check_finished => 1,
|
||||||
) if !$Self->{vlt_all};
|
);
|
||||||
|
|
||||||
ok(1);
|
ok(1);
|
||||||
1;
|
1;
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,17 @@ class Wrap #(parameter P = 13);
|
||||||
localparam PMINUS1 = P - 1; // Checking works when last
|
localparam PMINUS1 = P - 1; // Checking works when last
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
|
class Wrap2 #(parameter P = 35);
|
||||||
|
function int get_p;
|
||||||
|
return c1.get_p();
|
||||||
|
endfunction
|
||||||
|
function new;
|
||||||
|
c1 = new;
|
||||||
|
endfunction
|
||||||
|
Wrap#(PMINUS1 + 1) c1;
|
||||||
|
localparam PMINUS1 = P - 1; // Checking works when last
|
||||||
|
endclass
|
||||||
|
|
||||||
class Cls #(parameter PBASE = 12);
|
class Cls #(parameter PBASE = 12);
|
||||||
bit [PBASE-1:0] member;
|
bit [PBASE-1:0] member;
|
||||||
function bit [PBASE-1:0] get_member;
|
function bit [PBASE-1:0] get_member;
|
||||||
|
|
@ -40,11 +51,13 @@ module t (/*AUTOARG*/);
|
||||||
Cls #(.PBASE(4)) c4;
|
Cls #(.PBASE(4)) c4;
|
||||||
Cls8_t c8;
|
Cls8_t c8;
|
||||||
Wrap #(.P(16)) w16;
|
Wrap #(.P(16)) w16;
|
||||||
|
Wrap2 #(.P(32)) w32;
|
||||||
initial begin
|
initial begin
|
||||||
c12 = new;
|
c12 = new;
|
||||||
c4 = new;
|
c4 = new;
|
||||||
c8 = new;
|
c8 = new;
|
||||||
w16 = new;
|
w16 = new;
|
||||||
|
w32 = new;
|
||||||
if (Cls#()::PBASE != 12) $stop;
|
if (Cls#()::PBASE != 12) $stop;
|
||||||
if (Cls#(4)::PBASE != 4) $stop;
|
if (Cls#(4)::PBASE != 4) $stop;
|
||||||
if (Cls8_t::PBASE != 8) $stop;
|
if (Cls8_t::PBASE != 8) $stop;
|
||||||
|
|
@ -65,6 +78,7 @@ module t (/*AUTOARG*/);
|
||||||
if (c4.get_p() != 4) $stop;
|
if (c4.get_p() != 4) $stop;
|
||||||
if (c8.get_p() != 8) $stop;
|
if (c8.get_p() != 8) $stop;
|
||||||
if (w16.get_p() != 16) $stop;
|
if (w16.get_p() != 16) $stop;
|
||||||
|
if (w32.get_p() != 32) $stop;
|
||||||
|
|
||||||
// verilator lint_off WIDTH
|
// verilator lint_off WIDTH
|
||||||
c12.member = 32'haaaaaaaa;
|
c12.member = 32'haaaaaaaa;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
%Error: t/t_class_param_circ_bad.v:14:4: Exceeded maximum --module-recursion-depth of 100
|
||||||
|
: ... In instance t
|
||||||
|
14 | ClsA #(PARAM+1) a;
|
||||||
|
| ^~~~
|
||||||
|
%Error: Internal Error: ../V3Param.cpp:#: should find just-made module
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2022 by Wilson Snyder. This program is free software; you
|
||||||
|
# can redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
scenarios(simulator => 1);
|
||||||
|
|
||||||
|
lint(
|
||||||
|
fails => 1,
|
||||||
|
expect_filename => $Self->{golden_filename},
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2022 by Wilson Snyder.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
typedef class ClsB;
|
||||||
|
|
||||||
|
class ClsA #(parameter PARAM = 12);
|
||||||
|
ClsB #(PARAM+1) b;
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class ClsB #(parameter PARAM = 12);
|
||||||
|
ClsA #(PARAM+1) a;
|
||||||
|
endclass
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/);
|
||||||
|
|
||||||
|
ClsA #(.PARAM(15)) c; // Bad param name
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2022 by Wilson Snyder. This program is free software; you
|
||||||
|
# can redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
scenarios(simulator => 1);
|
||||||
|
|
||||||
|
compile(
|
||||||
|
);
|
||||||
|
|
||||||
|
execute(
|
||||||
|
check_finished => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2022 by Wilson Snyder.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
// Code your testbench here
|
||||||
|
// or browse Examples
|
||||||
|
class Base #(parameter PBASE = 12);
|
||||||
|
bit [PBASE-1:0] member;
|
||||||
|
function bit [PBASE-1:0] get_member;
|
||||||
|
return member;
|
||||||
|
endfunction
|
||||||
|
function int get_p;
|
||||||
|
return PBASE;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class Cls #(parameter P = 13) extends Base #(P);
|
||||||
|
endclass
|
||||||
|
|
||||||
|
typedef Cls#(8) Cls8_t;
|
||||||
|
|
||||||
|
// See also t_class_param_mod.v
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/);
|
||||||
|
|
||||||
|
Cls #(.P(4)) c4;
|
||||||
|
Cls8_t c8;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
c4 = new;
|
||||||
|
c8 = new;
|
||||||
|
if (c4.PBASE != 4) $stop;
|
||||||
|
if (c8.PBASE != 8) $stop;
|
||||||
|
if (c4.get_p() != 4) $stop;
|
||||||
|
if (c8.get_p() != 8) $stop;
|
||||||
|
// verilator lint_off WIDTH
|
||||||
|
c4.member = 32'haaaaaaaa;
|
||||||
|
c8.member = 32'haaaaaaaa;
|
||||||
|
// verilator lint_on WIDTH
|
||||||
|
if (c4.member != 4'ha) $stop;
|
||||||
|
if (c4.get_member() != 4'ha) $stop;
|
||||||
|
if (c8.member != 8'haa) $stop;
|
||||||
|
if (c8.get_member() != 8'haa) $stop;
|
||||||
|
$display("c4 = %s", $sformatf("%p", c4));
|
||||||
|
if ($sformatf("%p", c4) != "'{member:'ha}") $stop;
|
||||||
|
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -11,12 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||||
scenarios(simulator => 1);
|
scenarios(simulator => 1);
|
||||||
|
|
||||||
compile(
|
compile(
|
||||||
fails => $Self->{vlt_all},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
check_finished => 1,
|
check_finished => 1,
|
||||||
) if !$Self->{vlt_all};
|
);
|
||||||
|
|
||||||
ok(1);
|
ok(1);
|
||||||
1;
|
1;
|
||||||
|
|
|
||||||
|
|
@ -32,17 +32,30 @@ class Wrap #(parameter P = 13);
|
||||||
localparam PMINUS1 = P - 1; // Checking works when last
|
localparam PMINUS1 = P - 1; // Checking works when last
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
|
class Wrap2 #(parameter P = 35);
|
||||||
|
function int get_p;
|
||||||
|
return c1.get_p();
|
||||||
|
endfunction
|
||||||
|
function new;
|
||||||
|
c1 = new;
|
||||||
|
endfunction
|
||||||
|
Wrap#(PMINUS1 + 1) c1;
|
||||||
|
localparam PMINUS1 = P - 1; // Checking works when last
|
||||||
|
endclass
|
||||||
|
|
||||||
typedef Cls#(8) Cls8_t;
|
typedef Cls#(8) Cls8_t;
|
||||||
|
|
||||||
Cls c12;
|
Cls c12;
|
||||||
Cls #(.PBASE(4)) c4;
|
Cls #(.PBASE(4)) c4;
|
||||||
Cls8_t c8;
|
Cls8_t c8;
|
||||||
Wrap #(.P(16)) w16;
|
Wrap #(.P(16)) w16;
|
||||||
|
Wrap2 #(.P(32)) w32;
|
||||||
initial begin
|
initial begin
|
||||||
c12 = new;
|
c12 = new;
|
||||||
c4 = new;
|
c4 = new;
|
||||||
c8 = new;
|
c8 = new;
|
||||||
w16 = new;
|
w16 = new;
|
||||||
|
w32 = new;
|
||||||
if (Cls#()::PBASE != 12) $stop;
|
if (Cls#()::PBASE != 12) $stop;
|
||||||
if (Cls#(4)::PBASE != 4) $stop;
|
if (Cls#(4)::PBASE != 4) $stop;
|
||||||
if (Cls8_t::PBASE != 8) $stop;
|
if (Cls8_t::PBASE != 8) $stop;
|
||||||
|
|
@ -63,6 +76,7 @@ endclass
|
||||||
if (c4.get_p() != 4) $stop;
|
if (c4.get_p() != 4) $stop;
|
||||||
if (c8.get_p() != 8) $stop;
|
if (c8.get_p() != 8) $stop;
|
||||||
if (w16.get_p() != 16) $stop;
|
if (w16.get_p() != 16) $stop;
|
||||||
|
if (w32.get_p() != 32) $stop;
|
||||||
|
|
||||||
// verilator lint_off WIDTH
|
// verilator lint_off WIDTH
|
||||||
c12.member = 32'haaaaaaaa;
|
c12.member = 32'haaaaaaaa;
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
%Error-UNSUPPORTED: t/t_class_param_nconst_bad.v:12:11: Unsupported: parameterized classes
|
%Error: t/t_class_param_nconst_bad.v:12:17: Expecting expression to be constant, but can't convert a RAND to constant.
|
||||||
|
: ... In instance t
|
||||||
|
12 | Cls #(.PARAM($random)) c;
|
||||||
|
| ^~~~~~~
|
||||||
|
%Error: t/t_class_param_nconst_bad.v:12:11: Can't convert defparam value to constant: Param 'PARAM' of 'Cls'
|
||||||
: ... In instance t
|
: ... In instance t
|
||||||
12 | Cls #(.PARAM($random)) c;
|
12 | Cls #(.PARAM($random)) c;
|
||||||
| ^~~~~
|
|
||||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
|
||||||
%Error-UNSUPPORTED: t/t_class_param_nconst_bad.v:7:23: Unsupported: class parameters
|
|
||||||
: ... In instance t
|
|
||||||
7 | class Cls #(parameter PARAM = 12);
|
|
||||||
| ^~~~~
|
| ^~~~~
|
||||||
%Error: Exiting due to
|
%Error: Exiting due to
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
%Error-UNSUPPORTED: t/t_class_param_nested_bad.v:51:23: dotted expressions in parameters
|
||||||
|
: ... In instance t
|
||||||
|
: ... Suggest use a typedef
|
||||||
|
51 | Wrap2 #(Wrap#(19)::PBASE * 2) w38;
|
||||||
|
| ^~~~~
|
||||||
|
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||||
|
%Error: Internal Error: t/t_class_param_nested_bad.v:51:29: ../V3Width.cpp:#: Node has no type
|
||||||
|
: ... In instance t
|
||||||
|
51 | Wrap2 #(Wrap#(19)::PBASE * 2) w38;
|
||||||
|
| ^
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2022 by Wilson Snyder. This program is free software; you
|
||||||
|
# can redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
scenarios(simulator => 1);
|
||||||
|
|
||||||
|
lint(
|
||||||
|
fails => 1,
|
||||||
|
expect_filename => $Self->{golden_filename},
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2022 by Arkadiusz Kozdra.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
typedef class Cls;
|
||||||
|
|
||||||
|
class Wrap #(parameter P = 13);
|
||||||
|
function int get_p;
|
||||||
|
return c1.get_p();
|
||||||
|
endfunction
|
||||||
|
function new;
|
||||||
|
c1 = new;
|
||||||
|
endfunction
|
||||||
|
Cls#(PMINUS1 + 1) c1;
|
||||||
|
localparam PMINUS1 = P - 1; // Checking works when last
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class Wrap2 #(parameter P = 35);
|
||||||
|
function int get_p;
|
||||||
|
return c1.get_p();
|
||||||
|
endfunction
|
||||||
|
function new;
|
||||||
|
c1 = new;
|
||||||
|
endfunction
|
||||||
|
Wrap#(PMINUS1 + 1) c1;
|
||||||
|
localparam PMINUS1 = P - 1; // Checking works when last
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class Cls #(parameter PBASE = 12);
|
||||||
|
bit [PBASE-1:0] member;
|
||||||
|
function bit [PBASE-1:0] get_member;
|
||||||
|
return member;
|
||||||
|
endfunction
|
||||||
|
static function int get_p;
|
||||||
|
return PBASE;
|
||||||
|
endfunction
|
||||||
|
typedef enum { E_PBASE = PBASE } enum_t;
|
||||||
|
endclass
|
||||||
|
|
||||||
|
typedef Cls#(8) Cls8_t;
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/);
|
||||||
|
|
||||||
|
Cls c12;
|
||||||
|
Cls #(.PBASE(4)) c4;
|
||||||
|
Cls8_t c8;
|
||||||
|
Wrap #(.P(16)) w16;
|
||||||
|
Wrap2 #(.P(32)) w32;
|
||||||
|
Wrap2 #(Wrap#(19)::PBASE * 2) w38;
|
||||||
|
initial begin
|
||||||
|
c12 = new;
|
||||||
|
c4 = new;
|
||||||
|
c8 = new;
|
||||||
|
w16 = new;
|
||||||
|
w32 = new;
|
||||||
|
w38 = new;
|
||||||
|
if (w38.get_p() != 38) $stop;
|
||||||
|
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
%Error-UNSUPPORTED: t/t_class_param_pkg.v:43:16: Unsupported: parameterized classes
|
|
||||||
: ... In instance t
|
|
||||||
43 | Pkg::Cls #(.PBASE(4)) c4;
|
|
||||||
| ^~~~~
|
|
||||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
|
||||||
%Error-UNSUPPORTED: t/t_class_param_pkg.v:45:17: Unsupported: parameterized classes
|
|
||||||
: ... In instance t
|
|
||||||
45 | Pkg::Wrap #(.P(16)) w16;
|
|
||||||
| ^
|
|
||||||
%Error-UNSUPPORTED: t/t_class_param_pkg.v:14:27: Unsupported: class parameters
|
|
||||||
: ... In instance t
|
|
||||||
14 | class Wrap #(parameter P = 13);
|
|
||||||
| ^
|
|
||||||
%Error-UNSUPPORTED: t/t_class_param_pkg.v:22:18: Unsupported: class parameters
|
|
||||||
: ... In instance t
|
|
||||||
22 | localparam PMINUS1 = P - 1;
|
|
||||||
| ^~~~~~~
|
|
||||||
%Error-UNSUPPORTED: t/t_class_param_pkg.v:21:20: Unsupported: parameterized classes
|
|
||||||
: ... In instance t
|
|
||||||
21 | Cls#(PMINUS1 + 1) c1;
|
|
||||||
| ^
|
|
||||||
%Error-UNSUPPORTED: t/t_class_param_pkg.v:25:26: Unsupported: class parameters
|
|
||||||
: ... In instance t
|
|
||||||
25 | class Cls #(parameter PBASE = 12);
|
|
||||||
| ^~~~~
|
|
||||||
%Error-UNSUPPORTED: t/t_class_param_pkg.v:36:22: Unsupported: parameterized classes
|
|
||||||
: ... In instance t
|
|
||||||
36 | typedef Pkg::Cls#(8) Cls8_t;
|
|
||||||
| ^
|
|
||||||
%Error: Exiting due to
|
|
||||||
|
|
@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||||
scenarios(simulator => 1);
|
scenarios(simulator => 1);
|
||||||
|
|
||||||
compile(
|
compile(
|
||||||
fails => $Self->{vlt_all},
|
|
||||||
expect_filename => $Self->{golden_filename},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
check_finished => 1,
|
check_finished => 1,
|
||||||
) if !$Self->{vlt_all};
|
);
|
||||||
|
|
||||||
ok(1);
|
ok(1);
|
||||||
1;
|
1;
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,17 @@ package Pkg;
|
||||||
localparam PMINUS1 = P - 1; // Checking works when last
|
localparam PMINUS1 = P - 1; // Checking works when last
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
|
class Wrap2 #(parameter P = 35);
|
||||||
|
function int get_p;
|
||||||
|
return c1.get_p();
|
||||||
|
endfunction
|
||||||
|
function new;
|
||||||
|
c1 = new;
|
||||||
|
endfunction
|
||||||
|
Wrap#(PMINUS1 + 1) c1;
|
||||||
|
localparam PMINUS1 = P - 1; // Checking works when last
|
||||||
|
endclass
|
||||||
|
|
||||||
class Cls #(parameter PBASE = 12);
|
class Cls #(parameter PBASE = 12);
|
||||||
bit [PBASE-1:0] member;
|
bit [PBASE-1:0] member;
|
||||||
function bit [PBASE-1:0] get_member;
|
function bit [PBASE-1:0] get_member;
|
||||||
|
|
@ -43,11 +54,13 @@ module t (/*AUTOARG*/);
|
||||||
Pkg::Cls #(.PBASE(4)) c4;
|
Pkg::Cls #(.PBASE(4)) c4;
|
||||||
Pkg::Cls8_t c8;
|
Pkg::Cls8_t c8;
|
||||||
Pkg::Wrap #(.P(16)) w16;
|
Pkg::Wrap #(.P(16)) w16;
|
||||||
|
Pkg::Wrap2 #(.P(32)) w32;
|
||||||
initial begin
|
initial begin
|
||||||
c12 = new;
|
c12 = new;
|
||||||
c4 = new;
|
c4 = new;
|
||||||
c8 = new;
|
c8 = new;
|
||||||
w16 = new;
|
w16 = new;
|
||||||
|
w32 = new;
|
||||||
if (Pkg::Cls#()::PBASE != 12) $stop;
|
if (Pkg::Cls#()::PBASE != 12) $stop;
|
||||||
if (Pkg::Cls#(4)::PBASE != 4) $stop;
|
if (Pkg::Cls#(4)::PBASE != 4) $stop;
|
||||||
if (Pkg::Cls8_t::PBASE != 8) $stop;
|
if (Pkg::Cls8_t::PBASE != 8) $stop;
|
||||||
|
|
@ -68,6 +81,7 @@ module t (/*AUTOARG*/);
|
||||||
if (c4.get_p() != 4) $stop;
|
if (c4.get_p() != 4) $stop;
|
||||||
if (c8.get_p() != 8) $stop;
|
if (c8.get_p() != 8) $stop;
|
||||||
if (w16.get_p() != 16) $stop;
|
if (w16.get_p() != 16) $stop;
|
||||||
|
if (w32.get_p() != 32) $stop;
|
||||||
|
|
||||||
// verilator lint_off WIDTH
|
// verilator lint_off WIDTH
|
||||||
c12.member = 32'haaaaaaaa;
|
c12.member = 32'haaaaaaaa;
|
||||||
|
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
%Error-UNSUPPORTED: t/t_class_vparam.v:11:26: Unsupported: parameterized classes
|
|
||||||
: ... In instance t
|
|
||||||
11 | typedef paramed_class_t#(real, 1) paramed_class_double_t;
|
|
||||||
| ^~~~
|
|
||||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
|
||||||
%Error-UNSUPPORTED: t/t_class_vparam.v:13:56: Unsupported: class parameters
|
|
||||||
: ... In instance t
|
|
||||||
13 | virtual class vclass #(type CTYPE_t = arg_class_t, int I = 0);
|
|
||||||
| ^
|
|
||||||
%Error-UNSUPPORTED: t/t_class_vparam.v:14:58: Unsupported: parameterized classes
|
|
||||||
: ... In instance t
|
|
||||||
14 | pure virtual function void funcname(paramed_class_t #(CTYPE_t) v);
|
|
||||||
| ^~~~~~~
|
|
||||||
%Error-UNSUPPORTED: t/t_class_vparam.v:17:46: Unsupported: class parameters
|
|
||||||
: ... In instance t
|
|
||||||
17 | class paramed_class_t #(type TYPE = int, int I = 0);
|
|
||||||
| ^
|
|
||||||
%Error: Exiting due to
|
|
||||||
|
|
@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||||
scenarios(simulator => 1);
|
scenarios(simulator => 1);
|
||||||
|
|
||||||
compile(
|
compile(
|
||||||
fails => $Self->{vlt_all},
|
|
||||||
expect_filename => $Self->{golden_filename},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
check_finished => 1,
|
check_finished => 1,
|
||||||
) if !$Self->{vlt_all};
|
);
|
||||||
|
|
||||||
ok(1);
|
ok(1);
|
||||||
1;
|
1;
|
||||||
|
|
|
||||||
|
|
@ -8,16 +8,18 @@
|
||||||
|
|
||||||
typedef class paramed_class_t;
|
typedef class paramed_class_t;
|
||||||
typedef class arg_class_t;
|
typedef class arg_class_t;
|
||||||
typedef paramed_class_t#(real, 1) paramed_class_double_t;
|
typedef paramed_class_t#(logic[3:0], 1) paramed_class_logic4_t;
|
||||||
|
|
||||||
virtual class vclass #(type CTYPE_t = arg_class_t, int I = 0);
|
virtual class vclass #(type CTYPE_t = arg_class_t, int I = 0);
|
||||||
pure virtual function void funcname(paramed_class_t #(CTYPE_t) v);
|
pure virtual function void funcname(paramed_class_t #(CTYPE_t) v);
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
class paramed_class_t #(type TYPE = int, int I = 0);
|
class paramed_class_t #(type TYPE = int, int I = 0);
|
||||||
|
TYPE memb;
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
class arg_class_t;
|
class arg_class_t;
|
||||||
|
int ifield;
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
module t (/*AUTOARG*/
|
module t (/*AUTOARG*/
|
||||||
|
|
@ -26,7 +28,15 @@ module t (/*AUTOARG*/
|
||||||
);
|
);
|
||||||
input clk;
|
input clk;
|
||||||
|
|
||||||
always @ (posedge clk) begin
|
vclass vir;
|
||||||
|
paramed_class_t#(arg_class_t) argu;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
argu = new;
|
||||||
|
argu.memb = new;
|
||||||
|
argu.memb.ifield = 1234;
|
||||||
|
// vir.funcname(argu);
|
||||||
|
if (argu.memb.ifield != 1234) $stop;
|
||||||
$write("*-* All Finished *-*\n");
|
$write("*-* All Finished *-*\n");
|
||||||
$finish;
|
$finish;
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue