0001-Support-interfaces-and-modports.patch
| b/src/Makefile_obj.in | ||
|---|---|---|
| 188 | 188 |
V3Hashed.o \ |
| 189 | 189 |
V3Inline.o \ |
| 190 | 190 |
V3Inst.o \ |
| 191 |
V3Interface.o \ |
|
| 191 | 192 |
V3Life.o \ |
| 192 | 193 |
V3LifePost.o \ |
| 193 | 194 |
V3Link.o \ |
| b/src/V3Ast.h | ||
|---|---|---|
| 310 | 310 |
BLOCKTEMP, |
| 311 | 311 |
MODULETEMP, |
| 312 | 312 |
STMTTEMP, |
| 313 |
XTEMP |
|
| 313 |
XTEMP, |
|
| 314 |
INTERFACE, // Used to link Interfaces between modules |
|
| 314 | 315 |
}; |
| 315 | 316 |
enum en m_e; |
| 316 | 317 |
inline AstVarType () {}
|
| ... | ... | |
| 322 | 323 |
"?","GPARAM","LPARAM","GENVAR", |
| 323 | 324 |
"VAR","INPUT","OUTPUT","INOUT", |
| 324 | 325 |
"SUPPLY0","SUPPLY1","WIRE","IMPLICITWIRE","TRIWIRE","PORT", |
| 325 |
"BLOCKTEMP","MODULETEMP","STMTTEMP","XTEMP"}; |
|
| 326 |
"BLOCKTEMP","MODULETEMP","STMTTEMP","XTEMP", "INTERFACE"};
|
|
| 326 | 327 |
return names[m_e]; } |
| 327 | 328 |
}; |
| 328 | 329 |
inline bool operator== (AstVarType lhs, AstVarType rhs) { return (lhs.m_e == rhs.m_e); }
|
| b/src/V3AstNodes.cpp | ||
|---|---|---|
| 508 | 508 |
this->AstNode::dump(str); |
| 509 | 509 |
if (littleEndian()) str<<" [LITTLE]"; |
| 510 | 510 |
} |
| 511 |
void AstInterfaceDType::dump(ostream& str) {
|
|
| 512 |
this->AstNode::dump(str); |
|
| 513 |
if (interfacep()) { str<<" -> "; interfacep()->dump(str); }
|
|
| 514 |
else { str<<" -> UNLINKED"; }
|
|
| 515 |
} |
|
| 516 |
void AstModportVar::dump(ostream& str) {
|
|
| 517 |
this->AstNode::dump(str); |
|
| 518 |
str<<" "<<varType(); |
|
| 519 |
if (varp()) { str<<" -> "; varp()->dump(str); }
|
|
| 520 |
else { str<<" -> UNLINKED"; }
|
|
| 521 |
} |
|
| 511 | 522 |
void AstRefDType::dump(ostream& str) {
|
| 512 | 523 |
this->AstNode::dump(str); |
| 513 | 524 |
if (defp()) { str<<" -> "; defp()->dump(str); }
|
| ... | ... | |
| 539 | 550 |
if (varp()) { str<<" -> "; varp()->dump(str); }
|
| 540 | 551 |
else { str<<" ->UNLINKED"; }
|
| 541 | 552 |
} |
| 553 |
void AstScopeAlias::dump(ostream& str) {
|
|
| 554 |
this->AstNode::dump(str); |
|
| 555 |
if (aliasp()) { str<<" -> " << aliasp(); }
|
|
| 556 |
else { str<<" ->UNLINKED"; }
|
|
| 557 |
} |
|
| 542 | 558 |
void AstVarRef::dump(ostream& str) {
|
| 543 | 559 |
this->AstNode::dump(str); |
| 544 | 560 |
if (lvalue()) str<<" [LV] => "; |
| b/src/V3AstNodes.h | ||
|---|---|---|
| 295 | 295 |
void implicit(bool flag) { m_implicit = flag; }
|
| 296 | 296 |
}; |
| 297 | 297 | |
| 298 |
struct AstInterfaceDType : public AstNodeDType {
|
|
| 299 |
private: |
|
| 300 |
AstInterface* m_interfacep; |
|
| 301 |
string m_name; |
|
| 302 |
string m_varName; |
|
| 303 |
string m_modportName; |
|
| 304 |
AstModport* m_modportp; |
|
| 305 |
public: |
|
| 306 |
AstInterfaceDType(FileLine* fl, const string& name) |
|
| 307 |
: AstNodeDType(fl), m_interfacep(NULL), m_name(name), m_varName(name), |
|
| 308 |
m_modportName(""), m_modportp(NULL) { }
|
|
| 309 |
AstInterfaceDType(FileLine* fl, const string& name, const string& modport) |
|
| 310 |
: AstNodeDType(fl), m_interfacep(NULL), m_name(name), m_varName(name), |
|
| 311 |
m_modportName(modport), m_modportp(NULL) { }
|
|
| 312 |
ASTNODE_NODE_FUNCS(InterfaceDType, INTERFACEDTYPE) |
|
| 313 |
// METHODS |
|
| 314 |
virtual void dump(ostream& str=cout); |
|
| 315 |
virtual string name() const { return m_name; }
|
|
| 316 |
virtual AstBasicDType* basicp() const { return NULL; }
|
|
| 317 |
virtual int widthAlignBytes() const { return 1; }
|
|
| 318 |
virtual int widthTotalBytes() const { return 1; }
|
|
| 319 |
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
|
|
| 320 |
AstInterface* interfacep() const { return m_interfacep; }
|
|
| 321 |
void interfacep(AstInterface* nodep) { m_interfacep=nodep; }
|
|
| 322 |
string varName() const { return m_varName; }
|
|
| 323 |
void varName(const string& name) { m_varName=name; }
|
|
| 324 |
string modportName() const { return m_modportName; }
|
|
| 325 |
void modportName(const string& name) { m_modportName=name; }
|
|
| 326 |
AstModport* modportp() const { return m_modportp; }
|
|
| 327 |
void modportp(AstModport* modportp) { m_modportp=modportp; }
|
|
| 328 |
bool isModport() { return !!modportName().size(); }
|
|
| 329 |
}; |
|
| 330 | ||
| 298 | 331 |
struct AstRefDType : public AstNodeDType {
|
| 299 | 332 |
private: |
| 300 | 333 |
AstTypedef* m_defp; |
| ... | ... | |
| 534 | 567 |
// A variable (in/out/wire/reg/param) inside a module |
| 535 | 568 |
private: |
| 536 | 569 |
string m_name; // Name of variable |
| 570 |
string m_origName; // Original name before dot addition |
|
| 537 | 571 |
AstVarType m_varType; // Type of variable |
| 538 | 572 |
bool m_input:1; // Input or inout |
| 539 | 573 |
bool m_output:1; // Output or inout |
| ... | ... | |
| 570 | 604 |
public: |
| 571 | 605 |
AstVar(FileLine* fl, AstVarType type, const string& name, AstNodeDType* dtypep) |
| 572 | 606 |
:AstNode(fl) |
| 573 |
, m_name(name) {
|
|
| 607 |
, m_name(name), m_origName(name) {
|
|
| 574 | 608 |
init(); |
| 575 | 609 |
combineType(type); setOp1p(dtypep); |
| 576 | 610 |
if (dtypep && dtypep->basicp()) {
|
| ... | ... | |
| 579 | 613 |
} |
| 580 | 614 |
AstVar(FileLine* fl, AstVarType type, const string& name, AstLogicPacked, int wantwidth) |
| 581 | 615 |
:AstNode(fl) |
| 582 |
, m_name(name) {
|
|
| 616 |
, m_name(name), m_origName(name) {
|
|
| 583 | 617 |
init(); |
| 584 | 618 |
combineType(type); |
| 585 | 619 |
setOp1p(new AstBasicDType(fl, AstLogicPacked(), wantwidth)); |
| ... | ... | |
| 587 | 621 |
} |
| 588 | 622 |
AstVar(FileLine* fl, AstVarType type, const string& name, AstVar* examplep) |
| 589 | 623 |
:AstNode(fl) |
| 590 |
, m_name(name) {
|
|
| 624 |
, m_name(name), m_origName(name) {
|
|
| 591 | 625 |
init(); |
| 592 | 626 |
combineType(type); |
| 593 | 627 |
if (examplep->dtypep()) {
|
| ... | ... | |
| 598 | 632 |
ASTNODE_NODE_FUNCS(Var, VAR) |
| 599 | 633 |
virtual void dump(ostream& str); |
| 600 | 634 |
virtual string name() const { return m_name; } // * = Var name
|
| 635 |
string origName() const { return m_origName; } // * = Original name
|
|
| 601 | 636 |
virtual bool maybePointedTo() const { return true; }
|
| 602 | 637 |
virtual bool broken() const { return !dtypep(); }
|
| 603 | 638 |
AstVarType varType() const { return m_varType; } // * = Type of variable
|
| 639 |
AstVarType varType(AstVarType::en type) { m_varType == type; }
|
|
| 604 | 640 |
void varType2Out() { m_tristate=0; m_input=0; m_output=1; }
|
| 605 | 641 |
void varType2In() { m_tristate=0; m_input=1; m_output=0; }
|
| 606 | 642 |
string scType() const; // Return SysC type: bool, uint32_t, uint64_t, sc_bv |
| ... | ... | |
| 647 | 683 |
bool isPrimaryIO() const { return m_primaryIO; }
|
| 648 | 684 |
bool isPrimaryIn() const { return isPrimaryIO() && isInput(); }
|
| 649 | 685 |
bool isIO() const { return (m_input||m_output); }
|
| 686 |
bool isInterface() const { return (varType()==AstVarType::INTERFACE); }
|
|
| 650 | 687 |
bool isSignal() const { return (varType()==AstVarType::WIRE || varType()==AstVarType::IMPLICITWIRE
|
| 651 | 688 |
|| varType()==AstVarType::VAR); } |
| 652 | 689 |
bool isTemp() const { return (varType()==AstVarType::BLOCKTEMP || varType()==AstVarType::MODULETEMP
|
| ... | ... | |
| 826 | 863 |
void circular(bool flag) { m_circular = flag; }
|
| 827 | 864 |
}; |
| 828 | 865 | |
| 866 |
struct AstScopeAlias : public AstVarScope {
|
|
| 867 |
// An Alias to another Scope |
|
| 868 |
private: |
|
| 869 |
AstScope* m_aliasp; // The scope this points to |
|
| 870 |
public: |
|
| 871 |
AstScopeAlias(FileLine* fl, AstScope* scopep, AstVar* varp, AstScope* aliasp) |
|
| 872 |
:AstVarScope(fl, scopep, varp), m_aliasp(aliasp) {}
|
|
| 873 |
ASTNODE_NODE_FUNCS(ScopeAlias, SCOPEALIAS) |
|
| 874 |
AstScope* aliasp() const { return m_aliasp; }
|
|
| 875 |
void aliasp(AstScope* aliasp) { m_aliasp = aliasp; }
|
|
| 876 |
virtual void dump(ostream& str); |
|
| 877 |
virtual string name() const {return scopep()->name()+"."+varp()->name();} // * = Var name
|
|
| 878 |
}; |
|
| 879 | ||
| 829 | 880 |
struct AstVarRef : public AstNodeVarRef {
|
| 830 | 881 |
// A reference to a variable (lvalue or rvalue) |
| 831 | 882 |
AstVarRef(FileLine* fl, const string& name, bool lvalue) |
| ... | ... | |
| 953 | 1004 |
void packagep(AstPackage* nodep) { m_packagep=nodep; }
|
| 954 | 1005 |
}; |
| 955 | 1006 | |
| 1007 |
struct AstInterface : public AstNodeModule {
|
|
| 1008 |
// A module declaration |
|
| 1009 |
AstInterface(FileLine* fl, const string& name) |
|
| 1010 |
: AstNodeModule (fl,name) { }
|
|
| 1011 |
ASTNODE_NODE_FUNCS(Interface, INTERFACE) |
|
| 1012 |
}; |
|
| 1013 | ||
| 1014 |
struct AstModportVar : public AstNode {
|
|
| 1015 |
// A Var under a modport |
|
| 1016 |
private: |
|
| 1017 |
string m_name; // Name of the variable |
|
| 1018 |
AstVarType m_type; // Type of the variable |
|
| 1019 |
AstVar* m_varp; // Link to the actual Var |
|
| 1020 |
public: |
|
| 1021 |
AstModportVar(FileLine* fl, const string& name, AstVarType::en type) |
|
| 1022 |
: AstNode(fl), m_name(name), m_type(type), m_varp(NULL) { }
|
|
| 1023 |
ASTNODE_NODE_FUNCS(ModportVar, MODPORTVAR) |
|
| 1024 |
virtual void dump(ostream& str); |
|
| 1025 |
AstVarType varType() const { return m_type; } // * = Type of variable
|
|
| 1026 |
virtual string name() const { return m_name; }
|
|
| 1027 |
bool isInput() const { return (varType()==AstVarType::INPUT || varType()==AstVarType::INOUT); }
|
|
| 1028 |
bool isOutput() const { return (varType()==AstVarType::OUTPUT || varType()==AstVarType::INOUT); }
|
|
| 1029 |
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
|
|
| 1030 |
void varp(AstVar* varp) { m_varp=varp; }
|
|
| 1031 |
}; |
|
| 1032 | ||
| 1033 |
struct AstModport : public AstNode {
|
|
| 1034 |
// A modport in an interface |
|
| 1035 |
private: |
|
| 1036 |
string m_name; // Name of the modport |
|
| 1037 |
public: |
|
| 1038 |
AstModport(FileLine* fl, const string& name, AstModportVar* varsp) |
|
| 1039 |
: AstNode(fl), m_name(name) {
|
|
| 1040 |
addNOp1p(varsp); } |
|
| 1041 |
virtual string name() const { return m_name; }
|
|
| 1042 |
ASTNODE_NODE_FUNCS(Modport, MODPORT) |
|
| 1043 |
AstModportVar* varsp() const { return op1p()->castModportVar(); } // op1 = List of Vars
|
|
| 1044 |
}; |
|
| 1045 | ||
| 956 | 1046 |
struct AstCell : public AstNode {
|
| 957 | 1047 |
// A instantiation cell or interface call (don't know which until link) |
| 958 | 1048 |
private: |
| ... | ... | |
| 960 | 1050 |
string m_origName; // Original name before dot addition |
| 961 | 1051 |
string m_modName; // Module the cell instances |
| 962 | 1052 |
AstNodeModule* m_modp; // [AfterLink] Pointer to module instanced |
| 1053 |
bool m_hasVar; // True if a Var has been created for this cell |
|
| 963 | 1054 |
public: |
| 964 | 1055 |
AstCell(FileLine* fl, const string& instName, const string& modName, |
| 965 | 1056 |
AstPin* pinsp, AstPin* paramsp, AstRange* rangep) |
| 966 | 1057 |
: AstNode(fl) |
| 967 | 1058 |
, m_name(instName), m_origName(instName), m_modName(modName) |
| 968 |
, m_modp(NULL) {
|
|
| 1059 |
, m_modp(NULL), m_hasVar(false) {
|
|
| 969 | 1060 |
addNOp1p(pinsp); addNOp2p(paramsp); setNOp3p(rangep); } |
| 970 | 1061 |
ASTNODE_NODE_FUNCS(Cell, CELL) |
| 971 | 1062 |
// No cloneRelink, we presume cloneee's want the same module linkages |
| ... | ... | |
| 986 | 1077 |
void addPinsp(AstPin* nodep) { addOp1p(nodep); }
|
| 987 | 1078 |
void addParamsp(AstPin* nodep) { addOp2p(nodep); }
|
| 988 | 1079 |
void modp(AstNodeModule* nodep) { m_modp = nodep; }
|
| 1080 |
virtual bool hasVar() const { return m_hasVar; }
|
|
| 1081 |
virtual void hasVar(bool status) { m_hasVar = status; }
|
|
| 989 | 1082 |
}; |
| 990 | 1083 | |
| 991 | 1084 |
struct AstCellInline : public AstNode {
|
| ... | ... | |
| 1320 | 1413 |
} |
| 1321 | 1414 |
}; |
| 1322 | 1415 | |
| 1416 |
struct AstAssignVarScope : public AstNodeAssign {
|
|
| 1417 |
// Assign two VarScopes to each other |
|
| 1418 |
AstAssignVarScope(FileLine* fileline, AstNode* lhsp, AstNode* rhsp) |
|
| 1419 |
: AstNodeAssign(fileline, lhsp, rhsp) { }
|
|
| 1420 |
ASTNODE_NODE_FUNCS(AssignVarScope, ASSIGNVARSCOPE) |
|
| 1421 |
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAssignVarScope(this->fileline(), lhsp, rhsp); }
|
|
| 1422 |
}; |
|
| 1423 | ||
| 1323 | 1424 |
struct AstPull : public AstNode {
|
| 1324 | 1425 |
private: |
| 1325 | 1426 |
bool m_direction; |
| b/src/V3Const.cpp | ||
|---|---|---|
| 1309 | 1309 |
virtual void visit(AstAssignAlias* nodep, AstNUser*) {
|
| 1310 | 1310 |
// Don't perform any optimizations, keep the alias around |
| 1311 | 1311 |
} |
| 1312 |
virtual void visit(AstAssignVarScope* nodep, AstNUser*) {
|
|
| 1313 |
// Don't perform any optimizations, the node won't be linked yet |
|
| 1314 |
} |
|
| 1312 | 1315 |
virtual void visit(AstAssignW* nodep, AstNUser*) {
|
| 1313 | 1316 |
nodep->iterateChildren(*this); |
| 1314 | 1317 |
if (replaceNodeAssign(nodep)) return; |
| b/src/V3Inline.cpp | ||
|---|---|---|
| 182 | 182 |
m_modp->addStmtp(new AstAssignW(nodep->fileline(), |
| 183 | 183 |
new AstVarRef(nodep->fileline(), nodep, true), |
| 184 | 184 |
exprconstp->cloneTree(true))); |
| 185 |
} else {
|
|
| 185 |
} else if (!nodep->isInterface()) {
|
|
| 186 | 186 |
m_modp->addStmtp(new AstAssignAlias(nodep->fileline(), |
| 187 | 187 |
new AstVarRef(nodep->fileline(), nodep, true), |
| 188 | 188 |
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false))); |
| 189 | 189 |
AstNode* nodebp=exprvarrefp->varp(); |
| 190 | 190 |
nodep ->fileline()->modifyStateInherit(nodebp->fileline()); |
| 191 | 191 |
nodebp->fileline()->modifyStateInherit(nodep ->fileline()); |
| 192 |
} else {
|
|
| 193 |
m_modp->addStmtp(new AstAssignVarScope(nodep->fileline(), |
|
| 194 |
new AstVarRef(nodep->fileline(), nodep, true), |
|
| 195 |
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false))); |
|
| 196 |
AstNode* nodebp=exprvarrefp->varp(); |
|
| 197 |
nodep ->fileline()->modifyStateInherit(nodebp->fileline()); |
|
| 198 |
nodebp->fileline()->modifyStateInherit(nodep ->fileline()); |
|
| 192 | 199 |
} |
| 193 | 200 |
} |
| 194 | 201 |
// Variable under the inline cell, need to rename to avoid conflicts |
| ... | ... | |
| 330 | 337 |
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
| 331 | 338 |
m_stmtCnt = 0; |
| 332 | 339 |
m_modp = nodep; |
| 333 |
m_modp->user2(true); // Allowed = true |
|
| 340 |
if (nodep->castInterface()) {
|
|
| 341 |
m_modp->user2(false); |
|
| 342 |
} else {
|
|
| 343 |
m_modp->user2(true); // Allowed = true |
|
| 344 |
} |
|
| 334 | 345 |
if (m_modp->modPublic()) cantInline("modPublic");
|
| 335 | 346 |
// |
| 336 | 347 |
nodep->iterateChildren(*this); |
| ... | ... | |
| 399 | 410 |
nodep->iterateChildren(*this); |
| 400 | 411 |
m_stmtCnt = oldcnt; |
| 401 | 412 |
} |
| 413 |
virtual void visit(AstInterfaceDType* nodep, AstNUser*) {
|
|
| 414 |
// Unsupported: Inlining of modules with interfaces |
|
| 415 |
m_modp->user2(false); |
|
| 416 |
} |
|
| 402 | 417 |
//-------------------- |
| 403 | 418 |
// Default: Just iterate |
| 404 | 419 |
virtual void visit(AstNode* nodep, AstNUser*) {
|
| b/src/V3Inst.cpp | ||
|---|---|---|
| 113 | 113 |
exprp); |
| 114 | 114 |
m_modp->addStmtp(assp); |
| 115 | 115 |
if (debug()>=9) assp->dumpTree(cout," _new: "); |
| 116 |
} else if (nodep->modVarp()->isInterface()) {
|
|
| 117 |
// Create an AstAssignVarScope for Vars to Cells so we can link with their scope later |
|
| 118 |
AstNode* rhsp = new AstVarXRef (exprp->fileline(), nodep->modVarp()->name(), m_cellp->name(), false); |
|
| 119 |
rhsp->widthSignedFrom(nodep); |
|
| 120 |
if (AstVarRef* refp = exprp->castVarRef()) {
|
|
| 121 |
refp->varp(NULL); |
|
| 122 |
} else {
|
|
| 123 |
exprp->v3fatalSrc("Interfaces: Pin is not connected to a VarRef");
|
|
| 124 |
} |
|
| 125 |
AstAssignVarScope* assp = new AstAssignVarScope(exprp->fileline(), exprp, rhsp); |
|
| 126 |
m_modp->addStmtp(assp); |
|
| 116 | 127 |
} else {
|
| 117 | 128 |
nodep->v3error("Assigned pin is neither input nor output");
|
| 118 | 129 |
} |
| b/src/V3Interface.cpp | ||
|---|---|---|
| 1 |
//************************************************************************* |
|
| 2 |
// DESCRIPTION: Verilator: Parse module/signal name references |
|
| 3 |
// |
|
| 4 |
// Code available from: http://www.veripool.org/verilator |
|
| 5 |
// |
|
| 6 |
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli |
|
| 7 |
// |
|
| 8 |
//************************************************************************* |
|
| 9 |
// |
|
| 10 |
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can |
|
| 11 |
// redistribute it and/or modify it under the terms of either the GNU |
|
| 12 |
// Lesser General Public License Version 3 or the Perl Artistic License |
|
| 13 |
// Version 2.0. |
|
| 14 |
// |
|
| 15 |
// Verilator is distributed in the hope that it will be useful, |
|
| 16 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 17 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 18 |
// GNU General Public License for more details. |
|
| 19 |
// |
|
| 20 |
//************************************************************************* |
|
| 21 |
// Interface TRANSFORMATIONS: |
|
| 22 |
// Top-down traversal: |
|
| 23 |
// MODPORT |
|
| 24 |
// Delete tree |
|
| 25 |
//************************************************************************* |
|
| 26 | ||
| 27 |
#include "config_build.h" |
|
| 28 |
#include "verilatedos.h" |
|
| 29 |
#include <cstdio> |
|
| 30 |
#include <cstdarg> |
|
| 31 |
#include <unistd.h> |
|
| 32 | ||
| 33 |
#include "V3Global.h" |
|
| 34 |
#include "V3Interface.h" |
|
| 35 |
#include "V3Ast.h" |
|
| 36 | ||
| 37 |
//###################################################################### |
|
| 38 |
// Lint interfaces/modports, as a visitor of each AstNode |
|
| 39 | ||
| 40 |
class InterfaceCleanup : public AstNVisitor {
|
|
| 41 |
private: |
|
| 42 |
// NODE STATE |
|
| 43 | ||
| 44 |
// ENUMS |
|
| 45 | ||
| 46 |
// STATE |
|
| 47 | ||
| 48 |
// METHODS |
|
| 49 |
virtual void visit(AstModport* nodep, AstNUser*) {
|
|
| 50 |
// Modports aren't needed anymore, delete them |
|
| 51 |
nodep->unlinkFrBack()->deleteTree(); nodep=NULL; |
|
| 52 |
} |
|
| 53 | ||
| 54 |
virtual void visit(AstNode* nodep, AstNUser*) {
|
|
| 55 |
// Default: Just iterate |
|
| 56 |
nodep->iterateChildren(*this); |
|
| 57 |
} |
|
| 58 | ||
| 59 |
public: |
|
| 60 |
// CONSTUCTORS |
|
| 61 |
InterfaceCleanup(AstNetlist* rootp) {
|
|
| 62 |
rootp->accept(*this); |
|
| 63 |
} |
|
| 64 |
virtual ~InterfaceCleanup() {}
|
|
| 65 |
}; |
|
| 66 | ||
| 67 |
//###################################################################### |
|
| 68 |
// Interface class functions |
|
| 69 | ||
| 70 |
void V3Interface::lint(AstNetlist* rootp) {
|
|
| 71 |
UINFO(4,__FUNCTION__<<": "<<endl); |
|
| 72 |
InterfaceCleanup visitor(rootp); |
|
| 73 |
} |
|
| b/src/V3Interface.h | ||
|---|---|---|
| 1 |
// -*- C++ -*- |
|
| 2 |
//************************************************************************* |
|
| 3 |
// DESCRIPTION: Verilator: Link modules/signals together |
|
| 4 |
// |
|
| 5 |
// Code available from: http://www.veripool.org/verilator |
|
| 6 |
// |
|
| 7 |
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli |
|
| 8 |
// |
|
| 9 |
//************************************************************************* |
|
| 10 |
// |
|
| 11 |
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can |
|
| 12 |
// redistribute it and/or modify it under the terms of either the GNU |
|
| 13 |
// Lesser General Public License Version 3 or the Perl Artistic License |
|
| 14 |
// Version 2.0. |
|
| 15 |
// |
|
| 16 |
// Verilator is distributed in the hope that it will be useful, |
|
| 17 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 18 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 19 |
// GNU General Public License for more details. |
|
| 20 |
// |
|
| 21 |
//************************************************************************* |
|
| 22 | ||
| 23 |
#ifndef _V3INTERFACE_H_ |
|
| 24 |
#define _V3INTERFACE_H 1 |
|
| 25 |
#include "config_build.h" |
|
| 26 |
#include "verilatedos.h" |
|
| 27 |
#include "V3Error.h" |
|
| 28 |
#include "V3Ast.h" |
|
| 29 | ||
| 30 |
//============================================================================ |
|
| 31 | ||
| 32 |
class V3Interface {
|
|
| 33 |
public: |
|
| 34 |
static void lint(AstNetlist* nodep); |
|
| 35 |
}; |
|
| 36 | ||
| 37 |
#endif // Guard |
|
| b/src/V3Link.cpp | ||
|---|---|---|
| 530 | 530 |
nodep->iterateChildren(*this); |
| 531 | 531 |
} |
| 532 | 532 |
virtual void visit(AstCell* nodep, AstNUser*) {
|
| 533 |
// Cell: Resolve its filename. If necessary, parse it. |
|
| 534 | 533 |
m_cellp = nodep; |
| 535 |
if (m_idState==ID_FIND) {
|
|
| 536 |
// Add to list of all cells, for error checking and defparam's |
|
| 537 |
findAndInsertAndCheck(nodep, nodep->name()); |
|
| 538 |
} |
|
| 539 | 534 |
if (!nodep->modp()) {
|
| 540 | 535 |
nodep->v3fatalSrc("Cell has unlinked module"); // V3LinkCell should have errored out
|
| 541 | 536 |
} |
| 542 | 537 |
else {
|
| 543 |
// Need to pass the module info to this cell, so we can link up the pin names |
|
| 544 |
if (m_idState==ID_RESOLVE) {
|
|
| 538 |
if (m_idState==ID_FIND) {
|
|
| 539 |
if (AstInterface* interfacep = nodep->modp()->castInterface()) {
|
|
| 540 |
if (!nodep->hasVar()) {
|
|
| 541 |
// If the Cell connects to an interface, create a new Var with a CellDType |
|
| 542 |
AstNodeDType* iDTypep = new AstInterfaceDType(nodep->fileline(), interfacep->name()); |
|
| 543 |
iDTypep->castInterfaceDType()->interfacep(nodep->modp()->castInterface()); |
|
| 544 |
AstVar* varp = new AstVar(nodep->fileline(), AstVarType::INTERFACE, nodep->name(), iDTypep); |
|
| 545 |
nodep->addNext(varp); |
|
| 546 |
} |
|
| 547 |
} else {
|
|
| 548 |
// Add to list of all cells, for error checking and defparam's |
|
| 549 |
findAndInsertAndCheck(nodep, nodep->name()); |
|
| 550 |
} |
|
| 551 |
} else if (m_idState==ID_RESOLVE) {
|
|
| 552 |
// Need to pass the module info to this cell, so we can link up the pin names |
|
| 545 | 553 |
m_cellVarsp = nodep->modp()->user4p()->castSymTable(); |
| 546 | 554 |
UINFO(4,"(Backto) Link Cell: "<<nodep<<endl); |
| 547 | 555 |
//if (debug()) { nodep->dumpTree(cout,"linkcell:"); }
|
| ... | ... | |
| 558 | 566 |
// This is done bottom up in the LinkBotupVisitor stage |
| 559 | 567 |
} |
| 560 | 568 | |
| 569 |
virtual void visit(AstInterfaceDType* nodep, AstNUser*) {
|
|
| 570 |
nodep->iterateChildren(*this); |
|
| 571 |
// Link Modport names to the Modport Node under the Interface |
|
| 572 |
if (m_idState==ID_RESOLVE) {
|
|
| 573 |
if (nodep->isModport() && !nodep->modportp()) {
|
|
| 574 |
for (AstNode* subnodep=nodep->interfacep()->stmtsp(); subnodep; subnodep = subnodep->nextp()) {
|
|
| 575 |
if (AstModport* modportp = subnodep->castModport()) {
|
|
| 576 |
if (modportp->name() == nodep->modportName()) {
|
|
| 577 |
nodep->modportp(modportp); |
|
| 578 |
UINFO(4,"Link Modport: "<<modportp<<endl); |
|
| 579 |
} |
|
| 580 |
} |
|
| 581 |
} |
|
| 582 |
} |
|
| 583 |
} |
|
| 584 |
} |
|
| 585 | ||
| 586 |
virtual void visit(AstModport* nodep, AstNUser*) {
|
|
| 587 |
nodep->iterateChildren(*this); |
|
| 588 |
} |
|
| 589 | ||
| 590 |
virtual void visit(AstModportVar* nodep, AstNUser*) {
|
|
| 591 |
nodep->iterateChildren(*this); |
|
| 592 |
if (m_idState==ID_RESOLVE) {
|
|
| 593 |
AstVar* varp = m_curVarsp->findIdUpward(nodep->name())->castVar(); |
|
| 594 |
nodep->varp(varp); |
|
| 595 |
UINFO(4,"Link ModportVar: "<<nodep<<endl); |
|
| 596 |
} |
|
| 597 |
} |
|
| 598 | ||
| 561 | 599 |
virtual void visit(AstPort* nodep, AstNUser*) {
|
| 562 | 600 |
// Port: Stash the pin number |
| 563 | 601 |
if (!m_curVarsp) nodep->v3fatalSrc("Port not under module??\n");
|
| ... | ... | |
| 567 | 605 |
AstVar* refp = m_curVarsp->findIdFlat(nodep->name())->castVar(); |
| 568 | 606 |
if (!refp) {
|
| 569 | 607 |
nodep->v3error("Input/output/inout declaration not found for port: "<<nodep->prettyName());
|
| 570 |
} else if (!refp->isIO()) {
|
|
| 571 |
nodep->v3error("Pin is not an in/out/inout: "<<nodep->prettyName());
|
|
| 608 |
} else if (!refp->isIO() && !refp->isInterface()) {
|
|
| 609 |
nodep->v3error("Pin is not an in/out/inout/interface: "<<nodep->prettyName());
|
|
| 572 | 610 |
} else {
|
| 573 | 611 |
symsInsert("__pinNumber"+cvtToStr(nodep->pinNum()), refp);
|
| 574 | 612 |
refp->user2(true); |
| ... | ... | |
| 612 | 650 |
return; |
| 613 | 651 |
} |
| 614 | 652 |
nodep->v3error("Pin not found: "<<nodep->prettyName());
|
| 615 |
} else if (!refp->isIO() && !refp->isParam()) {
|
|
| 616 |
nodep->v3error("Pin is not an in/out/inout/param: "<<nodep->prettyName());
|
|
| 653 |
} else if (!refp->isIO() && !refp->isParam() && !refp->isInterface()) {
|
|
| 654 |
nodep->v3error("Pin is not an in/out/inout/param/interface: "<<nodep->prettyName());
|
|
| 617 | 655 |
} else {
|
| 618 | 656 |
nodep->modVarp(refp); |
| 619 | 657 |
} |
| b/src/V3LinkCells.cpp | ||
|---|---|---|
| 269 | 269 |
//if (debug()>=9) m_mods.dump(cout, "-syms: "); |
| 270 | 270 |
} |
| 271 | 271 | |
| 272 |
virtual void visit(AstInterfaceDType* nodep, AstNUser*) {
|
|
| 273 |
// Cell: Resolve its filename. If necessary, parse it. |
|
| 274 |
if (!nodep->interfacep()) {
|
|
| 275 |
UINFO(4,"Link Cell: "<<nodep<<endl); |
|
| 276 |
// Use findIdUpward instead of findIdFlat; it doesn't matter for now |
|
| 277 |
// but we might support modules-under-modules someday. |
|
| 278 |
AstNodeModule* modp = m_mods.findIdUpward(nodep->name())->castNodeModule(); |
|
| 279 |
if (!modp) {
|
|
| 280 |
// Read-subfile |
|
| 281 |
V3Parse parser (v3Global.rootp(), m_filterp); |
|
| 282 |
parser.parseFile(nodep->fileline(), nodep->name(), false); |
|
| 283 |
V3Error::abortIfErrors(); |
|
| 284 |
// We've read new modules, grab new pointers to their names |
|
| 285 |
readModNames(); |
|
| 286 |
// Check again |
|
| 287 |
modp = m_mods.findIdUpward(nodep->name())->castNodeModule(); |
|
| 288 |
if (!modp) {
|
|
| 289 |
nodep->v3error("Can't resolve interface reference: "<<nodep->name());
|
|
| 290 |
} |
|
| 291 |
} |
|
| 292 |
if (modp) {
|
|
| 293 |
// Track module depths, so can sort list from parent down to children |
|
| 294 |
new V3GraphEdge(&m_graph, vertex(m_modp), vertex(modp), 1, false); |
|
| 295 |
nodep->interfacep(modp->castInterface()); |
|
| 296 |
} |
|
| 297 |
} |
|
| 298 |
} |
|
| 299 | ||
| 300 | ||
| 272 | 301 |
public: |
| 273 | 302 |
// CONSTUCTORS |
| 274 | 303 |
LinkCellsVisitor(AstNetlist* rootp, V3InFilter* filterp) {
|
| b/src/V3LinkDot.cpp | ||
|---|---|---|
| 122 | 122 |
virtual string modName() const { return (modp() ? modp()->origName() : "*NULL*"); }
|
| 123 | 123 |
virtual string cellName() const { return (cellp() ? cellp()->origName() : "*NULL*"); }
|
| 124 | 124 |
virtual string name() const { return (string)("C:")+cellName()+" M:"+modName(); }
|
| 125 |
virtual string dotColor() const { return (modp()->castInterface() ? "green" : "black"); }
|
|
| 125 | 126 |
}; |
| 126 | 127 | |
| 127 | 128 |
class LinkDotInlineVertex : public LinkDotBaseVertex {
|
| ... | ... | |
| 181 | 182 | |
| 182 | 183 |
// TYPES |
| 183 | 184 |
typedef std::multimap<string,LinkDotCellVertex*> NameScopeMap; |
| 185 |
typedef std::multimap<string,AstScope*> NameAstScopeMap; |
|
| 186 |
typedef std::map<string,string> ScopenameAliasMap; |
|
| 187 | ||
| 184 | 188 |
// MEMBERS |
| 185 | 189 |
LinkDotGraph m_graph; // Graph of hierarchy |
| 186 | 190 |
NameScopeMap m_nameScopeMap; // Hash of scope referenced by non-pretty textual name |
| 191 |
NameAstScopeMap m_nameAstScopeMap; // Hash of AstScope nodes referenced by non-pretty textual name |
|
| 192 |
ScopenameAliasMap m_scopenameMap; // Map of scopename aliases |
|
| 187 | 193 |
bool m_forPrearray; // Compress cell__[array] refs |
| 188 | 194 |
bool m_forScopeCreation; // Remove VarXRefs for V3Scope |
| 189 | 195 |
public: |
| ... | ... | |
| 270 | 276 |
} |
| 271 | 277 |
return iter->second; |
| 272 | 278 |
} |
| 279 |
void insertScopeAlias(const string& lhs, const string& rhs) {
|
|
| 280 |
m_scopenameMap.insert(make_pair(lhs, rhs)); |
|
| 281 |
} |
|
| 282 |
void insertScope(AstScope* nodep) {
|
|
| 283 |
m_nameAstScopeMap.insert(make_pair(nodep->name(), nodep)); |
|
| 284 |
} |
|
| 285 |
AstScope* findScopeByName(const string& scopename, bool useAlias) {
|
|
| 286 |
NameAstScopeMap::iterator iter = m_nameAstScopeMap.find(scopename); |
|
| 287 |
if (iter == m_nameAstScopeMap.end()) {
|
|
| 288 |
if (useAlias) {
|
|
| 289 |
ScopenameAliasMap::iterator itera = m_scopenameMap.find(scopename); |
|
| 290 |
if (itera != m_scopenameMap.end()) |
|
| 291 |
return findScopeByName(itera->second, useAlias); |
|
| 292 |
} |
|
| 293 |
return NULL; |
|
| 294 |
} |
|
| 295 |
return iter->second; |
|
| 296 |
} |
|
| 273 | 297 |
void dump() {
|
| 274 | 298 |
if (debug()>=6) m_graph.dumpDotFilePrefixed("linkdot");
|
| 275 | 299 |
} |
| ... | ... | |
| 372 | 396 | |
| 373 | 397 |
class LinkDotFindVisitor : public AstNVisitor {
|
| 374 | 398 |
private: |
| 399 |
// TYPEs |
|
| 400 |
typedef std::multimap<AstInterfaceDType*,LinkDotCellVertex*> InterfaceVarMap; |
|
| 401 | ||
| 375 | 402 |
// STATE |
| 376 | 403 |
LinkDotState* m_statep; // State to pass between visitors, including symbol table |
| 377 | 404 |
LinkDotCellVertex* m_cellVxp; // Vertex for current module |
| 378 | 405 |
LinkDotBaseVertex* m_inlineVxp; // Vertex for current module, possibly a fake inlined one |
| 379 | 406 |
string m_scope; // Scope text |
| 380 | 407 |
AstBegin* m_beginp; // Current Begin/end block |
| 408 |
AstInterfaceDType* m_interfaceDTypep; // InterfaceDType for the current Var |
|
| 409 |
InterfaceVarMap m_interfaceVarMap; // A map of unconnected Interface Vars |
|
| 381 | 410 | |
| 382 | 411 |
int debug() { return LinkDotState::debug(); }
|
| 383 | 412 | |
| ... | ... | |
| 420 | 449 |
} |
| 421 | 450 |
virtual void visit(AstScope* nodep, AstNUser*) {
|
| 422 | 451 |
if (!m_statep->forScopeCreation()) v3fatalSrc("Scopes should only exist right after V3Scope");
|
| 423 |
// Ignored. Processed in next step |
|
| 452 |
// Store the scope in case it is aliased elsewhere (Interfaces). Otherwise ignored. Processed in next step |
|
| 453 |
m_statep->insertScope(nodep); |
|
| 424 | 454 |
} |
| 425 | 455 |
virtual void visit(AstCell* nodep, AstNUser*) {
|
| 426 | 456 |
UINFO(5," CELL under "<<m_scope<<" is "<<nodep<<endl); |
| ... | ... | |
| 455 | 485 |
m_cellVxp = oldVxp; |
| 456 | 486 |
m_inlineVxp = oldInlineVxp; |
| 457 | 487 |
} |
| 488 |
virtual void visit(AstInterfaceDType* nodep, AstNUser*) {
|
|
| 489 |
m_interfaceDTypep = nodep; |
|
| 490 |
nodep->iterateChildren(*this); |
|
| 491 |
} |
|
| 458 | 492 |
virtual void visit(AstCellInline* nodep, AstNUser*) {
|
| 459 | 493 |
UINFO(5," CELLINLINE under "<<m_scope<<" is "<<nodep<<endl); |
| 460 | 494 |
LinkDotBaseVertex* aboveVxp = m_inlineVxp; |
| ... | ... | |
| 488 | 522 |
m_beginp = oldbegin; |
| 489 | 523 |
} |
| 490 | 524 |
virtual void visit(AstVar* nodep, AstNUser*) {
|
| 491 |
if (!m_statep->forScopeCreation() |
|
| 492 |
&& !m_beginp // For now, we don't support xrefs into begin blocks |
|
| 493 |
&& !nodep->isFuncLocal()) {
|
|
| 525 |
// Look for any InterfaceDTypes, these use dotted variables |
|
| 526 |
m_interfaceDTypep = NULL; |
|
| 527 |
nodep->iterateChildren(*this); |
|
| 528 |
if (m_interfaceDTypep && !m_statep->forScopeCreation()) {
|
|
| 529 |
// Interfaces need to be added as sub-cells and syms, but not before we've found all the modules |
|
| 530 |
m_interfaceDTypep->varName(nodep->origName()); |
|
| 531 |
m_interfaceVarMap.insert(make_pair(m_interfaceDTypep, m_cellVxp)); |
|
| 494 | 532 |
m_statep->insertSym(m_cellVxp, nodep->name(), nodep); |
| 495 | 533 |
} else {
|
| 496 |
UINFO(9," Not allowing dot refs to: "<<nodep<<endl); |
|
| 534 |
if (!m_statep->forScopeCreation() |
|
| 535 |
&& !m_beginp // For now, we don't support xrefs into begin blocks |
|
| 536 |
&& !nodep->isFuncLocal()) {
|
|
| 537 |
m_statep->insertSym(m_cellVxp, nodep->name(), nodep); |
|
| 538 |
} else {
|
|
| 539 |
UINFO(9," Not allowing dot refs to: "<<nodep<<endl); |
|
| 540 |
} |
|
| 497 | 541 |
} |
| 498 | 542 |
} |
| 499 | 543 |
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
|
| ... | ... | |
| 519 | 563 |
m_cellVxp = NULL; |
| 520 | 564 |
m_statep = statep; |
| 521 | 565 |
m_beginp = NULL; |
| 566 |
m_interfaceDTypep = NULL; |
|
| 522 | 567 |
// |
| 523 | 568 |
rootp->accept(*this); |
| 569 | ||
| 570 |
// Insert any interfaces as sub-cells |
|
| 571 |
InterfaceVarMap::iterator iter = m_interfaceVarMap.begin(); |
|
| 572 |
for (; iter != m_interfaceVarMap.end(); ++iter) {
|
|
| 573 |
AstInterfaceDType* interfaceDTypep = iter->first; |
|
| 574 |
LinkDotCellVertex* aboveVxp = iter->second; |
|
| 575 |
LinkDotCellVertex* cellVxp = m_statep->findModScope(interfaceDTypep->interfacep()); |
|
| 576 |
aboveVxp->insertSubcellName(interfaceDTypep->varName(), cellVxp); |
|
| 577 |
} |
|
| 524 | 578 |
} |
| 525 | 579 |
virtual ~LinkDotFindVisitor() {}
|
| 526 | 580 |
}; |
| ... | ... | |
| 529 | 583 | |
| 530 | 584 |
class LinkDotScopeVisitor : public AstNVisitor {
|
| 531 | 585 |
private: |
| 586 |
// TYPEs |
|
| 587 |
typedef std::map<string,LinkDotCellVertex*> NameScopeVxpMap; |
|
| 588 | ||
| 532 | 589 |
// STATE |
| 590 |
AstScope* m_scopep; // The current scope |
|
| 533 | 591 |
LinkDotState* m_statep; // State to pass between visitors, including symbol table |
| 534 | 592 |
LinkDotCellVertex* m_cellVxp; // Vertex for current module |
| 593 |
NameScopeVxpMap m_scopeMap; // Map of unlinked scope alias to CellVertex |
|
| 535 | 594 | |
| 536 | 595 |
int debug() { return LinkDotState::debug(); }
|
| 537 | 596 | |
| ... | ... | |
| 542 | 601 |
// Using the CELL names, we created all hierarchy. We now need to match this Scope |
| 543 | 602 |
// up with the hierarchy created by the CELL names. |
| 544 | 603 |
m_cellVxp = m_statep->findScope(nodep); |
| 604 |
m_scopep = nodep; |
|
| 545 | 605 |
nodep->iterateChildren(*this); |
| 546 | 606 |
m_cellVxp = NULL; |
| 547 | 607 |
} |
| ... | ... | |
| 550 | 610 |
m_statep->insertSym(m_cellVxp, nodep->varp()->name(), nodep); |
| 551 | 611 |
} |
| 552 | 612 |
} |
| 613 |
virtual void visit(AstScopeAlias* nodep, AstNUser*) {
|
|
| 614 |
// Link the ScopeAlias to its Scope, may be NULL |
|
| 615 |
AstScope* scope = m_statep->findScopeByName(nodep->name(), false); |
|
| 616 |
if (scope) {
|
|
| 617 |
nodep->aliasp(scope); |
|
| 618 |
} else {
|
|
| 619 |
NameScopeVxpMap::const_iterator iter = m_scopeMap.find(nodep->name()); |
|
| 620 |
if (iter == m_scopeMap.end()) {
|
|
| 621 |
nodep->v3fatalSrc("Could not link scope for "+nodep->varp()->name());
|
|
| 622 |
} else {
|
|
| 623 |
m_cellVxp->insertSubcellName(nodep->varp()->name(), iter->second); |
|
| 624 |
} |
|
| 625 |
} |
|
| 626 |
} |
|
| 553 | 627 |
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
|
| 554 | 628 |
m_statep->insertSym(m_cellVxp, nodep->name(), nodep); |
| 555 | 629 |
// No recursion, we don't want to pick up variables |
| 556 | 630 |
} |
| 631 |
virtual void visit(AstAssignVarScope* nodep, AstNUser*) {
|
|
| 632 |
LinkDotCellVertex* linkedVxp = NULL; |
|
| 633 |
string lhspScopename; |
|
| 634 |
string rhspScopename; |
|
| 635 |
if (AstVarRef* refp = nodep->lhsp()->castVarRef()) {
|
|
| 636 |
lhspScopename = m_scopep->name()+"."+refp->name(); |
|
| 637 |
AstScope* scopep = m_statep->findScopeByName(lhspScopename, true); |
|
| 638 |
LinkDotCellVertex* scopeVxp = m_statep->findScope(scopep); |
|
| 639 |
if (scopep) {
|
|
| 640 |
UINFO(5, " Found a linked scope: "<<lhspScopename<<endl); |
|
| 641 |
linkedVxp = scopeVxp; |
|
| 642 |
} else {
|
|
| 643 |
nodep->v3fatalSrc("Unsupported: Found a scopep on a VarXRef");
|
|
| 644 |
} |
|
| 645 |
} else {
|
|
| 646 |
nodep->v3fatalSrc("Unsupported: Non VarRef on lhsp of AssignVarScope");
|
|
| 647 |
} |
|
| 648 |
if (AstVarXRef* refp = nodep->rhsp()->castVarXRef()) {
|
|
| 649 |
rhspScopename = m_scopep->name()+"."+refp->dotted()+"."+refp->name(); |
|
| 650 |
AstScope* scopep = m_statep->findScopeByName(rhspScopename, true); |
|
| 651 |
if (scopep) {
|
|
| 652 |
UINFO(5," "<<scopep<<endl); |
|
| 653 |
nodep->v3fatalSrc("Unsupported: Found a scopep on a VarXRef");
|
|
| 654 |
} else {
|
|
| 655 |
UINFO(5, " Found an unlinked scope: "<<rhspScopename<<endl); |
|
| 656 |
m_scopeMap.insert(make_pair(rhspScopename,linkedVxp)); |
|
| 657 |
m_statep->insertScopeAlias(rhspScopename, lhspScopename); |
|
| 658 |
} |
|
| 659 |
} else {
|
|
| 660 |
nodep->v3fatalSrc("Unsupported: Non VarXRef on rhsp of AssignVarScope");
|
|
| 661 |
} |
|
| 662 |
// We have stored the link, we don't need these any more |
|
| 663 |
nodep->unlinkFrBack()->deleteTree(); nodep=NULL; |
|
| 664 |
} |
|
| 557 | 665 |
virtual void visit(AstAssignAlias* nodep, AstNUser*) {
|
| 558 | 666 |
// Track aliases created by V3Inline; if we get a VARXREF(aliased_from) |
| 559 | 667 |
// we'll need to replace it with a VARXREF(aliased_to) |
| ... | ... | |
| 647 | 755 |
nodep->varp(varp); |
| 648 | 756 |
UINFO(7," Resolved "<<nodep<<endl); // Also prints varp |
| 649 | 757 |
if (!nodep->varp()) {
|
| 758 |
// If this is an interface, that might be a modport not a signal |
|
| 759 |
LinkDotCellVertex* cellVxp = dynamic_cast<LinkDotCellVertex*>(dotVxp); |
|
| 760 |
if (cellVxp) {
|
|
| 761 |
AstInterface* interfacep = cellVxp->modp()->castInterface(); |
|
| 762 |
if (interfacep) {
|
|
| 763 |
// Look for a modport under the Interface |
|
| 764 |
for (AstNode* subnodep=interfacep->stmtsp(); subnodep; subnodep = subnodep->nextp()) {
|
|
| 765 |
if (AstModport* modportp = subnodep->castModport()) {
|
|
| 766 |
if (modportp->name() == nodep->name()) {
|
|
| 767 |
// Change this VarXRef into a VarRef and link it to the Var |
|
| 768 |
AstVar* varp = (m_statep->findSym(m_cellVxp, nodep->dotted(), baddot) |
|
| 769 |
->castVar()); // maybe NULL |
|
| 770 |
if (!varp) {
|
|
| 771 |
nodep->v3error("Can't find definition of '"<<baddot<<"' (interface) in dotted signal: "<<nodep->dotted()+"."+nodep->prettyName());
|
|
| 772 |
return; |
|
| 773 |
} |
|
| 774 |
AstVarRef* refp = new AstVarRef(nodep->fileline(), varp, false); |
|
| 775 |
nodep->replaceWith(refp); |
|
| 776 |
// :TODO: byronb - Link the modport to the InterfaceDType under the Var |
|
| 777 |
return; |
|
| 778 |
} |
|
| 779 |
} |
|
| 780 |
} |
|
| 781 |
} |
|
| 782 |
} |
|
| 650 | 783 |
nodep->v3error("Can't find definition of '"<<baddot<<"' in dotted signal: "<<nodep->dotted()+"."+nodep->prettyName());
|
| 651 | 784 |
okVxp->errorScopes(nodep); |
| 652 | 785 |
} |
| b/src/V3LinkLevel.cpp | ||
|---|---|---|
| 125 | 125 |
pinp->modVarp(oldvarp); |
| 126 | 126 |
pinp->widthSignedFrom(oldvarp); |
| 127 | 127 |
cellp->addPinsp(pinp); |
| 128 |
} else if (oldvarp->isInterface()) {
|
|
| 129 |
// Link the interface at the top-level |
|
| 130 |
AstInterfaceDType* dtypep = oldvarp->dtypep()->castInterfaceDType(); |
|
| 131 |
if (!dtypep || !dtypep->isModport()) |
|
| 132 |
continue; |
|
| 133 |
for (AstNode* inodep=dtypep->modportp()->varsp(); inodep; inodep = inodep->nextp()) {
|
|
| 134 |
AstModportVar* ivarp = inodep->castModportVar(); |
|
| 135 |
if (ivarp) {
|
|
| 136 |
AstVar* newvarp = ivarp->varp()->cloneTree(false); |
|
| 137 |
newvarp->name(oldvarp->name()+"__DOT__"+newvarp->name()); |
|
| 138 |
newvarp->varType(ivarp->varType()); |
|
| 139 |
if (ivarp->isInput()) {
|
|
| 140 |
newvarp->varType2In(); |
|
| 141 |
AstVarXRef* lhsp = new AstVarXRef(newvarp->fileline(), ivarp->varp()->name(), |
|
| 142 |
oldvarp->name(), true); |
|
| 143 |
AstVarRef* rhsp = new AstVarRef(newvarp->fileline(), newvarp->name(), false); |
|
| 144 |
rhsp->varp(newvarp); |
|
| 145 |
AstAssignW* assignp = new AstAssignW(newvarp->fileline(), lhsp, rhsp); |
|
| 146 |
lhsp->widthSignedFrom(newvarp); |
|
| 147 |
rhsp->widthSignedFrom(newvarp); |
|
| 148 |
assignp->widthSignedFrom(newvarp); |
|
| 149 |
oldmodp->addStmtp(newvarp); |
|
| 150 |
oldmodp->addStmtp(assignp); |
|
| 151 |
} else {
|
|
| 152 |
newvarp->varType2Out(); |
|
| 153 |
AstVarRef* lhsp = new AstVarRef(newvarp->fileline(), newvarp->name(), true); |
|
| 154 |
AstVarXRef* rhsp = new AstVarXRef(newvarp->fileline(), ivarp->varp()->name(), |
|
| 155 |
oldvarp->name(), false); |
|
| 156 |
lhsp->varp(newvarp); |
|
| 157 |
AstAssignW* assignp = new AstAssignW(newvarp->fileline(), lhsp, rhsp); |
|
| 158 |
lhsp->widthSignedFrom(newvarp); |
|
| 159 |
rhsp->widthSignedFrom(newvarp); |
|
| 160 |
assignp->widthSignedFrom(newvarp); |
|
| 161 |
oldmodp->addStmtp(newvarp); |
|
| 162 |
oldmodp->addStmtp(assignp); |
|
| 163 |
} |
|
| 164 |
} |
|
| 165 |
} |
|
| 128 | 166 |
} |
| 129 | 167 |
} |
| 130 | 168 |
} |
| b/src/V3LinkParse.cpp | ||
|---|---|---|
| 60 | 60 |
AstText* m_baseTextp; // Lowest TEXT node that needs replacement with varref |
| 61 | 61 |
AstVar* m_varp; // Variable we're under |
| 62 | 62 |
ImplTypedefMap m_implTypedef; // Created typedefs for each <container,name> |
| 63 |
AstModule* m_topModule; // The top-level module we are under |
|
| 63 | 64 | |
| 64 | 65 |
// METHODS |
| 65 | 66 |
static int debug() {
|
| ... | ... | |
| 329 | 330 |
nodep->deleteTree(); nodep=NULL; |
| 330 | 331 |
} |
| 331 | 332 | |
| 333 |
virtual void visit(AstModule* nodep, AstNUser*) {
|
|
| 334 |
// Look for interfaces in the port list of the top-level module |
|
| 335 |
if (nodep->level() == 2) {
|
|
| 336 |
m_topModule = nodep; |
|
| 337 |
} |
|
| 338 |
nodep->iterateChildren(*this); |
|
| 339 |
m_topModule = NULL; |
|
| 340 |
} |
|
| 341 | ||
| 342 |
virtual void visit(AstInterfaceDType* nodep, AstNUser*) {
|
|
| 343 |
if (m_topModule) {
|
|
| 344 |
AstCell* cellp = new AstCell(nodep->fileline(), m_varp->name(), nodep->name(), NULL, NULL, NULL); |
|
| 345 |
cellp->hasVar(true); // We created the Cell from an existing Var |
|
| 346 |
m_topModule->addStmtp(cellp); |
|
| 347 |
} |
|
| 348 |
} |
|
| 349 | ||
| 332 | 350 |
virtual void visit(AstNode* nodep, AstNUser*) {
|
| 333 | 351 |
// Default: Just iterate |
| 334 | 352 |
checkExpected(nodep); // So we detect node types we forgot to list here |
| ... | ... | |
| 342 | 360 |
m_exp = AstParseRefExp::NONE; |
| 343 | 361 |
m_baseTextp = NULL; |
| 344 | 362 |
m_varp = NULL; |
| 363 |
m_topModule = NULL; |
|
| 345 | 364 |
rootp->accept(*this); |
| 346 | 365 |
} |
| 347 | 366 |
virtual ~LinkParseVisitor() {}
|
| b/src/V3Param.cpp | ||
|---|---|---|
| 334 | 334 |
// Note we allow multiple users of a parameterized model, thus we need to stash this info. |
| 335 | 335 |
for (AstNode* stmtp=modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
| 336 | 336 |
if (AstVar* varp = stmtp->castVar()) {
|
| 337 |
if (varp->isIO() || varp->isGParam()) {
|
|
| 337 |
if (varp->isIO() || varp->isGParam() || varp->isInterface()) {
|
|
| 338 | 338 |
// Cloning saved a pointer to the new node for us, so just follow that link. |
| 339 | 339 |
AstVar* oldvarp = varp->clonep()->castVar(); |
| 340 | 340 |
//UINFO(8,"Clone list 0x"<<hex<<(uint32_t)oldvarp<<" -> 0x"<<(uint32_t)varp<<endl); |
| b/src/V3ParseImp.h | ||
|---|---|---|
| 65 | 65 |
AstCase* casep; |
| 66 | 66 |
AstCaseItem* caseitemp; |
| 67 | 67 |
AstConst* constp; |
| 68 |
AstModportVar* modportvarp; |
|
| 68 | 69 |
AstNodeModule* modulep; |
| 69 | 70 |
AstNodeDType* dtypep; |
| 70 | 71 |
AstNodeFTask* ftaskp; |
| b/src/V3Scope.cpp | ||
|---|---|---|
| 149 | 149 |
m_scopep->addActivep(clonep); |
| 150 | 150 |
clonep->iterateChildren(*this); // We iterate under the *clone* |
| 151 | 151 |
} |
| 152 |
virtual void visit(AstAssignVarScope* nodep, AstNUser*) {
|
|
| 153 |
// Copy under the scope but don't recurse, interfaces aren't linked yet |
|
| 154 |
UINFO(4," Move "<<nodep<<endl); |
|
| 155 |
AstNode* clonep = nodep->cloneTree(false); |
|
| 156 |
nodep->user2p(clonep); |
|
| 157 |
m_scopep->addActivep(clonep); |
|
| 158 |
} |
|
| 152 | 159 |
virtual void visit(AstAssignW* nodep, AstNUser*) {
|
| 153 | 160 |
// Add to list of blocks under this scope |
| 154 | 161 |
UINFO(4," Move "<<nodep<<endl); |
| ... | ... | |
| 195 | 202 |
virtual void visit(AstVar* nodep, AstNUser*) {
|
| 196 | 203 |
// Make new scope variable |
| 197 | 204 |
if (!nodep->user1p()) {
|
| 198 |
AstVarScope* varscp = new AstVarScope(nodep->fileline(), m_scopep, nodep); |
|
| 199 |
UINFO(6," New scope "<<varscp<<endl); |
|
| 200 |
nodep->user1p(varscp); |
|
| 201 |
m_scopep->addVarp(varscp); |
|
| 205 |
if (nodep->isInterface()) {
|
|
| 206 |
AstVarScope* varscp = new AstScopeAlias(nodep->fileline(), m_scopep, nodep, NULL); |
|
| 207 |
UINFO(6," New scope alias "<<varscp<<endl); |
|
| 208 |
nodep->user1p(varscp); |
|
| 209 |
m_scopep->addVarp(varscp); |
|
| 210 |
} else {
|
|
| 211 |
AstVarScope* varscp = new AstVarScope(nodep->fileline(), m_scopep, nodep); |
|
| 212 |
UINFO(6," New scope "<<varscp<<endl); |
|
| 213 |
nodep->user1p(varscp); |
|
| 214 |
m_scopep->addVarp(varscp); |
|
| 215 |
} |
|
| 202 | 216 |
} |
| 203 | 217 |
} |
| 204 | 218 |
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
| 205 | 219 |
// VarRef needs to point to VarScope |
| 206 | 220 |
// Make sure variable has made user1p. |
| 207 |
nodep->varp()->accept(*this); |
|
| 208 |
AstVarScope* varscp = (AstVarScope*)nodep->varp()->user1p(); |
|
| 209 |
if (!varscp) nodep->v3fatalSrc("Can't locate varref scope");
|
|
| 210 |
nodep->varScopep(varscp); |
|
| 221 |
if (!nodep->varp()->isInterface()) {
|
|
| 222 |
nodep->varp()->accept(*this); |
|
| 223 |
AstVarScope* varscp = (AstVarScope*)nodep->varp()->user1p(); |
|
| 224 |
if (!varscp) nodep->v3fatalSrc("Can't locate varref scope");
|
|
| 225 |
nodep->varScopep(varscp); |
|
| 226 |
} else {
|
|
| 227 |
nodep->varScopep(NULL); |
|
| 228 |
} |
|
| 211 | 229 |
} |
| 212 | 230 |
virtual void visit(AstScopeName* nodep, AstNUser*) {
|
| 213 | 231 |
// If there's a %m in the display text, we add a special node that will contain the name() |
| ... | ... | |
| 285 | 303 |
virtual void visit(AstAssignAlias* nodep, AstNUser*) {
|
| 286 | 304 |
movedDeleteOrIterate(nodep); |
| 287 | 305 |
} |
| 306 |
virtual void visit(AstAssignVarScope* nodep, AstNUser*) {
|
|
| 307 |
movedDeleteOrIterate(nodep); |
|
| 308 |
} |
|
| 288 | 309 |
virtual void visit(AstAssignW* nodep, AstNUser*) {
|
| 289 | 310 |
movedDeleteOrIterate(nodep); |
| 290 | 311 |
} |
| b/src/V3Width.cpp | ||
|---|---|---|
| 513 | 513 |
// else width in node is correct; it was set based on keyword().width() |
| 514 | 514 |
// at construction time |
| 515 | 515 |
} |
| 516 |
virtual void visit(AstInterfaceDType* nodep, AstNUser* vup) {
|
|
| 517 |
nodep->iterateChildren(*this, vup); |
|
| 518 |
nodep->width(1, 1); |
|
| 519 |
} |
|
| 516 | 520 |
virtual void visit(AstRefDType* nodep, AstNUser* vup) {
|
| 517 | 521 |
nodep->iterateChildren(*this, vup); |
| 518 | 522 |
if (nodep->defp()) nodep->defp()->iterate(*this,vup); |
| b/src/Verilator.cpp | ||
|---|---|---|
| 56 | 56 |
#include "V3GenClk.h" |
| 57 | 57 |
#include "V3Inline.h" |
| 58 | 58 |
#include "V3Inst.h" |
| 59 |
#include "V3Interface.h" |
|
| 59 | 60 |
#include "V3Life.h" |
| 60 | 61 |
#include "V3LifePost.h" |
| 61 | 62 |
#include "V3Link.h" |
| ... | ... | |
| 135 | 136 | |
| 136 | 137 |
// Convert parseref's to varrefs, and other directly post parsing fixups |
| 137 | 138 |
V3LinkParse::linkParse(v3Global.rootp()); |
| 139 |
// Link any new cells created from interfaces (empty filter) |
|
| 140 |
V3InFilter filter (v3Global.opt.pipeFilter()); |
|
| 141 |
V3LinkCells::link(v3Global.rootp(), &filter); |
|
| 138 | 142 |
// Cross-link signal names |
| 139 | 143 |
V3Link::link(v3Global.rootp()); |
| 140 | 144 |
// Cross-link dotted hierarchical references |
| ... | ... | |
| 145 | 149 |
V3LinkLValue::linkLValue(v3Global.rootp()); |
| 146 | 150 |
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("link.tree"));
|
| 147 | 151 |
V3Error::abortIfErrors(); |
| 148 | ||
| 149 | 152 |
if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "Link"); |
| 150 | 153 | |
| 151 | 154 |
// Remove parameters by cloning modules to de-parameterized versions |
| ... | ... | |
| 194 | 197 |
// Must do this after we know the width of any parameters |
| 195 | 198 |
// We also do it after coverage/assertion insertion so we don't 'cover' the top level. |
| 196 | 199 |
V3LinkLevel::wrapTop(v3Global.rootp()); |
| 200 |
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linklevel.tree"));
|
|
| 201 | ||
| 202 |
// Lint interfaces |
|
| 203 |
V3Interface::lint(v3Global.rootp()); |
|
| 204 |
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("interface.tree"));
|
|
| 197 | 205 | |
| 198 | 206 |
// Propagate constants into expressions |
| 199 | 207 |
V3Const::constifyAllLint(v3Global.rootp()); |
| b/src/verilog.l | ||
|---|---|---|
| 389 | 389 |
"do" { FL; return yDO; }
|
| 390 | 390 |
"endclocking" { FL; return yENDCLOCKING; }
|
| 391 | 391 |
"endpackage" { FL; return yENDPACKAGE; }
|
| 392 |
"endinterface" { FL; return yENDINTERFACE; }
|
|
| 392 | 393 |
"endprogram" { FL; return yENDPROGRAM; }
|
| 393 | 394 |
"endproperty" { FL; return yENDPROPERTY; }
|
| 394 | 395 |
"enum" { FL; return yENUM; }
|
| ... | ... | |
| 396 | 397 |
"final" { FL; return yFINAL; }
|
| 397 | 398 |
"iff" { FL; return yIFF; }
|
| 398 | 399 |
"import" { FL; return yIMPORT; }
|
| 400 |
"interface" { FL; return yINTERFACE; }
|
|
| 399 | 401 |
"int" { FL; return yINT; }
|
| 400 | 402 |
"logic" { FL; return yLOGIC; }
|
| 401 | 403 |
"longint" { FL; return yLONGINT; }
|
| 404 |
"modport" { FL; return yMODPORT; }
|
|
| 402 | 405 |
"package" { FL; return yPACKAGE; }
|
| 403 | 406 |
"priority" { FL; return yPRIORITY; }
|
| 404 | 407 |
"program" { FL; return yPROGRAM; }
|
| ... | ... | |
| 429 | 432 |
"dist" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
| 430 | 433 |
"endclass" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
| 431 | 434 |
"endgroup" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
| 432 |
"endinterface" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
|
| 433 | 435 |
"endsequence" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
| 434 | 436 |
"expect" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
| 435 | 437 |
"extends" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
| ... | ... | |
| 440 | 442 |
"ignore_bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
| 441 | 443 |
"illegal_bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
| 442 | 444 |
"inside" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
| 443 |
"interface" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
|
| 444 | 445 |
"intersect" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
| 445 | 446 |
"join_any" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
| 446 | 447 |
"join_none" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
| 447 | 448 |
"local" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
| 448 | 449 |
"matches" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
| 449 |
"modport" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
|
| 450 | 450 |
"new" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
| 451 | 451 |
"null" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
| 452 | 452 |
"packed" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
| b/src/verilog.y | ||
|---|---|---|
| 287 | 287 |
%token<fl> yENDCLOCKING "endclocking" |
| 288 | 288 |
%token<fl> yENDFUNCTION "endfunction" |
| 289 | 289 |
%token<fl> yENDGENERATE "endgenerate" |
| 290 |
%token<fl> yENDINTERFACE "endinterface" |
|
| 290 | 291 |
%token<fl> yENDMODULE "endmodule" |
| 291 | 292 |
%token<fl> yENDPACKAGE "endpackage" |
| 292 | 293 |
%token<fl> yENDPRIMITIVE "endprimitive" |
| ... | ... | |
| 311 | 312 |
%token<fl> yINITIAL "initial" |
| 312 | 313 |
%token<fl> yINOUT "inout" |
| 313 | 314 |
%token<fl> yINPUT "input" |
| 315 |
%token<fl> yINTERFACE "interface" |
|
| 314 | 316 |
%token<fl> yINT "int" |
| 315 | 317 |
%token<fl> yINTEGER "integer" |
| 316 | 318 |
%token<fl> yLOCALPARAM "localparam" |
| 317 | 319 |
%token<fl> yLOGIC "logic" |
| 318 | 320 |
%token<fl> yLONGINT "longint" |
| 321 |
%token<fl> yMODPORT "modport" |
|
| 319 | 322 |
%token<fl> yMODULE "module" |
| 320 | 323 |
%token<fl> yNAND "nand" |
| 321 | 324 |
%token<fl> yNEGEDGE "negedge" |
| ... | ... | |
| 549 | 552 |
// Blank lines for type insertion |
| 550 | 553 |
// Blank lines for type insertion |
| 551 | 554 |
// Blank lines for type insertion |
| 555 |
// Blank lines for type insertion |
|
| 552 | 556 | |
| 553 | 557 |
%start source_text |
| 554 | 558 | |
| ... | ... | |
| 583 | 587 | |
| 584 | 588 |
description: // ==IEEE: description |
| 585 | 589 |
module_declaration { }
|
| 586 |
//UNSUP interface_declaration { }
|
|
| 590 |
| interface_declaration { }
|
|
| 587 | 591 |
| program_declaration { }
|
| 588 | 592 |
| package_declaration { }
|
| 589 | 593 |
| package_item { if ($1) GRAMMARP->unitPackage($1->fileline())->addStmtp($1); }
|
| ... | ... | |
| 771 | 775 |
// // IEEE: interface_port_header port_identifier { unpacked_dimension }
|
| 772 | 776 |
// // Expanded interface_port_header |
| 773 | 777 |
// // We use instantCb here because the non-port form looks just like a module instantiation |
| 774 |
//UNSUP portDirNetE id/*interface*/ idAny/*port*/ rangeListE sigAttrListE { VARDTYPE($2); VARDONEA($3, $4); PARSEP->instantCb(CRELINE(), $2, $3, $4); PINNUMINC(); }
|
|
| 778 |
portDirNetE id/*interface*/ idAny/*port*/ /* UNSUPP variable_dimensionListE*/ /* UNSUPP sigAttrListE */ |
|
| 779 |
{ $$ = new AstPort(CRELINE(),PINNUMINC(),*$3);
|
|
| 780 |
$$->addNext(new AstVar($<fl>2,AstVarType(AstVarType::INTERFACE),*$3,new AstInterfaceDType($<fl>2,*$2))); } |
|
| 775 | 781 |
//UNSUP portDirNetE yINTERFACE idAny/*port*/ rangeListE sigAttrListE { VARDTYPE($2); VARDONEA($3, $4); PINNUMINC(); }
|
| 776 |
//UNSUP portDirNetE id/*interface*/ '.' idAny/*modport*/ idAny/*port*/ rangeListE sigAttrListE { VARDTYPE($2); VARDONEA($5, $6); PARSEP->instantCb(CRELINE(), $2, $5, $6); PINNUMINC(); }
|
|
| 782 |
| portDirNetE id/*interface*/ '.' idAny/*modport*/ idAny/*port*/ /* UNSUPP rangeListE sigAttrListE */ |
|
| 783 |
{ $$ = new AstPort(CRELINE(),PINNUMINC(),*$5);
|
|
| 784 |
$$->addNext(new AstVar($3,AstVarType(AstVarType::INTERFACE),*$5,new AstInterfaceDType($3,*$2,*$4))); } |
|
| 777 | 785 |
//UNSUP portDirNetE yINTERFACE '.' idAny/*modport*/ idAny/*port*/ rangeListE sigAttrListE { VARDTYPE($2); VARDONEA($5, $6); PINNUMINC(); }
|
| 786 | ||
| 778 | 787 |
// |
| 779 | 788 |
// // IEEE: ansi_port_declaration, with [port_direction] removed |
| 780 | 789 |
// // IEEE: [ net_port_header | interface_port_header ] port_identifier { unpacked_dimension }
|
| ... | ... | |
| 807 | 816 |
//UNSUP portDirNetE signingE rangeList '.' portSig '(' portAssignExprE ')' sigAttrListE { UNSUP }
|
| 808 | 817 |
//UNSUP portDirNetE /*implicit*/ '.' portSig '(' portAssignExprE ')' sigAttrListE { UNSUP }
|
| 809 | 818 |
// |
| 810 |
portDirNetE data_type portSig variable_dimensionListE sigAttrListE
|
|
| 819 |
| portDirNetE data_type portSig variable_dimensionListE sigAttrListE
|
|
| 811 | 820 |
{ $$=$3; VARDTYPE($2); $$->addNextNull(VARDONEP($$,$4,$5)); }
|
| 812 | 821 |
| portDirNetE yVAR data_type portSig variable_dimensionListE sigAttrListE |
| 813 | 822 |
{ $$=$4; VARDTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); }
|
| ... | ... | |
| 850 | 859 |
//********************************************************************** |
| 851 | 860 |
// Interface headers |
| 852 | 861 | |
| 862 |
interface_declaration: // IEEE: interface_declaration + interface_nonansi_header + interface_ansi_header: |
|
| 863 |
// // timeunits_delcarationE is instead in interface_item |
|
| 864 |
intFront parameter_port_listE portsStarE ';' |
|
| 865 |
interface_itemListE yENDINTERFACE endLabelE |
|
| 866 |
{ if ($2) { $1->addStmtp($2); $2->v3error("Unsupported: Interfaces with parameters"); }
|
|
| 867 |
if ($3) $1->addStmtp($3); |
|
| 868 |
if ($5) $1->addStmtp($5); |
|
| 869 |
SYMP->popScope($1); } |
|
| 870 |
//UNSUPP yEXTERN intFront parameter_port_listE portsStarE ';' { }
|
|
| 871 |
; |
|
| 872 | ||
| 873 |
intFront<modulep>: |
|
| 874 |
yINTERFACE lifetimeE idAny/*new_interface*/ |
|
| 875 |
{ $$ = new AstInterface($1,*$3);
|
|
| 876 |
$$->inLibrary(true); |
|
| 877 |
PARSEP->rootp()->addModulep($$); |
|
| 878 |
SYMP->pushNew($$); } |
|
| 879 |
; |
|
| 880 | ||
| 881 |
interface_itemListE<nodep>: |
|
| 882 |
/* empty */ { $$ = NULL; }
|
|
| 883 |
| interface_itemList { $$ = $1; }
|
|
| 884 |
; |
|
| 885 | ||
| 886 |
interface_itemList<nodep>: |
|
| 887 |
interface_item { $$ = $1 }
|
|
| 888 |
| interface_itemList interface_item { $$ = $1->addNextNull($2) }
|
|
| 889 |
; |
|
| 890 | ||
| 891 |
interface_item<nodep>: // IEEE: interface_item + non_port_interface_item |
|
| 892 |
port_declaration ';' { $$ = $1; }
|
|
| 893 |
// // IEEE: non_port_interface_item |
|
| 894 |
//UNSUP generate_region { $$ = $1; }
|
|
| 895 |
| interface_or_generate_item { $$ = $1; }
|
|
| 896 |
//UNSUP program_declaration { $$ = $1; }
|
|
| 897 |
//UNSUP interface_declaration { $$ = $1; }
|
|
| 898 |
| timeunits_declaration { $$ = $1; }
|
|
| 899 |
// // See note in interface_or_generate item |
|
| 900 |
| module_common_item { $$ = $1; }
|
|
| 901 |
; |
|
| 902 | ||
| 903 |
interface_or_generate_item<nodep>: // ==IEEE: interface_or_generate_item |
|
| 904 |
// // module_common_item in interface_item, as otherwise duplicated |
|
| 905 |
// // with module_or_generate_item's module_common_item |
|
| 906 |
modport_declaration { $$ = $1; }
|
|
| 907 |
//UNSUP extern_tf_declaration { }
|
|
| 908 |
; |
|
| 909 | ||
| 853 | 910 |
//********************************************************************** |
| 854 | 911 |
// Program headers |
| 855 | 912 | |
| ... | ... | |
| 905 | 962 |
| generate_region { $$ = $1; }
|
| 906 | 963 |
; |
| 907 | 964 | |
| 965 |
modport_declaration<nodep>: // ==IEEE: modport_declaration |
|
| 966 |
yMODPORT modport_itemList ';' { $$ = $2; }
|
|
| 967 |
; |
|
| 968 | ||
| 969 |
modport_itemList<nodep>: // IEEE: part of modport_declaration |
|
| 970 |
modport_item { $$ = $1; }
|
|
| 971 |
| modport_itemList ',' modport_item { $$ = $1->addNextNull($3) }
|
|
| 972 |
; |
|
| 973 | ||
| 974 |
modport_item<nodep>: // ==IEEE: modport_item |
|
| 975 |
id/*new-modport*/ '(' modportPortsDeclList ')' { $$ = new AstModport($2,*$1,$3); }
|
|
| 976 |
; |
|
| 977 | ||
| 978 |
modportPortsDeclList<modportvarp>: |
|
| 979 |
modportPortsDecl { $$ = $1; }
|
|
| 980 |
| modportPortsDeclList ',' modportPortsDecl { $$ = $1->addNextNull($3)->castModportVar(); }
|
|
| 981 |
; |
|
| 982 | ||
| 983 |
// IEEE: modport_ports_declaration + modport_simple_ports_declaration |
|
| 984 |
// + (modport_tf_ports_declaration+import_export) + modport_clocking_declaration |
|
| 985 |
// We've expanded the lists each take to instead just have standalone ID ports. |
|
| 986 |
// We track the type as with the V2k series of defines, then create as each ID is seen. |
|
| 987 |
modportPortsDecl<modportvarp>: |
|
| 988 |
// // IEEE: modport_simple_ports_declaration |
|
| 989 |
port_direction modportSimplePort { $$ = new AstModportVar($<fl>1,*$2,GRAMMARP->m_varIO); }
|
|
| 990 |
// // IEEE: modport_clocking_declaration |
|
| 991 |
//UNSUP yCLOCKING idAny/*clocking_identifier*/ { }
|
|
| 992 |
//UNSUP yIMPORT modport_tf_port { }
|
|
| 993 |
//UNSUP yEXPORT modport_tf_port { }
|
|
| 994 |
// Continuations of above after a comma. |
|
| 995 |
// // IEEE: modport_simple_ports_declaration |
|
| 996 |
| modportSimplePort { $$ = new AstModportVar($<fl>1,*$1,AstVarType::INOUT); }
|
|
| 997 |
; |
|
| 998 | ||
| 999 |
modportSimplePort<strp>: // IEEE: modport_simple_port or modport_tf_port, depending what keyword was earlier |
|
| 1000 |
id { $$ = $1; }
|
|
| 1001 |
//UNSUP '.' idAny '(' ')' { }
|
|
| 1002 |
//UNSUP '.' idAny '(' expr ')' { }
|
|
| 1003 |
; |
|
| 1004 | ||
| 908 | 1005 |
//************************************************ |
| 909 | 1006 |
// Variable Declarations |
| 910 | 1007 | |
| b/test_regress/t/t_interface.pl | ||
|---|---|---|
| 1 |
#!/usr/bin/perl |
|
| 2 |
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
|
| 3 |
# DESCRIPTION: Verilator: Verilog Test driver/expect definition |
|
| 4 |
# |
|
| 5 |
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can |
|
| 6 |
# redistribute it and/or modify it under the terms of either the GNU |
|
| 7 |
# Lesser General Public License Version 3 or the Perl Artistic License |
|
| 8 |
# Version 2.0. |
|
| 9 | ||
| 10 |
compile ( |
|
| 11 |
v_flags => [] |
|
| 12 |
); |
|
| 13 | ||
| 14 |
execute ( |
|
| 15 |
check_finished=>1, |
|
| 16 |
); |
|
| 17 | ||
| 18 |
ok(1); |
|
| 19 |
1; |
|
| b/test_regress/t/t_interface.v | ||
|---|---|---|
| 1 |
// DESCRIPTION: Verilator: Verilog Test module |
|
| 2 |
// |
|
| 3 |
// This file ONLY is placed into the Public Domain, for any use, |
|
| 4 |
// without warranty, 2006 by Wilson Snyder. |
|
| 5 | ||
| 6 |
interface counter_io; |
|
| 7 |
logic [3:0] value; |
|
| 8 |
logic reset; |
|
| 9 |
endinterface |
|
| 10 | ||
| 11 |
module t (/*AUTOARG*/ |
|
| 12 |
// Inputs |
|
| 13 |
clk |
|
| 14 |
); |
|
| 15 | ||
| 16 |
input clk; |
|
| 17 |
integer cyc=1; |
|
| 18 | ||
| 19 |
counter_io c1_data(); |
|
| 20 |
counter_io c2_data(); |
|
| 21 | ||
| 22 |
counter c1 (.clkm(clk), |
|
| 23 |
.c_data(c1_data), |
|
| 24 |
.i_value(4'h1)); |
|
| 25 |
counter c2 (.clkm(clk), |
|
| 26 |
.c_data(c2_data), |
|
| 27 |
.i_value(4'h2)); |
|
| 28 | ||
| 29 |
initial begin |
|
| 30 |
c1_data.value = 4'h4; |
|
| 31 |
c2_data.value = 4'h5; |
|
| 32 |
end |
|
| 33 | ||
| 34 |
always @ (posedge clk) begin |
|
| 35 |
cyc <= cyc + 1; |
|
| 36 |
if (cyc<2) begin |
|
| 37 |
c1_data.reset <= 1; |
|
| 38 |
c2_data.reset <= 1; |
|
| 39 |
end |
|
| 40 |
if (cyc==2) begin |
|
| 41 |
c1_data.reset <= 0; |
|
| 42 |
c2_data.reset <= 0; |
|
| 43 |
end |
|
| 44 |
if (cyc==20) begin |
|
| 45 |
$write("[%0t] c1 cyc%0d: %0x %0x\n", $time, cyc, c1_data.value, c1_data.reset);
|
|
| 46 |
$write("[%0t] c2 cyc%0d: %0x %0x\n", $time, cyc, c2_data.value, c2_data.reset);
|
|
| 47 |
if (c1_data.value != 2) $stop; |
|
| 48 |
if (c2_data.value != 3) $stop; |
|
| 49 |
$write("*-* All Finished *-*\n");
|
|
| 50 |
$finish; |
|
| 51 |
end |
|
| 52 |
end |
|
| 53 |
endmodule |
|
| 54 | ||
| 55 |
module counter |
|
| 56 |
( |
|
| 57 |
input clkm, |
|
| 58 |
counter_io c_data, |
|
| 59 |
input logic [3:0] i_value |
|
| 60 |
); |
|
| 61 | ||
| 62 |
always @ (posedge clkm) begin |
|
| 63 |
if (c_data.reset) |
|
| 64 |
c_data.value <= i_value; |
|
| 65 |
else |
|
| 66 |
c_data.value <= c_data.value + 1; |
|
| 67 |
end |
|
| 68 |
endmodule : counter |
|
| b/test_regress/t/t_interface_inl.pl | ||
|---|---|---|
| 1 |
#!/usr/bin/perl |
|
| 2 |
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
|
| 3 |
# DESCRIPTION: Verilator: Verilog Test driver/expect definition |
|
| 4 |
# |
|
| 5 |
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can |
|
| 6 |
# redistribute it and/or modify it under the terms of either the GNU |
|
| 7 |
# Lesser General Public License Version 3 or the Perl Artistic License |
|
| 8 |
# Version 2.0. |
|
| 9 | ||
| 10 |
top_filename("t/t_interface.v");
|
|
| 11 | ||
| 12 |
compile ( |
|
| 13 |
# Avoid inlining so we find bugs in the non-inliner connection code |
|
| 14 |
v_flags => ["-Oi"], |
|
| 15 |
); |
|
| 16 | ||
| 17 |
execute ( |
|
| 18 |
check_finished=>1, |
|
| 19 |
); |
|
| 20 | ||
| 21 |
ok(1); |
|
| 22 |
1; |
|
![[logo]](/img/veripool_small.png)