From 38e586fabeea5f2c816cf9b15b0b45c7260046ed Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 1 Dec 2019 06:09:58 -0500 Subject: [PATCH] Internals: Misc refectoring for assoc/queues. --- src/V3AstNodes.cpp | 100 +++++++++++----------- src/V3AstNodes.h | 5 +- src/V3EmitC.cpp | 184 +++++++++++++++++++++-------------------- src/V3ParseGrammar.cpp | 14 ++-- src/V3Premit.cpp | 3 +- src/V3Width.cpp | 17 +++- 6 files changed, 173 insertions(+), 150 deletions(-) diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 58872b4a8..255265aff 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -226,48 +226,56 @@ string AstVar::verilogKwd() const { } } -class AstVar::VlArgTypeRecurseInfo { +class AstVar::VlArgTypeRecursed { public: - bool m_named; - bool m_forFunc; - bool m_mayParen; - string m_namespc; - string paren(const string& s) { - if (m_mayParen) { m_mayParen = false; return " ("+s+")"; } - else return s; + string m_oref; // To output, reference part before name, "&" + string m_osuffix; // To output, suffixed after name, "[3]" + string m_oprefix; // To output, prefixed before name, "Foo_t" + void clear() { + m_oref.clear(); + m_osuffix.clear(); + m_oprefix.clear(); + } + string refParen(const string& name) { + return m_oref.empty() ? name : "("+m_oref+" "+name+")"; } }; string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc) const { UASSERT_OBJ(!forReturn, this, "Internal data is never passed as return, but as first argument"); - VlArgTypeRecurseInfo info; - info.m_named = named; - info.m_forFunc = forFunc; - info.m_mayParen = false; - info.m_namespc = namespc; - string ostatic; - if (isStatic() && info.m_namespc.empty()) ostatic = "static "; - return ostatic + vlArgTypeRecurse(dtypep(), &info, ""); + if (isStatic() && namespc.empty()) ostatic = "static "; + + VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, dtypep()); + + string oname; + if (named) { + oname += " "; + if (!namespc.empty()) oname += namespc+"::"; + oname += VIdProtect::protectIf(name(), protect()); + } + return ostatic + info.m_oprefix + info.refParen(oname) + info.m_osuffix; } -string AstVar::vlArgTypeRecurse(AstNodeDType* dtypep, VlArgTypeRecurseInfo* infop, - const string& inarray) const { +AstVar::VlArgTypeRecursed AstVar::vlArgTypeRecurse(bool forFunc, + const AstNodeDType* dtypep) const { dtypep = dtypep->skipRefp(); - if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) { - string oarray = "["+cvtToStr(adtypep->declRange().elements())+"]"; - return vlArgTypeRecurse(adtypep->subDTypep(), infop, inarray+oarray); - } else if (AstBasicDType* bdtypep = basicp()) { + if (const AstUnpackArrayDType* adtypep = VN_CAST_CONST(dtypep, UnpackArrayDType)) { + VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, adtypep->subDTypep()); + info.m_osuffix = "[" + cvtToStr(adtypep->declRange().elements()) + "]" + info.m_osuffix; + return info; + } else if (const AstBasicDType* bdtypep = dtypep->basicp()) { string otype; - string oarray = inarray; + string oarray; bool strtype = bdtypep && bdtypep->keyword() == AstBasicDTypeKwd::STRING; string bitvec; if (bdtypep && !bdtypep->isOpaque() && !v3Global.opt.protectIds()) { - bitvec = ("/*"+cvtToStr(bdtypep->lsb()+bdtypep->width()-1) - +":"+cvtToStr(bdtypep->lsb())+"*/"); + // We don't print msb()/lsb() as multidim packed would require recursion, + // and may confuse users as C++ data is stored always with bit 0 used + bitvec += "/*"+cvtToStr(dtypep->width()-1)+":0*/"; } - if ((infop->m_forFunc && isReadOnly()) + if ((forFunc && isReadOnly()) || bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR || bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) otype += "const "; if (bdtypep && bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR) { @@ -280,35 +288,35 @@ string AstVar::vlArgTypeRecurse(AstNodeDType* dtypep, VlArgTypeRecurseInfo* info otype += "float"; } else if (strtype) { otype += "std::string"; - } else if (widthMin() <= 8) { + } else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width otype += "CData"+bitvec; - } else if (widthMin() <= 16) { + } else if (dtypep->widthMin() <= 16) { otype += "SData"+bitvec; - } else if (widthMin() <= VL_WORDSIZE) { + } else if (dtypep->widthMin() <= VL_WORDSIZE) { otype += "IData"+bitvec; - } else if (isQuad()) { + } else if (dtypep->isQuad()) { otype += "QData"+bitvec; - } else if (isWide()) { + } else if (dtypep->isWide()) { otype += "WData"+bitvec; // []'s added later - oarray += "["+cvtToStr(widthWords())+"]"; + oarray += "["+cvtToStr(dtypep->widthWords())+"]"; } - string oname; + string oref; if (isDpiOpenArray() - || (infop->m_forFunc && (isWritable() - || direction() == VDirection::REF - || direction() == VDirection::CONSTREF - || (strtype && isNonOutput())))) { - oname += "&"; - infop->m_mayParen = true; + || (forFunc && (isWritable() + || direction() == VDirection::REF + || direction() == VDirection::CONSTREF + || (strtype && isNonOutput())))) { + oref = "&"; } - if (infop->m_named) { - oname += " "; - if (!infop->m_namespc.empty()) oname += infop->m_namespc+"::"; - oname += VIdProtect::protectIf(name(), protect()); - } - if (!oarray.empty()) oname = infop->paren(oname); - return otype+oname+oarray; + + VlArgTypeRecursed info; + info.m_oprefix = otype; + info.m_osuffix = oarray; + info.m_oref = oref; + //UINFO(9, "vlArgRec "<<"oprefix="<prettyName()); } diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 7abb4a561..6ad46e7a8 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -1411,9 +1411,8 @@ public: const MTaskIdSet& mtaskIds() const { return m_mtaskIds; } string mtasksString() const; private: - class VlArgTypeRecurseInfo; - string vlArgTypeRecurse(AstNodeDType* dtypep, VlArgTypeRecurseInfo* infop, - const string& oarray) const; + class VlArgTypeRecursed; + VlArgTypeRecursed vlArgTypeRecurse(bool forFunc, const AstNodeDType* dtypep) const; }; class AstDefParam : public AstNode { diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index d00a38e64..776fe920b 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -1264,7 +1264,99 @@ class EmitCImp : EmitCStmts { // METHODS // Low level - void emitVarReset(AstVar* varp); + void emitVarReset(AstVar* varp) { + AstNodeDType* dtypep = varp->dtypep()->skipRefp(); + if (varp->isIO() && m_modp->isTop() && optSystemC()) { + // System C top I/O doesn't need loading, as the lower level subinst code does it.} + } else if (varp->isParam()) { + UASSERT_OBJ(varp->valuep(), varp, "No init for a param?"); + // If a simple CONST value we initialize it using an enum + // If an ARRAYINIT we initialize it using an initial block similar to a signal + //puts("// parameter "+varp->nameProtect()+" = "+varp->valuep()->name()+"\n"); + } else if (AstInitArray* initarp = VN_CAST(varp->valuep(), InitArray)) { + if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) { + if (initarp->defaultp()) { + // MSVC++ pre V7 doesn't support 'for (int ...)', so declare in sep block + puts("{ int __Vi=0;"); + puts(" for (; __Vi<"+cvtToStr(adtypep->elementsConst())); + puts("; ++__Vi) {\n"); + emitSetVarConstant(varp->nameProtect()+"[__Vi]", + VN_CAST(initarp->defaultp(), Const)); + puts("}}\n"); + } + const AstInitArray::KeyItemMap& mapr = initarp->map(); + for (AstInitArray::KeyItemMap::const_iterator it = mapr.begin(); + it != mapr.end(); ++it) { + AstNode* valuep = it->second->valuep(); + emitSetVarConstant(varp->nameProtect() + +"["+cvtToStr(it->first)+"]", + VN_CAST(valuep, Const)); + } + } else { + varp->v3fatalSrc("InitArray under non-arrayed var"); + } + } else { + puts(emitVarResetRecurse(varp, dtypep, 0, "")); + } + } + string emitVarResetRecurse(AstVar* varp, AstNodeDType* dtypep, int depth, string suffix) { + dtypep = dtypep->skipRefp(); + AstBasicDType* basicp = dtypep->basicp(); + // Returns string to do resetting, empty to do nothing (which caller should handle) + if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) { + UASSERT_OBJ(adtypep->msb() >= adtypep->lsb(), varp, + "Should have swapped msb & lsb earlier."); + string ivar = string("__Vi")+cvtToStr(depth); + // MSVC++ pre V7 doesn't support 'for (int ...)', so declare in sep block + string pre = ("{ int "+ivar+"="+cvtToStr(0)+";" + +" for (; "+ivar+"<"+cvtToStr(adtypep->elementsConst()) + +"; ++"+ivar+") {\n"); + string below = emitVarResetRecurse(varp, adtypep->subDTypep(), depth+1, suffix+"["+ivar+"]"); + string post = "}}\n"; + return below.empty() ? "" : pre + below + post; + } + else if (basicp && basicp->keyword() == AstBasicDTypeKwd::STRING) { + // String's constructor deals with it + return ""; + } + else if (basicp) { + bool zeroit = (varp->attrFileDescr() // Zero so we don't core dump if never $fopen + || (basicp && basicp->isZeroInit()) + || (v3Global.opt.underlineZero() + && !varp->name().empty() && varp->name()[0] == '_') + || (v3Global.opt.xInitial() == "fast" + || v3Global.opt.xInitial() == "0")); + splitSizeInc(1); + if (dtypep->isWide()) { // Handle unpacked; not basicp->isWide + string out; + if (zeroit) out += "VL_ZERO_RESET_W("; + else out += "VL_RAND_RESET_W("; + out += cvtToStr(dtypep->widthMin()); + out += ", "+varp->nameProtect()+suffix+");\n"; + return out; + } else { + string out = varp->nameProtect() + suffix; + // If --x-initial-edge is set, we want to force an initial + // edge on uninitialized clocks (from 'X' to whatever the + // first value is). Since the class is instantiated before + // initial blocks are evaluated, this should not clash + // with any initial block settings. + if (zeroit || (v3Global.opt.xInitialEdge() && varp->isUsedClock())) { + out += " = 0;\n"; + } else { + out += " = VL_RAND_RESET_"; + out += dtypep->charIQWN(); + out += "("+ cvtToStr(dtypep->widthMin())+");\n"; + } + return out; + } + } + else { + v3fatalSrc("Unknown node type in reset generator: "<prettyTypeName()); + } + return ""; + } + void emitCellCtors(AstNodeModule* modp); void emitSensitives(); // Medium level @@ -1303,8 +1395,8 @@ public: void EmitCStmts::emitVarDecl(const AstVar* nodep, const string& prefixIfImp) { AstBasicDType* basicp = nodep->basicp(); - UASSERT_OBJ(basicp, nodep, "Unimplemented: Outputting this data type"); if (nodep->isIO() && nodep->isSc()) { + UASSERT_OBJ(basicp, nodep, "Unimplemented: Outputting this data type"); m_ctorVarsVec.push_back(nodep); if (nodep->attrScClocked() && nodep->isReadOnly()) { puts("sc_in_clk "); @@ -1698,94 +1790,6 @@ void EmitCStmts::displayNode(AstNode* nodep, AstScopeName* scopenamep, //###################################################################### // Internal EmitC -void EmitCImp::emitVarReset(AstVar* varp) { - if (varp->isIO() && m_modp->isTop() && optSystemC()) { - // System C top I/O doesn't need loading, as the lower level subinst code does it.} - } else if (varp->isParam()) { - UASSERT_OBJ(varp->valuep(), varp, "No init for a param?"); - // If a simple CONST value we initialize it using an enum - // If an ARRAYINIT we initialize it using an initial block similar to a signal - //puts("// parameter "+varp->nameProtect()+" = "+varp->valuep()->name()+"\n"); - } - else if (AstInitArray* initarp = VN_CAST(varp->valuep(), InitArray)) { - if (AstUnpackArrayDType* arrayp = VN_CAST(varp->dtypeSkipRefp(), UnpackArrayDType)) { - if (initarp->defaultp()) { - // MSVC++ pre V7 doesn't support 'for (int ...)', so declare in sep block - puts("{ int __Vi=0;"); - puts(" for (; __Vi<"+cvtToStr(arrayp->elementsConst())); - puts("; ++__Vi) {\n"); - emitSetVarConstant(varp->nameProtect()+"[__Vi]", - VN_CAST(initarp->defaultp(), Const)); - puts("}}\n"); - } - const AstInitArray::KeyItemMap& mapr = initarp->map(); - for (AstInitArray::KeyItemMap::const_iterator it = mapr.begin(); - it != mapr.end(); ++it) { - AstNode* valuep = it->second->valuep(); - emitSetVarConstant(varp->nameProtect() - +"["+cvtToStr(it->first)+"]", - VN_CAST(valuep, Const)); - } - } else { - varp->v3fatalSrc("InitArray under non-arrayed var"); - } - } - else if (varp->basicp() && varp->basicp()->keyword() == AstBasicDTypeKwd::STRING) { - // Constructor deals with it - } - else { - int vects = 0; - // This isn't very robust and may need cleanup for other data types - for (AstUnpackArrayDType* arrayp=VN_CAST(varp->dtypeSkipRefp(), UnpackArrayDType); - arrayp; - arrayp = VN_CAST(arrayp->subDTypep()->skipRefp(), UnpackArrayDType)) { - int vecnum = vects++; - UASSERT_OBJ(arrayp->msb() >= arrayp->lsb(), varp, - "Should have swapped msb & lsb earlier."); - string ivar = string("__Vi")+cvtToStr(vecnum); - // MSVC++ pre V7 doesn't support 'for (int ...)', so declare in sep block - puts("{ int __Vi"+cvtToStr(vecnum)+"="+cvtToStr(0)+";"); - puts(" for (; "+ivar+"<"+cvtToStr(arrayp->elementsConst())); - puts("; ++"+ivar+") {\n"); - } - bool zeroit = (varp->attrFileDescr() // Zero it out, so we don't core dump if never call $fopen - || (varp->basicp() && varp->basicp()->isZeroInit()) - || (v3Global.opt.underlineZero() - && !varp->name().empty() && varp->name()[0]=='_') - || (v3Global.opt.xInitial() == "fast" || v3Global.opt.xInitial() == "0")); - if (varp->isWide()) { - // DOCUMENT: We randomize everything. If the user wants a _var to be zero, - // there should be a initial statement. (Different from verilator2.) - if (zeroit) puts("VL_ZERO_RESET_W("); - else puts("VL_RAND_RESET_W("); - puts(cvtToStr(varp->widthMin())); - puts(","); - puts(varp->nameProtect()); - for (int v=0; vnameProtect()); - for (int v=0; visUsedClock())) { - puts(" = 0;\n"); - } else { - puts(" = VL_RAND_RESET_"); - emitIQW(varp); - puts("("); - puts(cvtToStr(varp->widthMin())); - puts(");\n"); - } - } - for (int v=0; vputsPrivate(true); diff --git a/src/V3ParseGrammar.cpp b/src/V3ParseGrammar.cpp index 520436bf5..264da33a4 100644 --- a/src/V3ParseGrammar.cpp +++ b/src/V3ParseGrammar.cpp @@ -113,17 +113,17 @@ AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstNodeRange* prevp = VN_CAST(nrangep->backp(), NodeRange); if (prevp) nrangep->unlinkFrBack(); AstRange* rangep = VN_CAST(nrangep, Range); - if (!rangep) { - UASSERT_OBJ(VN_IS(nrangep, UnsizedRange), nrangep, - "Expected range or unsized range"); - arrayp = new AstUnsizedArrayDType - (nrangep->fileline(), VFlagChildDType(), arrayp); - } else if (isPacked) { + if (rangep && isPacked) { arrayp = new AstPackArrayDType (rangep->fileline(), VFlagChildDType(), arrayp, rangep); - } else { + } else if (rangep) { arrayp = new AstUnpackArrayDType (rangep->fileline(), VFlagChildDType(), arrayp, rangep); + } else if (VN_IS(nrangep, UnsizedRange)) { + arrayp = new AstUnsizedArrayDType + (nrangep->fileline(), VFlagChildDType(), arrayp); + } else { + UASSERT_OBJ(0, nrangep, "Expected range or unsized range"); } nrangep = prevp; } diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index cdfb31799..cb16d3a48 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -388,7 +388,8 @@ private: // Any strings sent to a display must be var of string data type, // to avoid passing a pointer to a temporary. for (AstNode* expp=nodep->exprsp(); expp; expp = expp->nextp()) { - if (expp->dtypep()->basicp()->isString() + if (expp->dtypep()->basicp() + && expp->dtypep()->basicp()->isString() && !VN_IS(expp, VarRef)) { createDeepTemp(expp, true); } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index a7b7574af..531258dae 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1358,7 +1358,7 @@ private: // Note genvar's are also entered as integers nodep->dtypeFrom(nodep->varp()); if (VN_IS(nodep->backp(), NodeAssign) && nodep->lvalue()) { // On LHS - UASSERT_OBJ(nodep->widthMin(), nodep, "LHS var should be size complete"); + UASSERT_OBJ(nodep->dtypep(), nodep, "LHS var should be dtype completed"); } //if (debug()>=9) nodep->dumpTree(cout, " VRout "); if (nodep->lvalue() && nodep->varp()->direction() == VDirection::CONSTREF) { @@ -1631,6 +1631,7 @@ private: virtual void visit(AstMethodCall* nodep) { UINFO(5," METHODSEL "<didWidth()) return; if (debug()>=9) nodep->dumpTree("-mts-in: "); // Should check types the method requires, but at present we don't do much userIterate(nodep->fromp(), WidthVP(SELF, BOTH).p()); @@ -2308,10 +2309,10 @@ private: } case 'p': { // Packed AstBasicDType* basicp = argp ? argp->dtypep()->basicp() : NULL; - if (basicp->isString()) { + if (basicp && basicp->isString()) { added = true; newFormat += "\"%@\""; - } else if (basicp->isDouble()) { + } else if (basicp && basicp->isDouble()) { added = true; newFormat += "%g"; } else { @@ -3482,6 +3483,16 @@ private: } if (underp) {} // cppcheck } + void iterateCheckTyped(AstNode* nodep, const char* side, AstNode* underp, + AstNodeDType* expDTypep, Stage stage) { + if (stage & PRELIM) { + underp = userIterateSubtreeReturnEdits(underp, WidthVP(SELF, PRELIM).p()); + } + if (stage & FINAL) { + underp = iterateCheck(nodep, side, underp, SELF, FINAL, expDTypep, EXTEND_EXP); + } + if (underp) {} // cppcheck + } void iterateCheckSizedSelf(AstNode* nodep, const char* side, AstNode* underp, Determ determ, Stage stage) { // Coerce child to any sized-number data type; child is self-determined