Internals: Pass class parameters through link.

This commit is contained in:
Wilson Snyder 2020-11-27 22:48:42 -05:00
parent cf2810db8b
commit 1299b70945
7 changed files with 93 additions and 9 deletions

View File

@ -988,14 +988,16 @@ public:
class AstClassRefDType final : public AstNodeDType { class AstClassRefDType final : public AstNodeDType {
// Reference to a class // Reference to a class
// Children: PINs (for parameter settings)
private: private:
AstClass* m_classp; // data type pointed to, BELOW the AstTypedef AstClass* m_classp; // data type pointed to, BELOW the AstTypedef
AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy
public: public:
AstClassRefDType(FileLine* fl, AstClass* classp) AstClassRefDType(FileLine* fl, AstClass* classp, AstNode* paramsp)
: ASTGEN_SUPER(fl) : ASTGEN_SUPER(fl)
, m_classp{classp} { , m_classp{classp} {
dtypep(this); dtypep(this);
addNOp4p(paramsp);
} }
ASTNODE_NODE_FUNCS(ClassRefDType) ASTNODE_NODE_FUNCS(ClassRefDType)
// METHODS // METHODS
@ -1032,6 +1034,7 @@ public:
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
AstClass* classp() const { return m_classp; } AstClass* classp() const { return m_classp; }
void classp(AstClass* nodep) { m_classp = nodep; } void classp(AstClass* nodep) { m_classp = nodep; }
AstPin* paramsp() const { return VN_CAST(op4p(), Pin); }
}; };
class AstIfaceRefDType final : public AstNodeDType { class AstIfaceRefDType final : public AstNodeDType {

View File

@ -457,6 +457,13 @@ private:
UINFO(4, " Link Cell done: " << nodep << endl); UINFO(4, " Link Cell done: " << nodep << endl);
} }
virtual void visit(AstRefDType* nodep) override {
for (AstPin* pinp = nodep->paramsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) {
pinp->param(true);
if (pinp->name() == "") pinp->name("__paramNumber" + cvtToStr(pinp->pinNum()));
}
}
// Accelerate the recursion // Accelerate the recursion
// Must do statements to support Generates, math though... // Must do statements to support Generates, math though...
virtual void visit(AstNodeMath*) override {} virtual void visit(AstNodeMath*) override {}

View File

@ -1941,11 +1941,13 @@ private:
virtual void visit(AstCell* nodep) override { virtual void visit(AstCell* nodep) override {
// Cell: Recurse inside or cleanup not founds // Cell: Recurse inside or cleanup not founds
checkNoDot(nodep); checkNoDot(nodep);
m_cellp = nodep;
AstNode::user5ClearTree(); AstNode::user5ClearTree();
UASSERT_OBJ(nodep->modp(), nodep, UASSERT_OBJ(nodep->modp(), nodep,
"Cell has unlinked module"); // V3LinkCell should have errored out "Cell has unlinked module"); // V3LinkCell should have errored out
VL_RESTORER(m_cellp);
VL_RESTORER(m_pinSymp);
{ {
m_cellp = nodep;
if (VN_IS(nodep->modp(), NotFoundModule)) { if (VN_IS(nodep->modp(), NotFoundModule)) {
// Prevent warnings about missing pin connects // Prevent warnings about missing pin connects
if (nodep->pinsp()) nodep->pinsp()->unlinkFrBackWithNext()->deleteTree(); if (nodep->pinsp()) nodep->pinsp()->unlinkFrBackWithNext()->deleteTree();
@ -1960,13 +1962,26 @@ private:
// if (debug()) nodep->dumpTree(cout, "linkcell:"); // if (debug()) nodep->dumpTree(cout, "linkcell:");
// if (debug()) nodep->modp()->dumpTree(cout, "linkcemd:"); // if (debug()) nodep->modp()->dumpTree(cout, "linkcemd:");
iterateChildren(nodep); iterateChildren(nodep);
m_pinSymp = nullptr;
} }
} }
m_cellp = nullptr;
// Parent module inherits child's publicity // Parent module inherits child's publicity
// This is done bottom up in the LinkBotupVisitor stage // This is done bottom up in the LinkBotupVisitor stage
} }
virtual void visit(AstClassRefDType* nodep) override {
// Cell: Recurse inside or cleanup not founds
checkNoDot(nodep);
AstNode::user5ClearTree();
UASSERT_OBJ(nodep->classp(), nodep, "ClassRef has unlinked class");
VL_RESTORER(m_pinSymp);
{
// ClassRef's have pins, so track
m_pinSymp = m_statep->getNodeSym(nodep->classp());
UINFO(4, "(Backto) Link ClassRefDType: " << nodep << endl);
// if (debug()) nodep->dumpTree(cout, "linkcell:");
// if (debug()) nodep->modp()->dumpTree(cout, "linkcemd:");
iterateChildren(nodep);
}
}
virtual void visit(AstPin* nodep) override { virtual void visit(AstPin* nodep) override {
// Pin: Link to submodule's port // Pin: Link to submodule's port
checkNoDot(nodep); checkNoDot(nodep);
@ -1976,7 +1991,8 @@ private:
VSymEnt* foundp = m_pinSymp->findIdFlat(nodep->name()); VSymEnt* foundp = m_pinSymp->findIdFlat(nodep->name());
const char* whatp = nodep->param() ? "parameter pin" : "pin"; const char* whatp = nodep->param() ? "parameter pin" : "pin";
if (!foundp) { if (!foundp) {
if (nodep->name() == "__paramNumber1" && VN_IS(m_cellp->modp(), Primitive)) { if (nodep->name() == "__paramNumber1" && m_cellp
&& VN_IS(m_cellp->modp(), Primitive)) {
// Primitive parameter is really a delay we can just ignore // Primitive parameter is really a delay we can just ignore
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
return; return;
@ -2540,7 +2556,7 @@ private:
"Unsupported: " << AstNode::prettyNameQ(cpackagerefp->name())); "Unsupported: " << AstNode::prettyNameQ(cpackagerefp->name()));
} }
if (cpackagerefp->paramsp()) { if (cpackagerefp->paramsp()) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: parameterized packages"); nodep->v3warn(E_UNSUPPORTED, "Unsupported: parameterized packages for task calls");
} }
UASSERT_OBJ(cpackagerefp->classOrPackagep(), m_ds.m_dotp->lhsp(), "Bad package link"); UASSERT_OBJ(cpackagerefp->classOrPackagep(), m_ds.m_dotp->lhsp(), "Bad package link");
nodep->classOrPackagep(cpackagerefp->classOrPackagep()); nodep->classOrPackagep(cpackagerefp->classOrPackagep());
@ -2817,8 +2833,10 @@ private:
cextp->v3error("Attempting to extend class " cextp->v3error("Attempting to extend class "
<< nodep->prettyNameQ() << " from itself"); << nodep->prettyNameQ() << " from itself");
} else { } else {
AstClassRefDType* newp AstNode* paramsp = cpackagerefp->paramsp();
= new AstClassRefDType{nodep->fileline(), classp}; if (paramsp) paramsp = paramsp->cloneTree(true);
const auto newp
= new AstClassRefDType{nodep->fileline(), classp, paramsp};
cextp->childDTypep(newp); cextp->childDTypep(newp);
classp->isExtended(true); classp->isExtended(true);
nodep->isExtended(true); nodep->isExtended(true);
@ -2909,7 +2927,9 @@ private:
nodep->refDTypep(defp); nodep->refDTypep(defp);
nodep->classOrPackagep(foundp->classOrPackagep()); nodep->classOrPackagep(foundp->classOrPackagep());
} else if (AstClass* defp = foundp ? VN_CAST(foundp->nodep(), Class) : nullptr) { } else if (AstClass* defp = foundp ? VN_CAST(foundp->nodep(), Class) : nullptr) {
AstClassRefDType* newp = new AstClassRefDType(nodep->fileline(), defp); AstNode* paramsp = nodep->paramsp();
if (paramsp) paramsp->unlinkFrBackWithNext();
AstClassRefDType* newp = new AstClassRefDType{nodep->fileline(), defp, paramsp};
newp->classOrPackagep(foundp->classOrPackagep()); newp->classOrPackagep(foundp->classOrPackagep());
nodep->replaceWith(newp); nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep); VL_DO_DANGLING(nodep->deleteTree(), nodep);

View File

@ -0,0 +1,17 @@
%Error-UNSUPPORTED: t/t_class_param_bad.v:12:4: Unsupported: parameterized packages
12 | Cls #(.PARAMBAD(1)) c;
| ^~~
%Error: t/t_class_param_bad.v:12:11: Parameter pin not found: 'PARAMBAD'
: ... Suggested alternative: 'PARAMB'
12 | Cls #(.PARAMBAD(1)) c;
| ^~~~~~~~
%Error-UNSUPPORTED: t/t_class_param_bad.v:13:4: Unsupported: parameterized packages
13 | Cls #(13, 1) cd;
| ^~~
%Error: t/t_class_param_bad.v:13:14: Parameter pin not found: '__paramNumber2'
13 | Cls #(13, 1) cd;
| ^
%Error-UNSUPPORTED: t/t_class_param_bad.v:7:23: Unsupported: class parameter
7 | class Cls #(parameter PARAMB = 12);
| ^~~~~~
%Error: Exiting due to

View File

@ -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 2020 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(linter => 1);
lint(
fails => 1,
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

View File

@ -0,0 +1,15 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
class Cls #(parameter PARAMB = 12);
endclass
module t (/*AUTOARG*/);
Cls #(.PARAMBAD(1)) c; // Bad param name
Cls #(13, 1) cd; // Bad param number
endmodule

View File

@ -1,4 +1,7 @@
%Error-UNSUPPORTED: t/t_class_vparam.v:13:40: Unsupported: parameterized packages %Error-UNSUPPORTED: t/t_class_vparam.v:13:40: Unsupported: parameterized packages
13 | pure virtual function void funcname(paramed_class_t #(CTYPE_t) v); 13 | pure virtual function void funcname(paramed_class_t #(CTYPE_t) v);
| ^~~~~~~~~~~~~~~ | ^~~~~~~~~~~~~~~
%Error: t/t_class_vparam.v:13:58: Parameter pin not found: '__paramNumber1'
13 | pure virtual function void funcname(paramed_class_t #(CTYPE_t) v);
| ^~~~~~~
%Error: Exiting due to %Error: Exiting due to