Fix package resolution of parameters, bug586.

This commit is contained in:
Wilson Snyder 2012-12-31 17:05:13 -05:00
parent 562460606f
commit 229d854607
10 changed files with 264 additions and 225 deletions

View File

@ -7,6 +7,8 @@ indicates the contributor was also the author of the fix; Thanks!
*** Support "unsigned int" DPI import functions, msg966. [Alex Lee] *** Support "unsigned int" DPI import functions, msg966. [Alex Lee]
*** Fix package resolution of parameters, bug586. [Jeremy Bennett]
**** Fix non-integer vpi_get_value, bug587. [Rich Porter] **** Fix non-integer vpi_get_value, bug587. [Rich Porter]
**** Fix task inlining under $display, bug589. [Holger Waechtler] **** Fix task inlining under $display, bug589. [Holger Waechtler]

View File

@ -505,10 +505,7 @@ class AstParseRefExp {
public: public:
enum en { enum en {
PX_NONE, // Used in V3LinkParse only PX_NONE, // Used in V3LinkParse only
PX_TEXT, // Unknown ID component PX_TEXT // Unknown ID component
PX_PREDOT, // Module name or misc component above var/task/func/member
PX_VAR_ANY, // Variable/structure member
PX_FTASK // Task/Function (AstParse::ftaskrefp() will be set)
}; };
enum en m_e; enum en m_e;
inline AstParseRefExp() : m_e(PX_NONE) {} inline AstParseRefExp() : m_e(PX_NONE) {}
@ -517,7 +514,7 @@ public:
operator en () const { return m_e; } operator en () const { return m_e; }
const char* ascii() const { const char* ascii() const {
static const char* names[] = { static const char* names[] = {
"","TEXT","PREDOT","VAR_MEM","VAR_ANY","FTASK"}; "","TEXT","PREDOT"};
return names[m_e]; } return names[m_e]; }
}; };
inline bool operator== (AstParseRefExp lhs, AstParseRefExp rhs) { return (lhs.m_e == rhs.m_e); } inline bool operator== (AstParseRefExp lhs, AstParseRefExp rhs) { return (lhs.m_e == rhs.m_e); }

View File

@ -859,11 +859,16 @@ void AstSenItem::dump(ostream& str) {
void AstParseRef::dump(ostream& str) { void AstParseRef::dump(ostream& str) {
this->AstNode::dump(str); this->AstNode::dump(str);
str<<" ["<<expect().ascii()<<"]"; str<<" ["<<expect().ascii()<<"]";
if (start()) str<<" [START]"; }
void AstPackageRef::dump(ostream& str) {
this->AstNode::dump(str);
if (packagep()) { str<<" pkg="<<(void*)packagep(); }
str<<" -> ";
if (packagep()) { packagep()->dump(str); }
else { str<<"UNLINKED"; }
} }
void AstDot::dump(ostream& str) { void AstDot::dump(ostream& str) {
this->AstNode::dump(str); this->AstNode::dump(str);
if (start()) str<<" [START]";
} }
void AstActive::dump(ostream& str) { void AstActive::dump(ostream& str) {
this->AstNode::dump(str); this->AstNode::dump(str);

View File

@ -1367,15 +1367,16 @@ struct AstParseRef : public AstNode {
private: private:
AstParseRefExp m_expect; // Type we think it should resolve to AstParseRefExp m_expect; // Type we think it should resolve to
string m_name; string m_name;
bool m_start; // Start of parseref stack
public: public:
AstParseRef(FileLine* fl, AstParseRefExp expect, const string& name, AstNode* lhsp, AstNodeFTaskRef* ftaskrefp) AstParseRef(FileLine* fl, AstParseRefExp expect, const string& name, AstNode* lhsp, AstNodeFTaskRef* ftaskrefp)
:AstNode(fl), m_expect(expect), m_name(name) { setNOp1p(lhsp); setNOp2p(ftaskrefp); m_start=false; } :AstNode(fl), m_expect(expect), m_name(name) { setNOp1p(lhsp); setNOp2p(ftaskrefp); }
ASTNODE_NODE_FUNCS(ParseRef, PARSEREF) ASTNODE_NODE_FUNCS(ParseRef, PARSEREF)
virtual void dump(ostream& str); virtual void dump(ostream& str);
virtual string name() const { return m_name; } // * = Var name virtual string name() const { return m_name; } // * = Var name
virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_expect),V3Hash(m_name)); } virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_expect),V3Hash(m_name)); }
virtual bool same(AstNode* samep) const { return expect() == samep->castParseRef()->expect() && m_name==samep->castParseRef()->m_name; } virtual bool same(AstNode* samep) const {
return (expect() == samep->castParseRef()->expect()
&& m_name==samep->castParseRef()->m_name); }
virtual string emitVerilog() { V3ERROR_NA; return ""; } virtual string emitVerilog() { V3ERROR_NA; return ""; }
virtual string emitC() { V3ERROR_NA; return ""; } virtual string emitC() { V3ERROR_NA; return ""; }
virtual void name(const string& name) { m_name = name; } virtual void name(const string& name) { m_name = name; }
@ -1385,26 +1386,44 @@ public:
AstNode* lhsp() const { return op1p(); } // op1 = List of statements AstNode* lhsp() const { return op1p(); } // op1 = List of statements
AstNode* ftaskrefp() const { return op2p(); } // op2 = Function/task reference AstNode* ftaskrefp() const { return op2p(); } // op2 = Function/task reference
void ftaskrefp(AstNodeFTaskRef* nodep) { setNOp2p(nodep); } // op2 = Function/task reference void ftaskrefp(AstNodeFTaskRef* nodep) { setNOp2p(nodep); } // op2 = Function/task reference
bool start() const { return m_start; } };
void start(bool flag) { m_start = flag; }
struct AstPackageRef : public AstNode {
private:
AstPackage* m_packagep; // Package hierarchy
public:
AstPackageRef(FileLine* fl, AstPackage* packagep)
: AstNode(fl), m_packagep(packagep) {}
ASTNODE_NODE_FUNCS(PackageRef, PACKAGEREF)
// METHODS
virtual bool broken() const { return !m_packagep || !m_packagep->brokeExists(); }
virtual void cloneRelink() { if (m_packagep && m_packagep->clonep()) {
m_packagep = m_packagep->clonep()->castPackage();
}}
virtual bool same(AstNode* samep) const {
return (m_packagep==samep->castPackageRef()->m_packagep); }
virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_packagep)); }
virtual void dump(ostream& str=cout);
AstPackage* packagep() const { return m_packagep; }
void packagep(AstPackage* nodep) { m_packagep=nodep; }
}; };
struct AstDot : public AstNode { struct AstDot : public AstNode {
// A dot separating paths in an AstXRef, AstFuncRef or AstTaskRef // A dot separating paths in an AstXRef, AstFuncRef or AstTaskRef
// These are eliminated in the link stage // These are eliminated in the link stage
private:
bool m_start; // Start of parseref stack
public: public:
AstDot(FileLine* fl, AstNode* lhsp, AstNode* rhsp) AstDot(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
:AstNode(fl) { setOp1p(lhsp); setOp2p(rhsp); m_start=false; } :AstNode(fl) { setOp1p(lhsp); setOp2p(rhsp); }
ASTNODE_NODE_FUNCS(Dot, DOT) ASTNODE_NODE_FUNCS(Dot, DOT)
static AstNode* newIfPkg(FileLine*fl, AstPackage* packagep, AstNode* rhsp) { // For parser, make only if non-null package
if (!packagep) return rhsp;
return new AstDot(fl, new AstPackageRef(fl, packagep), rhsp);
}
virtual void dump(ostream& str); virtual void dump(ostream& str);
virtual string emitVerilog() { V3ERROR_NA; return ""; } virtual string emitVerilog() { V3ERROR_NA; return ""; }
virtual string emitC() { V3ERROR_NA; return ""; } virtual string emitC() { V3ERROR_NA; return ""; }
AstNode* lhsp() const { return op1p(); } AstNode* lhsp() const { return op1p(); }
AstNode* rhsp() const { return op2p(); } AstNode* rhsp() const { return op2p(); }
bool start() const { return m_start; }
void start(bool flag) { m_start = flag; }
}; };
//###################################################################### //######################################################################
@ -1474,11 +1493,7 @@ public:
class Initial {}; // for creator type-overload selection class Initial {}; // for creator type-overload selection
class Settle {}; // for creator type-overload selection class Settle {}; // for creator type-overload selection
class Never {}; // for creator type-overload selection class Never {}; // for creator type-overload selection
AstSenItem(FileLine* fl, AstEdgeType edgeType, AstNodeVarRef* varrefp) AstSenItem(FileLine* fl, AstEdgeType edgeType, AstNode* varrefp)
: AstNodeSenItem(fl), m_edgeType(edgeType) {
setOp1p(varrefp);
}
AstSenItem(FileLine* fl, AstEdgeType edgeType, AstParseRef* varrefp)
: AstNodeSenItem(fl), m_edgeType(edgeType) { : AstNodeSenItem(fl), m_edgeType(edgeType) {
setOp1p(varrefp); setOp1p(varrefp);
} }

View File

@ -809,7 +809,7 @@ private:
if (nodep->castDot()) { // Not creating a simple implied type, if (nodep->castDot()) { // Not creating a simple implied type,
// and implying something else would just confuse later errors // and implying something else would just confuse later errors
} }
else if (nodep->castVarRef() || (nodep->castParseRef() && nodep->castParseRef()->start())) { else if (nodep->castVarRef() || nodep->castParseRef()) {
// To prevent user errors, we should only do single bit // To prevent user errors, we should only do single bit
// implicit vars, however some netlists (MIPS) expect single // implicit vars, however some netlists (MIPS) expect single
// bit implicit wires to get created with range 0:0 etc. // bit implicit wires to get created with range 0:0 etc.
@ -1018,7 +1018,11 @@ private:
AstUser5InUse m_inuser5; AstUser5InUse m_inuser5;
// TYPES // TYPES
enum DotPosition { DP_SCOPE, DP_VAR_ETC, DP_MEMBER }; enum DotPosition { DP_NONE=0, // Not under a DOT
DP_PACKAGE, // {package}:: DOT
DP_SCOPE, // [DOT...] {scope-or-var} DOT
DP_FINAL, // [DOT...] {var-or-func-or-dtype} with no following dots
DP_MEMBER }; // DOT {member-name} [DOT...]
// STATE // STATE
LinkDotState* m_statep; // State, including dotted symbol table LinkDotState* m_statep; // State, including dotted symbol table
@ -1030,16 +1034,24 @@ private:
AstNodeFTask* m_ftaskp; // Current function/task AstNodeFTask* m_ftaskp; // Current function/task
struct DotStates { struct DotStates {
DotPosition m_dotPos; // Scope part of dotted resolution
VSymEnt* m_dotSymp; // SymEnt for dotted AstParse lookup VSymEnt* m_dotSymp; // SymEnt for dotted AstParse lookup
AstDot* m_dotp; // Current dot AstDot* m_dotp; // Current dot
DotPosition m_dotPos; // Scope part of dotted resolution
bool m_dotErr; // Error found in dotted resolution, ignore upwards bool m_dotErr; // Error found in dotted resolution, ignore upwards
string m_dotText; // String of dotted names found in below parseref string m_dotText; // String of dotted names found in below parseref
void init(VSymEnt* curSymp) {
m_dotSymp = curSymp; m_dotp = NULL; m_dotPos = DP_VAR_ETC; m_dotErr = false; m_dotText = "";
}
DotStates() { init(NULL); } DotStates() { init(NULL); }
~DotStates() {} ~DotStates() {}
void init(VSymEnt* curSymp) {
m_dotPos = DP_NONE; m_dotSymp = curSymp; m_dotp = NULL; m_dotErr = false; m_dotText = "";
}
string ascii() const {
static const char* names[] = { "NONE","PACKAGE","SCOPE","FINAL","MEMBER" };
ostringstream sstr;
sstr<<"ds="<<names[m_dotPos];
sstr<<" dse"<<(void*)m_dotSymp;
sstr<<" txt="<<m_dotText;
return sstr.str();
}
} m_ds; // State to preserve across recursions } m_ds; // State to preserve across recursions
int debug() { return LinkDotState::debug(); } int debug() { return LinkDotState::debug(); }
@ -1068,6 +1080,14 @@ private:
if (nodep->taskp() && nodep->taskp()->castTask() if (nodep->taskp() && nodep->taskp()->castTask()
&& nodep->castFuncRef()) nodep->v3error("Illegal call of a task as a function: "<<nodep->prettyName()); && nodep->castFuncRef()) nodep->v3error("Illegal call of a task as a function: "<<nodep->prettyName());
} }
inline void checkNoDot(AstNode* nodep) {
if (VL_UNLIKELY(m_ds.m_dotPos != DP_NONE)) {
m_statep->preErrorDump();
UINFO(1,"ds="<<m_ds.ascii()<<endl);
nodep->v3error("Syntax Error: Not expecting "<<nodep->type()<<" under a "<<nodep->backp()->type()<<" in dotted expression");
m_ds.m_dotErr = true;
}
}
// VISITs // VISITs
virtual void visit(AstNetlist* nodep, AstNUser* vup) { virtual void visit(AstNetlist* nodep, AstNUser* vup) {
@ -1077,6 +1097,7 @@ private:
virtual void visit(AstTypeTable* nodep, AstNUser*) {} virtual void visit(AstTypeTable* nodep, AstNUser*) {}
virtual void visit(AstNodeModule* nodep, AstNUser*) { virtual void visit(AstNodeModule* nodep, AstNUser*) {
if (nodep->dead()) return; if (nodep->dead()) return;
checkNoDot(nodep);
UINFO(8," "<<nodep<<endl); UINFO(8," "<<nodep<<endl);
m_ds.init(m_curSymp); m_ds.init(m_curSymp);
m_ds.m_dotSymp = m_curSymp = m_modSymp = m_statep->getNodeSym(nodep); // Until overridden by a SCOPE m_ds.m_dotSymp = m_curSymp = m_modSymp = m_statep->getNodeSym(nodep); // Until overridden by a SCOPE
@ -1088,17 +1109,20 @@ private:
} }
virtual void visit(AstScope* nodep, AstNUser*) { virtual void visit(AstScope* nodep, AstNUser*) {
UINFO(8," "<<nodep<<endl); UINFO(8," "<<nodep<<endl);
checkNoDot(nodep);
m_ds.m_dotSymp = m_curSymp = m_statep->getScopeSym(nodep); m_ds.m_dotSymp = m_curSymp = m_statep->getScopeSym(nodep);
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
m_ds.m_dotSymp = m_curSymp = NULL; m_ds.m_dotSymp = m_curSymp = NULL;
} }
virtual void visit(AstCellInline* nodep, AstNUser*) { virtual void visit(AstCellInline* nodep, AstNUser*) {
checkNoDot(nodep);
if (m_statep->forScopeCreation()) { if (m_statep->forScopeCreation()) {
nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL; nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL;
} }
} }
virtual void visit(AstCell* nodep, AstNUser*) { virtual void visit(AstCell* nodep, AstNUser*) {
// Cell: Resolve its filename. If necessary, parse it. // Cell: Resolve its filename. If necessary, parse it.
checkNoDot(nodep);
m_cellp = nodep; m_cellp = nodep;
AstNode::user5ClearTree(); AstNode::user5ClearTree();
if (!nodep->modp()) { if (!nodep->modp()) {
@ -1127,6 +1151,7 @@ private:
} }
virtual void visit(AstPin* nodep, AstNUser*) { virtual void visit(AstPin* nodep, AstNUser*) {
// Pin: Link to submodule's port // Pin: Link to submodule's port
checkNoDot(nodep);
if (!nodep->modVarp()) { if (!nodep->modVarp()) {
if (!m_pinSymp) nodep->v3fatalSrc("Pin not under cell?\n"); if (!m_pinSymp) nodep->v3fatalSrc("Pin not under cell?\n");
VSymEnt* foundp = m_pinSymp->findIdFlat(nodep->name()); VSymEnt* foundp = m_pinSymp->findIdFlat(nodep->name());
@ -1155,10 +1180,14 @@ private:
// Early return() above when deleted // Early return() above when deleted
} }
virtual void visit(AstDot* nodep, AstNUser*) { virtual void visit(AstDot* nodep, AstNUser*) {
// Legal under a DOT: AstDot, AstParseRef, AstPackageRef, AstNodeSel
// also a DOT can be part of an expression, but only above plus AstFTaskRef are legal children
// DOT(PACKAGEREF, PARSEREF(text))
// DOT(DOT(DOT(PARSEREF(text), ...
if (nodep->user3SetOnce()) return; if (nodep->user3SetOnce()) return;
UINFO(8," "<<nodep<<endl); UINFO(8," "<<nodep<<endl);
DotStates lastStates = m_ds; DotStates lastStates = m_ds;
bool start = nodep->start(); // Save, as nodep may go NULL bool start = !m_ds.m_dotp; // Save, as m_dotp will be changed
{ {
if (start) { // Starting dot sequence if (start) { // Starting dot sequence
if (debug()>=9) nodep->dumpTree("-dot-in: "); if (debug()>=9) nodep->dumpTree("-dot-in: ");
@ -1166,10 +1195,17 @@ private:
} }
m_ds.m_dotp = nodep; // Always, not just at start m_ds.m_dotp = nodep; // Always, not just at start
m_ds.m_dotPos = DP_SCOPE; m_ds.m_dotPos = DP_SCOPE;
// m_ds.m_dotText communicates the cell prefix between stages // m_ds.m_dotText communicates the cell prefix between stages
nodep->lhsp()->iterateAndNext(*this); if (nodep->lhsp()->castPackageRef()) {
if (!start) { nodep->lhsp()->v3error("Package reference may not be embedded in dotted reference"); m_ds.m_dotErr=true; }
m_ds.m_dotPos = DP_PACKAGE;
} else {
m_ds.m_dotPos = DP_SCOPE;
nodep->lhsp()->iterateAndNext(*this);
}
if (!m_ds.m_dotErr) { // Once something wrong, give up if (!m_ds.m_dotErr) { // Once something wrong, give up
if (start && m_ds.m_dotPos==DP_SCOPE) m_ds.m_dotPos = DP_VAR_ETC; // Top dot RHS is final RHS, else it's a DOT(DOT(x,*here*),real-rhs) which we consider a RHS if (start && m_ds.m_dotPos==DP_SCOPE) m_ds.m_dotPos = DP_FINAL; // Top 'final' dot RHS is final RHS, else it's a DOT(DOT(x,*here*),real-rhs) which we consider a RHS
nodep->rhsp()->iterateAndNext(*this); nodep->rhsp()->iterateAndNext(*this);
} }
if (start) { if (start) {
@ -1197,15 +1233,16 @@ private:
} }
virtual void visit(AstParseRef* nodep, AstNUser*) { virtual void visit(AstParseRef* nodep, AstNUser*) {
if (nodep->user3SetOnce()) return; if (nodep->user3SetOnce()) return;
UINFO(9," linkPARSEREF se"<<(void*)m_ds.m_dotSymp<<" pos="<<m_ds.m_dotPos<<" txt="<<m_ds.m_dotText<<" n="<<nodep<<endl); UINFO(9," linkPARSEREF "<<m_ds.ascii()<<" n="<<nodep<<endl);
// m_curSymp is symbol table of outer expression // m_curSymp is symbol table of outer expression
// m_ds.m_dotSymp is symbol table relative to "."'s above now // m_ds.m_dotSymp is symbol table relative to "."'s above now
if (!m_ds.m_dotSymp) nodep->v3fatalSrc("NULL lookup symbol table"); if (!m_ds.m_dotSymp) nodep->v3fatalSrc("NULL lookup symbol table");
if (!m_statep->forPrimary()) nodep->v3fatalSrc("ParseRefs should no longer exist"); if (!m_statep->forPrimary()) nodep->v3fatalSrc("ParseRefs should no longer exist");
DotStates lastStates = m_ds; DotStates lastStates = m_ds;
bool start = nodep->start(); // Save, as nodep may go NULL bool start = !m_ds.m_dotp;
if (start) { if (start) {
m_ds.init(m_curSymp); m_ds.init(m_curSymp);
// Note m_ds.m_dot remains NULL; this is a reference not under a dot
} }
if (m_ds.m_dotPos == DP_MEMBER) { if (m_ds.m_dotPos == DP_MEMBER) {
// Found a Var, everything following is membership. {scope}.{var}.HERE {member} // Found a Var, everything following is membership. {scope}.{var}.HERE {member}
@ -1219,20 +1256,29 @@ private:
string expectWhat; string expectWhat;
bool allowScope = false; bool allowScope = false;
bool allowVar = false; bool allowVar = false;
bool onlyVar = false; AstPackage* packagep = NULL;
if (nodep->expect() == AstParseRefExp::PX_PREDOT) { if (m_ds.m_dotPos == DP_PACKAGE) {
// {package}::{a}
expectWhat = "scope/variable";
allowScope = true;
allowVar = true;
if (!m_ds.m_dotp->lhsp()->castPackageRef()) m_ds.m_dotp->lhsp()->v3fatalSrc("Bad package link");
packagep = m_ds.m_dotp->lhsp()->castPackageRef()->packagep();
if (!packagep) m_ds.m_dotp->lhsp()->v3fatalSrc("Bad package link");
m_ds.m_dotSymp = m_statep->getNodeSym(packagep);
m_ds.m_dotPos = DP_SCOPE;
} else if (m_ds.m_dotPos == DP_SCOPE) {
// {a}.{b}, where {a} maybe a module name // {a}.{b}, where {a} maybe a module name
// or variable, where dotting into structure member // or variable, where dotting into structure member
expectWhat = "scope/variable"; expectWhat = "scope/variable";
allowScope = true; allowScope = true;
allowVar = true; allowVar = true;
} else if (nodep->expect() == AstParseRefExp::PX_VAR_ANY) { } else if (m_ds.m_dotPos == DP_NONE
|| m_ds.m_dotPos == DP_FINAL) {
expectWhat = "variable"; expectWhat = "variable";
onlyVar = true;
allowVar = true; allowVar = true;
} else if (nodep->expect() == AstParseRefExp::PX_FTASK) {
expectWhat = "task/function";
} else { } else {
UINFO(1,"ds="<<m_ds.ascii()<<endl);
nodep->v3fatalSrc("Unhandled AstParseRefExp"); nodep->v3fatalSrc("Unhandled AstParseRefExp");
} }
// Lookup // Lookup
@ -1283,23 +1329,9 @@ private:
m_ds.m_dotText = ""; m_ds.m_dotText = "";
} }
} }
else if (AstNodeFTask* ftaskp = foundp->nodep()->castNodeFTask()) {
if (nodep->expect() == AstParseRefExp::PX_FTASK) {
AstNodeFTaskRef* refp = nodep->ftaskrefp()->castNodeFTaskRef();
if (!refp) nodep->v3fatalSrc("Parseref indicates FTASKref but none found");
refp->name(nodep->name());
refp->dotted(m_ds.m_dotText); // Maybe ""
refp->taskp(ftaskp);
refp->packagep(foundp->packagep()); // Generally set by parse, but might be an import
taskFuncSwapCheck(refp);
refp->unlinkFrBack();
nodep->replaceWith(refp); pushDeletep(nodep); nodep = NULL;
ok = true;
}
}
// //
if (!ok) { if (!ok) {
bool checkImplicit = (onlyVar && m_ds.m_dotText==""); bool checkImplicit = (!m_ds.m_dotp && m_ds.m_dotText=="");
bool err = !(checkImplicit && m_statep->implicitOk(m_modp, nodep->name())); bool err = !(checkImplicit && m_statep->implicitOk(m_modp, nodep->name()));
if (err) { if (err) {
m_statep->preErrorDump(); m_statep->preErrorDump();
@ -1308,7 +1340,7 @@ private:
<<"'"<<" as a "<<foundp->nodep()->typeName() <<"'"<<" as a "<<foundp->nodep()->typeName()
<<" but expected a "<<expectWhat); <<" but expected a "<<expectWhat);
} else if (m_ds.m_dotText=="") { } else if (m_ds.m_dotText=="") {
UINFO(7," ErrParseRef curSymp=se"<<(void*)m_curSymp<<" dotSymp=se"<<(void*)m_ds.m_dotSymp<<endl); UINFO(7," ErrParseRef curSymp=se"<<(void*)m_curSymp<<" ds="<<m_ds.ascii()<<endl);
nodep->v3error("Can't find definition of "<<expectWhat nodep->v3error("Can't find definition of "<<expectWhat
<<": "<<nodep->prettyName()); <<": "<<nodep->prettyName());
} else { } else {
@ -1335,6 +1367,7 @@ private:
// VarRef: Resolve its reference // VarRef: Resolve its reference
// ParseRefs are used the first pass (forPrimary) so we shouldn't get can't find // ParseRefs are used the first pass (forPrimary) so we shouldn't get can't find
// errors here now that we have a VarRef. // errors here now that we have a VarRef.
// No checkNoDot; created and iterated from a parseRef
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
if (!nodep->varp()) { if (!nodep->varp()) {
UINFO(9," linkVarRef se"<<(void*)m_curSymp<<" n="<<nodep<<endl); UINFO(9," linkVarRef se"<<(void*)m_curSymp<<" n="<<nodep<<endl);
@ -1356,6 +1389,7 @@ private:
// due to creating new modules, flattening, etc. // due to creating new modules, flattening, etc.
if (nodep->user3SetOnce()) return; if (nodep->user3SetOnce()) return;
UINFO(8," "<<nodep<<endl); UINFO(8," "<<nodep<<endl);
// No checkNoDot; created and iterated from a parseRef
if (!m_modSymp) { if (!m_modSymp) {
UINFO(9,"Dead module for "<<nodep<<endl); UINFO(9,"Dead module for "<<nodep<<endl);
nodep->varp(NULL); // Module that is not in hierarchy. We'll be dead code eliminating it later. nodep->varp(NULL); // Module that is not in hierarchy. We'll be dead code eliminating it later.
@ -1408,6 +1442,7 @@ private:
} }
} }
virtual void visit(AstVar* nodep, AstNUser*) { virtual void visit(AstVar* nodep, AstNUser*) {
checkNoDot(nodep);
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
if (m_statep->forPrimary() && nodep->isIO() && !m_ftaskp && !nodep->user4()) { if (m_statep->forPrimary() && nodep->isIO() && !m_ftaskp && !nodep->user4()) {
nodep->v3error("Input/output/inout does not appear in port list: "<<nodep->prettyName()); nodep->v3error("Input/output/inout does not appear in port list: "<<nodep->prettyName());
@ -1416,6 +1451,17 @@ private:
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) { virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
if (nodep->user3SetOnce()) return; if (nodep->user3SetOnce()) return;
UINFO(8," "<<nodep<<endl); UINFO(8," "<<nodep<<endl);
if (m_ds.m_dotp && m_ds.m_dotPos == DP_PACKAGE) {
if (!m_ds.m_dotp->lhsp()->castPackageRef()) m_ds.m_dotp->lhsp()->v3fatalSrc("Bad package link");
if (!m_ds.m_dotp->lhsp()->castPackageRef()->packagep()) m_ds.m_dotp->lhsp()->v3fatalSrc("Bad package link");
nodep->packagep(m_ds.m_dotp->lhsp()->castPackageRef()->packagep());
m_ds.m_dotPos = DP_SCOPE;
m_ds.m_dotp = NULL;
} else if (m_ds.m_dotp && m_ds.m_dotPos == DP_FINAL) {
nodep->dotted(m_ds.m_dotText); // Maybe ""
} else {
checkNoDot(nodep);
}
if (nodep->packagep() && nodep->taskp()) { if (nodep->packagep() && nodep->taskp()) {
// References into packages don't care about cell hierarchy. // References into packages don't care about cell hierarchy.
} else if (!m_modSymp) { } else if (!m_modSymp) {
@ -1457,7 +1503,11 @@ private:
// Note ParseRef has similar error handling/message output // Note ParseRef has similar error handling/message output
m_statep->preErrorDump(); m_statep->preErrorDump();
UINFO(7," ErrFtask curSymp=se"<<(void*)m_curSymp<<" dotSymp=se"<<(void*)dotSymp<<endl); UINFO(7," ErrFtask curSymp=se"<<(void*)m_curSymp<<" dotSymp=se"<<(void*)dotSymp<<endl);
if (nodep->dotted() == "") { if (foundp) {
nodep->v3error("Found definition of '"<<m_ds.m_dotText<<(m_ds.m_dotText==""?"":".")<<nodep->prettyName()
<<"'"<<" as a "<<foundp->nodep()->typeName()
<<" but expected a task/function");
} else if (nodep->dotted() == "") {
nodep->v3error("Can't find definition of task/function: "<<nodep->prettyName()); nodep->v3error("Can't find definition of task/function: "<<nodep->prettyName());
} else { } else {
nodep->v3error("Can't find definition of '"<<baddot<<"' in dotted task/function: "<<nodep->dotted()+"."+nodep->prettyName()); nodep->v3error("Can't find definition of '"<<baddot<<"' in dotted task/function: "<<nodep->dotted()+"."+nodep->prettyName());
@ -1466,7 +1516,12 @@ private:
} }
taskFuncSwapCheck(nodep); taskFuncSwapCheck(nodep);
} }
nodep->iterateChildren(*this); DotStates lastStates = m_ds;
{
m_ds.init(m_curSymp);
nodep->iterateChildren(*this);
}
m_ds = lastStates;
} }
virtual void visit(AstSelBit* nodep, AstNUser*) { virtual void visit(AstSelBit* nodep, AstNUser*) {
if (nodep->user3SetOnce()) return; if (nodep->user3SetOnce()) return;
@ -1480,12 +1535,40 @@ private:
} }
// And pass up m_ds.m_dotText // And pass up m_ds.m_dotText
} }
// Pass dot state down to fromp()
nodep->fromp()->iterateAndNext(*this); nodep->fromp()->iterateAndNext(*this);
nodep->bitp()->iterateAndNext(*this); DotStates lastStates = m_ds;
nodep->attrp()->iterateAndNext(*this); {
m_ds.init(m_curSymp);
nodep->bitp()->iterateAndNext(*this);
nodep->attrp()->iterateAndNext(*this);
}
m_ds = lastStates;
}
virtual void visit(AstNodePreSel* nodep, AstNUser*) {
// Excludes simple AstSelBit, see above
if (nodep->user3SetOnce()) return;
if (m_ds.m_dotPos == DP_SCOPE) { // Already under dot, so this is {modulepart} DOT {modulepart}
nodep->v3error("Syntax Error: Range ':', '+:' etc are not allowed in the cell part of a dotted reference");
m_ds.m_dotErr = true;
return;
}
nodep->lhsp()->iterateAndNext(*this);
DotStates lastStates = m_ds;
{
m_ds.init(m_curSymp);
nodep->rhsp()->iterateAndNext(*this);
nodep->thsp()->iterateAndNext(*this);
}
m_ds = lastStates;
}
virtual void visit(AstMemberSel* nodep, AstNUser*) {
// checkNoDot not appropriate, can be under a dot
nodep->iterateChildren(*this);
} }
virtual void visit(AstBegin* nodep, AstNUser*) { virtual void visit(AstBegin* nodep, AstNUser*) {
UINFO(5," "<<nodep<<endl); UINFO(5," "<<nodep<<endl);
checkNoDot(nodep);
VSymEnt* oldCurSymp = m_curSymp; VSymEnt* oldCurSymp = m_curSymp;
{ {
m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep); m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep);
@ -1497,6 +1580,7 @@ private:
} }
virtual void visit(AstNodeFTask* nodep, AstNUser*) { virtual void visit(AstNodeFTask* nodep, AstNUser*) {
UINFO(5," "<<nodep<<endl); UINFO(5," "<<nodep<<endl);
checkNoDot(nodep);
VSymEnt* oldCurSymp = m_curSymp; VSymEnt* oldCurSymp = m_curSymp;
{ {
m_ftaskp = nodep; m_ftaskp = nodep;
@ -1509,6 +1593,15 @@ private:
virtual void visit(AstRefDType* nodep, AstNUser*) { virtual void visit(AstRefDType* nodep, AstNUser*) {
// Resolve its reference // Resolve its reference
if (nodep->user3SetOnce()) return; if (nodep->user3SetOnce()) return;
if (m_ds.m_dotp && m_ds.m_dotPos == DP_PACKAGE) {
if (!m_ds.m_dotp->lhsp()->castPackageRef()) m_ds.m_dotp->lhsp()->v3fatalSrc("Bad package link");
if (!m_ds.m_dotp->lhsp()->castPackageRef()->packagep()) m_ds.m_dotp->lhsp()->v3fatalSrc("Bad package link");
nodep->packagep(m_ds.m_dotp->lhsp()->castPackageRef()->packagep());
m_ds.m_dotPos = DP_SCOPE;
m_ds.m_dotp = NULL;
} else {
checkNoDot(nodep);
}
if (!nodep->defp()) { if (!nodep->defp()) {
VSymEnt* foundp; VSymEnt* foundp;
if (nodep->packagep()) { if (nodep->packagep()) {
@ -1528,6 +1621,7 @@ private:
virtual void visit(AstDpiExport* nodep, AstNUser*) { virtual void visit(AstDpiExport* nodep, AstNUser*) {
// AstDpiExport: Make sure the function referenced exists, then dump it // AstDpiExport: Make sure the function referenced exists, then dump it
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
checkNoDot(nodep);
VSymEnt* foundp = m_curSymp->findIdFallback(nodep->name()); VSymEnt* foundp = m_curSymp->findIdFallback(nodep->name());
AstNodeFTask* taskp = foundp->nodep()->castNodeFTask(); AstNodeFTask* taskp = foundp->nodep()->castNodeFTask();
if (!taskp) { nodep->v3error("Can't find definition of exported task/function: "<<nodep->prettyName()); } if (!taskp) { nodep->v3error("Can't find definition of exported task/function: "<<nodep->prettyName()); }
@ -1541,10 +1635,12 @@ private:
} }
virtual void visit(AstPackageImport* nodep, AstNUser*) { virtual void visit(AstPackageImport* nodep, AstNUser*) {
// No longer needed // No longer needed
checkNoDot(nodep);
nodep->unlinkFrBack()->deleteTree(); nodep=NULL; nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
} }
virtual void visit(AstNode* nodep, AstNUser*) { virtual void visit(AstNode* nodep, AstNUser*) {
// Default: Just iterate // Default: Just iterate
checkNoDot(nodep);
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
} }
public: public:

View File

@ -19,11 +19,7 @@
//************************************************************************* //*************************************************************************
// LinkParse TRANSFORMATIONS: // LinkParse TRANSFORMATIONS:
// Top-down traversal // Top-down traversal
// Replace ParseRef with lower parseref // Move some attributes around
// TASKREF(PARSEREF(DOT(TEXTa,TEXTb))) -> DOT(PARSEREF(a),TASKREF(b))
// PARSEREF(TEXTa) -> PARSEREF(a) (no change)
// PARSEREF(DOT(TEXTa,TEXTb)) -> DOT(PARSEREF(A),PARSEREF(b)
// PARSEREF(DOT(DOT(TEXTa,TEXTb),TEXTc)) -> DOT(DOT(PARSEREF(a),PARSEREF(b)),PARSEREF(c))
//************************************************************************* //*************************************************************************
#include "config_build.h" #include "config_build.h"
@ -57,7 +53,6 @@ private:
typedef set <FileLine*> FileLineSet; typedef set <FileLine*> FileLineSet;
// STATE // STATE
AstParseRefExp m_exp; // Type of data we're looking for
AstVar* m_varp; // Variable we're under AstVar* m_varp; // Variable we're under
ImplTypedefMap m_implTypedef; // Created typedefs for each <container,name> ImplTypedefMap m_implTypedef; // Created typedefs for each <container,name>
FileLineSet m_filelines; // Filelines that have been seen FileLineSet m_filelines; // Filelines that have been seen
@ -66,7 +61,6 @@ private:
bool m_needStart; // Need start marker on lower AstParse bool m_needStart; // Need start marker on lower AstParse
AstNodeModule* m_valueModp; // If set, move AstVar->valuep() initial values to this module AstNodeModule* m_valueModp; // If set, move AstVar->valuep() initial values to this module
AstNodeModule* m_modp; // Current module AstNodeModule* m_modp; // Current module
AstParseRef* m_rightParsep; // RHS()-most parseref
// METHODS // METHODS
static int debug() { static int debug() {
@ -90,125 +84,17 @@ private:
} }
} }
void checkExpected(AstNode* nodep) {
if (m_exp != AstParseRefExp::PX_NONE) {
nodep->v3fatalSrc("Tree syntax error: Not expecting "<<nodep->type()<<" under a "<<nodep->backp()->type());
m_exp = AstParseRefExp::PX_NONE;
}
}
// VISITs // VISITs
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) { virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
if (!nodep->user1SetOnce()) { // Process only once. if (!nodep->user1SetOnce()) { // Process only once.
cleanFileline(nodep); cleanFileline(nodep);
UINFO(5," "<<nodep<<endl); UINFO(5," "<<nodep<<endl);
checkExpected(nodep);
AstNodeModule* upperValueModp = m_valueModp; AstNodeModule* upperValueModp = m_valueModp;
m_valueModp = NULL; m_valueModp = NULL;
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
m_valueModp = upperValueModp; m_valueModp = upperValueModp;
} }
} }
virtual void visit(AstParseRef* nodep, AstNUser*) {
if (nodep->user1SetOnce()) return; // Process only once.
// VarRef: Parse its reference
UINFO(5," "<<nodep<<endl);
{ // First do any function call
AstParseRefExp lastExp = m_exp;
{
m_exp = AstParseRefExp::PX_NONE;
if (nodep->ftaskrefp()) nodep->ftaskrefp()->iterateAndNext(*this);
}
m_exp = lastExp;
}
if (nodep->start()) { // Start of new parseref stack
// The start parseref indicates the type of element to be created.
// Push the start marking down to the lowest non-start parseref under any DOTs.
// May be a varref inside a select, etc, so save state and recurse
AstParseRefExp lastExp = m_exp;
AstParseRef* lastRightp = m_rightParsep;
{
m_exp = nodep->expect();
m_rightParsep = NULL;
m_needStart = true;
nodep->lhsp()->accept(*this);
if (!m_rightParsep) nodep->v3fatalSrc("No child ParseRef found");
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
if (nodep->expect() == AstParseRefExp::PX_FTASK) {
// Put the FTaskRef under the final DOT
AstNodeFTaskRef* ftaskrefp = nodep->ftaskrefp()->castNodeFTaskRef();
if (!ftaskrefp) nodep->v3fatalSrc("Parseref indicates FTASKref but none found");
ftaskrefp->name(m_rightParsep->name());
ftaskrefp->unlinkFrBack();
if (ftaskrefp->packagep()) {
// Can remove the parse stack entirely and V3LinkDot will deal with it natively
lhsp = ftaskrefp;
} else {
m_rightParsep->ftaskrefp(ftaskrefp);
}
}
nodep->replaceWith(lhsp);
nodep->deleteTree(); nodep=NULL;
}
m_exp = lastExp;
m_rightParsep = lastRightp;
}
else { // inside existing stack
nodep->expect(m_exp);
m_rightParsep = nodep;
// Move the start marker down to a standalone parse reference
if (m_needStart) { nodep->start(true); m_needStart = false; }
}
}
virtual void visit(AstDot* nodep, AstNUser*) {
UINFO(5," "<<nodep<<endl);
if (!nodep->user1SetOnce()) { // Process only once.
cleanFileline(nodep);
if (m_exp == AstParseRefExp::PX_NONE) nodep->v3fatalSrc("Tree syntax error: Not expecting "<<nodep->type()<<" under a "<<nodep->backp()->type());
AstParseRefExp lastExp = m_exp;
m_exp = AstParseRefExp::PX_PREDOT;
if (m_needStart) { nodep->start(true); m_needStart = false; }
nodep->lhsp()->iterateAndNext(*this);
m_exp = lastExp;
nodep->rhsp()->iterateAndNext(*this);
}
}
virtual void visit(AstSelBit* nodep, AstNUser*) {
if (!nodep->user1SetOnce()) { // Process only once.
cleanFileline(nodep);
if (m_exp==AstParseRefExp::PX_FTASK) {
nodep->v3error("Syntax Error: Range selection '[]' is not allowed as part of function/task names");
} else {
nodep->lhsp()->iterateAndNext(*this);
AstParseRefExp lastExp = m_exp;
{
m_exp = AstParseRefExp::PX_NONE;
nodep->rhsp()->iterateAndNext(*this);
}
m_exp = lastExp;
}
}
}
virtual void visit(AstNodePreSel* nodep, AstNUser*) {
// Excludes simple AstSel, see above
if (!nodep->user1SetOnce()) { // Process only once.
cleanFileline(nodep);
if (m_exp == AstParseRefExp::PX_PREDOT) { // Already under dot, so this is {modulepart} DOT {modulepart}
nodep->v3error("Syntax Error: Range ':', '+:' etc are not allowed in the cell part of a dotted reference");
} else if (m_exp==AstParseRefExp::PX_FTASK) {
nodep->v3error("Syntax Error: Range ':', '+:' etc are not allowed as part of function/task names");
} else {
nodep->lhsp()->iterateAndNext(*this);
AstParseRefExp lastExp = m_exp;
{
m_exp = AstParseRefExp::PX_NONE;
nodep->rhsp()->iterateAndNext(*this);
nodep->thsp()->iterateAndNext(*this);
}
m_exp = lastExp;
}
}
}
virtual void visit(AstEnumItem* nodep, AstNUser*) { virtual void visit(AstEnumItem* nodep, AstNUser*) {
// Expand ranges // Expand ranges
cleanFileline(nodep); cleanFileline(nodep);
@ -379,7 +265,6 @@ private:
virtual void visit(AstNodeModule* nodep, AstNUser*) { virtual void visit(AstNodeModule* nodep, AstNUser*) {
// Module: Create sim table for entire module and iterate // Module: Create sim table for entire module and iterate
cleanFileline(nodep); cleanFileline(nodep);
checkExpected(nodep); // So we detect node types we forgot to list here
// //
m_modp = nodep; m_modp = nodep;
m_valueModp = nodep; m_valueModp = nodep;
@ -390,7 +275,6 @@ private:
void visitIterateNoValueMod(AstNode* nodep) { void visitIterateNoValueMod(AstNode* nodep) {
// Iterate a node which shouldn't have any local variables moved to an Initial // Iterate a node which shouldn't have any local variables moved to an Initial
cleanFileline(nodep); cleanFileline(nodep);
checkExpected(nodep); // So we detect node types we forgot to list here
// //
AstNodeModule* upperValueModp = m_valueModp; AstNodeModule* upperValueModp = m_valueModp;
m_valueModp = NULL; m_valueModp = NULL;
@ -415,7 +299,6 @@ private:
virtual void visit(AstNode* nodep, AstNUser*) { virtual void visit(AstNode* nodep, AstNUser*) {
// Default: Just iterate // Default: Just iterate
cleanFileline(nodep); cleanFileline(nodep);
checkExpected(nodep); // So we detect node types we forgot to list here
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
} }
@ -423,13 +306,11 @@ public:
// CONSTUCTORS // CONSTUCTORS
LinkParseVisitor(AstNetlist* rootp) { LinkParseVisitor(AstNetlist* rootp) {
m_varp = NULL; m_varp = NULL;
m_exp = AstParseRefExp::PX_NONE;
m_modp = NULL; m_modp = NULL;
m_inAlways = false; m_inAlways = false;
m_inGenerate = false; m_inGenerate = false;
m_needStart = false; m_needStart = false;
m_valueModp = NULL; m_valueModp = NULL;
m_rightParsep = NULL;
rootp->accept(*this); rootp->accept(*this);
} }
virtual ~LinkParseVisitor() {} virtual ~LinkParseVisitor() {}

View File

@ -74,6 +74,7 @@ struct V3ParseBisonYYSType {
AstNodeSenItem* senitemp; AstNodeSenItem* senitemp;
AstNodeVarRef* varnodep; AstNodeVarRef* varnodep;
AstPackage* packagep; AstPackage* packagep;
AstPackageRef* packagerefp;
AstParseRef* parserefp; AstParseRef* parserefp;
AstPatMember* patmemberp; AstPatMember* patmemberp;
AstPin* pinp; AstPin* pinp;

View File

@ -499,6 +499,7 @@ class AstSenTree;
%token<fl> yP_WILDNOTEQUAL "!=?" %token<fl> yP_WILDNOTEQUAL "!=?"
%token<fl> yP_GTE ">=" %token<fl> yP_GTE ">="
%token<fl> yP_LTE "<=" %token<fl> yP_LTE "<="
%token<fl> yP_LTE__IGNORE "<=-ignored" // Used when expr:<= means assignment
%token<fl> yP_SLEFT "<<" %token<fl> yP_SLEFT "<<"
%token<fl> yP_SRIGHT ">>" %token<fl> yP_SRIGHT ">>"
%token<fl> yP_SSRIGHT ">>>" %token<fl> yP_SSRIGHT ">>>"
@ -560,7 +561,7 @@ class AstSenTree;
%left '^' yP_XNOR %left '^' yP_XNOR
%left '&' yP_NAND %left '&' yP_NAND
%left yP_EQUAL yP_NOTEQUAL yP_CASEEQUAL yP_CASENOTEQUAL yP_WILDEQUAL yP_WILDNOTEQUAL %left yP_EQUAL yP_NOTEQUAL yP_CASEEQUAL yP_CASENOTEQUAL yP_WILDEQUAL yP_WILDNOTEQUAL
%left '>' '<' yP_GTE yP_LTE %left '>' '<' yP_GTE yP_LTE yP_LTE__IGNORE
%left yP_SLEFT yP_SRIGHT yP_SSRIGHT %left yP_SLEFT yP_SRIGHT yP_SSRIGHT
%left '+' '-' %left '+' '-'
%left '*' '/' '%' %left '*' '/' '%'
@ -2023,8 +2024,7 @@ statement_item<nodep>: // IEEE: statement_item
//UNSUP fexprLvalue '=' dynamic_array_new ';' { UNSUP } //UNSUP fexprLvalue '=' dynamic_array_new ';' { UNSUP }
// //
// // IEEE: nonblocking_assignment // // IEEE: nonblocking_assignment
| idClassSel yP_LTE delayE expr ';' { $$ = new AstAssignDly($2,$1,$4); } | fexprLvalue yP_LTE delayE expr ';' { $$ = new AstAssignDly($2,$1,$4); }
| '{' variable_lvalueConcList '}' yP_LTE delayE expr ';' { $$ = new AstAssignDly($4,$2,$6); }
//UNSUP fexprLvalue yP_LTE delay_or_event_controlE expr ';' { UNSUP } //UNSUP fexprLvalue yP_LTE delay_or_event_controlE expr ';' { UNSUP }
// //
// // IEEE: procedural_continuous_assignment // // IEEE: procedural_continuous_assignment
@ -2065,7 +2065,7 @@ statement_item<nodep>: // IEEE: statement_item
// // Expr here must result in a subroutine_call // // Expr here must result in a subroutine_call
| task_subroutine_callNoMethod ';' { $$ = $1; } | task_subroutine_callNoMethod ';' { $$ = $1; }
//UNSUP fexpr '.' array_methodNoRoot ';' { UNSUP } //UNSUP fexpr '.' array_methodNoRoot ';' { UNSUP }
//UNSUP fexpr '.' task_subroutine_callNoMethod ';' { UNSUP } | fexpr '.' task_subroutine_callNoMethod ';' { $$ = new AstDot($<fl>2,$1,$3); }
//UNSUP fexprScope ';' { UNSUP } //UNSUP fexprScope ';' { UNSUP }
// // Not here in IEEE; from class_constructor_declaration // // Not here in IEEE; from class_constructor_declaration
// // Because we've joined class_constructor_declaration into generic functions // // Because we've joined class_constructor_declaration into generic functions
@ -2140,35 +2140,22 @@ statementVerilatorPragmas<nodep>:
; ;
foperator_assignment<nodep>: // IEEE: operator_assignment (for first part of expression) foperator_assignment<nodep>: // IEEE: operator_assignment (for first part of expression)
idClassSel '=' delayE expr { $$ = new AstAssign($2,$1,$4); } fexprLvalue '=' delayE expr { $$ = new AstAssign($2,$1,$4); }
| idClassSel '=' yD_FOPEN '(' expr ',' expr ')' { $$ = new AstFOpen($3,$1,$5,$7); } | fexprLvalue '=' yD_FOPEN '(' expr ',' expr ')' { $$ = new AstFOpen($3,$1,$5,$7); }
| '{' variable_lvalueConcList '}' '=' delayE expr { $$ = new AstAssign($4,$2,$6); }
// //
//UNSUP ~f~exprLvalue '=' delay_or_event_controlE expr { UNSUP } //UNSUP ~f~exprLvalue '=' delay_or_event_controlE expr { UNSUP }
//UNSUP ~f~exprLvalue yP_PLUS(etc) expr { UNSUP } //UNSUP ~f~exprLvalue yP_PLUS(etc) expr { UNSUP }
| idClassSel yP_PLUSEQ expr { $$ = new AstAssign($2,$1,new AstAdd ($2,$1->cloneTree(true),$3)); } | fexprLvalue yP_PLUSEQ expr { $$ = new AstAssign($2,$1,new AstAdd ($2,$1->cloneTree(true),$3)); }
| idClassSel yP_MINUSEQ expr { $$ = new AstAssign($2,$1,new AstSub ($2,$1->cloneTree(true),$3)); } | fexprLvalue yP_MINUSEQ expr { $$ = new AstAssign($2,$1,new AstSub ($2,$1->cloneTree(true),$3)); }
| idClassSel yP_TIMESEQ expr { $$ = new AstAssign($2,$1,new AstMul ($2,$1->cloneTree(true),$3)); } | fexprLvalue yP_TIMESEQ expr { $$ = new AstAssign($2,$1,new AstMul ($2,$1->cloneTree(true),$3)); }
| idClassSel yP_DIVEQ expr { $$ = new AstAssign($2,$1,new AstDiv ($2,$1->cloneTree(true),$3)); } | fexprLvalue yP_DIVEQ expr { $$ = new AstAssign($2,$1,new AstDiv ($2,$1->cloneTree(true),$3)); }
| idClassSel yP_MODEQ expr { $$ = new AstAssign($2,$1,new AstModDiv ($2,$1->cloneTree(true),$3)); } | fexprLvalue yP_MODEQ expr { $$ = new AstAssign($2,$1,new AstModDiv ($2,$1->cloneTree(true),$3)); }
| idClassSel yP_ANDEQ expr { $$ = new AstAssign($2,$1,new AstAnd ($2,$1->cloneTree(true),$3)); } | fexprLvalue yP_ANDEQ expr { $$ = new AstAssign($2,$1,new AstAnd ($2,$1->cloneTree(true),$3)); }
| idClassSel yP_OREQ expr { $$ = new AstAssign($2,$1,new AstOr ($2,$1->cloneTree(true),$3)); } | fexprLvalue yP_OREQ expr { $$ = new AstAssign($2,$1,new AstOr ($2,$1->cloneTree(true),$3)); }
| idClassSel yP_XOREQ expr { $$ = new AstAssign($2,$1,new AstXor ($2,$1->cloneTree(true),$3)); } | fexprLvalue yP_XOREQ expr { $$ = new AstAssign($2,$1,new AstXor ($2,$1->cloneTree(true),$3)); }
| idClassSel yP_SLEFTEQ expr { $$ = new AstAssign($2,$1,new AstShiftL ($2,$1->cloneTree(true),$3)); } | fexprLvalue yP_SLEFTEQ expr { $$ = new AstAssign($2,$1,new AstShiftL ($2,$1->cloneTree(true),$3)); }
| idClassSel yP_SRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftR ($2,$1->cloneTree(true),$3)); } | fexprLvalue yP_SRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftR ($2,$1->cloneTree(true),$3)); }
| idClassSel yP_SSRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftRS($2,$1->cloneTree(true),$3)); } | fexprLvalue yP_SSRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftRS($2,$1->cloneTree(true),$3)); }
//
| '{' variable_lvalueConcList '}' yP_PLUSEQ expr { $$ = new AstAssign($4,$2,new AstAdd ($4,$2->cloneTree(true),$5)); }
| '{' variable_lvalueConcList '}' yP_MINUSEQ expr { $$ = new AstAssign($4,$2,new AstSub ($4,$2->cloneTree(true),$5)); }
| '{' variable_lvalueConcList '}' yP_TIMESEQ expr { $$ = new AstAssign($4,$2,new AstMul ($4,$2->cloneTree(true),$5)); }
| '{' variable_lvalueConcList '}' yP_DIVEQ expr { $$ = new AstAssign($4,$2,new AstDiv ($4,$2->cloneTree(true),$5)); }
| '{' variable_lvalueConcList '}' yP_MODEQ expr { $$ = new AstAssign($4,$2,new AstModDiv ($4,$2->cloneTree(true),$5)); }
| '{' variable_lvalueConcList '}' yP_ANDEQ expr { $$ = new AstAssign($4,$2,new AstAnd ($4,$2->cloneTree(true),$5)); }
| '{' variable_lvalueConcList '}' yP_OREQ expr { $$ = new AstAssign($4,$2,new AstOr ($4,$2->cloneTree(true),$5)); }
| '{' variable_lvalueConcList '}' yP_XOREQ expr { $$ = new AstAssign($4,$2,new AstXor ($4,$2->cloneTree(true),$5)); }
| '{' variable_lvalueConcList '}' yP_SLEFTEQ expr { $$ = new AstAssign($4,$2,new AstShiftL ($4,$2->cloneTree(true),$5)); }
| '{' variable_lvalueConcList '}' yP_SRIGHTEQ expr { $$ = new AstAssign($4,$2,new AstShiftR ($4,$2->cloneTree(true),$5)); }
| '{' variable_lvalueConcList '}' yP_SSRIGHTEQ expr { $$ = new AstAssign($4,$2,new AstShiftRS($4,$2->cloneTree(true),$5)); }
; ;
finc_or_dec_expression<nodep>: // ==IEEE: inc_or_dec_expression finc_or_dec_expression<nodep>: // ==IEEE: inc_or_dec_expression
@ -2309,15 +2296,13 @@ for_step<nodep>: // IEEE: for_step
//************************************************ //************************************************
// Functions/tasks // Functions/tasks
taskRef<parserefp>: // IEEE: part of tf_call taskRef<nodep>: // IEEE: part of tf_call
idDotted { $$ = new AstParseRef($1->fileline(), AstParseRefExp::PX_FTASK, "", $1, new AstTaskRef($1->fileline(),"",NULL)); $$->start(true); } id { $$ = new AstTaskRef($<fl>1,*$1,NULL); }
| idDotted '(' list_of_argumentsE ')' { $$ = new AstParseRef($1->fileline(), AstParseRefExp::PX_FTASK, "", $1, new AstTaskRef($1->fileline(),"",$3)); $$->start(true); } | id '(' list_of_argumentsE ')' { $$ = new AstTaskRef($<fl>1,*$1,$3); }
//UNSUP: package_scopeIdFollows idDotted { } | package_scopeIdFollows id '(' list_of_argumentsE ')' { $$ = AstDot::newIfPkg($<fl>2, $1, new AstTaskRef($<fl>2,*$2,$4)); }
//UNSUP: package_scopeIdFollows idDotted '(' list_of_argumentsE ')' { }
//UNSUP: idDotted is really just id to allow dotted method calls
; ;
funcRef<parserefp>: // IEEE: part of tf_call funcRef<nodep>: // IEEE: part of tf_call
// // package_scope/hierarchical_... is part of expr, so just need ID // // package_scope/hierarchical_... is part of expr, so just need ID
// // making-a id-is-a // // making-a id-is-a
// // ----------------- ------------------ // // ----------------- ------------------
@ -2326,8 +2311,8 @@ funcRef<parserefp>: // IEEE: part of tf_call
// // property_instance property_identifier property_actual_arg // // property_instance property_identifier property_actual_arg
// // sequence_instance sequence_identifier sequence_actual_arg // // sequence_instance sequence_identifier sequence_actual_arg
// // let_expression let_identifier let_actual_arg // // let_expression let_identifier let_actual_arg
idDotted '(' list_of_argumentsE ')' { $$ = new AstParseRef($1->fileline(), AstParseRefExp::PX_FTASK, "", $1, new AstFuncRef($2, "", $3)); $$->start(true); } id '(' list_of_argumentsE ')' { $$ = new AstFuncRef($2, *$1, $3); }
| package_scopeIdFollows idDotted '(' list_of_argumentsE ')' { AstFuncRef* f=new AstFuncRef($3,"",$4); f->packagep($1); $$ = new AstParseRef($2->fileline(), AstParseRefExp::PX_FTASK, "", $2, f); $$->start(true); } | package_scopeIdFollows id '(' list_of_argumentsE ')' { $$ = AstDot::newIfPkg($<fl>2, $1, new AstFuncRef($<fl>2,*$2,$4)); }
//UNSUP: idDotted is really just id to allow dotted method calls //UNSUP: idDotted is really just id to allow dotted method calls
; ;
@ -2745,7 +2730,7 @@ expr<nodep>: // IEEE: part of expression/constant_expression/primary
// //
| function_subroutine_callNoMethod { $$ = $1; } | function_subroutine_callNoMethod { $$ = $1; }
// // method_call // // method_call
//UNSUP ~l~expr '.' function_subroutine_callNoMethod { UNSUP } | ~l~expr '.' function_subroutine_callNoMethod { $$ = new AstDot($2,$1,$3); }
// // method_call:array_method requires a '.' // // method_call:array_method requires a '.'
//UNSUP ~l~expr '.' array_methodNoRoot { UNSUP } //UNSUP ~l~expr '.' array_methodNoRoot { UNSUP }
// //
@ -2781,6 +2766,7 @@ expr<nodep>: // IEEE: part of expression/constant_expression/primary
// //
//---------------------- //----------------------
// //
// // Part of expr that may also be used as lvalue
| ~l~exprOkLvalue { $$ = $1; } | ~l~exprOkLvalue { $$ = $1; }
// //
//---------------------- //----------------------
@ -2800,6 +2786,10 @@ expr<nodep>: // IEEE: part of expression/constant_expression/primary
//UNSUP ~l~expr yDIST '{' dist_list '}' { UNSUP } //UNSUP ~l~expr yDIST '{' dist_list '}' { UNSUP }
; ;
fexpr<nodep>: // For use as first part of statement (disambiguates <=)
BISONPRE_COPY(expr,{s/~l~/f/g; s/~r~/f/g; s/~f__IGNORE~/__IGNORE/g;}) // {copied}
;
exprNoStr<nodep>: // expression with string removed exprNoStr<nodep>: // expression with string removed
BISONPRE_COPY(expr,{s/~noStr__IGNORE~/Ignore/g;}) // {copied} BISONPRE_COPY(expr,{s/~noStr__IGNORE~/Ignore/g;}) // {copied}
; ;
@ -2818,6 +2808,14 @@ exprOkLvalue<nodep>: // expression that's also OK to use as a variable_lvalue
//UNSUP streaming_concatenation { UNSUP } //UNSUP streaming_concatenation { UNSUP }
; ;
fexprOkLvalue<nodep>: // exprOkLValue, For use as first part of statement (disambiguates <=)
BISONPRE_COPY(exprOkLvalue,{s/~l~/f/g}) // {copied}
;
fexprLvalue<nodep>: // For use as first part of statement (disambiguates <=)
fexprOkLvalue { $<fl>$=$<fl>1; $$ = $1; }
;
exprScope<nodep>: // scope and variable for use to inside an expression exprScope<nodep>: // scope and variable for use to inside an expression
// // Here we've split method_call_root | implicit_class_handle | class_scope | package_scope // // Here we've split method_call_root | implicit_class_handle | class_scope | package_scope
// // from the object being called and let expr's "." deal with resolving it. // // from the object being called and let expr's "." deal with resolving it.
@ -2827,17 +2825,20 @@ exprScope<nodep>: // scope and variable for use to inside an expression
// // Or method_call_body without parenthesis // // Or method_call_body without parenthesis
// // See also varRefClassBit, which is the non-expr version of most of this // // See also varRefClassBit, which is the non-expr version of most of this
//UNSUP yTHIS { UNSUP } //UNSUP yTHIS { UNSUP }
idClassSel { $$ = $1; } idArrayed { $$ = $1; }
//UNSUP: idArrayed instead of idClassSel | package_scopeIdFollows idArrayed { $$ = AstDot::newIfPkg($2->fileline(), $1, $2); }
//UNSUP package_scopeIdFollows idArrayed { UNSUP }
//UNSUP class_scopeIdFollows idArrayed { UNSUP } //UNSUP class_scopeIdFollows idArrayed { UNSUP }
//UNSUP ~l~expr '.' idArrayed { UNSUP } | ~l~expr '.' idArrayed { $$ = new AstDot($<fl>2,$1,$3); }
// // expr below must be a "yTHIS" // // expr below must be a "yTHIS"
//UNSUP ~l~expr '.' ySUPER { UNSUP } //UNSUP ~l~expr '.' ySUPER { UNSUP }
// // Part of implicit_class_handle // // Part of implicit_class_handle
//UNSUP ySUPER { UNSUP } //UNSUP ySUPER { UNSUP }
; ;
fexprScope<nodep>: // exprScope, For use as first part of statement (disambiguates <=)
BISONPRE_COPY(exprScope,{s/~l~/f/g}) // {copied}
;
// Psl excludes {}'s by lexer converting to different token // Psl excludes {}'s by lexer converting to different token
exprPsl<nodep>: exprPsl<nodep>:
expr { $$ = $1; } expr { $$ = $1; }
@ -3163,8 +3164,8 @@ variable_lvalueConcList<nodep>: // IEEE: part of variable_lvalue: '{' variable_l
; ;
// VarRef to dotted, and/or arrayed, and/or bit-ranged variable // VarRef to dotted, and/or arrayed, and/or bit-ranged variable
idClassSel<parserefp>: // Misc Ref to dotted, and/or arrayed, and/or bit-ranged variable idClassSel<nodep>: // Misc Ref to dotted, and/or arrayed, and/or bit-ranged variable
idDotted { $$ = new AstParseRef($1->fileline(), AstParseRefExp::PX_VAR_ANY, "", $1, NULL); $$->start(true); } idDotted { $$ = $1; }
// // IEEE: [ implicit_class_handle . | package_scope ] hierarchical_variable_identifier select // // IEEE: [ implicit_class_handle . | package_scope ] hierarchical_variable_identifier select
//UNSUP yTHIS '.' idDotted { UNSUP } //UNSUP yTHIS '.' idDotted { UNSUP }
//UNSUP ySUPER '.' idDotted { UNSUP } //UNSUP ySUPER '.' idDotted { UNSUP }

View File

@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 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.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;

View File

@ -0,0 +1,23 @@
// DESCRIPTION: Verilator: Verilog Test module
module t;
Test0 t0 (.val0('0));
Test1 t1 (.val1('0));
initial begin
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
package params;
parameter P = 7;
endpackage
module Test0 (val0);
parameter Z = 1;
input [Z : 0] val0;
endmodule
module Test1 (val1);
input logic [params::P : 0] val1; // Fully qualified parameter
endmodule