diff --git a/Changes b/Changes index 58b2bd1b2..bfbe4c93f 100644 --- a/Changes +++ b/Changes @@ -16,6 +16,8 @@ indicates the contributor was also the author of the fix; Thanks! *** Support "program". +*** Support typedef. [Donal Casey] + * Verilator 3.720 2009/10/26 ** Support little endian bit vectors ("reg [0:2] x;"). diff --git a/bin/verilator b/bin/verilator index 00ff65097..aa0e72439 100755 --- a/bin/verilator +++ b/bin/verilator @@ -1706,7 +1706,7 @@ endcase, endfunction, endgenerate, endmodule, endspecify, endtask, final, for, function, generate, genvar, if, initial, inout, input, int, integer, localparam, logic, longint, macromodule, module, nand, negedge, nor, not, or, output, parameter, posedge, reg, scalared, shortint, signed, supply0, -supply1, task, tri, var, vectored, while, wire, xnor, xor +supply1, task, tri, typedef, var, vectored, while, wire, xnor, xor Generally supported. diff --git a/src/V3Ast.h b/src/V3Ast.h index 76eeaab24..713dbe511 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1188,6 +1188,7 @@ struct AstNodeDType : public AstNode { ASTNODE_BASE_FUNCS(NodeDType) // Accessors virtual AstBasicDType* basicp() = 0; // (Slow) recurse down to find basic data type + virtual AstNodeDType* skipRefp() = 0; // recurses over typedefs to next non-typeref type virtual int widthAlignBytes() const = 0; // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) virtual int widthTotalBytes() const = 0; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,... }; diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 5a00cb860..d5dd2ce70 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -146,13 +146,15 @@ AstNodeDType* AstVar::dtypeDimensionp(int dimension) const { // SEL1 needs to select from entire variable which is a pointer to ARRAYSEL0 int dim = 0; for (AstNodeDType* dtypep=this->dtypep(); dtypep; ) { + dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node if (AstArrayDType* adtypep = dtypep->castArrayDType()) { if ((dim++)==dimension) { return dtypep; } dtypep = adtypep->dtypep(); continue; - } else if (AstBasicDType* adtypep = dtypep->castBasicDType()) { + } + else if (AstBasicDType* adtypep = dtypep->castBasicDType()) { // AstBasicDType - nothing below, return null if (adtypep->rangep()) { if ((dim++) == dimension) { @@ -170,10 +172,12 @@ AstNodeDType* AstVar::dtypeDimensionp(int dimension) const { uint32_t AstVar::arrayElements() const { uint32_t entries=1; for (AstNodeDType* dtypep=this->dtypep(); dtypep; ) { + dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node if (AstArrayDType* adtypep = dtypep->castArrayDType()) { entries *= adtypep->elementsConst(); dtypep = adtypep->dtypep(); - } else { + } + else { // AstBasicDType - nothing below, 1 break; } @@ -378,6 +382,11 @@ void AstRange::dump(ostream& str) { this->AstNode::dump(str); if (littleEndian()) str<<" [LITTLE]"; } +void AstRefDType::dump(ostream& str) { + this->AstNode::dump(str); + if (defp()) { str<<" -> "; defp()->dump(str); } + else { str<<" -> UNLINKED"; } +} void AstVarXRef::dump(ostream& str) { this->AstNode::dump(str); if (lvalue()) str<<" [LV] => "; diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 570a34ea5..fd92b5729 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -108,7 +108,36 @@ public: //###################################################################### //==== Data Types +struct AstTypedef : public AstNode { + string m_name; +public: + AstTypedef(FileLine* fl, const string& name, AstNodeDType* dtypep) + : AstNode(fl), m_name(name) { + setOp1p(dtypep); + widthSignedFrom(dtypep); + } + ASTNODE_NODE_FUNCS(Typedef, TYPEDEF) + AstNodeDType* dtypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable + void dtypep(AstNodeDType* nodep) { setOp1p(nodep); } + // METHODS + virtual string name() const { return m_name; } + virtual bool maybePointedTo() const { return true; } + void name(const string& flag) { m_name = flag; } +}; + +struct AstTypedefFwd : public AstNode { + // Forward declaration of a type; stripped after netlist parsing is complete + string m_name; +public: + AstTypedefFwd(FileLine* fl, const string& name) + : AstNode(fl), m_name(name) {} + ASTNODE_NODE_FUNCS(TypedefFwd, TYPEDEFFWD) + // METHODS + virtual string name() const { return m_name; } +}; + struct AstArrayDType : public AstNodeDType { + // Array data type, ie "some_dtype var_name [2:0]" AstArrayDType(FileLine* fl, AstNodeDType* dtypep, AstRange* rangep) : AstNodeDType(fl) { setOp1p(dtypep); @@ -117,11 +146,13 @@ struct AstArrayDType : public AstNodeDType { } ASTNODE_NODE_FUNCS(ArrayDType, ARRAYDTYPE) AstNodeDType* dtypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable + AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } // op1 = Range of variable void dtypep(AstNodeDType* nodep) { setOp1p(nodep); } AstRange* arrayp() const { return op2p()->castRange(); } // op2 = Array(s) of variable void arrayp(AstRange* nodep) { setOp2p(nodep); } // METHODS virtual AstBasicDType* basicp() { return dtypep()->basicp(); } // (Slow) recurse down to find basic data type + virtual AstNodeDType* skipRefp() { return this; } virtual int widthAlignBytes() const { return dtypep()->widthAlignBytes(); } virtual int widthTotalBytes() const { return elementsConst() * dtypep()->widthTotalBytes(); } int msb() const { return arrayp()->msbConst(); } @@ -181,6 +212,7 @@ public: } // METHODS virtual AstBasicDType* basicp() { return this; } // (Slow) recurse down to find basic data type + virtual AstNodeDType* skipRefp() { return this; } virtual int widthAlignBytes() const; // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) virtual int widthTotalBytes() const; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,... bool isBitLogic() const { return keyword().isBitLogic(); } @@ -195,6 +227,42 @@ public: void implicit(bool flag) { m_implicit = flag; } }; +struct AstRefDType : public AstNodeDType { + AstTypedef* m_defp; + string m_name; +public: + AstRefDType(FileLine* fl, const string& name) + : AstNodeDType(fl), m_defp(NULL), m_name(name) {} + AstRefDType(FileLine* fl, AstTypedef* defp) + : AstNodeDType(fl), m_defp(defp), m_name(defp->name()) { + widthSignedFrom(defp); + } + ASTNODE_NODE_FUNCS(RefDType, REFDTYPE) + // METHODS + virtual bool broken() const { return m_defp && !m_defp->brokeExists(); } + virtual void cloneRelink() { if (m_defp && m_defp->clonep()) { + m_defp = m_defp->clonep()->castTypedef(); + }} + virtual void dump(ostream& str=cout); + virtual string name() const { return m_name; } + virtual AstBasicDType* basicp() { return defp() ? dtypep()->basicp() : NULL; } + virtual AstNodeDType* skipRefp() { + // Skip past both the Ref and the Typedef + if (defp()) return defp()->dtypep(); + else { v3fatalSrc("Typedef not linked"); return NULL; } + } + virtual int widthAlignBytes() const { return dtypep()->widthAlignBytes(); } + virtual int widthTotalBytes() const { return dtypep()->widthTotalBytes(); } + void name(const string& flag) { m_name = flag; } + AstNodeDType* dtypep() const { + if (defp()) return defp()->dtypep(); + else { v3fatalSrc("Typedef not linked"); return NULL; } + } + AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } // op1 = Range of variable + AstTypedef* defp() const { return m_defp; } + void defp(AstTypedef* nodep) { m_defp=nodep; } +}; + //###################################################################### struct AstArraySel : public AstNodeSel { @@ -394,6 +462,7 @@ public: string scType() const; // Return SysC type: bool, uint32_t, uint64_t, sc_bv void combineType(AstVarType type); AstNodeDType* dtypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable + AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } // op1 = Range of variable AstNodeDType* dtypeDimensionp(int depth) const; AstNode* initp() const { return op3p()->castNode(); } // op3 = Initial value that never changes (static const) void initp(AstNode* nodep) { setOp3p(nodep); } @@ -1719,7 +1788,7 @@ public: m_code = 0; m_codeInc = varp->arrayElements() * varp->widthWords(); m_lsb = varp->lsbEndianed(); m_msb = varp->msbEndianed(); - if (AstArrayDType* adtypep = varp->dtypep()->castArrayDType()) { + if (AstArrayDType* adtypep = varp->dtypeSkipRefp()->castArrayDType()) { m_arrayLsb = adtypep->arrayp()->lsbConst(); m_arrayMsb = adtypep->arrayp()->msbConst(); } else { diff --git a/src/V3Changed.cpp b/src/V3Changed.cpp index 07e3ad0ab..e7420faf6 100644 --- a/src/V3Changed.cpp +++ b/src/V3Changed.cpp @@ -72,7 +72,7 @@ private: #endif AstVar* varp = vscp->varp(); vscp->v3warn(IMPERFECTSCH,"Imperfect scheduling of variable: "<dtypep()->castBasicDType()) { + if (!varp->dtypeSkipRefp()->castBasicDType()) { vscp->v3error("Unsupported: Can't detect changes on arrayed variable (probably with UNOPTFLAT warning suppressed): "<prettyName()); } else { string newvarname = "__Vchglast__"+vscp->scopep()->nameDotless()+"__"+varp->shortName(); diff --git a/src/V3Coverage.cpp b/src/V3Coverage.cpp index ac2a4d4f7..f1135e74c 100644 --- a/src/V3Coverage.cpp +++ b/src/V3Coverage.cpp @@ -168,14 +168,14 @@ private: ToggleEnt newvec (string(""), new AstVarRef(nodep->fileline(), nodep, false), new AstVarRef(nodep->fileline(), chgVarp, true)); - toggleVarRecurse(nodep->dtypep(), 0, newvec, + toggleVarRecurse(nodep->dtypeSkipRefp(), 0, newvec, nodep, chgVarp); newvec.cleanup(); } } } - void toggleVarBottom(AstNodeDType* nodep, int depth, // per-iteration + void toggleVarBottom(AstNodeDType* dtypep, int depth, // per-iteration const ToggleEnt& above, AstVar* varp, AstVar* chgVarp) { // Constant AstCoverToggle* newp @@ -187,41 +187,41 @@ private: m_modp->addStmtp(newp); } - void toggleVarRecurse(AstNodeDType* nodep, int depth, // per-iteration + void toggleVarRecurse(AstNodeDType* dtypep, int depth, // per-iteration const ToggleEnt& above, AstVar* varp, AstVar* chgVarp) { // Constant - if (AstBasicDType* bdtypep = nodep->castBasicDType()) { + if (AstBasicDType* bdtypep = dtypep->castBasicDType()) { if (bdtypep->rangep()) { for (int index_docs=bdtypep->lsb(); index_docsmsb()+1; index_docs++) { int index_code = index_docs - bdtypep->lsb(); ToggleEnt newent (above.m_comment+string("[")+cvtToStr(index_docs)+"]", new AstSel(varp->fileline(), above.m_varRefp->cloneTree(true), index_code, 1), new AstSel(varp->fileline(), above.m_chgRefp->cloneTree(true), index_code, 1)); - toggleVarBottom(nodep, depth+1, + toggleVarBottom(dtypep, depth+1, newent, varp, chgVarp); newent.cleanup(); } } else { - toggleVarBottom(nodep, depth+1, + toggleVarBottom(dtypep, depth+1, above, varp, chgVarp); } } - else if (AstArrayDType* adtypep = nodep->castArrayDType()) { + else if (AstArrayDType* adtypep = dtypep->castArrayDType()) { for (int index_docs=adtypep->lsb(); index_docs<=adtypep->msb()+1; ++index_docs) { int index_code = index_docs - adtypep->lsb(); ToggleEnt newent (above.m_comment+string("[")+cvtToStr(index_docs)+"]", new AstArraySel(varp->fileline(), above.m_varRefp->cloneTree(true), index_code), new AstArraySel(varp->fileline(), above.m_chgRefp->cloneTree(true), index_code)); - toggleVarRecurse(adtypep->dtypep(), depth+1, + toggleVarRecurse(adtypep->dtypeSkipRefp(), depth+1, newent, varp, chgVarp); newent.cleanup(); } } else { - nodep->v3fatalSrc("Unexpected node data type in toggle coverage generation: "<prettyTypeName()); + dtypep->v3fatalSrc("Unexpected node data type in toggle coverage generation: "<prettyTypeName()); } } diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index fad5350fd..2f425d626 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -275,7 +275,7 @@ public: { AstVarRef* varrefp = nodep->memp()->castVarRef(); if (!varrefp) { nodep->v3error("Readmem loading non-variable"); } - else if (AstArrayDType* adtypep = varrefp->varp()->dtypep()->castArrayDType()) { + else if (AstArrayDType* adtypep = varrefp->varp()->dtypeSkipRefp()->castArrayDType()) { puts(cvtToStr(varrefp->varp()->arrayElements())); array_lsb = adtypep->lsb(); } @@ -773,8 +773,8 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) { puts(nodep->name()); puts(";\n"); } else { // C++ signals - ofp()->putAlign(nodep->isStatic(), nodep->dtypep()->widthAlignBytes(), - nodep->dtypep()->widthTotalBytes()); + ofp()->putAlign(nodep->isStatic(), nodep->dtypeSkipRefp()->widthAlignBytes(), + nodep->dtypeSkipRefp()->widthTotalBytes()); if (nodep->isInout()) puts("VL_INOUT"); else if (nodep->isInput()) puts("VL_IN"); else if (nodep->isOutput()) puts("VL_OUT"); @@ -797,8 +797,8 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) { } else { // Arrays need a small alignment, but may need different padding after. // For example three VL_SIG8's needs alignment 1 but size 3. - ofp()->putAlign(nodep->isStatic(), nodep->dtypep()->widthAlignBytes(), - nodep->dtypep()->widthTotalBytes()); + ofp()->putAlign(nodep->isStatic(), nodep->dtypeSkipRefp()->widthAlignBytes(), + nodep->dtypeSkipRefp()->widthTotalBytes()); if (nodep->isStatic() && prefixIfImp=="") puts("static "); if (nodep->isStatic()) puts("VL_ST_"); else puts("VL_"); if (nodep->widthMin() <= 8) { @@ -815,7 +815,7 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) { if (prefixIfImp!="") { puts(prefixIfImp); puts("::"); } puts(nodep->name()); // This isn't very robust and may need cleanup for other data types - for (AstArrayDType* arrayp=nodep->dtypep()->castArrayDType(); arrayp; arrayp = arrayp->dtypep()->castArrayDType()) { + for (AstArrayDType* arrayp=nodep->dtypeSkipRefp()->castArrayDType(); arrayp; arrayp = arrayp->dtypeSkipRefp()->castArrayDType()) { puts("["+cvtToStr(arrayp->elementsConst())+"]"); } puts(","+cvtToStr(nodep->msb())+","+cvtToStr(nodep->lsb())); @@ -1160,7 +1160,7 @@ void EmitCImp::emitVarResets(AstModule* modp) { } else if (AstInitArray* initarp = varp->initp()->castInitArray()) { AstConst* constsp = initarp->initsp()->castConst(); - if (AstArrayDType* arrayp = varp->dtypep()->castArrayDType()) { + if (AstArrayDType* arrayp = varp->dtypeSkipRefp()->castArrayDType()) { for (int i=0; ielementsConst(); i++) { if (!constsp) initarp->v3fatalSrc("Not enough values in array initalizement"); emitSetVarConstant(varp->name()+"["+cvtToStr(i)+"]", constsp); @@ -1173,7 +1173,8 @@ void EmitCImp::emitVarResets(AstModule* modp) { else { int vects = 0; // This isn't very robust and may need cleanup for other data types - for (AstArrayDType* arrayp=varp->dtypep()->castArrayDType(); arrayp; arrayp = arrayp->dtypep()->castArrayDType()) { + for (AstArrayDType* arrayp=varp->dtypeSkipRefp()->castArrayDType(); arrayp; + arrayp = arrayp->dtypeSkipRefp()->castArrayDType()) { int vecnum = vects++; if (arrayp->msb() < arrayp->lsb()) varp->v3fatalSrc("Should have swapped msb & lsb earlier."); string ivar = string("__Vi")+cvtToStr(vecnum); @@ -1423,10 +1424,10 @@ void EmitCStmts::emitVarList(AstNode* firstp, EisWhich which, const string& pref } if (varp->isStatic() ? !isstatic : isstatic) doit=false; if (doit) { - int sigbytes = varp->dtypep()->widthAlignBytes(); + int sigbytes = varp->dtypeSkipRefp()->widthAlignBytes(); int sortbytes = 7; if (varp->isUsedClock() && varp->widthMin()==1) sortbytes = 0; - else if (varp->dtypep()->castArrayDType()) sortbytes=7; + else if (varp->dtypeSkipRefp()->castArrayDType()) sortbytes=7; else if (varp->isScBv()) sortbytes=6; else if (sigbytes==8) sortbytes=5; else if (sigbytes==4) sortbytes=4; @@ -1901,7 +1902,7 @@ class EmitCTrace : EmitCStmts { if (emitTraceIsScBv(nodep)) puts("VL_SC_BV_DATAP("); varrefp->iterate(*this); // Put var name out // Tracing only supports 1D arrays - if (varp->dtypep()->castArrayDType()) { + if (varp->dtypeSkipRefp()->castArrayDType()) { if (arrayindex==-2) puts("[i]"); else if (arrayindex==-1) puts("[0]"); else puts("["+cvtToStr(arrayindex)+"]"); diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index 55469eb5b..0168ef42e 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -389,6 +389,12 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { } puts("]"); } + virtual void visit(AstTypedef* nodep, AstNUser*) { + puts("typedef "); + nodep->dtypep()->iterateAndNext(*this); puts(" "); + puts(nodep->name()); + puts(";\n"); + } virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) { if (nodep->dotted()!="") { puts(nodep->dotted()); puts("."); } puts(nodep->name()); diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index 55cb78ea1..5911c0910 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -206,6 +206,13 @@ private: } nodep->iterateChildren(*this); } + virtual void visit(AstTypedef* nodep, AstNUser*) { + if (m_cellp) { + // Typedef under the inline cell, need to rename to avoid conflicts + nodep->name(m_cellp->name() + "__DOT__" + nodep->name()); + } + nodep->iterateChildren(*this); + } virtual void visit(AstVarRef* nodep, AstNUser*) { if (m_cellp) { if (nodep->varp()->user2p() // It's being converted to a alias. @@ -248,6 +255,10 @@ private: } nodep->iterateChildren(*this); } + + // Not needed, as V3LinkDot doesn't care about typedefs + //virtual void visit(AstRefDType* 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() // Similar code in V3Begin diff --git a/src/V3Link.cpp b/src/V3Link.cpp index 58972c1aa..fa4748302 100644 --- a/src/V3Link.cpp +++ b/src/V3Link.cpp @@ -376,6 +376,30 @@ private: nodep->iterateChildren(*this); } + virtual void visit(AstTypedef* nodep, AstNUser*) { + // Remember its name for later resolution + if (!m_curVarsp) nodep->v3fatalSrc("Typedef not under module??\n"); + nodep->iterateChildren(*this); + if (m_idState==ID_FIND) { + findAndInsertAndCheck(nodep, nodep->name()); + } + } + virtual void visit(AstTypedefFwd* nodep, AstNUser*) { + // We only needed the forward declaration in order to parse correctly. + // We won't even check it was ever really defined, as it might have been in a header + // file referring to a module we never needed + nodep->unlinkFrBack()->deleteTree(); + } + virtual void visit(AstRefDType* nodep, AstNUser*) { + // Resolve its reference + if (m_idState==ID_RESOLVE && !nodep->defp()) { + AstTypedef* defp = m_curVarsp->findIdUpward(nodep->name())->castTypedef(); + if (!defp) { nodep->v3error("Can't find typedef: "<prettyName()); } + nodep->defp(defp); + } + nodep->iterateChildren(*this); + } + virtual void visit(AstCell* nodep, AstNUser*) { // Cell: Resolve its filename. If necessary, parse it. if (m_idState==ID_FIND) { diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 5abde7836..7ab9c7f8f 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -84,7 +84,7 @@ private: virtual void visit(AstVar* nodep, AstNUser*) { nodep->iterateChildren(*this); - if (nodep->isIO() && !nodep->dtypep()->castBasicDType()) { + if (nodep->isIO() && !nodep->dtypeSkipRefp()->castBasicDType()) { nodep->v3error("Unsupported: Inputs and outputs must be simple data types; no arrays"); } if (m_ftaskp) nodep->funcLocal(true); diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index 03f2784ec..e647fa484 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -177,7 +177,8 @@ public: V3ParseSym(AstNetlist* rootp) { s_anonNum = 0; // Number of next anonymous object pushScope(findNewTable(rootp, NULL)); - m_symTableNextId = symCurrentp(); + m_symTableNextId = NULL; + m_symCurrentp = symCurrentp(); } ~V3ParseSym() { for (SymStack::iterator it = m_symsp.begin(); it != m_symsp.end(); ++it) { diff --git a/src/V3Signed.cpp b/src/V3Signed.cpp index 537a11721..ddccae0e6 100644 --- a/src/V3Signed.cpp +++ b/src/V3Signed.cpp @@ -172,6 +172,11 @@ private: if (nodep->taskp()) nodep->taskp()->iterate(*this); nodep->signedFrom(nodep->taskp()); } + virtual void visit(AstRefDType* nodep, AstNUser*) { + nodep->iterateChildren(*this); + if (nodep->defp()) nodep->defp()->iterate(*this); + nodep->signedFrom(nodep->skipRefp()); + } virtual void visit(AstNodeIf* nodep, AstNUser*) { if (!nodep->castGenIf()) { // for m_paramsOnly nodep->ifsp()->iterateAndNext(*this); diff --git a/src/V3Simulate.h b/src/V3Simulate.h index b9e5be435..762459747 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -244,7 +244,7 @@ private: // We can't have non-delayed assignments with same value on LHS and RHS // as we don't figure out variable ordering. // Delayed is OK though, as we'll decode the next state separately. - if (!nodep->varp()->dtypep()->castBasicDType()) clearOptimizable(nodep,"Array references/not basic"); + if (!nodep->varp()->dtypeSkipRefp()->castBasicDType()) clearOptimizable(nodep,"Array references/not basic"); if (nodep->lvalue()) { if (m_inDlyAssign) { if (!(vscp->user1() & VU_LVDLY)) { diff --git a/src/V3Stats.cpp b/src/V3Stats.cpp index 8e0173fba..e5bc45cfc 100644 --- a/src/V3Stats.cpp +++ b/src/V3Stats.cpp @@ -94,8 +94,8 @@ private: nodep->iterateChildren(*this); if (m_counting) { if (nodep->isUsedClock()) ++m_statVarClock; - if (nodep->dtypep()->castArrayDType()) ++m_statVarArray; - else m_statVarBytes += nodep->dtypep()->widthTotalBytes(); + if (nodep->dtypeSkipRefp()->castArrayDType()) ++m_statVarArray; + else m_statVarBytes += nodep->dtypeSkipRefp()->widthTotalBytes(); if (int(m_statVarWidths.size()) <= nodep->width()) { m_statVarWidths.resize(nodep->width()+5); } @@ -106,8 +106,8 @@ private: allNodes(nodep); nodep->iterateChildren(*this); if (m_counting) { - if (nodep->varp()->dtypep()->castBasicDType()) { - m_statVarScpBytes += nodep->varp()->dtypep()->widthTotalBytes(); + if (nodep->varp()->dtypeSkipRefp()->castBasicDType()) { + m_statVarScpBytes += nodep->varp()->dtypeSkipRefp()->widthTotalBytes(); } } } diff --git a/src/V3SymTable.h b/src/V3SymTable.h index aa18805b2..9a0d6ea7c 100644 --- a/src/V3SymTable.h +++ b/src/V3SymTable.h @@ -29,6 +29,7 @@ #include #include #include +#include #include "V3Global.h" @@ -90,10 +91,12 @@ class V3SymTable : public AstNUser { for (IdNameMap::const_iterator it=m_idNameMap.begin(); it!=m_idNameMap.end(); ++it) { os<first; for (int i=it->first.length(); i<30; ++i) os<<" "; - os<second<second)->user4p()->castSymTable(); - belowp->dump(os, indent+" ", user4p_is_table); + os<second<dump(os, indent+"+ ", user4p_is_table); + } else { + os<second<varScopep(); if (nodep->lvalue()) { - m_outWidth += nodep->varp()->dtypep()->widthTotalBytes(); + m_outWidth += nodep->varp()->dtypeSkipRefp()->widthTotalBytes(); m_outVarps.push_back(vscp); } else { // We'll make the table with a separate natural alignment for each diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp index f22a3ce19..e798ae66c 100644 --- a/src/V3TraceDecl.cpp +++ b/src/V3TraceDecl.cpp @@ -75,9 +75,9 @@ private: return "Inlined leading underscore"; if (nodep->width() > 256) return "Wide bus > 256 bits"; if (nodep->arrayElements() > 32) return "Wide memory > 32 ents"; - if (!(nodep->dtypep()->castBasicDType() - || (nodep->dtypep()->castArrayDType() - && nodep->dtypep()->castArrayDType()->dtypep()->castBasicDType()))) { + if (!(nodep->dtypeSkipRefp()->castBasicDType() + || (nodep->dtypeSkipRefp()->castArrayDType() + && nodep->dtypeSkipRefp()->castArrayDType()->dtypeSkipRefp()->castBasicDType()))) { return "Unsupported: Multi-dimensional array"; } return NULL; diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 66cad2eb1..b4cb428d7 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -501,6 +501,15 @@ private: // else width in node is correct; it was set based on keyword().width() // at construction time } + virtual void visit(AstRefDType* nodep, AstNUser* vup) { + nodep->iterateChildren(*this, vup); + if (nodep->defp()) nodep->defp()->iterate(*this,vup); + nodep->widthFrom(nodep->dtypeSkipRefp()); + } + virtual void visit(AstTypedef* nodep, AstNUser* vup) { + nodep->iterateChildren(*this, vup); + nodep->widthFrom(nodep->dtypep()->skipRefp()); + } virtual void visit(AstVar* nodep, AstNUser* vup) { //if (debug()) nodep->dumpTree(cout," InitPre: "); // Must have deterministic constant width diff --git a/src/verilog.l b/src/verilog.l index 82669c786..b84b929ee 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -35,7 +35,7 @@ extern void yyerrorf(const char* format, ...); #define STATE_VERILOG_RECENT S05 // State name for most recent Verilog Version #define PARSEP V3ParseImp::parsep() - +#define SYMP PARSEP->symp() #define YY_INPUT(buf,result,max_size) \ result = PARSEP->flexPpInputToLex(buf,max_size); @@ -378,6 +378,7 @@ escid \\[^ \t\f\r\n]+ "static" { FL; return ySTATIC; } "timeprecision" { FL; return yTIMEPRECISION; } "timeunit" { FL; return yTIMEUNIT; } + "typedef" { FL; return yTYPEDEF; } "unique" { FL; return yUNIQUE; } "var" { FL; return yVAR; } "void" { FL; return yVOID; } @@ -445,7 +446,6 @@ escid \\[^ \t\f\r\n]+ "this" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "throughout" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "type" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } - "typedef" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "virtual" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "wait_order" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "wildcard" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } @@ -876,7 +876,31 @@ int V3ParseImp::lexToken() { // called from lexToBison, has a "this" // yylvalp is global int token = yylexThis(); - if (token == yaID__LEX) { token = yaID__ETC; } + if (token == yaID__LEX) { + AstNode* scp; + if (V3SymTable* look_underp = SYMP->nextId()) { + if (debugFlex()) { cout<<" lexToken: next id lookup forced under "<findIdUpward(*(yylval.strp)); + // "consume" it. Must set again if want another token under temp scope + SYMP->nextId(NULL); + } else { + UINFO(7," lexToken: find upward "<symCurrentp()<<" for '"<<*(yylval.strp)<<"'"<=9) SYMP->symCurrentp()->dump(cout," -findtree: ",true); + scp = SYMP->symCurrentp()->findIdUpward(*(yylval.strp)); + } + if (scp) { + UINFO(7," lexToken: Found "<scp = scp; + if (scp->castTypedef()) token = yaID__aTYPE; + else if (scp->castTypedefFwd()) token = yaID__aTYPE; + //UNSUP else if (scp->castClass()) token = yaID__aCLASS; + //UNSUP else if (scp->castPackage()) token = yaID__aPACKAGE; + //UNSUP else if (scp->castCoverGroup()) token = yaID__aCOVERGROUP; + else token = yaID__ETC; + } else { // Not found + token = yaID__ETC; + } + } return token; } @@ -886,6 +910,9 @@ int V3ParseImp::lexToBison() { //yylval.scp = NULL; // Symbol table not yet needed - no packages if (debugFlex()>=6 || debugBison()>=6) { cout<<" lexToBison TOKEN="< yaID__ETC "IDENTIFIER" %token yaID__LEX "IDENTIFIER-in-lex" +%token yaID__aTYPE "TYPE-IDENTIFIER" // IEEE: integral_number %token yaINTNUM "INTEGER NUMBER" @@ -296,6 +297,7 @@ class AstSenTree; %token yTIMEUNIT "timeunit" %token yTRI "tri" %token yTRUE "true" +%token yTYPEDEF "typedef" %token yUNIQUE "unique" %token yUNSIGNED "unsigned" %token yVAR "var" @@ -513,9 +515,9 @@ description: // ==IEEE: description | error { } ; -timeunits_declaration: // ==IEEE: timeunits_declaration - yTIMEUNIT yaTIMENUM ';' { } - | yTIMEPRECISION yaTIMENUM ';' { } +timeunits_declaration: // ==IEEE: timeunits_declaration + yTIMEUNIT yaTIMENUM ';' { $$ = NULL; } + | yTIMEPRECISION yaTIMENUM ';' { $$ = NULL; } ; //********************************************************************** @@ -738,7 +740,7 @@ non_port_program_item: // ==IEEE: non_port_program_item | initial_construct { $$ = $1; } | final_construct { $$ = $1; } | concurrent_assertion_item { $$ = $1; } - //UNSUP timeunits_declaration { $$ = $1; } + | timeunits_declaration { $$ = $1; } | program_generate_item { $$ = $1; } ; @@ -919,7 +921,7 @@ data_type: // ==IEEE: data_type // // This expansion also replicated elsewhere, IE data_type__AndID data_typeNoRef { $$ = $1; } // // IEEE: [ class_scope | package_scope ] type_identifier { packed_dimension } - //UNSUP ps_type packed_dimensionE { UNSUP } + | ps_type packed_dimensionE { $$ = GRAMMARP->createArray($1,$2); } //UNSUP class_scope_type packed_dimensionE { UNSUP } // // IEEE: class_type //UNSUP class_typeWithoutId { $$ = $1; } @@ -1023,7 +1025,7 @@ variable_dimension: // ==IEEE: variable_dimension data_declaration: // ==IEEE: data_declaration // // VARRESET can't be called here - conflicts data_declarationVar { $$ = $1; } - //UNSUP type_declaration { $$ = $1; } + | type_declaration { $$ = $1; } //UNSUP package_import_declaration { $$ = $1; } // // IEEE: virtual_interface_declaration // // "yVIRTUAL yID yID" looks just like a data_declaration @@ -1060,6 +1062,19 @@ implicit_type: // IEEE: part of *data_type_or_implicit | signing { $$ = new AstBasicDType($1, LOGIC_IMPLICIT, $1); } ; +type_declaration: // ==IEEE: type_declaration + // // Use idAny, as we can redeclare a typedef on an existing typedef + /*U*/ yTYPEDEF data_type idAny variable_dimensionListE ';' { $$ = new AstTypedef($1, *$3, GRAMMARP->createArray($2,$4)); SYMP->reinsert($$); } + //UNSUP yTYPEDEF id/*interface*/ '.' idAny/*type*/ idAny/*type*/ ';' { $$ = NULL; $1->v3error("Unsupported: SystemVerilog 2005 typedef in this context"); } //UNSUP + // // Combines into above "data_type id" rule + // // Verilator: Not important what it is in the AST, just need to make sure the yaID__aTYPE gets returned + | yTYPEDEF id ';' { $$ = NULL; $$ = new AstTypedefFwd($1, *$2); SYMP->reinsert($$); } + //UNSUP yTYPEDEF yENUM idAny ';' { $$ = NULL; $$ = new AstTypedefFwd($1, *$2); SYMP->reinsert($$); } + //UNSUP yTYPEDEF ySTRUCT idAny ';' { $$ = NULL; $$ = new AstTypedefFwd($1, *$2); SYMP->reinsert($$); } + //UNSUP yTYPEDEF yUNION idAny ';' { $$ = NULL; $$ = new AstTypedefFwd($1, *$2); SYMP->reinsert($$); } + //UNSUP yTYPEDEF yCLASS idAny ';' { $$ = NULL; $$ = new AstTypedefFwd($1, *$2); SYMP->reinsert($$); } + ; + //************************************************ // Module Items @@ -1086,7 +1101,7 @@ non_port_module_item: // ==IEEE: non_port_module_item //UNSUP program_declaration { $$ = $1; } //UNSUP module_declaration { $$ = $1; } //UNSUP interface_declaration { $$ = $1; } - | timeunits_declaration { $$ = NULL; } + | timeunits_declaration { $$ = $1; } // // Verilator specific | yaSCHDR { $$ = new AstScHdr($1,*$1); } | yaSCINT { $$ = new AstScInt($1,*$1); } @@ -1347,6 +1362,16 @@ anyrange: '[' constExpr ':' constExpr ']' { $$ = new AstRange($1,$2,$4); } ; +packed_dimensionE: // IEEE: [ packed_dimension ] + /* empty */ { $$ = NULL; } + | packed_dimension { $$ = $1; } + ; + +packed_dimension: // ==IEEE: packed_dimension + anyrange { $$ = $1; } + //UNSUP '[' ']' { UNSUP } + ; + delayrange: wirerangeE delayE { $$ = $1; } | ySCALARED wirerangeE delayE { $$ = $2; } @@ -2424,8 +2449,8 @@ idAny: // Any kind of identifier //UNSUP yaID__aCLASS { $$ = $1; $$=$1; } //UNSUP yaID__aCOVERGROUP { $$ = $1; $$=$1; } //UNSUP yaID__aPACKAGE { $$ = $1; $$=$1; } - //UNSUP yaID__aTYPE { $$ = $1; $$=$1; } - yaID__ETC { $$ = $1; $$=$1; } + yaID__aTYPE { $$ = $1; $$=$1; } + | yaID__ETC { $$ = $1; $$=$1; } ; idSVKwd: // Warn about non-forward compatible Verilog 2001 code @@ -2581,7 +2606,13 @@ immediate_assert_statement: // ==IEEE: immediate_assert_statement // Each of these must end with {symsPackageDone | symsClassDone} ps_id_etc: // package_scope + general id - package_scopeIdFollowsE id { $$=$2; } + package_scopeIdFollowsE id { $$ = $2; } + ; + +ps_type: // IEEE: ps_parameter_identifier | ps_type_identifier + // Even though we looked up the type and have a AstNode* to it, + // we can't fully resolve it because it may have been just a forward definition. + package_scopeIdFollowsE yaID__aTYPE { $$ = new AstRefDType($1, *$2); } ; //=== Below rules assume special scoping per above @@ -2721,8 +2752,7 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, string name, AstRange // Split RANGE0-RANGE1-RANGE2 into ARRAYDTYPE0(ARRAYDTYPE1(ARRAYDTYPE2(BASICTYPE3),RANGE),RANGE) AstNodeDType* arrayDTypep = createArray(dtypep,arrayp); - AstVar* nodep = new AstVar(fileline, type, name, - arrayDTypep); + AstVar* nodep = new AstVar(fileline, type, name, arrayDTypep); nodep->addAttrsp(attrsp); if (GRAMMARP->m_varDecl != AstVarType::UNKNOWN) nodep->combineType(GRAMMARP->m_varDecl); if (GRAMMARP->m_varIO != AstVarType::UNKNOWN) nodep->combineType(GRAMMARP->m_varIO); diff --git a/test_regress/t/t_typedef.pl b/test_regress/t/t_typedef.pl new file mode 100755 index 000000000..7058e622f --- /dev/null +++ b/test_regress/t/t_typedef.pl @@ -0,0 +1,18 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. + +compile ( + ); + +execute ( + check_finished=>1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_typedef.v b/test_regress/t/t_typedef.v new file mode 100644 index 000000000..b29da6aff --- /dev/null +++ b/test_regress/t/t_typedef.v @@ -0,0 +1,57 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2009 by Wilson Snyder. + +program t; + parameter SIZE = 5; + + typedef reg [SIZE-1:0] vec_t ; + vec_t a; initial a =0; + + typedef bit [SIZE-1:0] vec_bit_t ; + vec_bit_t b; initial b =0; + + typedef int array [3]; + typedef array array2 [2]; + array2 ar [1]; + + // Define before use + // Not sure how well supported this is elsewhere + //UNSUP typedef preuse; + //UNSUP preuse p; + //UNSUP typedef int preuse; + +//reg [SIZE-1:0] a; initial a =0; +//reg [SIZE-1:0] b; initial b =0; + + integer j; + initial begin + for (j=0;j<=(1<1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_typedef_port.v b/test_regress/t/t_typedef_port.v new file mode 100644 index 000000000..4245f7d1b --- /dev/null +++ b/test_regress/t/t_typedef_port.v @@ -0,0 +1,112 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2009 by Wilson Snyder. + +//UNSUPtypedef reg [2:0] three_t; + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + typedef reg [2:0] three_t; //UNSUP remove + + integer cyc=0; + reg [63:0] crc; + reg [63:0] sum; + + // Take CRC data and apply to testblock inputs + wire [2:0] in = crc[2:0]; + + /*AUTOWIRE*/ + // Beginning of automatic wires (for undeclared instantiated-module outputs) + three_t outna; // From test of TestNonAnsi.v + // End of automatics + + TestNonAnsi test (// Outputs + .out (outna), + /*AUTOINST*/ + // Inputs + .clk (clk), + .in (in)); + +//UNSUP +// TestAnsi testa (// Outputs +// .out (outa), +// /*AUTOINST*/ +// // Inputs +// .clk (clk), +// .in (in)); + wire [2:0] outa = outna; + + // Aggregate outputs into a single result vector + wire [63:0] result = {57'h0, outna, 1'b0, outa}; + + // Test loop + always @ (posedge clk) begin +`ifdef TEST_VERBOSE + $write("[%0t] cyc==%0d crc=%x result=%x\n",$time, cyc, crc, result); +`endif + cyc <= cyc + 1; + crc <= {crc[62:0], crc[63]^crc[2]^crc[0]}; + sum <= result ^ {sum[62:0],sum[63]^sum[2]^sum[0]}; + if (cyc==0) begin + // Setup + crc <= 64'h5aef0c8d_d70a4497; + sum <= 64'h0; + end + else if (cyc<10) begin + sum <= 64'h0; + end + else if (cyc<90) begin + end + else if (cyc==99) begin + $write("[%0t] cyc==%0d crc=%x sum=%x\n",$time, cyc, crc, sum); + if (crc !== 64'hc77bb9b3784ea091) $stop; + // What checksum will we end up with (above print should match) +`define EXPECTED_SUM 64'h018decfea0a8828a + if (sum !== `EXPECTED_SUM) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule + +module TestNonAnsi (/*AUTOARG*/ + // Outputs + out, + // Inputs + clk, in + ); + typedef reg [2:0] three_t; + + input clk; + input three_t in; + output three_t out; + + always @(posedge clk) begin + out <= ~in; + end +endmodule + +`ifndef verilator //UNSUPPORTED +typedef reg [2:0] three_t; + +module TestAnsi ( + input clk, + input three_t in, + output three_t out + ); + always @(posedge clk) begin + out <= ~in; + end +endmodule + +`endif + +// Local Variables: +// verilog-typedef-regexp: "_t$" +// End: