Support interfaces and modports, bug102.
This commit is contained in:
parent
7c834ad118
commit
23bb045a72
2
Changes
2
Changes
|
|
@ -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]
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
11
src/V3Ast.h
11
src/V3Ast.h
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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); }
|
||||||
|
|
|
||||||
105
src/V3AstNodes.h
105
src/V3AstNodes.h
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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*) {
|
||||||
|
|
|
||||||
140
src/V3Param.cpp
140
src/V3Param.cpp
|
|
@ -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"));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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); }
|
||||||
|
|
|
||||||
121
src/verilog.y
121
src/verilog.y
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 (
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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];
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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 (
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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 (
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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 (
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 (
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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 (
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue