Support interfaces and modports, bug102.

This commit is contained in:
Wilson Snyder 2013-05-27 21:39:19 -04:00
parent 7c834ad118
commit 23bb045a72
56 changed files with 1914 additions and 131 deletions

View File

@ -5,6 +5,8 @@ indicates the contributor was also the author of the fix; Thanks!
* Verilator 3.848 devel * Verilator 3.848 devel
** Support interfaces and modports, bug102. [Byron Bradley, Jeremy Bennett]
**** Fix arrayed input compile error, bug645. [Krzysztof Jankowski] **** Fix arrayed input compile error, bug645. [Krzysztof Jankowski]
**** Fix GCC version runtime changes, bug651. [Jeremy Bennett] **** Fix GCC version runtime changes, bug651. [Jeremy Bennett]

View File

@ -1920,16 +1920,12 @@ uwire keyword.
=head2 SystemVerilog 2005 (IEEE 1800-2005) Support =head2 SystemVerilog 2005 (IEEE 1800-2005) Support
Verilator currently has some support for SystemVerilog synthesis
constructs. As SystemVerilog features enter common usage they are added;
please file a bug if a feature you need is missing.
Verilator supports ==? and !=? operators, ++ and -- in some contexts, Verilator supports ==? and !=? operators, ++ and -- in some contexts,
$bits, $countones, $error, $fatal, $info, $isunknown, $onehot, $onehot0, $bits, $countones, $error, $fatal, $info, $isunknown, $onehot, $onehot0,
$unit, $warning, always_comb, always_ff, always_latch, bit, byte, chandle, $unit, $warning, always_comb, always_ff, always_latch, bit, byte, chandle,
const, do-while, enum, export, final, import, int, logic, longint, package, const, do-while, enum, export, final, import, int, interface, logic,
program, shortint, struct, time, typedef, union, var, void, priority longint, modport, package, program, shortint, struct, time, typedef, union,
case/if, and unique case/if. var, void, priority case/if, and unique case/if.
It also supports .name and .* interconnection. It also supports .name and .* interconnection.
@ -2605,6 +2601,12 @@ and continue keywords.
Inside expressions may not include unpacked array traversal or $ as an Inside expressions may not include unpacked array traversal or $ as an
upper bound. Case inside and case matches are also unsupported. upper bound. Case inside and case matches are also unsupported.
=item interface
Interfaces and modports, including with generated data types are supported.
Generate blocks around modports are not supported, nor are virtual
interfaces nor unnamed interfaces.
=item priority if, unique if =item priority if, unique if
Priority and unique if's are treated as normal ifs and not asserted to be Priority and unique if's are treated as normal ifs and not asserted to be

View File

@ -410,7 +410,8 @@ public:
BLOCKTEMP, BLOCKTEMP,
MODULETEMP, MODULETEMP,
STMTTEMP, STMTTEMP,
XTEMP XTEMP,
IFACEREF // Used to link Interfaces between modules
}; };
enum en m_e; enum en m_e;
inline AstVarType () : m_e(UNKNOWN) {} inline AstVarType () : m_e(UNKNOWN) {}
@ -424,7 +425,8 @@ public:
"SUPPLY0","SUPPLY1","WIRE","IMPLICITWIRE", "SUPPLY0","SUPPLY1","WIRE","IMPLICITWIRE",
"TRIWIRE","TRI0","TRI1", "TRIWIRE","TRI0","TRI1",
"PORT", "PORT",
"BLOCKTEMP","MODULETEMP","STMTTEMP","XTEMP"}; "BLOCKTEMP","MODULETEMP","STMTTEMP","XTEMP",
"IFACEREF"};
return names[m_e]; } return names[m_e]; }
bool isSignal() const { return (m_e==WIRE || m_e==IMPLICITWIRE bool isSignal() const { return (m_e==WIRE || m_e==IMPLICITWIRE
|| m_e==TRIWIRE || m_e==TRIWIRE
@ -1850,4 +1852,9 @@ inline int AstNodeArrayDType::lsb() const { return rangep()->lsbConst(); }
inline int AstNodeArrayDType::elementsConst() const { return rangep()->elementsConst(); } inline int AstNodeArrayDType::elementsConst() const { return rangep()->elementsConst(); }
inline VNumRange AstNodeArrayDType::declRange() const { return VNumRange(msb(), lsb(), rangep()->littleEndian()); } inline VNumRange AstNodeArrayDType::declRange() const { return VNumRange(msb(), lsb(), rangep()->littleEndian()); }
inline void AstIfaceRefDType::cloneRelink() {
if (m_cellp && m_cellp->clonep()) m_cellp = m_cellp->clonep()->castCell();
if (m_ifacep && m_ifacep->clonep()) m_ifacep = m_ifacep->clonep()->castIface();
if (m_modportp && m_modportp->clonep()) m_modportp = m_modportp->clonep()->castModport(); }
#endif // Guard #endif // Guard

View File

@ -35,6 +35,17 @@
// Special methods // Special methods
// We need these here, because the classes they point to aren't defined when we declare the class // We need these here, because the classes they point to aren't defined when we declare the class
const char* AstIfaceRefDType::broken() const {
BROKEN_RTN(m_ifacep && !m_ifacep->brokeExists());
BROKEN_RTN(m_cellp && !m_cellp->brokeExists());
BROKEN_RTN(m_modportp && !m_modportp->brokeExists());
return NULL;
}
AstIface* AstIfaceRefDType::ifaceViaCellp() const {
return ((m_cellp && m_cellp->modp()) ? m_cellp->modp()->castIface() : m_ifacep);
}
const char* AstNodeVarRef::broken() const { const char* AstNodeVarRef::broken() const {
BROKEN_RTN(m_varScopep && !m_varScopep->brokeExists()); BROKEN_RTN(m_varScopep && !m_varScopep->brokeExists());
BROKEN_RTN(m_varp && !m_varp->brokeExists()); BROKEN_RTN(m_varp && !m_varp->brokeExists());
@ -723,12 +734,31 @@ void AstEnumItemRef::dump(ostream& str) {
if (itemp()) { itemp()->dump(str); } if (itemp()) { itemp()->dump(str); }
else { str<<"UNLINKED"; } else { str<<"UNLINKED"; }
} }
void AstIfaceRefDType::dump(ostream& str) {
this->AstNode::dump(str);
if (cellName()!="") { str<<" cell="<<cellName(); }
if (ifaceName()!="") { str<<" if="<<ifaceName(); }
if (modportName()!="") { str<<" mp="<<modportName(); }
if (cellp()) { str<<" -> "; cellp()->dump(str); }
else if (ifacep()) { str<<" -> "; ifacep()->dump(str); }
else { str<<" -> UNLINKED"; }
}
void AstIfaceRefDType::dumpSmall(ostream& str) {
this->AstNodeDType::dumpSmall(str);
str<<"iface";
}
void AstJumpGo::dump(ostream& str) { void AstJumpGo::dump(ostream& str) {
this->AstNode::dump(str); this->AstNode::dump(str);
str<<" -> "; str<<" -> ";
if (labelp()) { labelp()->dump(str); } if (labelp()) { labelp()->dump(str); }
else { str<<"%Error:UNLINKED"; } else { str<<"%Error:UNLINKED"; }
} }
void AstModportVarRef::dump(ostream& str) {
this->AstNode::dump(str);
str<<" "<<varType();
if (varp()) { str<<" -> "; varp()->dump(str); }
else { str<<" -> UNLINKED"; }
}
void AstPin::dump(ostream& str) { void AstPin::dump(ostream& str) {
this->AstNode::dump(str); this->AstNode::dump(str);
if (modVarp()) { str<<" -> "; modVarp()->dump(str); } if (modVarp()) { str<<" -> "; modVarp()->dump(str); }

View File

@ -432,6 +432,48 @@ public:
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); } virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); }
}; };
struct AstIfaceRefDType : public AstNodeDType {
// Reference to an interface, either for a port, or inside parent cell
private:
string m_cellName; // "" = no cell, such as when connects to 'input' iface
string m_ifaceName; // Interface name
string m_modportName; // "" = no modport
AstIface* m_ifacep; // Pointer to interface; note cellp() should override
AstCell* m_cellp; // When exact parent cell known; not a guess
AstModport* m_modportp; // NULL = unlinked or no modport
public:
AstIfaceRefDType(FileLine* fl, const string& cellName, const string& ifaceName)
: AstNodeDType(fl), m_cellName(cellName), m_ifaceName(ifaceName), m_modportName(""),
m_ifacep(NULL), m_cellp(NULL), m_modportp(NULL) { }
AstIfaceRefDType(FileLine* fl, const string& cellName, const string& ifaceName, const string& modport)
: AstNodeDType(fl), m_cellName(cellName), m_ifaceName(ifaceName), m_modportName(modport),
m_ifacep(NULL), m_cellp(NULL), m_modportp(NULL) { }
ASTNODE_NODE_FUNCS(IfaceRefDType, IFACEREFDTYPE)
// METHODS
virtual const char* broken() const;
virtual void dump(ostream& str=cout);
virtual void dumpSmall(ostream& str);
virtual void cloneRelink();
virtual AstBasicDType* basicp() const { return NULL; }
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
virtual int widthAlignBytes() const { return 1; }
virtual int widthTotalBytes() const { return 1; }
string cellName() const { return m_cellName; }
void cellName(const string& name) { m_cellName=name; }
string ifaceName() const { return m_ifaceName; }
void ifaceName(const string& name) { m_ifaceName=name; }
string modportName() const { return m_modportName; }
void modportName(const string& name) { m_modportName=name; }
AstIface* ifaceViaCellp() const; // Use cellp or ifacep
AstIface* ifacep() const { return m_ifacep; }
void ifacep(AstIface* nodep) { m_ifacep=nodep; }
AstCell* cellp() const { return m_cellp; }
void cellp(AstCell* nodep) { m_cellp=nodep; }
AstModport* modportp() const { return m_modportp; }
void modportp(AstModport* modportp) { m_modportp=modportp; }
bool isModport() { return !m_modportName.empty(); }
};
struct AstRefDType : public AstNodeDType { struct AstRefDType : public AstNodeDType {
private: private:
AstNodeDType* m_refDTypep; // data type pointed to, BELOW the AstTypedef AstNodeDType* m_refDTypep; // data type pointed to, BELOW the AstTypedef
@ -843,6 +885,7 @@ private:
bool m_isStatic:1; // Static variable bool m_isStatic:1; // Static variable
bool m_isPulldown:1; // Tri0 bool m_isPulldown:1; // Tri0
bool m_isPullup:1; // Tri1 bool m_isPullup:1; // Tri1
bool m_isIfaceParent:1; // dtype is reference to interface present in this module
bool m_trace:1; // Trace this variable bool m_trace:1; // Trace this variable
void init() { void init() {
@ -854,6 +897,7 @@ private:
m_funcLocal=false; m_funcReturn=false; m_funcLocal=false; m_funcReturn=false;
m_attrClockEn=false; m_attrScBv=false; m_attrIsolateAssign=false; m_attrSFormat=false; m_attrClockEn=false; m_attrScBv=false; m_attrIsolateAssign=false; m_attrSFormat=false;
m_fileDescr=false; m_isConst=false; m_isStatic=false; m_isPulldown=false; m_isPullup=false; m_fileDescr=false; m_isConst=false; m_isStatic=false; m_isPulldown=false; m_isPullup=false;
m_isIfaceParent=false;
m_trace=false; m_trace=false;
} }
public: public:
@ -944,6 +988,7 @@ public:
void primaryIO(bool flag) { m_primaryIO = flag; } void primaryIO(bool flag) { m_primaryIO = flag; }
void isConst(bool flag) { m_isConst = flag; } void isConst(bool flag) { m_isConst = flag; }
void isStatic(bool flag) { m_isStatic = flag; } void isStatic(bool flag) { m_isStatic = flag; }
void isIfaceParent(bool flag) { m_isIfaceParent = flag; }
void funcLocal(bool flag) { m_funcLocal = flag; } void funcLocal(bool flag) { m_funcLocal = flag; }
void funcReturn(bool flag) { m_funcReturn = flag; } void funcReturn(bool flag) { m_funcReturn = flag; }
void trace(bool flag) { m_trace=flag; } void trace(bool flag) { m_trace=flag; }
@ -959,6 +1004,8 @@ public:
bool isPrimaryIO() const { return m_primaryIO; } bool isPrimaryIO() const { return m_primaryIO; }
bool isPrimaryIn() const { return isPrimaryIO() && isInput(); } bool isPrimaryIn() const { return isPrimaryIO() && isInput(); }
bool isIO() const { return (m_input||m_output); } bool isIO() const { return (m_input||m_output); }
bool isIfaceRef() const { return (varType()==AstVarType::IFACEREF); }
bool isIfaceParent() const { return m_isIfaceParent; }
bool isSignal() const { return varType().isSignal(); } bool isSignal() const { return varType().isSignal(); }
bool isTemp() const { return (varType()==AstVarType::BLOCKTEMP || varType()==AstVarType::MODULETEMP bool isTemp() const { return (varType()==AstVarType::BLOCKTEMP || varType()==AstVarType::MODULETEMP
|| varType()==AstVarType::STMTTEMP || varType()==AstVarType::XTEMP); } || varType()==AstVarType::STMTTEMP || varType()==AstVarType::XTEMP); }
@ -1298,6 +1345,49 @@ public:
void packagep(AstPackage* nodep) { m_packagep=nodep; } void packagep(AstPackage* nodep) { m_packagep=nodep; }
}; };
struct AstIface : public AstNodeModule {
// A module declaration
AstIface(FileLine* fl, const string& name)
: AstNodeModule (fl,name) { }
ASTNODE_NODE_FUNCS(Iface, IFACE)
};
struct AstModportVarRef : public AstNode {
// A input/output/etc variable referenced under a modport
// The storage for the variable itself is inside the interface, thus this is a reference
// PARENT: AstIface
private:
string m_name; // Name of the variable referenced
AstVarType m_type; // Type of the variable (in/out)
AstVar* m_varp; // Link to the actual Var
public:
AstModportVarRef(FileLine* fl, const string& name, AstVarType::en type)
: AstNode(fl), m_name(name), m_type(type), m_varp(NULL) { }
ASTNODE_NODE_FUNCS(ModportVarRef, MODPORTVARREF)
virtual const char* broken() const { BROKEN_RTN(m_varp && !m_varp->brokeExists()); return NULL; }
virtual void dump(ostream& str);
AstVarType varType() const { return m_type; } // * = Type of variable
virtual string name() const { return m_name; }
bool isInput() const { return (varType()==AstVarType::INPUT || varType()==AstVarType::INOUT); }
bool isOutput() const { return (varType()==AstVarType::OUTPUT || varType()==AstVarType::INOUT); }
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
void varp(AstVar* varp) { m_varp=varp; }
};
struct AstModport : public AstNode {
// A modport in an interface
private:
string m_name; // Name of the modport
public:
AstModport(FileLine* fl, const string& name, AstModportVarRef* varsp)
: AstNode(fl), m_name(name) {
addNOp1p(varsp); }
virtual string name() const { return m_name; }
virtual bool maybePointedTo() const { return true; }
ASTNODE_NODE_FUNCS(Modport, MODPORT)
AstModportVarRef* varsp() const { return op1p()->castModportVarRef(); } // op1 = List of Vars
};
struct AstCell : public AstNode { struct AstCell : public AstNode {
// A instantiation cell or interface call (don't know which until link) // A instantiation cell or interface call (don't know which until link)
private: private:
@ -1305,12 +1395,13 @@ private:
string m_origName; // Original name before dot addition string m_origName; // Original name before dot addition
string m_modName; // Module the cell instances string m_modName; // Module the cell instances
AstNodeModule* m_modp; // [AfterLink] Pointer to module instanced AstNodeModule* m_modp; // [AfterLink] Pointer to module instanced
bool m_hasIfaceVar; // True if a Var has been created for this cell
public: public:
AstCell(FileLine* fl, const string& instName, const string& modName, AstCell(FileLine* fl, const string& instName, const string& modName,
AstPin* pinsp, AstPin* paramsp, AstRange* rangep) AstPin* pinsp, AstPin* paramsp, AstRange* rangep)
: AstNode(fl) : AstNode(fl)
, m_name(instName), m_origName(instName), m_modName(modName) , m_name(instName), m_origName(instName), m_modName(modName)
, m_modp(NULL) { , m_modp(NULL), m_hasIfaceVar(false) {
addNOp1p(pinsp); addNOp2p(paramsp); setNOp3p(rangep); } addNOp1p(pinsp); addNOp2p(paramsp); setNOp3p(rangep); }
ASTNODE_NODE_FUNCS(Cell, CELL) ASTNODE_NODE_FUNCS(Cell, CELL)
// No cloneRelink, we presume cloneee's want the same module linkages // No cloneRelink, we presume cloneee's want the same module linkages
@ -1331,6 +1422,8 @@ public:
void addPinsp(AstPin* nodep) { addOp1p(nodep); } void addPinsp(AstPin* nodep) { addOp1p(nodep); }
void addParamsp(AstPin* nodep) { addOp2p(nodep); } void addParamsp(AstPin* nodep) { addOp2p(nodep); }
void modp(AstNodeModule* nodep) { m_modp = nodep; } void modp(AstNodeModule* nodep) { m_modp = nodep; }
bool hasIfaceVar() const { return m_hasIfaceVar; }
void hasIfaceVar(bool flag) { m_hasIfaceVar = flag; }
}; };
struct AstCellInline : public AstNode { struct AstCellInline : public AstNode {
@ -1713,6 +1806,16 @@ struct AstAssignW : public AstNodeAssign {
} }
}; };
struct AstAssignVarScope : public AstNodeAssign {
// Assign two VarScopes to each other
AstAssignVarScope(FileLine* fileline, AstNode* lhsp, AstNode* rhsp)
: AstNodeAssign(fileline, lhsp, rhsp) {
dtypeFrom(rhsp);
}
ASTNODE_NODE_FUNCS(AssignVarScope, ASSIGNVARSCOPE)
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAssignVarScope(this->fileline(), lhsp, rhsp); }
};
struct AstPull : public AstNode { struct AstPull : public AstNode {
private: private:
bool m_direction; bool m_direction;

View File

@ -1466,6 +1466,9 @@ private:
virtual void visit(AstAssignAlias* nodep, AstNUser*) { virtual void visit(AstAssignAlias* nodep, AstNUser*) {
// Don't perform any optimizations, keep the alias around // Don't perform any optimizations, keep the alias around
} }
virtual void visit(AstAssignVarScope* nodep, AstNUser*) {
// Don't perform any optimizations, the node won't be linked yet
}
virtual void visit(AstAssignW* nodep, AstNUser*) { virtual void visit(AstAssignW* nodep, AstNUser*) {
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
if (m_doNConst && replaceNodeAssign(nodep)) return; if (m_doNConst && replaceNodeAssign(nodep)) return;

View File

@ -95,6 +95,11 @@ private:
m_stmtCnt = 0; m_stmtCnt = 0;
m_modp = nodep; m_modp = nodep;
m_modp->user2(CIL_MAYBE); m_modp->user2(CIL_MAYBE);
if (m_modp->castIface()) {
// Inlining an interface means we no longer have a cell handle to resolve to.
// If inlining moves post-scope this can perhaps be relaxed.
cantInline("modIface",true);
}
if (m_modp->modPublic()) cantInline("modPublic",false); if (m_modp->modPublic()) cantInline("modPublic",false);
// //
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
@ -146,6 +151,14 @@ private:
// Cleanup link until V3LinkDot can correct it // Cleanup link until V3LinkDot can correct it
nodep->varp(NULL); nodep->varp(NULL);
} }
virtual void visit(AstVar* nodep, AstNUser*) {
// Can't look at AstIfaceRefDType directly as it is no longer underneath the module
if (nodep->isIfaceRef()) {
// Unsupported: Inlining of modules with ifaces (see AstIface comment above)
if (m_modp) cantInline("Interfaced",true);
}
nodep->iterateChildren(*this);
}
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) { virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
// Cleanup link until V3LinkDot can correct it // Cleanup link until V3LinkDot can correct it
if (!nodep->packagep()) nodep->taskp(NULL); if (!nodep->packagep()) nodep->taskp(NULL);
@ -185,6 +198,41 @@ public:
} }
}; };
//######################################################################
// Using clonep(), find cell cross references.
// clone() must not be called inside this visitor
class InlineCollectVisitor : public AstNVisitor {
private:
// NODE STATE
// Output:
// AstCell::user4p() // AstCell* of the created clone
static int debug() {
static int level = -1;
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
return level;
}
// VISITORS
virtual void visit(AstCell* nodep, AstNUser*) {
nodep->user4p(nodep->clonep());
}
// Accelerate
virtual void visit(AstNodeStmt* nodep, AstNUser*) {}
virtual void visit(AstNodeMath* nodep, AstNUser*) {}
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->iterateChildren(*this);
}
public:
// CONSTUCTORS
InlineCollectVisitor(AstNodeModule* nodep) { // passed OLD module, not new one
nodep->accept(*this);
}
virtual ~InlineCollectVisitor() {}
};
//###################################################################### //######################################################################
// After cell is cloned, relink the new module's contents // After cell is cloned, relink the new module's contents
@ -245,6 +293,13 @@ private:
m_modp->addStmtp(new AstAssignW(nodep->fileline(), m_modp->addStmtp(new AstAssignW(nodep->fileline(),
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true), new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true),
new AstVarRef(nodep->fileline(), nodep, false))); new AstVarRef(nodep->fileline(), nodep, false)));
} else if (nodep->isIfaceRef()) {
m_modp->addStmtp(new AstAssignVarScope(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep, true),
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false)));
AstNode* nodebp=exprvarrefp->varp();
nodep ->fileline()->modifyStateInherit(nodebp->fileline());
nodebp->fileline()->modifyStateInherit(nodep ->fileline());
} else { } else {
// Do to inlining child's variable now within the same module, so a AstVarRef not AstVarXRef below // Do to inlining child's variable now within the same module, so a AstVarRef not AstVarXRef below
m_modp->addStmtp(new AstAssignAlias(nodep->fileline(), m_modp->addStmtp(new AstAssignAlias(nodep->fileline(),
@ -261,7 +316,17 @@ private:
if (!nodep->isFuncLocal()) nodep->inlineAttrReset(name); if (!nodep->isFuncLocal()) nodep->inlineAttrReset(name);
if (debug()>=9) { nodep->dumpTree(cout,"varchanged:"); } if (debug()>=9) { nodep->dumpTree(cout,"varchanged:"); }
if (debug()>=9) { nodep->valuep()->dumpTree(cout,"varchangei:"); } if (debug()>=9) { nodep->valuep()->dumpTree(cout,"varchangei:"); }
if (nodep) nodep->iterateChildren(*this); // Iterate won't hit AstIfaceRefDType directly as it is no longer underneath the module
if (AstIfaceRefDType* ifacerefp = nodep->dtypep()->castIfaceRefDType()) {
// Relink to point to newly cloned cell
if (ifacerefp->cellp()) {
if (AstCell* newcellp = ifacerefp->cellp()->user4p()->castNode()->castCell()) {
ifacerefp->cellp(newcellp);
ifacerefp->cellName(newcellp->name());
}
}
}
nodep->iterateChildren(*this);
} }
virtual void visit(AstNodeFTask* nodep, AstNUser*) { virtual void visit(AstNodeFTask* nodep, AstNUser*) {
// Function under the inline cell, need to rename to avoid conflicts // Function under the inline cell, need to rename to avoid conflicts
@ -357,6 +422,9 @@ private:
// Cleared each cell // Cleared each cell
// AstVar::user2p() // AstVarRef*/AstConst* Points to signal this is a direct connect to // AstVar::user2p() // AstVarRef*/AstConst* Points to signal this is a direct connect to
// AstVar::user3() // bool Don't alias the user2, keep it as signal // AstVar::user3() // bool Don't alias the user2, keep it as signal
// AstCell::user4 // AstCell* of the created clone
AstUser4InUse m_inuser4;
// STATE // STATE
AstNodeModule* m_modp; // Current module AstNodeModule* m_modp; // Current module
@ -397,8 +465,10 @@ private:
//if (debug()>=9) { nodep->modp()->dumpTree(cout,"oldmod:"); } //if (debug()>=9) { nodep->modp()->dumpTree(cout,"oldmod:"); }
AstNodeModule* newmodp = nodep->modp()->cloneTree(false); AstNodeModule* newmodp = nodep->modp()->cloneTree(false);
if (debug()>=9) { newmodp->dumpTree(cout,"newmod:"); } if (debug()>=9) { newmodp->dumpTree(cout,"newmod:"); }
// Clear var markings // Clear var markings and find cell cross references
AstNode::user2ClearTree(); AstNode::user2ClearTree();
AstNode::user4ClearTree();
{ InlineCollectVisitor(nodep->modp()); } // {} to destroy visitor immediately
// Create data for dotted variable resolution // Create data for dotted variable resolution
AstCellInline* inlinep = new AstCellInline(nodep->fileline(), AstCellInline* inlinep = new AstCellInline(nodep->fileline(),
nodep->name(), nodep->modp()->origName()); nodep->name(), nodep->modp()->origName());

View File

@ -105,6 +105,13 @@ private:
exprp); exprp);
m_modp->addStmtp(assp); m_modp->addStmtp(assp);
if (debug()>=9) assp->dumpTree(cout," _new: "); if (debug()>=9) assp->dumpTree(cout," _new: ");
} else if (nodep->modVarp()->isIfaceRef()) {
// Create an AstAssignVarScope for Vars to Cells so we can link with their scope later
AstNode* lhsp = new AstVarXRef (exprp->fileline(), nodep->modVarp(), m_cellp->name(), false);
AstVarRef* refp = exprp->castVarRef();
if (!refp) exprp->v3fatalSrc("Interfaces: Pin is not connected to a VarRef");
AstAssignVarScope* assp = new AstAssignVarScope(exprp->fileline(), lhsp, refp);
m_modp->addStmtp(assp);
} else { } else {
nodep->v3error("Assigned pin is neither input nor output"); nodep->v3error("Assigned pin is neither input nor output");
} }
@ -252,7 +259,11 @@ AstAssignW* V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp, AstNodeModu
&& connectRefp && connectRefp
&& connectRefp->varp()->dtypep()->sameTree(pinVarp->dtypep()) && connectRefp->varp()->dtypep()->sameTree(pinVarp->dtypep())
&& !connectRefp->varp()->isSc()) { // Need the signal as a 'shell' to convert types && !connectRefp->varp()->isSc()) { // Need the signal as a 'shell' to convert types
// Done. Same data type // Done. Same data type
} else if (!alwaysCvt
&& connectRefp
&& connectRefp->varp()->isIfaceRef()) {
// Done. Interface
} else if (!alwaysCvt } else if (!alwaysCvt
&& connBasicp && connBasicp
&& pinBasicp && pinBasicp

View File

@ -190,6 +190,7 @@ private:
<<"' does not match "<<nodep->typeName()<<" name: "<<nodep->prettyName()); <<"' does not match "<<nodep->typeName()<<" name: "<<nodep->prettyName());
} }
} }
if (nodep->castIface() || nodep->castPackage()) nodep->inLibrary(true); // Interfaces can't be at top, unless asked
bool topMatch = (v3Global.opt.topModule()==nodep->prettyName()); bool topMatch = (v3Global.opt.topModule()==nodep->prettyName());
if (topMatch) { if (topMatch) {
m_topVertexp = vertex(nodep); m_topVertexp = vertex(nodep);
@ -210,6 +211,25 @@ private:
m_modp = NULL; m_modp = NULL;
} }
virtual void visit(AstIfaceRefDType* nodep, AstNUser*) {
// Cell: Resolve its filename. If necessary, parse it.
UINFO(4,"Link IfaceRef: "<<nodep<<endl);
// Use findIdUpward instead of findIdFlat; it doesn't matter for now
// but we might support modules-under-modules someday.
AstNodeModule* modp = resolveModule(nodep, nodep->ifaceName());
if (modp) {
if (modp->castIface()) {
// Track module depths, so can sort list from parent down to children
new V3GraphEdge(&m_graph, vertex(m_modp), vertex(modp), 1, false);
if (!nodep->cellp()) nodep->ifacep(modp->castIface());
} else if (modp->castNotFoundModule()) { // Will error out later
} else {
nodep->v3error("Non-interface used as an interface: "<<nodep->prettyName());
}
}
// Note cannot do modport resolution here; modports are allowed underneath generates
}
virtual void visit(AstPackageImport* nodep, AstNUser*) { virtual void visit(AstPackageImport* nodep, AstNUser*) {
// Package Import: We need to do the package before the use of a package // Package Import: We need to do the package before the use of a package
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
@ -314,6 +334,23 @@ private:
} }
} }
} }
if (nodep->modp()->castIface()) {
// Cell really is the parent's instantiation of an interface, not a normal module
// Make sure we have a variable to refer to this cell, so can <ifacename>.<innermember>
// in the same way that a child does. Rename though to avoid conflict with cell.
// This is quite similar to how classes work; when unpacked classes are better supported
// may remap interfaces to be more like a class.
if (!nodep->hasIfaceVar()) {
string varName = nodep->name()+"__Viftop"; // V3LinkDot looks for this naming
AstIfaceRefDType* idtypep = new AstIfaceRefDType(nodep->fileline(), nodep->name(), nodep->modp()->name());
idtypep->cellp(nodep); // Only set when real parent cell known
idtypep->ifacep(NULL); // cellp overrides
AstVar* varp = new AstVar(nodep->fileline(), AstVarType::IFACEREF, varName, VFlagChildDType(), idtypep);
varp->isIfaceParent(true);
nodep->addNextHere(varp);
nodep->hasIfaceVar(true);
}
}
if (nodep->modp()) { if (nodep->modp()) {
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
} }

View File

@ -31,6 +31,26 @@
// VarXRef/Func's: // VarXRef/Func's:
// Find appropriate named cell and link to var they reference // Find appropriate named cell and link to var they reference
//************************************************************************* //*************************************************************************
// Interfaces:
// CELL (.port (ifref)
// ^--- cell -> IfaceDTypeRef(iface)
// ^--- cell.modport -> IfaceDTypeRef(iface,modport)
// ^--- varref(input_ifref) -> IfaceDTypeRef(iface)
// ^--- varref(input_ifref).modport -> IfaceDTypeRef(iface,modport)
// FindVisitor:
// #1: Insert interface Vars
// #2: Insert ModPort names
// IfaceVisitor:
// #3: Update ModPortVarRef to point at interface vars (after #1)
// #4: Create ModPortVarRef symbol table entries
// FindVisitor-insertIfaceRefs()
// #5: Resolve IfaceRefDtype modport names (after #2)
// #7: Record sym of IfaceRefDType and aliased interface and/or modport (after #4,#5)
// insertAllScopeAliases():
// #8: Insert modport's symbols under IfaceRefDType (after #7)
// ResolveVisitor:
// #9: Resolve general variables, which may point into the interface or modport (after #8)
//*************************************************************************
// TOP // TOP
// {name-of-top-modulename} // {name-of-top-modulename}
// a (VSymEnt->AstCell) // a (VSymEnt->AstCell)
@ -77,8 +97,11 @@ private:
AstUser4InUse m_inuser4; AstUser4InUse m_inuser4;
// TYPES // TYPES
typedef std::multimap<string,VSymEnt*> NameScopeSymMap; typedef multimap<string,VSymEnt*> NameScopeSymMap;
typedef set <pair<AstNodeModule*,string> > ImplicitNameSet; typedef map<VSymEnt*,VSymEnt*> ScopeAliasMap;
typedef set<pair<AstNodeModule*,string> > ImplicitNameSet;
typedef vector<VSymEnt*> IfaceVarSyms;
typedef vector<pair<AstIface*,VSymEnt*> > IfaceModSyms;
static LinkDotState* s_errorThisp; // Last self, for error reporting only static LinkDotState* s_errorThisp; // Last self, for error reporting only
@ -87,6 +110,9 @@ private:
VSymEnt* m_dunitEntp; // $unit entry VSymEnt* m_dunitEntp; // $unit entry
NameScopeSymMap m_nameScopeSymMap; // Map of scope referenced by non-pretty textual name NameScopeSymMap m_nameScopeSymMap; // Map of scope referenced by non-pretty textual name
ImplicitNameSet m_implicitNameSet; // For [module][signalname] if we can implicitly create it ImplicitNameSet m_implicitNameSet; // For [module][signalname] if we can implicitly create it
ScopeAliasMap m_scopeAliasMap; // Map of <lhs,rhs> aliases
IfaceVarSyms m_ifaceVarSyms; // List of AstIfaceRefDType's to be imported
IfaceModSyms m_ifaceModSyms; // List of AstIface+Symbols to be processed
bool m_forPrimary; // First link bool m_forPrimary; // First link
bool m_forPrearray; // Compress cell__[array] refs bool m_forPrearray; // Compress cell__[array] refs
bool m_forScopeCreation; // Remove VarXRefs for V3Scope bool m_forScopeCreation; // Remove VarXRefs for V3Scope
@ -105,6 +131,10 @@ public:
if (logp->fail()) v3fatalSrc("Can't write "<<filename); if (logp->fail()) v3fatalSrc("Can't write "<<filename);
ostream& os = *logp; ostream& os = *logp;
m_syms.dump(os); m_syms.dump(os);
if (!m_scopeAliasMap.empty()) os<<"\nScopeAliasMap:\n";
for (ScopeAliasMap::iterator it = m_scopeAliasMap.begin(); it != m_scopeAliasMap.end(); ++it) {
os<<"\t"<<it->first<<" -> "<<it->second<<endl;
}
} }
} }
static void preErrorDumpHandler() { static void preErrorDumpHandler() {
@ -148,6 +178,7 @@ public:
else if (nodep->castTask()) return "task"; else if (nodep->castTask()) return "task";
else if (nodep->castFunc()) return "function"; else if (nodep->castFunc()) return "function";
else if (nodep->castBegin()) return "block"; else if (nodep->castBegin()) return "block";
else if (nodep->castIface()) return "interface";
else return nodep->prettyTypeName(); else return nodep->prettyTypeName();
} }
static string ucfirst(const string& text) { static string ucfirst(const string& text) {
@ -314,6 +345,69 @@ public:
&& (m_implicitNameSet.find(make_pair(nodep,varname)) != m_implicitNameSet.end()); && (m_implicitNameSet.find(make_pair(nodep,varname)) != m_implicitNameSet.end());
} }
// Track and later recurse interface modules
void insertIfaceModSym(AstIface* nodep, VSymEnt* symp) {
m_ifaceModSyms.push_back(make_pair(nodep, symp));
}
void computeIfaceModSyms();
// Track and later insert interface references
void insertIfaceVarSym(VSymEnt* symp) { // Where sym is for a VAR of dtype IFACEREFDTYPE
m_ifaceVarSyms.push_back(symp);
}
void computeIfaceVarSyms() {
for (IfaceVarSyms::iterator it = m_ifaceVarSyms.begin(); it != m_ifaceVarSyms.end(); ++it) {
VSymEnt* varSymp = *it;
AstVar* varp = varSymp->nodep()->castVar();
UINFO(9, " insAllIface se"<<(void*)varSymp<<" "<<varp<<endl);
AstIfaceRefDType* ifacerefp = varp->subDTypep()->castIfaceRefDType();
if (!ifacerefp) varp->v3fatalSrc("Non-ifacerefs on list!");
if (!ifacerefp->ifaceViaCellp()) ifacerefp->v3fatalSrc("Unlinked interface");
VSymEnt* ifaceSymp = getNodeSym(ifacerefp->ifaceViaCellp());
VSymEnt* ifOrPortSymp = ifaceSymp;
// Link Modport names to the Modport Node under the Interface
if (ifacerefp->isModport()) {
VSymEnt* foundp = ifaceSymp->findIdFallback(ifacerefp->modportName());
bool ok = false;
if (foundp) {
if (AstModport* modportp = foundp->nodep()->castModport()) {
UINFO(4,"Link Modport: "<<modportp<<endl);
ifacerefp->modportp(modportp);
ifOrPortSymp = foundp;
ok = true;
}
}
if (!ok) ifacerefp->v3error("Modport not found under interface '"
<<ifacerefp->prettyName(ifacerefp->ifaceName())
<<"': "<<ifacerefp->prettyName(ifacerefp->modportName()));
}
// Alias won't expand until interfaces and modport names are known; see notes at top
insertScopeAlias(varSymp, ifOrPortSymp);
}
m_ifaceVarSyms.clear();
}
// Track and later insert scope aliases
void insertScopeAlias(VSymEnt* lhsp, VSymEnt* rhsp) { // Typically lhsp=VAR w/dtype IFACEREF, rhsp=IFACE cell
UINFO(9," insertScopeAlias se"<<(void*)lhsp<<" se"<<(void*)rhsp<<endl);
m_scopeAliasMap.insert(make_pair(lhsp, rhsp));
}
void computeScopeAliases() {
UINFO(9,"computeIfaceAliases\n");
for (ScopeAliasMap::iterator it=m_scopeAliasMap.begin(); it!=m_scopeAliasMap.end(); ++it) {
VSymEnt* lhsp = it->first;
VSymEnt* srcp = lhsp;
while (1) { // Follow chain of aliases up to highest level non-alias
ScopeAliasMap::iterator it2 = m_scopeAliasMap.find(srcp);
if (it2 != m_scopeAliasMap.end()) { srcp = it2->second; continue; }
else break;
}
UINFO(9," iiasa: Insert alias se"<<lhsp<<" <- se"<<srcp<<" "<<srcp->nodep()<<endl);
// srcp should be an interface reference pointing to the interface we want to import
lhsp->importFromIface(symsp(), srcp);
}
m_scopeAliasMap.clear();
}
private: private:
VSymEnt* findWithAltFallback(VSymEnt* symp, const string& name, const string& altname) { VSymEnt* findWithAltFallback(VSymEnt* symp, const string& name, const string& altname) {
VSymEnt* findp = symp->findIdFallback(name); VSymEnt* findp = symp->findIdFallback(name);
@ -503,6 +597,10 @@ class LinkDotFindVisitor : public AstNVisitor {
// Iterate // Iterate
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
nodep->user4(true); nodep->user4(true);
// Interfaces need another pass when signals are resolved
if (AstIface* ifacep = nodep->castIface()) {
m_statep->insertIfaceModSym(ifacep, m_curSymp);
}
} else { //!doit } else { //!doit
// Will be optimized away later // Will be optimized away later
// Can't remove now, as our backwards iterator will throw up // Can't remove now, as our backwards iterator will throw up
@ -719,12 +817,16 @@ class LinkDotFindVisitor : public AstNVisitor {
} }
} }
if (ins) { if (ins) {
m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep); VSymEnt* insp = m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep);
if (m_statep->forPrimary() && nodep->isGParam()) { if (m_statep->forPrimary() && nodep->isGParam()) {
m_paramNum++; m_paramNum++;
VSymEnt* symp = m_statep->insertSym(m_curSymp, "__paramNumber"+cvtToStr(m_paramNum), nodep, m_packagep); VSymEnt* symp = m_statep->insertSym(m_curSymp, "__paramNumber"+cvtToStr(m_paramNum), nodep, m_packagep);
symp->exported(false); symp->exported(false);
} }
if (nodep->subDTypep()->castIfaceRefDType()) {
// Can't resolve until interfaces and modport names are known; see notes at top
m_statep->insertIfaceVarSym(insp);
}
} }
} }
} }
@ -899,8 +1001,8 @@ private:
AstVar* refp = foundp->nodep()->castVar(); AstVar* refp = foundp->nodep()->castVar();
if (!refp) { if (!refp) {
nodep->v3error("Input/output/inout declaration not found for port: "<<nodep->prettyName()); nodep->v3error("Input/output/inout declaration not found for port: "<<nodep->prettyName());
} else if (!refp->isIO()) { } else if (!refp->isIO() && !refp->isIfaceRef()) {
nodep->v3error("Pin is not an in/out/inout: "<<nodep->prettyName()); nodep->v3error("Pin is not an in/out/inout/interface: "<<nodep->prettyName());
} else { } else {
refp->user4(true); refp->user4(true);
VSymEnt* symp = m_statep->insertSym(m_statep->getNodeSym(m_modp), VSymEnt* symp = m_statep->insertSym(m_statep->getNodeSym(m_modp),
@ -956,9 +1058,10 @@ public:
//====================================================================== //======================================================================
class LinkDotScopeVisitor : public AstNVisitor { class LinkDotScopeVisitor : public AstNVisitor {
private:
// STATE // STATE
LinkDotState* m_statep; // State to pass between visitors, including symbol table LinkDotState* m_statep; // State to pass between visitors, including symbol table
AstScope* m_scopep; // The current scope
VSymEnt* m_modSymp; // Symbol entry for current module VSymEnt* m_modSymp; // Symbol entry for current module
int debug() { return LinkDotState::debug(); } int debug() { return LinkDotState::debug(); }
@ -974,12 +1077,36 @@ private:
// Using the CELL names, we created all hierarchy. We now need to match this Scope // Using the CELL names, we created all hierarchy. We now need to match this Scope
// up with the hierarchy created by the CELL names. // up with the hierarchy created by the CELL names.
m_modSymp = m_statep->getScopeSym(nodep); m_modSymp = m_statep->getScopeSym(nodep);
m_scopep = nodep;
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
m_modSymp = NULL; m_modSymp = NULL;
m_scopep = NULL;
} }
virtual void visit(AstVarScope* nodep, AstNUser*) { virtual void visit(AstVarScope* nodep, AstNUser*) {
if (!nodep->varp()->isFuncLocal()) { if (!nodep->varp()->isFuncLocal()) {
m_statep->insertSym(m_modSymp, nodep->varp()->name(), nodep, NULL); VSymEnt* varSymp = m_statep->insertSym(m_modSymp, nodep->varp()->name(), nodep, NULL);
if (nodep->varp()->isIfaceRef()
&& nodep->varp()->isIfaceParent()) {
UINFO(9,"Iface parent ref var "<<nodep->varp()->name()<<" "<<nodep<<endl);
// Find the interface cell the var references
AstIfaceRefDType* dtypep = nodep->varp()->dtypep()->castIfaceRefDType();
if (!dtypep) nodep->v3fatalSrc("Non AstIfaceRefDType on isIfaceRef() var");
UINFO(9,"Iface parent dtype "<<dtypep<<endl);
string ifcellname = dtypep->cellName();
string baddot; VSymEnt* okSymp;
VSymEnt* cellSymp = m_statep->findDotted(m_modSymp, ifcellname, baddot, okSymp);
if (!cellSymp) nodep->v3fatalSrc("No symbol for interface cell: " <<nodep->prettyName(ifcellname));
UINFO(5, " Found interface cell: se"<<(void*)cellSymp<<" "<<cellSymp->nodep()<<endl);
if (dtypep->modportName()!="") {
VSymEnt* mpSymp = m_statep->findDotted(m_modSymp, ifcellname, baddot, okSymp);
if (!mpSymp) { nodep->v3fatalSrc("No symbol for interface modport: " <<nodep->prettyName(dtypep->modportName())); }
else cellSymp = mpSymp;
UINFO(5, " Found modport cell: se"<<(void*)cellSymp<<" "<<mpSymp->nodep()<<endl);
}
// Interface reference; need to put whole thing into symtable, but can't clone it now
// as we may have a later alias for it.
m_statep->insertScopeAlias(varSymp, cellSymp);
}
} }
} }
virtual void visit(AstNodeFTask* nodep, AstNUser*) { virtual void visit(AstNodeFTask* nodep, AstNUser*) {
@ -997,6 +1124,37 @@ private:
fromVscp->user2p(toVscp); fromVscp->user2p(toVscp);
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
} }
virtual void visit(AstAssignVarScope* nodep, AstNUser*) {
UINFO(5,"ASSIGNVARSCOPE "<<nodep<<endl);
if (debug()>=9) nodep->dumpTree(cout,"-\t\t\t\tavs: ");
VSymEnt* rhsSymp;
{
AstVarRef* refp = nodep->rhsp()->castVarRef();
if (!refp) nodep->v3fatalSrc("Unsupported: Non VarRef attached to interface pin");
string scopename = refp->name();
string baddot; VSymEnt* okSymp;
VSymEnt* symp = m_statep->findDotted(m_modSymp, scopename, baddot, okSymp);
if (!symp) nodep->v3fatalSrc("No symbol for interface alias rhs");
UINFO(5, " Found a linked scope RHS: "<<scopename<<" se"<<(void*)symp<<" "<<symp->nodep()<<endl);
rhsSymp = symp;
}
VSymEnt* lhsSymp;
{
AstVarXRef* refp = nodep->lhsp()->castVarXRef();
if (!refp) nodep->v3fatalSrc("Unsupported: Non VarXRef attached to interface pin");
string scopename = refp->dotted()+"."+refp->name();
string baddot; VSymEnt* okSymp;
VSymEnt* symp = m_statep->findDotted(m_modSymp, scopename, baddot, okSymp);
if (!symp) nodep->v3fatalSrc("No symbol for interface alias lhs");
UINFO(5, " Found a linked scope LHS: "<<scopename<<" se"<<(void*)symp<<" "<<symp->nodep()<<endl);
lhsSymp = symp;
}
// Remember the alias - can't do it yet because we may have additional symbols to be added,
// or maybe an alias of an alias
m_statep->insertScopeAlias(lhsSymp, rhsSymp);
// We have stored the link, we don't need these any more
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
}
// For speed, don't recurse things that can't have scope // For speed, don't recurse things that can't have scope
// Note we allow AstNodeStmt's as generates may be under them // Note we allow AstNodeStmt's as generates may be under them
virtual void visit(AstCell*, AstNUser*) {} virtual void visit(AstCell*, AstNUser*) {}
@ -1012,6 +1170,7 @@ public:
LinkDotScopeVisitor(AstNetlist* rootp, LinkDotState* statep) { LinkDotScopeVisitor(AstNetlist* rootp, LinkDotState* statep) {
UINFO(4,__FUNCTION__<<": "<<endl); UINFO(4,__FUNCTION__<<": "<<endl);
m_modSymp = NULL; m_modSymp = NULL;
m_scopep = NULL;
m_statep = statep; m_statep = statep;
// //
rootp->accept(*this); rootp->accept(*this);
@ -1021,6 +1180,78 @@ public:
//====================================================================== //======================================================================
// Iterate an interface to resolve modports
class LinkDotIfaceVisitor : public AstNVisitor {
// STATE
LinkDotState* m_statep; // State to pass between visitors, including symbol table
VSymEnt* m_curSymp; // Symbol Entry for current table, where to lookup/insert
// METHODS
int debug() { return LinkDotState::debug(); }
// VISITs
virtual void visit(AstModport* nodep, AstNUser*) {
// Modport: Remember its name for later resolution
UINFO(5," fiv: "<<nodep<<endl);
VSymEnt* oldCurSymp = m_curSymp;
{
// Create symbol table for the vars
m_curSymp = m_statep->insertBlock(m_curSymp, nodep->name(), nodep, NULL);
m_curSymp->fallbackp(oldCurSymp);
nodep->iterateChildren(*this);
}
m_curSymp = oldCurSymp;
}
virtual void visit(AstModportVarRef* nodep, AstNUser*) {
UINFO(5," fiv: "<<nodep<<endl);
nodep->iterateChildren(*this);
VSymEnt* symp = m_curSymp->findIdFallback(nodep->name());
if (!symp) {
nodep->v3error("Modport item not found: "<<nodep->prettyName());
} else if (AstVar* varp = symp->nodep()->castVar()) {
// Make symbol under modport that points at the _interface_'s var, not the modport.
nodep->varp(varp);
m_statep->insertSym(m_curSymp, nodep->name(), varp, NULL/*package*/);
} else if (AstVarScope* vscp = symp->nodep()->castVarScope()) {
// Make symbol under modport that points at the _interface_'s var, not the modport.
nodep->varp(vscp->varp());
m_statep->insertSym(m_curSymp, nodep->name(), vscp, NULL/*package*/);
} else {
nodep->v3error("Modport item is not a variable: "<<nodep->prettyName());
}
if (m_statep->forScopeCreation()) {
// Done with AstModportVarRef.
// Delete to prevent problems if we dead-delete pointed to variable
nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL;
}
}
virtual void visit(AstNode* nodep, AstNUser*) {
// Default: Just iterate
nodep->iterateChildren(*this);
}
public:
// CONSTUCTORS
LinkDotIfaceVisitor(AstIface* nodep, VSymEnt* curSymp, LinkDotState* statep) {
UINFO(4,__FUNCTION__<<": "<<endl);
m_curSymp = curSymp;
m_statep = statep;
nodep->accept(*this);
}
virtual ~LinkDotIfaceVisitor() {}
};
void LinkDotState::computeIfaceModSyms() {
for (IfaceModSyms::iterator it=m_ifaceModSyms.begin(); it!=m_ifaceModSyms.end(); ++it) {
AstIface* nodep = it->first;
VSymEnt* symp = it->second;
LinkDotIfaceVisitor(nodep, symp, this);
}
m_ifaceModSyms.clear();
}
//======================================================================
class LinkDotResolveVisitor : public AstNVisitor { class LinkDotResolveVisitor : public AstNVisitor {
private: private:
// NODE STATE // NODE STATE
@ -1049,6 +1280,7 @@ private:
AstCell* m_cellp; // Current cell AstCell* m_cellp; // Current cell
AstNodeModule* m_modp; // Current module AstNodeModule* m_modp; // Current module
AstNodeFTask* m_ftaskp; // Current function/task AstNodeFTask* m_ftaskp; // Current function/task
int m_modportNum; // Uniqueify modport numbers
struct DotStates { struct DotStates {
DotPosition m_dotPos; // Scope part of dotted resolution DotPosition m_dotPos; // Scope part of dotted resolution
@ -1104,6 +1336,16 @@ private:
m_ds.m_dotErr = true; m_ds.m_dotErr = true;
} }
} }
AstVar* makeIfaceModportVar(FileLine* fl, AstCell* cellp, AstIface* ifacep, AstModport* modportp) {
// Create iface variable, using duplicate var when under same module scope
string varName = ifacep->name()+"__Vmp__"+modportp->name()+"__Viftop"+cvtToStr(++m_modportNum);
AstIfaceRefDType* idtypep = new AstIfaceRefDType(fl, cellp->name(), ifacep->name(), modportp->name());
idtypep->cellp(cellp);
AstVar* varp = new AstVar(fl, AstVarType::IFACEREF, varName, VFlagChildDType(), idtypep);
varp->isIfaceParent(true);
m_modp->addStmtp(varp);
return varp;
}
// VISITs // VISITs
virtual void visit(AstNetlist* nodep, AstNUser* vup) { virtual void visit(AstNetlist* nodep, AstNUser* vup) {
@ -1119,6 +1361,7 @@ private:
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
m_cellp = NULL; m_cellp = NULL;
m_modp = nodep; m_modp = nodep;
m_modportNum = 0;
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
m_modp = NULL; m_modp = NULL;
m_ds.m_dotSymp = m_curSymp = m_modSymp = NULL; m_ds.m_dotSymp = m_curSymp = m_modSymp = NULL;
@ -1183,8 +1426,8 @@ private:
return; return;
} }
nodep->v3error("Pin not found: "<<nodep->prettyName()); nodep->v3error("Pin not found: "<<nodep->prettyName());
} else if (!refp->isIO() && !refp->isParam()) { } else if (!refp->isIO() && !refp->isParam() && !refp->isIfaceRef()) {
nodep->v3error("Pin is not an in/out/inout/param: "<<nodep->prettyName()); nodep->v3error("Pin is not an in/out/inout/param/interface: "<<nodep->prettyName());
} else { } else {
nodep->modVarp(refp); nodep->modVarp(refp);
if (refp->user5p() && refp->user5p()->castNode()!=nodep) { if (refp->user5p() && refp->user5p()->castNode()!=nodep) {
@ -1326,9 +1569,41 @@ private:
m_ds.m_dotPos = DP_SCOPE; m_ds.m_dotPos = DP_SCOPE;
// Upper AstDot visitor will handle it from here // Upper AstDot visitor will handle it from here
} }
else if (foundp->nodep()->castCell()
&& allowVar && m_cellp
&& foundp->nodep()->castCell()->modp()->castIface()) {
// Interfaces can be referenced like a variable for interconnect
AstCell* cellp = foundp->nodep()->castCell();
VSymEnt* cellEntp = m_statep->getNodeSym(cellp); if (!cellEntp) nodep->v3fatalSrc("No interface sym entry");
VSymEnt* parentEntp = cellEntp->parentp(); // Container of the var; probably a module or generate begin
string findName = nodep->name()+"__Viftop";
AstVar* ifaceRefVarp = parentEntp->findIdFallback(findName)->nodep()->castVar();
if (!ifaceRefVarp) nodep->v3fatalSrc("Can't find interface var ref: "<<findName);
//
ok = true;
if (m_ds.m_dotText!="") m_ds.m_dotText += ".";
m_ds.m_dotText += nodep->name();
m_ds.m_dotSymp = foundp;
m_ds.m_dotPos = DP_SCOPE;
UINFO(9," cell -> iface varref "<<foundp->nodep()<<endl);
AstNode* newp = new AstVarRef(ifaceRefVarp->fileline(), ifaceRefVarp, false);
nodep->replaceWith(newp); pushDeletep(nodep); nodep = NULL;
}
} }
else if (AstVar* varp = foundp->nodep()->castVar()) { else if (AstVar* varp = foundp->nodep()->castVar()) {
if (allowVar) { if (AstIfaceRefDType* ifacerefp = varp->subDTypep()->castIfaceRefDType()) {
if (!ifacerefp->ifaceViaCellp()) ifacerefp->v3fatalSrc("Unlinked interface");
// Really this is a scope reference into an interface
UINFO(9,"varref-ifaceref "<<m_ds.m_dotText<<" "<<nodep<<endl);
if (m_ds.m_dotText!="") m_ds.m_dotText += ".";
m_ds.m_dotText += nodep->name();
m_ds.m_dotSymp = m_statep->getNodeSym(ifacerefp->ifaceViaCellp());
m_ds.m_dotPos = DP_SCOPE;
ok = true;
AstNode* newp = new AstVarRef(nodep->fileline(), varp, false);
nodep->replaceWith(newp); pushDeletep(nodep); nodep = NULL;
}
else if (allowVar) {
AstNodeVarRef* newp; AstNodeVarRef* newp;
if (m_ds.m_dotText != "") { if (m_ds.m_dotText != "") {
newp = new AstVarXRef(nodep->fileline(), nodep->name(), m_ds.m_dotText, false); // lvalue'ness computed later newp = new AstVarXRef(nodep->fileline(), nodep->name(), m_ds.m_dotText, false); // lvalue'ness computed later
@ -1345,6 +1620,34 @@ private:
ok = true; ok = true;
} }
} }
else if (AstModport* modportp = foundp->nodep()->castModport()) {
// A scope reference into an interface's modport (not necessarily at a pin connection)
UINFO(9,"cell-ref-to-modport "<<m_ds.m_dotText<<" "<<nodep<<endl);
UINFO(9,"dotSymp "<<m_ds.m_dotSymp<<" "<<m_ds.m_dotSymp->nodep()<<endl);
// Iface was the previously dotted component
if (!m_ds.m_dotSymp
|| !m_ds.m_dotSymp->nodep()->castCell()
|| !m_ds.m_dotSymp->nodep()->castCell()->modp()
|| !m_ds.m_dotSymp->nodep()->castCell()->modp()->castIface()) {
nodep->v3error("Modport not referenced as <interface>."<<modportp->prettyName());
} else if (!m_ds.m_dotSymp->nodep()->castCell()->modp()
|| !m_ds.m_dotSymp->nodep()->castCell()->modp()->castIface()) {
nodep->v3error("Modport not referenced from underneath an interface: "<<modportp->prettyName());
} else {
AstCell* cellp = m_ds.m_dotSymp->nodep()->castCell();
if (!cellp) nodep->v3fatalSrc("Modport not referenced from a cell");
AstIface* ifacep = cellp->modp()->castIface();
//string cellName = m_ds.m_dotText; // Use cellp->name
if (m_ds.m_dotText!="") m_ds.m_dotText += ".";
m_ds.m_dotText += nodep->name();
m_ds.m_dotSymp = m_statep->getNodeSym(modportp);
m_ds.m_dotPos = DP_SCOPE;
ok = true;
AstVar* varp = makeIfaceModportVar(nodep->fileline(), cellp, ifacep, modportp);
AstVarRef* refp = new AstVarRef(varp->fileline(), varp, false);
nodep->replaceWith(refp); pushDeletep(nodep); nodep = NULL;
}
}
else if (AstEnumItem* valuep = foundp->nodep()->castEnumItem()) { else if (AstEnumItem* valuep = foundp->nodep()->castEnumItem()) {
if (allowVar) { if (allowVar) {
AstNode* newp = new AstEnumItemRef(nodep->fileline(), valuep, foundp->packagep()); AstNode* newp = new AstEnumItemRef(nodep->fileline(), valuep, foundp->packagep());
@ -1677,6 +1980,7 @@ public:
m_cellp = NULL; m_cellp = NULL;
m_modp = NULL; m_modp = NULL;
m_ftaskp = NULL; m_ftaskp = NULL;
m_modportNum = 0;
// //
rootp->accept(*this); rootp->accept(*this);
} }
@ -1698,12 +2002,18 @@ void V3LinkDot::linkDotGuts(AstNetlist* rootp, VLinkDotStep step) {
LinkDotParamVisitor visitors(rootp,&state); LinkDotParamVisitor visitors(rootp,&state);
if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-param.tree")); if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-param.tree"));
} }
else if (step == LDS_ARRAYED) {}
else if (step == LDS_SCOPED) { else if (step == LDS_SCOPED) {
// Well after the initial link when we're ready to operate on the flat design, // Well after the initial link when we're ready to operate on the flat design,
// process AstScope's. This needs to be separate pass after whole hierarchy graph created. // process AstScope's. This needs to be separate pass after whole hierarchy graph created.
LinkDotScopeVisitor visitors(rootp,&state); LinkDotScopeVisitor visitors(rootp,&state);
if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-scoped.tree")); if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-scoped.tree"));
} }
else v3fatalSrc("Bad case");
state.dump();
state.computeIfaceModSyms();
state.computeIfaceVarSyms();
state.computeScopeAliases();
state.dump(); state.dump();
LinkDotResolveVisitor visitorb(rootp,&state); LinkDotResolveVisitor visitorb(rootp,&state);
} }

View File

@ -152,6 +152,12 @@ private:
nodep->valuep()->unlinkFrBack())); nodep->valuep()->unlinkFrBack()));
} }
} }
if (nodep->isIfaceRef() && !nodep->isIfaceParent()) {
// Only AstIfaceRefDType's at this point correspond to ports;
// haven't made additional ones for interconnect yet, so assert is simple
// What breaks later is we don't have a Scope/Cell representing the interface to attach to
if (m_modp->level()<=2) nodep->v3error("Unsupported: Interfaced port on top level module");
}
} }
virtual void visit(AstAttrOf* nodep, AstNUser*) { virtual void visit(AstAttrOf* nodep, AstNUser*) {

View File

@ -21,13 +21,31 @@
// Top down traversal: // Top down traversal:
// For each cell: // For each cell:
// If parameterized, // If parameterized,
// Determine all parameter widths, constant values // Determine all parameter widths, constant values.
// (Interfaces also matter, as if an interface is parameterized
// this effectively changes the width behavior of all that
// reference the iface.)
// Clone module cell calls, renaming with __{par1}_{par2}_... // Clone module cell calls, renaming with __{par1}_{par2}_...
// Substitute constants for cell's module's parameters // Substitute constants for cell's module's parameters.
// Relink pins and cell to point to new module // Relink pins and cell and ifacerefdtype to point to new module.
// Then process all modules called by that cell //
// For interface Parent's we have the AstIfaceRefDType::cellp()
// pointing to this module. If that parent cell's interface
// module gets parameterized, AstIfaceRefDType::cloneRelink
// will update AstIfaceRefDType::cellp(), and AstLinkDot will
// see the new interface.
//
// However if a submodule's AstIfaceRefDType::ifacep() points
// to the old (unparameterized) interface and needs correction.
// To detect this we must walk all pins looking for interfaces
// that the parent has changed and propagate down.
//
// Then process all modules called by that cell.
// (Cells never referenced after parameters expanded must be ignored.) // (Cells never referenced after parameters expanded must be ignored.)
// //
// After we complete parameters, the varp's will be wrong (point to old module)
// and must be relinked.
//
//************************************************************************* //*************************************************************************
#include "config_build.h" #include "config_build.h"
@ -62,23 +80,34 @@ private:
AstUser5InUse m_inuser5; AstUser5InUse m_inuser5;
// User1/2/3 used by constant function simulations // User1/2/3 used by constant function simulations
// TYPES
typedef deque<pair<AstIfaceRefDType*,AstIfaceRefDType*> > IfaceRefRefs; // Note may have duplicate entries
// STATE // STATE
typedef std::map<AstVar*,AstVar*> VarCloneMap; typedef map<AstVar*,AstVar*> VarCloneMap;
struct ModInfo { struct ModInfo {
AstNodeModule* m_modp; // Module with specified name AstNodeModule* m_modp; // Module with specified name
VarCloneMap m_cloneMap; // Map of old-varp -> new cloned varp VarCloneMap m_cloneMap; // Map of old-varp -> new cloned varp
ModInfo(AstNodeModule* modp) { m_modp=modp; } ModInfo(AstNodeModule* modp) { m_modp=modp; }
}; };
typedef std::map<string,ModInfo> ModNameMap; typedef map<string,ModInfo> ModNameMap;
ModNameMap m_modNameMap; // Hash of created module flavors by name ModNameMap m_modNameMap; // Hash of created module flavors by name
typedef std::map<string,string> LongMap; typedef map<string,string> LongMap;
LongMap m_longMap; // Hash of very long names to unique identity number LongMap m_longMap; // Hash of very long names to unique identity number
int m_longId; int m_longId;
typedef map<AstNode*,int> ValueMap;
typedef map<int,int> NextValueMap;
ValueMap m_valueMap; // Hash of node to param value
NextValueMap m_nextValueMap;// Hash of param value to next value to be used
typedef multimap<int,AstNodeModule*> LevelModMap; typedef multimap<int,AstNodeModule*> LevelModMap;
LevelModMap m_todoModps; // Modules left to process LevelModMap m_todoModps; // Modules left to process
typedef deque<AstCell*> CellList;
CellList m_cellps; // Cells left to process (in this module)
// METHODS // METHODS
static int debug() { static int debug() {
static int level = -1; static int level = -1;
@ -91,7 +120,7 @@ private:
// Pass 1, assign first letter to each gparam's name // Pass 1, assign first letter to each gparam's name
for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp=stmtp->nextp()) { for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp=stmtp->nextp()) {
if (AstVar* varp = stmtp->castVar()) { if (AstVar* varp = stmtp->castVar()) {
if (varp->isGParam()) { if (varp->isGParam()||varp->isIfaceRef()) {
char ch = varp->name()[0]; char ch = varp->name()[0];
ch = toupper(ch); if (ch<'A' || ch>'Z') ch='Z'; ch = toupper(ch); if (ch<'A' || ch>'Z') ch='Z';
varp->user4(usedLetter[static_cast<int>(ch)]*256 + ch); varp->user4(usedLetter[static_cast<int>(ch)]*256 + ch);
@ -113,6 +142,27 @@ private:
} }
return st; return st;
} }
string paramValueNumber(AstNode* nodep) {
// Given a compilcated object create a number to use for param module assignment
// Ideally would be relatively stable if design changes (not use pointer value),
// and must return same value given same input node
// Return must presently be numberic so doesn't collide with 'small' alphanumeric parameter names
ValueMap::iterator it = m_valueMap.find(nodep);
if (it != m_valueMap.end()) {
return cvtToStr(it->second);
} else {
static int BUCKETS = 1000;
V3Hash hash (nodep->name());
int bucket = hash.hshval() % BUCKETS;
int offset = 0;
NextValueMap::iterator it = m_nextValueMap.find(bucket);
if (it != m_nextValueMap.end()) { offset = it->second; it->second = offset + 1; }
else { m_nextValueMap.insert(make_pair(bucket, offset + 1)); }
int num = bucket + offset * BUCKETS;
m_valueMap.insert(make_pair(nodep, num));
return cvtToStr(num);
}
}
void relinkPins(VarCloneMap* clonemapp, AstPin* startpinp) { void relinkPins(VarCloneMap* clonemapp, AstPin* startpinp) {
for (AstPin* pinp = startpinp; pinp; pinp=pinp->nextp()->castPin()) { for (AstPin* pinp = startpinp; pinp; pinp=pinp->nextp()->castPin()) {
if (!pinp->modVarp()) pinp->v3fatalSrc("Not linked?\n"); if (!pinp->modVarp()) pinp->v3fatalSrc("Not linked?\n");
@ -123,9 +173,10 @@ private:
pinp->modVarp(cloneiter->second); pinp->modVarp(cloneiter->second);
} }
} }
void visitCell(AstCell* nodep);
void visitModules() { void visitModules() {
// Loop on all modules left to process // Loop on all modules left to process
// Hitting a cell adds to the appropriate leval of this level-sorted list, // Hitting a cell adds to the appropriate level of this level-sorted list,
// so since cells originally exist top->bottom we process in top->bottom order too. // so since cells originally exist top->bottom we process in top->bottom order too.
while (!m_todoModps.empty()) { while (!m_todoModps.empty()) {
LevelModMap::iterator it = m_todoModps.begin(); LevelModMap::iterator it = m_todoModps.begin();
@ -134,7 +185,19 @@ private:
if (!nodep->user5SetOnce()) { // Process once; note clone() must clear so we do it again if (!nodep->user5SetOnce()) { // Process once; note clone() must clear so we do it again
UINFO(4," MOD "<<nodep<<endl); UINFO(4," MOD "<<nodep<<endl);
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
// Note this may add to m_todoModps // Note above iterate may add to m_todoModps
//
// Process interface cells, then non-interface which may ref an interface cell
for (int nonIf=0; nonIf<2; ++nonIf) {
for (CellList::iterator it=m_cellps.begin(); it!=m_cellps.end(); ++it) {
AstCell* nodep = *it;
if ((nonIf==0 && nodep->modp()->castIface())
|| (nonIf==1 && !nodep->modp()->castIface())) {
visitCell(nodep);
}
}
}
m_cellps.clear();
} }
} }
} }
@ -157,7 +220,10 @@ private:
UINFO(4," MOD-dead? "<<nodep<<endl); // Should have been done by now, if not dead UINFO(4," MOD-dead? "<<nodep<<endl); // Should have been done by now, if not dead
} }
} }
virtual void visit(AstCell* nodep, AstNUser*); virtual void visit(AstCell* nodep, AstNUser*) {
// Must do ifaces first, so push to list and do in proper order
m_cellps.push_back(nodep);
}
// Make sure all parameters are constantified // Make sure all parameters are constantified
virtual void visit(AstVar* nodep, AstNUser*) { virtual void visit(AstVar* nodep, AstNUser*) {
@ -218,7 +284,7 @@ private:
//! Parameter subsitution for generated for loops. //! Parameter subsitution for generated for loops.
//! @todo Unlike generated IF, we don't have to worry about short-circuiting the conditional //! @todo Unlike generated IF, we don't have to worry about short-circuiting the conditional
//! expression, since this is currently restricted to simple comparisons. If we ever do //! expression, since this is currently restricted to simple comparisons. If we ever do
//! move to more generic constant expressions, such code will be neede here. //! move to more generic constant expressions, such code will be needed here.
virtual void visit(AstBegin* nodep, AstNUser*) { virtual void visit(AstBegin* nodep, AstNUser*) {
if (nodep->genforp()) { if (nodep->genforp()) {
AstGenFor* forp = nodep->genforp()->castGenFor(); AstGenFor* forp = nodep->genforp()->castGenFor();
@ -317,11 +383,13 @@ public:
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// VISITs // VISITs
void ParamVisitor::visit(AstCell* nodep, AstNUser*) { void ParamVisitor::visitCell(AstCell* nodep) {
// Cell: Check for parameters in the instantiation. // Cell: Check for parameters in the instantiation.
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
if (!nodep->modp()) { nodep->dumpTree(cerr,"error:"); nodep->v3fatalSrc("Not linked?"); } if (!nodep->modp()) nodep->v3fatalSrc("Not linked?");
if (nodep->paramsp()) { if (nodep->paramsp()
|| 1 // Need to look for interfaces; could track when one exists, but should be harmless to always do this
) {
UINFO(4,"De-parameterize: "<<nodep<<endl); UINFO(4,"De-parameterize: "<<nodep<<endl);
// Create new module name with _'s between the constants // Create new module name with _'s between the constants
if (debug()>=10) nodep->dumpTree(cout,"-cell:\t"); if (debug()>=10) nodep->dumpTree(cout,"-cell:\t");
@ -359,6 +427,30 @@ void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
} }
} }
} }
IfaceRefRefs ifaceRefRefs;
for (AstPin* pinp = nodep->pinsp(); pinp; pinp=pinp->nextp()->castPin()) {
AstVar* modvarp = pinp->modVarp();
if (modvarp->isIfaceRef()) {
AstIfaceRefDType* portIrefp = modvarp->subDTypep()->castIfaceRefDType();
//UINFO(9," portIfaceRef "<<portIrefp<<endl);
if (!pinp->exprp()
|| !pinp->exprp()->castVarRef()
|| !pinp->exprp()->castVarRef()->varp()
|| !pinp->exprp()->castVarRef()->varp()->subDTypep()
|| !pinp->exprp()->castVarRef()->varp()->subDTypep()->castIfaceRefDType()) {
pinp->v3error("Interface port '"<<modvarp->prettyName()<<"' is not connected to interface/modport pin expression");
} else {
AstIfaceRefDType* pinIrefp = pinp->exprp()->castVarRef()->varp()->subDTypep()->castIfaceRefDType();
//UINFO(9," pinIfaceRef "<<pinIrefp<<endl);
if (portIrefp->ifaceViaCellp() != pinIrefp->ifaceViaCellp()) {
UINFO(9," IfaceRefDType needs reconnect "<<pinIrefp<<endl);
longname += "_" + paramSmallName(nodep->modp(),pinp->modVarp())+paramValueNumber(pinIrefp);
any_overrides = true;
ifaceRefRefs.push_back(make_pair(portIrefp,pinIrefp));
}
}
}
}
if (!any_overrides) { if (!any_overrides) {
UINFO(8,"Cell parameters all match original values, skipping expansion.\n"); UINFO(8,"Cell parameters all match original values, skipping expansion.\n");
@ -401,7 +493,7 @@ void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
// Note we allow multiple users of a parameterized model, thus we need to stash this info. // Note we allow multiple users of a parameterized model, thus we need to stash this info.
for (AstNode* stmtp=modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) { for (AstNode* stmtp=modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
if (AstVar* varp = stmtp->castVar()) { if (AstVar* varp = stmtp->castVar()) {
if (varp->isIO() || varp->isGParam()) { if (varp->isIO() || varp->isGParam() || varp->isIfaceRef()) {
// Cloning saved a pointer to the new node for us, so just follow that link. // Cloning saved a pointer to the new node for us, so just follow that link.
AstVar* oldvarp = varp->clonep()->castVar(); AstVar* oldvarp = varp->clonep()->castVar();
//UINFO(8,"Clone list 0x"<<hex<<(uint32_t)oldvarp<<" -> 0x"<<(uint32_t)varp<<endl); //UINFO(8,"Clone list 0x"<<hex<<(uint32_t)oldvarp<<" -> 0x"<<(uint32_t)varp<<endl);
@ -413,7 +505,21 @@ void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
// Relink parameter vars to the new module // Relink parameter vars to the new module
relinkPins(clonemapp, nodep->paramsp()); relinkPins(clonemapp, nodep->paramsp());
// Fix any interface references
for (IfaceRefRefs::iterator it=ifaceRefRefs.begin(); it!=ifaceRefRefs.end(); ++it) {
AstIfaceRefDType* portIrefp = it->first;
AstIfaceRefDType* pinIrefp = it->second;
AstIfaceRefDType* cloneIrefp = portIrefp->clonep()->castIfaceRefDType();
UINFO(8," IfaceOld "<<portIrefp<<endl);
UINFO(8," IfaceTo "<<pinIrefp<<endl);
if (!cloneIrefp) portIrefp->v3fatalSrc("parameter clone didn't hit AstIfaceRefDType");
UINFO(8," IfaceClo "<<cloneIrefp<<endl);
cloneIrefp->ifacep(pinIrefp->ifaceViaCellp());
UINFO(8," IfaceNew "<<cloneIrefp<<endl);
}
// Assign parameters to the constants specified // Assign parameters to the constants specified
// DOES clone() so must be finished with module clonep() before here
for (AstPin* pinp = nodep->paramsp(); pinp; pinp=pinp->nextp()->castPin()) { for (AstPin* pinp = nodep->paramsp(); pinp; pinp=pinp->nextp()->castPin()) {
AstVar* modvarp = pinp->modVarp(); AstVar* modvarp = pinp->modVarp();
if (modvarp && pinp->exprp()) { if (modvarp && pinp->exprp()) {
@ -439,7 +545,7 @@ void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
} // if any_overrides } // if any_overrides
// Delete the parameters from the cell; they're not relevant any longer. // Delete the parameters from the cell; they're not relevant any longer.
nodep->paramsp()->unlinkFrBackWithNext()->deleteTree(); if (nodep->paramsp()) nodep->paramsp()->unlinkFrBackWithNext()->deleteTree();
UINFO(8," Done with "<<nodep<<endl); UINFO(8," Done with "<<nodep<<endl);
//if (debug()>=10) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("param-out.tree")); //if (debug()>=10) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("param-out.tree"));
} }

View File

@ -66,6 +66,7 @@ struct V3ParseBisonYYSType {
AstCell* cellp; AstCell* cellp;
AstConst* constp; AstConst* constp;
AstMemberDType* memberp; AstMemberDType* memberp;
AstModportVarRef* modportvarrefp;
AstNodeModule* modulep; AstNodeModule* modulep;
AstNodeClassDType* classp; AstNodeClassDType* classp;
AstNodeDType* dtypep; AstNodeDType* dtypep;

View File

@ -150,6 +150,14 @@ private:
m_scopep->addActivep(clonep); m_scopep->addActivep(clonep);
clonep->iterateChildren(*this); // We iterate under the *clone* clonep->iterateChildren(*this); // We iterate under the *clone*
} }
virtual void visit(AstAssignVarScope* nodep, AstNUser*) {
// Copy under the scope but don't recurse
UINFO(4," Move "<<nodep<<endl);
AstNode* clonep = nodep->cloneTree(false);
nodep->user2p(clonep);
m_scopep->addActivep(clonep);
clonep->iterateChildren(*this); // We iterate under the *clone*
}
virtual void visit(AstAssignW* nodep, AstNUser*) { virtual void visit(AstAssignW* nodep, AstNUser*) {
// Add to list of blocks under this scope // Add to list of blocks under this scope
UINFO(4," Move "<<nodep<<endl); UINFO(4," Move "<<nodep<<endl);
@ -215,12 +223,17 @@ private:
virtual void visit(AstVarRef* nodep, AstNUser*) { virtual void visit(AstVarRef* nodep, AstNUser*) {
// VarRef needs to point to VarScope // VarRef needs to point to VarScope
// Make sure variable has made user1p. // Make sure variable has made user1p.
nodep->varp()->accept(*this); if (!nodep->varp()) nodep->v3fatalSrc("Unlinked");
AstVarScope* varscp = nodep->packagep() if (nodep->varp()->isIfaceRef()) {
? (AstVarScope*)nodep->varp()->user3p() nodep->varScopep(NULL);
: (AstVarScope*)nodep->varp()->user1p(); } else {
if (!varscp) nodep->v3fatalSrc("Can't locate varref scope"); nodep->varp()->accept(*this);
nodep->varScopep(varscp); AstVarScope* varscp = nodep->packagep()
? (AstVarScope*)nodep->varp()->user3p()
: (AstVarScope*)nodep->varp()->user1p();
if (!varscp) nodep->v3fatalSrc("Can't locate varref scope");
nodep->varScopep(varscp);
}
} }
virtual void visit(AstScopeName* nodep, AstNUser*) { virtual void visit(AstScopeName* nodep, AstNUser*) {
// If there's a %m in the display text, we add a special node that will contain the name() // If there's a %m in the display text, we add a special node that will contain the name()
@ -298,6 +311,9 @@ private:
virtual void visit(AstAssignAlias* nodep, AstNUser*) { virtual void visit(AstAssignAlias* nodep, AstNUser*) {
movedDeleteOrIterate(nodep); movedDeleteOrIterate(nodep);
} }
virtual void visit(AstAssignVarScope* nodep, AstNUser*) {
movedDeleteOrIterate(nodep);
}
virtual void visit(AstAssignW* nodep, AstNUser*) { virtual void visit(AstAssignW* nodep, AstNUser*) {
movedDeleteOrIterate(nodep); movedDeleteOrIterate(nodep);
} }

View File

@ -183,6 +183,18 @@ public:
} }
return any; return any;
} }
void importFromIface(VSymGraph* graphp, const VSymEnt* srcp) {
// Import interface tokens from source symbol table into this symbol table, recursively
UINFO(9, " importIf se"<<(void*)this<<" from se"<<(void*)srcp<<endl);
for (IdNameMap::const_iterator it=srcp->m_idNameMap.begin(); it!=srcp->m_idNameMap.end(); ++it) {
const string& name = it->first;
VSymEnt* srcp = it->second;
VSymEnt* symp = new VSymEnt(graphp, srcp);
reinsert(name, symp);
// And recurse to create children
srcp->importFromIface(graphp, symp);
}
}
void cellErrorScopes(AstNode* lookp, string prettyName="") { void cellErrorScopes(AstNode* lookp, string prettyName="") {
if (prettyName=="") prettyName = lookp->prettyName(); if (prettyName=="") prettyName = lookp->prettyName();
string scopes; string scopes;

View File

@ -1073,6 +1073,14 @@ private:
nodep->dtypeFrom(nodep->lhsp()); nodep->dtypeFrom(nodep->lhsp());
} }
virtual void visit(AstIfaceRefDType* nodep, AstNUser* vup) {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
UINFO(5," IFACEREF "<<nodep<<endl);
nodep->iterateChildren(*this, vup);
nodep->dtypep(nodep);
nodep->widthForce(1, 1); // Not really relevant
UINFO(4,"dtWidthed "<<nodep<<endl);
}
virtual void visit(AstNodeClassDType* nodep, AstNUser* vup) { virtual void visit(AstNodeClassDType* nodep, AstNUser* vup) {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
UINFO(5," NODECLASS "<<nodep<<endl); UINFO(5," NODECLASS "<<nodep<<endl);

View File

@ -417,6 +417,7 @@ word [a-zA-Z0-9_]+
"do" { FL; return yDO; } "do" { FL; return yDO; }
"endclocking" { FL; return yENDCLOCKING; } "endclocking" { FL; return yENDCLOCKING; }
"endpackage" { FL; return yENDPACKAGE; } "endpackage" { FL; return yENDPACKAGE; }
"endinterface" { FL; return yENDINTERFACE; }
"endprogram" { FL; return yENDPROGRAM; } "endprogram" { FL; return yENDPROGRAM; }
"endproperty" { FL; return yENDPROPERTY; } "endproperty" { FL; return yENDPROPERTY; }
"enum" { FL; return yENUM; } "enum" { FL; return yENUM; }
@ -425,9 +426,11 @@ word [a-zA-Z0-9_]+
"iff" { FL; return yIFF; } "iff" { FL; return yIFF; }
"import" { FL; return yIMPORT; } "import" { FL; return yIMPORT; }
"inside" { FL; return yINSIDE; } "inside" { FL; return yINSIDE; }
"interface" { FL; return yINTERFACE; }
"int" { FL; return yINT; } "int" { FL; return yINT; }
"logic" { FL; return yLOGIC; } "logic" { FL; return yLOGIC; }
"longint" { FL; return yLONGINT; } "longint" { FL; return yLONGINT; }
"modport" { FL; return yMODPORT; }
"package" { FL; return yPACKAGE; } "package" { FL; return yPACKAGE; }
"packed" { FL; return yPACKED; } "packed" { FL; return yPACKED; }
"priority" { FL; return yPRIORITY; } "priority" { FL; return yPRIORITY; }
@ -460,7 +463,6 @@ word [a-zA-Z0-9_]+
"dist" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "dist" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"endclass" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "endclass" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"endgroup" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "endgroup" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"endinterface" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"endsequence" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "endsequence" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"expect" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "expect" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"extends" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "extends" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
@ -470,13 +472,11 @@ word [a-zA-Z0-9_]+
"forkjoin" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "forkjoin" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"ignore_bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "ignore_bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"illegal_bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "illegal_bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"interface" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"intersect" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "intersect" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"join_any" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "join_any" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"join_none" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "join_none" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"local" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "local" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"matches" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "matches" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"modport" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"new" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "new" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"null" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "null" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"protected" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "protected" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }

View File

@ -310,6 +310,7 @@ class AstSenTree;
%token<fl> yENDCLOCKING "endclocking" %token<fl> yENDCLOCKING "endclocking"
%token<fl> yENDFUNCTION "endfunction" %token<fl> yENDFUNCTION "endfunction"
%token<fl> yENDGENERATE "endgenerate" %token<fl> yENDGENERATE "endgenerate"
%token<fl> yENDINTERFACE "endinterface"
%token<fl> yENDMODULE "endmodule" %token<fl> yENDMODULE "endmodule"
%token<fl> yENDPACKAGE "endpackage" %token<fl> yENDPACKAGE "endpackage"
%token<fl> yENDPRIMITIVE "endprimitive" %token<fl> yENDPRIMITIVE "endprimitive"
@ -337,9 +338,11 @@ class AstSenTree;
%token<fl> yINSIDE "inside" %token<fl> yINSIDE "inside"
%token<fl> yINT "int" %token<fl> yINT "int"
%token<fl> yINTEGER "integer" %token<fl> yINTEGER "integer"
%token<fl> yINTERFACE "interface"
%token<fl> yLOCALPARAM "localparam" %token<fl> yLOCALPARAM "localparam"
%token<fl> yLOGIC "logic" %token<fl> yLOGIC "logic"
%token<fl> yLONGINT "longint" %token<fl> yLONGINT "longint"
%token<fl> yMODPORT "modport"
%token<fl> yMODULE "module" %token<fl> yMODULE "module"
%token<fl> yNAND "nand" %token<fl> yNAND "nand"
%token<fl> yNEGEDGE "negedge" %token<fl> yNEGEDGE "negedge"
@ -650,7 +653,7 @@ descriptionList: // IEEE: part of source_text
description: // ==IEEE: description description: // ==IEEE: description
module_declaration { } module_declaration { }
// // udp_declaration moved into module_declaration // // udp_declaration moved into module_declaration
//UNSUP interface_declaration { } | interface_declaration { }
| program_declaration { } | program_declaration { }
| package_declaration { } | package_declaration { }
| package_item { if ($1) GRAMMARP->unitPackage($1->fileline())->addStmtp($1); } | package_item { if ($1) GRAMMARP->unitPackage($1->fileline())->addStmtp($1); }
@ -844,14 +847,24 @@ port<nodep>: // ==IEEE: port
// // IEEE: interface_port_header port_identifier { unpacked_dimension } // // IEEE: interface_port_header port_identifier { unpacked_dimension }
// // Expanded interface_port_header // // Expanded interface_port_header
// // We use instantCb here because the non-port form looks just like a module instantiation // // We use instantCb here because the non-port form looks just like a module instantiation
//UNSUP portDirNetE id/*interface*/ idAny/*port*/ rangeListE sigAttrListE portDirNetE id/*interface*/ idAny/*port*/ variable_dimensionListE sigAttrListE
//UNSUP { VARDTYPE($2); VARDONEA($<fl>3, $3, $4); PARSEP->instantCb($<fl>2, $2, $3, $4); PINNUMINC(); } { $$ = new AstPort($<fl>2,PINNUMINC(),*$3);
//UNSUP portDirNetE yINTERFACE idAny/*port*/ rangeListE sigAttrListE AstVar* varp=new AstVar($<fl>2,AstVarType(AstVarType::IFACEREF),*$3,VFlagChildDType(),
//UNSUP { VARDTYPE($2); VARDONEA($<fl>3, $3, $4); PINNUMINC(); } new AstIfaceRefDType($<fl>2,"",*$2));
//UNSUP portDirNetE id/*interface*/ '.' idAny/*modport*/ idAny/*port*/ rangeListE sigAttrListE if ($4) varp->v3error("Unsupported: Arrayed interfaces");
//UNSUP { VARDTYPE($2); VARDONEA($<fl>5, $5, $6); PARSEP->instantCb($<fl>2, $2, $5, $6); PINNUMINC(); } varp->addAttrsp($5);
//UNSUP portDirNetE yINTERFACE '.' idAny/*modport*/ idAny/*port*/ rangeListE sigAttrListE $$->addNext(varp); }
//UNSUP { VARDTYPE($2); VARDONEA($<fl>5, $5, $6); PINNUMINC(); } | portDirNetE yINTERFACE idAny/*port*/ rangeListE sigAttrListE
{ $<fl>2->v3error("Unsupported: virtual interfaces"); }
| portDirNetE id/*interface*/ '.' idAny/*modport*/ idAny/*port*/ rangeListE sigAttrListE
{ $$ = new AstPort($3,PINNUMINC(),*$5);
AstVar* varp=new AstVar($<fl>2,AstVarType(AstVarType::IFACEREF),*$5,VFlagChildDType(),
new AstIfaceRefDType($<fl>2,"",*$2,*$4));
if ($6) varp->v3error("Unsupported: Arrayed interfaces");
varp->addAttrsp($7);
$$->addNext(varp); }
| portDirNetE yINTERFACE '.' idAny/*modport*/ idAny/*port*/ rangeListE sigAttrListE
{ $<fl>2->v3error("Unsupported: virtual interfaces"); }
// //
// // IEEE: ansi_port_declaration, with [port_direction] removed // // IEEE: ansi_port_declaration, with [port_direction] removed
// // IEEE: [ net_port_header | interface_port_header ] port_identifier { unpacked_dimension } [ '=' constant_expression ] // // IEEE: [ net_port_header | interface_port_header ] port_identifier { unpacked_dimension } [ '=' constant_expression ]
@ -889,7 +902,7 @@ port<nodep>: // ==IEEE: port
//UNSUP portDirNetE /*implicit*/ '.' portSig '(' portAssignExprE ')' sigAttrListE //UNSUP portDirNetE /*implicit*/ '.' portSig '(' portAssignExprE ')' sigAttrListE
//UNSUP { UNSUP } //UNSUP { UNSUP }
// //
portDirNetE data_type portSig variable_dimensionListE sigAttrListE | portDirNetE data_type portSig variable_dimensionListE sigAttrListE
{ $$=$3; VARDTYPE($2); $$->addNextNull(VARDONEP($$,$4,$5)); } { $$=$3; VARDTYPE($2); $$->addNextNull(VARDONEP($$,$4,$5)); }
| portDirNetE yVAR data_type portSig variable_dimensionListE sigAttrListE | portDirNetE yVAR data_type portSig variable_dimensionListE sigAttrListE
{ $$=$4; VARDTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); } { $$=$4; VARDTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); }
@ -932,6 +945,54 @@ portSig<nodep>:
//********************************************************************** //**********************************************************************
// Interface headers // Interface headers
interface_declaration: // IEEE: interface_declaration + interface_nonansi_header + interface_ansi_header:
// // timeunits_delcarationE is instead in interface_item
intFront parameter_port_listE portsStarE ';'
interface_itemListE yENDINTERFACE endLabelE
{ if ($2) $1->addStmtp($2);
if ($3) $1->addStmtp($3);
if ($5) $1->addStmtp($5);
SYMP->popScope($1); }
//UNSUP yEXTERN intFront parameter_port_listE portsStarE ';' { }
;
intFront<modulep>:
yINTERFACE lifetimeE idAny/*new_interface*/
{ $$ = new AstIface($1,*$3);
$$->inLibrary(true);
PARSEP->rootp()->addModulep($$);
SYMP->pushNew($$); }
;
interface_itemListE<nodep>:
/* empty */ { $$ = NULL; }
| interface_itemList { $$ = $1; }
;
interface_itemList<nodep>:
interface_item { $$ = $1; }
| interface_itemList interface_item { $$ = $1->addNextNull($2); }
;
interface_item<nodep>: // IEEE: interface_item + non_port_interface_item
port_declaration ';' { $$ = $1; }
// // IEEE: non_port_interface_item
//UNSUP generate_region { $$ = $1; }
| interface_or_generate_item { $$ = $1; }
//UNSUP program_declaration { $$ = $1; }
//UNSUP interface_declaration { $$ = $1; }
| timeunits_declaration { $$ = $1; }
// // See note in interface_or_generate item
| module_common_item { $$ = $1; }
;
interface_or_generate_item<nodep>: // ==IEEE: interface_or_generate_item
// // module_common_item in interface_item, as otherwise duplicated
// // with module_or_generate_item's module_common_item
modport_declaration { $$ = $1; }
//UNSUP extern_tf_declaration { $$ = $1; }
;
//********************************************************************** //**********************************************************************
// Program headers // Program headers
@ -989,6 +1050,46 @@ program_generate_item<nodep>: // ==IEEE: program_generate_item
//UNSUP elaboration_system_task { $$ = $1; } //UNSUP elaboration_system_task { $$ = $1; }
; ;
modport_declaration<nodep>: // ==IEEE: modport_declaration
yMODPORT modport_itemList ';' { $$ = $2; }
;
modport_itemList<nodep>: // IEEE: part of modport_declaration
modport_item { $$ = $1; }
| modport_itemList ',' modport_item { $$ = $1->addNextNull($3); }
;
modport_item<nodep>: // ==IEEE: modport_item
id/*new-modport*/ '(' modportPortsDeclList ')' { $$ = new AstModport($2,*$1,$3); }
;
modportPortsDeclList<modportvarrefp>:
modportPortsDecl { $$ = $1; }
| modportPortsDeclList ',' modportPortsDecl { $$ = $1->addNextNull($3)->castModportVarRef(); }
;
// IEEE: modport_ports_declaration + modport_simple_ports_declaration
// + (modport_tf_ports_declaration+import_export) + modport_clocking_declaration
// We've expanded the lists each take to instead just have standalone ID ports.
// We track the type as with the V2k series of defines, then create as each ID is seen.
modportPortsDecl<modportvarrefp>:
// // IEEE: modport_simple_ports_declaration
port_direction modportSimplePort { $$ = new AstModportVarRef($<fl>1,*$2,GRAMMARP->m_varIO); }
// // IEEE: modport_clocking_declaration
//UNSUP yCLOCKING idAny/*clocking_identifier*/ { }
//UNSUP yIMPORT modport_tf_port { }
//UNSUP yEXPORT modport_tf_port { }
// Continuations of above after a comma.
// // IEEE: modport_simple_ports_declaration
| modportSimplePort { $$ = new AstModportVarRef($<fl>1,*$1,AstVarType::INOUT); }
;
modportSimplePort<strp>: // IEEE: modport_simple_port or modport_tf_port, depending what keyword was earlier
id { $$ = $1; }
//UNSUP '.' idAny '(' ')' { }
//UNSUP '.' idAny '(' expr ')' { }
;
//************************************************ //************************************************
// Variable Declarations // Variable Declarations

View File

@ -7,8 +7,6 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Lesser General Public License Version 3 or the Perl Artistic License # Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0. # Version 2.0.
$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug102");
compile ( compile (
); );

View File

@ -100,7 +100,7 @@ interface handshake #(
// local logic (counter) // local logic (counter)
always @ (posedge clk, posedge rst) always @ (posedge clk, posedge rst)
if (rst) cnt <= '0; if (rst) cnt <= '0;
else cnt <= cnt + inc; else cnt <= cnt + {31'h0, inc};
endinterface : handshake endinterface : handshake
@ -129,7 +129,7 @@ module source #(
// counter // counter
always @ (posedge clk, posedge rst) always @ (posedge clk, posedge rst)
if (rst) cnt <= 32'd0; if (rst) cnt <= 32'd0;
else cnt <= cnt + (inf.req & inf.grt); else cnt <= cnt + {31'd0, (inf.req & inf.grt)};
// request signal // request signal
assign inf.req = rnd[0]; assign inf.req = rnd[0];
@ -161,7 +161,7 @@ module drain #(
// counter // counter
always @ (posedge clk, posedge rst) always @ (posedge clk, posedge rst)
if (rst) cnt <= 32'd0; if (rst) cnt <= 32'd0;
else cnt <= cnt + (inf.req & inf.grt); else cnt <= cnt + {31'd0, (inf.req & inf.grt)};
// grant signal // grant signal
assign inf.grt = rnd[0]; assign inf.grt = rnd[0];

View File

@ -7,10 +7,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Lesser General Public License Version 3 or the Perl Artistic License # Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0. # Version 2.0.
$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug102");
compile ( compile (
verilator_flags2 => ["--lint-only"] );
execute (
check_finished=>1,
); );
ok(1); ok(1);

View File

@ -0,0 +1,45 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Wilson Snyder.
// Very simple test for interface pathclearing
interface ifc;
logic [3:0] value;
endinterface
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=1;
ifc itop();
sub c1 (.isub(itop),
.i_value(4'h4));
always @ (posedge clk) begin
cyc <= cyc + 1;
if (cyc==20) begin
if (c1.i_value != 4) $stop; // 'Normal' crossref just for comparison
if (itop.value != 4) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module sub
(
ifc isub,
input logic [3:0] i_value
);
always @* begin
isub.value = i_value;
end
endmodule : sub

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-2009 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,48 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Wilson Snyder.
// Very simple test for interface pathclearing
interface ifc;
integer hidden_from_isub;
integer value;
modport out_modport (output value);
endinterface
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=1;
ifc itop();
sub c1 (.isub(itop),
.i_value(4));
always @ (posedge clk) begin
cyc <= cyc + 1;
if (cyc==20) begin
if (itop.value != 4) $stop;
itop.hidden_from_isub = 20;
if (itop.hidden_from_isub != 20) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module sub
(
ifc.out_modport isub,
input integer i_value
);
always @* begin
isub.value = i_value;
end
endmodule

View File

@ -7,10 +7,8 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Lesser General Public License Version 3 or the Perl Artistic License # Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0. # Version 2.0.
$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug102");
compile ( compile (
v_flags => [] verilator_flags2 => ["--top-module t"],
); );
execute ( execute (

View File

@ -3,11 +3,6 @@
// This file ONLY is placed into the Public Domain, for any use, // This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2010 by Wilson Snyder. // without warranty, 2010 by Wilson Snyder.
interface counter_io;
logic [3:0] value;
logic reset;
endinterface
module t (/*AUTOARG*/ module t (/*AUTOARG*/
// Inputs // Inputs
clk clk
@ -18,17 +13,24 @@ module t (/*AUTOARG*/
counter_io c1_data(); counter_io c1_data();
counter_io c2_data(); counter_io c2_data();
//counter_io c3_data; // IEEE illegal, and VCS doesn't allow non-() as it does with cells
counter_io c3_data();
counter c1 (.clkm(clk), counter_ansi c1 (.clkm(clk),
.c_data(c1_data), .c_data(c1_data),
.i_value(4'h1)); .i_value(4'h1));
counter2 c2 (.clkm(clk), counter_ansi c2 (.clkm(clk),
.c_data(c2_data), .c_data(c2_data),
.i_value(4'h2)); .i_value(4'h2));
`ifdef VERILATOR counter_ansi `else counter_nansi `endif
/**/ c3 (.clkm(clk),
.c_data(c3_data),
.i_value(4'h3));
initial begin initial begin
c1_data.value = 4'h4; c1_data.value = 4'h4;
c2_data.value = 4'h5; c2_data.value = 4'h5;
c3_data.value = 4'h6;
end end
always @ (posedge clk) begin always @ (posedge clk) begin
@ -36,46 +38,71 @@ module t (/*AUTOARG*/
if (cyc<2) begin if (cyc<2) begin
c1_data.reset <= 1; c1_data.reset <= 1;
c2_data.reset <= 1; c2_data.reset <= 1;
c3_data.reset <= 1;
end end
if (cyc==2) begin if (cyc==2) begin
c1_data.reset <= 0; c1_data.reset <= 0;
c2_data.reset <= 0; c2_data.reset <= 0;
c3_data.reset <= 0;
end
if (cyc==3) begin
if (c1_data.get_lcl() != 12345) $stop;
end end
if (cyc==20) begin if (cyc==20) begin
$write("[%0t] c1 cyc%0d: %0x %0x\n", $time, cyc, c1_data.value, c1_data.reset); $write("[%0t] c1 cyc%0d: c1 %0x %0x c2 %0x %0x c3 %0x %0x\n", $time, cyc,
$write("[%0t] c2 cyc%0d: %0x %0x\n", $time, cyc, c2_data.value, c2_data.reset); c1_data.value, c1_data.reset,
c2_data.value, c2_data.reset,
c3_data.value, c3_data.reset);
if (c1_data.value != 2) $stop; if (c1_data.value != 2) $stop;
if (c2_data.value != 3) $stop; if (c2_data.value != 3) $stop;
if (c3_data.value != 4) $stop;
$write("*-* All Finished *-*\n"); $write("*-* All Finished *-*\n");
$finish; $finish;
end end
end end
endmodule endmodule
module counter interface counter_io;
logic [3:0] value;
logic reset;
integer lcl;
task set_lcl (input integer a); lcl=a; endtask
function integer get_lcl (); return lcl; endfunction
endinterface
interface ifunused;
logic unused;
endinterface
module counter_ansi
( (
input clkm, input clkm,
counter_io c_data, counter_io c_data,
input logic [3:0] i_value input logic [3:0] i_value
); );
always @ (posedge clkm) begin initial begin
if (c_data.reset) c_data.set_lcl(12345);
c_data.value <= i_value;
else
c_data.value <= c_data.value + 1;
end end
endmodule : counter
module counter2(clkm, c_data, i_value); always @ (posedge clkm) begin
c_data.value <= c_data.reset ? i_value : c_data.value + 1;
end
endmodule : counter_ansi
`ifndef VERILATOR
// non-ansi modports not seen in the wild yet. Verilog-Perl needs parser improvement too.
module counter_nansi(clkm, c_data, i_value);
input clkm; input clkm;
counter_io c_data; counter_io c_data;
input logic [3:0] i_value; input logic [3:0] i_value;
always @ (posedge clkm) begin always @ (posedge clkm) begin
if (c_data.reset) c_data.value <= c_data.reset ? i_value : c_data.value + 1;
c_data.value <= i_value;
else
c_data.value <= c_data.value + 1;
end end
endmodule : counter2 endmodule : counter_nansi
`endif
module modunused (ifunused ifinunused);
ifunused ifunused();
endmodule

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-2009 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,72 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Wilson Snyder.
interface ifc;
integer value;
endinterface
module t (/*AUTOARG*/
// Inputs
clk
);
`ifdef INLINE_A //verilator inline_module
`else //verilator no_inline_module
`endif
input clk;
integer cyc=1;
ifc itop1a();
ifc itop1b();
ifc itop2a();
ifc itop2b();
wrapper c1 (.isuba(itop1a),
.isubb(itop1b),
.i_valuea(14),
.i_valueb(15));
wrapper c2 (.isuba(itop2a),
.isubb(itop2b),
.i_valuea(24),
.i_valueb(25));
always @ (posedge clk) begin
cyc <= cyc + 1;
if (cyc==20) begin
if (itop1a.value != 14) $stop;
if (itop1b.value != 15) $stop;
if (itop2a.value != 24) $stop;
if (itop2b.value != 25) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module wrapper
(
ifc isuba,
ifc isubb,
input integer i_valuea,
input integer i_valueb
);
`ifdef INLINE_B //verilator inline_module
`else //verilator no_inline_module
`endif
lower subsuba (.isub(isuba), .i_value(i_valuea));
lower subsubb (.isub(isubb), .i_value(i_valueb));
endmodule
module lower
(
ifc isub,
input integer i_value
);
`ifdef INLINE_C //verilator inline_module
`else //verilator no_inline_module
`endif
always @* begin
isub.value = i_value;
end
endmodule

View File

@ -0,0 +1,21 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003-2009 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.
$Self->{vlt} and $Self->unsupported("Verilator unsupported, interface generates changing types");
$Self->{vcs} and $Self->unsupported("Commercially unsupported, interface crossrefs");
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;

View File

@ -0,0 +1,78 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Wilson Snyder.
// This test demonstrates how not only parameters but the type of a parent
// interface could propagate down to child modules, changing their data type
// determinations. Note presently unsupported in all commercial simulators.
interface ifc;
parameter MODE = 0;
generate
// Note block must be named per SystemVerilog 2005
if (MODE==1) begin : g
integer value;
end
else if (MODE==2) begin : g
real value;
end
endgenerate
endinterface
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=1;
ifc #(1) itop1a();
ifc #(1) itop1b();
ifc #(2) itop2a();
ifc #(2) itop2b();
wrapper c1 (.isuba(itop1a),
.isubb(itop1b),
.i_valuea(14.1),
.i_valueb(15.2));
wrapper c2 (.isuba(itop2a),
.isubb(itop2b),
.i_valuea(24.3),
.i_valueb(25.4));
always @ (posedge clk) begin
cyc <= cyc + 1;
if (cyc==20) begin
if (itop1a.g.value != 14) $stop;
if (itop1b.g.value != 15) $stop;
if (itop2a.g.value != 24) $stop;
if (itop2b.g.value != 25) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module wrapper
(
ifc isuba,
ifc isubb,
input real i_valuea,
input real i_valueb
);
lower subsuba (.isub(isuba), .i_value(i_valuea));
lower subsubb (.isub(isubb), .i_value(i_valueb));
endmodule
module lower
(
ifc isub,
input real i_value
);
always @* begin
`error Commercial sims choke on cross ref here
isub.g.value = i_value;
end
endmodule

View File

@ -0,0 +1,22 @@
#!/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.
top_filename("t/t_interface_down.v");
compile (
v_flags2 => ['+define+INLINE_A'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;

View File

@ -0,0 +1,22 @@
#!/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.
top_filename("t/t_interface_down.v");
compile (
v_flags2 => ['+define+INLINE_A +define+INLINE_B'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;

View File

@ -0,0 +1,22 @@
#!/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.
top_filename("t/t_interface_down.v");
compile (
v_flags2 => ['+define+INLINE_A +define+INLINE_C'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;

View File

@ -0,0 +1,22 @@
#!/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.
top_filename("t/t_interface_down.v");
compile (
v_flags2 => ['+define+INLINE_A +define+INLINE_D'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;

View File

@ -0,0 +1,22 @@
#!/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.
top_filename("t/t_interface_down.v");
compile (
v_flags2 => ['+define+INLINE_B'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;

View File

@ -0,0 +1,22 @@
#!/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.
top_filename("t/t_interface_down.v");
compile (
v_flags2 => ['+define+INLINE_B +define+INLINE_C'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;

View File

@ -0,0 +1,22 @@
#!/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.
top_filename("t/t_interface_down.v");
compile (
v_flags2 => ['+define+INLINE_B +define+INLINE_D'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;

View File

@ -0,0 +1,22 @@
#!/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.
top_filename("t/t_interface_down.v");
compile (
v_flags2 => ['+define+INLINE_C'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;

View File

@ -0,0 +1,22 @@
#!/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.
top_filename("t/t_interface_down.v");
compile (
v_flags2 => ['+define+INLINE_C +define+INLINE_D'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;

View File

@ -0,0 +1,22 @@
#!/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.
top_filename("t/t_interface_down.v");
compile (
v_flags2 => ['+define+INLINE_D'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;

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-2009 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,87 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Wilson Snyder.
// Very simple test for interface pathclearing
`ifdef VCS
`define UNSUPPORTED_MOD_IN_GENS
`endif
`ifdef VERILATOR
`define UNSUPPORTED_MOD_IN_GENS
`endif
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=1;
ifc #(1) itopa();
ifc #(2) itopb();
sub #(1) ca (.isub(itopa),
.i_value(4));
sub #(2) cb (.isub(itopb),
.i_value(5));
always @ (posedge clk) begin
cyc <= cyc + 1;
if (cyc==1) begin
if (itopa.MODE != 1) $stop;
if (itopb.MODE != 2) $stop;
end
if (cyc==20) begin
if (itopa.get_value() != 4) $stop;
if (itopb.get_value() != 5) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module sub
#(parameter MODE = 0)
(
ifc.out_modport isub,
input integer i_value
);
`ifdef UNSUPPORTED_MOD_IN_GENS
always @* isub.value = i_value;
`else
generate if (MODE == 1) begin
always @* isub.valuea = i_value;
end
else if (MODE == 2) begin
always @* isub.valueb = i_value;
end
endgenerate
`endif
endmodule
interface ifc;
parameter MODE = 0;
// Modports under generates not supported by all commercial simulators
`ifdef UNSUPPORTED_MOD_IN_GENS
integer value;
modport out_modport (output value);
function integer get_value(); return value; endfunction
`else
generate if (MODE == 0) begin
integer valuea;
modport out_modport (output valuea);
function integer get_valuea(); return valuea; endfunction
end
else begin
integer valueb;
modport out_modport (output valueb);
function integer get_valueb(); return valueb; endfunction
end
endgenerate
`endif
endinterface

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-2009 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,70 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Wilson Snyder.
// Very simple test for interface pathclearing
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=1;
ifc #(2) itopa();
ifc #(4) itopb();
sub ca (.isub(itopa),
.clk);
sub cb (.isub(itopb),
.clk);
always @ (posedge clk) begin
`ifdef TEST_VERBOSE
$write("[%0t] cyc==%0d result=%b %b\n",$time, cyc, itopa.valueo, itopb.valueo);
`endif
cyc <= cyc + 1;
itopa.valuei <= cyc[1:0];
itopb.valuei <= cyc[3:0];
if (cyc==1) begin
if (itopa.WIDTH != 2) $stop;
if (itopb.WIDTH != 4) $stop;
if ($bits(itopa.valueo) != 2) $stop;
if ($bits(itopb.valueo) != 4) $stop;
if ($bits(itopa.out_modport.valueo) != 2) $stop;
if ($bits(itopb.out_modport.valueo) != 4) $stop;
end
if (cyc==4) begin
if (itopa.valueo != 2'b11) $stop;
if (itopb.valueo != 4'b0011) $stop;
end
if (cyc==5) begin
if (itopa.valueo != 2'b00) $stop;
if (itopb.valueo != 4'b0100) $stop;
end
if (cyc==20) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
interface ifc
#(parameter WIDTH = 1);
// verilator lint_off MULTIDRIVEN
logic [WIDTH-1:0] valuei;
logic [WIDTH-1:0] valueo;
// verilator lint_on MULTIDRIVEN
modport out_modport (input valuei, output valueo);
endinterface
// Note not parameterized
module sub
(
ifc.out_modport isub,
input clk
);
always @(posedge clk) isub.valueo <= isub.valuei + 1;
endmodule

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-2009 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,70 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Wilson Snyder.
// Very simple test for interface pathclearing
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=1;
ifc #(2) itopa();
ifc #(4) itopb();
sub ca (.isub(itopa.out_modport),
.clk);
sub cb (.isub(itopb.out_modport),
.clk);
always @ (posedge clk) begin
`ifdef TEST_VERBOSE
$write("[%0t] cyc==%0d result=%b %b\n",$time, cyc, itopa.valueo, itopb.valueo);
`endif
cyc <= cyc + 1;
itopa.valuei <= cyc[1:0];
itopb.valuei <= cyc[3:0];
if (cyc==1) begin
if (itopa.WIDTH != 2) $stop;
if (itopb.WIDTH != 4) $stop;
if ($bits(itopa.valueo) != 2) $stop;
if ($bits(itopb.valueo) != 4) $stop;
if ($bits(itopa.out_modport.valueo) != 2) $stop;
if ($bits(itopb.out_modport.valueo) != 4) $stop;
end
if (cyc==4) begin
if (itopa.valueo != 2'b11) $stop;
if (itopb.valueo != 4'b0011) $stop;
end
if (cyc==5) begin
if (itopa.valueo != 2'b00) $stop;
if (itopb.valueo != 4'b0100) $stop;
end
if (cyc==20) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
interface ifc
#(parameter WIDTH = 1);
// verilator lint_off MULTIDRIVEN
logic [WIDTH-1:0] valuei;
logic [WIDTH-1:0] valueo;
// verilator lint_on MULTIDRIVEN
modport out_modport (input valuei, output valueo);
endinterface
// Note not parameterized
module sub
(
ifc.out_modport isub,
input clk
);
always @(posedge clk) isub.valueo <= isub.valuei + 1;
endmodule

View File

@ -7,13 +7,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Lesser General Public License Version 3 or the Perl Artistic License # Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0. # Version 2.0.
$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug102");
top_filename("t/t_interface.v"); top_filename("t/t_interface.v");
compile ( compile (
# Avoid inlining so we find bugs in the non-inliner connection code # Avoid inlining so we find bugs in the non-inliner connection code
v_flags => ["-Oi"], verilator_flags2 => ["-Oi"],
); );
execute ( execute (

View File

@ -0,0 +1,22 @@
#!/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 (
verilator_flags2 => ["--lint-only"],
verilator_make_gcc => 0,
make_top_shell => 0,
make_main => 0,
fails => 1,
expect=>
'%Error: t/t_interface_mismodport_bad.v:\d+: Can\'t find definition of \'bad\' in dotted signal: isub.bad
.*%Error: Exiting due to.*',
);
ok(1);
1;

View File

@ -0,0 +1,37 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Wilson Snyder.
interface ifc;
integer ok;
integer bad;
modport out_modport (output ok);
endinterface
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=1;
ifc itop();
counter_ansi c1 (.isub(itop),
.i_value(4'h4));
endmodule
module counter_ansi
(
ifc.out_modport isub,
input logic [3:0] i_value
);
always @* begin
isub.ok = i_value;
isub.bad = i_value; // Illegal access
end
endmodule

View File

@ -7,10 +7,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Lesser General Public License Version 3 or the Perl Artistic License # Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0. # Version 2.0.
$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug102");
compile ( compile (
v_flags => [],
); );
execute ( execute (

View File

@ -3,13 +3,26 @@
// This file ONLY is placed into the Public Domain, for any use, // This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2010 by Wilson Snyder. // without warranty, 2010 by Wilson Snyder.
interface counter_io; interface counter_if;
logic [3:0] value; logic [3:0] value;
logic reset; logic reset;
modport counter_side (input reset, output value); modport counter_mp (input reset, output value);
modport core_side (output reset, input value); modport core_mp (output reset, input value);
endinterface endinterface
// Check can have inst module before top module
module counter_ansi
(
input clkm,
counter_if c_data,
input logic [3:0] i_value
);
always @ (posedge clkm) begin
c_data.value <= c_data.reset ? i_value : c_data.value + 1;
end
endmodule : counter_ansi
module t (/*AUTOARG*/ module t (/*AUTOARG*/
// Inputs // Inputs
clk clk
@ -18,19 +31,31 @@ module t (/*AUTOARG*/
input clk; input clk;
integer cyc=1; integer cyc=1;
counter_io c1_data(); counter_if c1_data();
counter_io c2_data(); counter_if c2_data();
counter_if c3_data();
counter_if c4_data();
counter c1 (.clkm(clk), counter_ansi c1 (.clkm(clk),
.c_data(c1_data), .c_data(c1_data.counter_mp),
.i_value(4'h1)); .i_value(4'h1));
counter c2 (.clkm(clk), `ifdef VERILATOR counter_ansi `else counter_nansi `endif
.c_data(c2_data.counter_side), /**/ c2 (.clkm(clk),
.i_value(4'h2)); .c_data(c2_data.counter_mp),
.i_value(4'h2));
counter_ansi_m c3 (.clkm(clk),
.c_data(c3_data),
.i_value(4'h3));
`ifdef VERILATOR counter_ansi_m `else counter_nansi_m `endif
/**/ c4 (.clkm(clk),
.c_data(c4_data),
.i_value(4'h4));
initial begin initial begin
c1_data.value = 4'h4; c1_data.value = 4'h4;
c2_data.value = 4'h5; c2_data.value = 4'h5;
c3_data.value = 4'h6;
c4_data.value = 4'h7;
end end
always @ (posedge clk) begin always @ (posedge clk) begin
@ -38,33 +63,69 @@ module t (/*AUTOARG*/
if (cyc<2) begin if (cyc<2) begin
c1_data.reset <= 1; c1_data.reset <= 1;
c2_data.reset <= 1; c2_data.reset <= 1;
c3_data.reset <= 1;
c4_data.reset <= 1;
end end
if (cyc==2) begin if (cyc==2) begin
c1_data.reset <= 0; c1_data.reset <= 0;
c2_data.reset <= 0; c2_data.reset <= 0;
c3_data.reset <= 0;
c4_data.reset <= 0;
end end
if (cyc==20) begin if (cyc==20) begin
$write("[%0t] c1 cyc%0d: %0x %0x\n", $time, cyc, c1_data.value, c1_data.reset); $write("[%0t] cyc%0d: c1 %0x %0x c2 %0x %0x c3 %0x %0x c4 %0x %0x\n", $time, cyc,
$write("[%0t] c2 cyc%0d: %0x %0x\n", $time, cyc, c2_data.value, c2_data.reset); c1_data.value, c1_data.reset,
c2_data.value, c2_data.reset,
c3_data.value, c3_data.reset,
c4_data.value, c4_data.reset);
if (c1_data.value != 2) $stop; if (c1_data.value != 2) $stop;
if (c2_data.value != 3) $stop; if (c2_data.value != 3) $stop;
if (c3_data.value != 4) $stop;
if (c4_data.value != 5) $stop;
$write("*-* All Finished *-*\n"); $write("*-* All Finished *-*\n");
$finish; $finish;
end end
end end
endmodule endmodule
module counter `ifndef VERILATOR
// non-ansi modports not seen in the wild yet. Verilog-Perl needs parser improvement too.
module counter_nansi
(clkm, c_data, i_value);
input clkm;
counter_if c_data;
input logic [3:0] i_value;
always @ (posedge clkm) begin
c_data.value <= c_data.reset ? i_value : c_data.value + 1;
end
endmodule : counter_nansi
`endif
module counter_ansi_m
( (
input clkm, input clkm,
counter_io c_data, counter_if.counter_mp c_data,
input logic [3:0] i_value input logic [3:0] i_value
); );
always @ (posedge clkm) begin always @ (posedge clkm) begin
if (c_data.reset) c_data.value <= c_data.reset ? i_value : c_data.value + 1;
c_data.value <= i_value;
else
c_data.value <= c_data.value + 1;
end end
endmodule : counter endmodule : counter_ansi_m
`ifndef VERILATOR
// non-ansi modports not seen in the wild yet. Verilog-Perl needs parser improvement too.
module counter_nansi_m
(clkm, c_data, i_value);
input clkm;
counter_if.counter_mp c_data;
input logic [3:0] i_value;
always @ (posedge clkm) begin
c_data.value <= c_data.reset ? i_value : c_data.value + 1;
end
endmodule : counter_nansi_m
`endif

View File

@ -7,13 +7,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Lesser General Public License Version 3 or the Perl Artistic License # Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0. # Version 2.0.
$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug102");
top_filename("t/t_interface_modport.v"); top_filename("t/t_interface_modport.v");
compile ( compile (
# Avoid inlining so we find bugs in the non-inliner connection code # Avoid inlining so we find bugs in the non-inliner connection code
v_flags => ["-Oi"], verilator_flags2 => ["-Oi"],
); );
execute ( execute (

View File

@ -0,0 +1,21 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003-2009 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 (
verilator_flags2 => ["--lint-only"],
verilator_make_gcc => 0,
make_top_shell => 0,
make_main => 0,
fails => 1,
expect=>
'%Error: t/t_interface_top_bad.v:\d+: Unsupported: Interfaced port on top level module',
);
ok(1);
1;

View File

@ -3,17 +3,17 @@
// This file ONLY is placed into the Public Domain, for any use, // This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2010 by Wilson Snyder. // without warranty, 2010 by Wilson Snyder.
interface counter_io; interface ifc;
logic [3:0] value; logic [3:0] value;
logic reset; logic reset;
modport counter_side (input reset, output value); modport counter_mp (input reset, output value);
modport core_side (output reset, input value); modport core_mp (output reset, input value);
endinterface endinterface
module t module t
(// Inputs (// Inputs
input clk, input clk,
counter_io.counter_side c_data ifc.counter_mp c_data
); );
integer cyc=1; integer cyc=1;

View File

@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
$Self->{vlt} or $Self->skip("Verilator only test"); $Self->{vlt} or $Self->skip("Verilator only test");
compile ( compile (
v_flags => ["-Wno-IMPLICIT"], v_flags2 => ["-Wno-IMPLICIT"],
); );
ok(1); ok(1);

View File

@ -8,7 +8,6 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Version 2.0. # Version 2.0.
compile ( compile (
v_flags => [],
); );
execute ( execute (