Internals: Misc refectoring for assoc/queues.

This commit is contained in:
Wilson Snyder 2019-12-01 06:09:58 -05:00
parent 3d6e8e9eb0
commit 38e586fabe
6 changed files with 173 additions and 150 deletions

View File

@ -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()
|| (forFunc && (isWritable()
|| direction() == VDirection::REF
|| direction() == VDirection::CONSTREF
|| (strtype && isNonOutput())))) {
oname += "&";
infop->m_mayParen = true;
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="<<info.m_oprefix<<" osuffix="<<info.m_osuffix
// <<" oref="<<info.m_oref<<" "<<dtypep);
return info;
} else {
v3fatalSrc("Unknown data type in var type emitter: "<<dtypep->prettyName());
}

View File

@ -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 {

View File

@ -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: "<<varp->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; v<vects; ++v) puts( "[__Vi"+cvtToStr(v)+"]");
puts(");\n");
} else {
puts(varp->nameProtect());
for (int v=0; v<vects; ++v) puts( "[__Vi"+cvtToStr(v)+"]");
// 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())) {
puts(" = 0;\n");
} else {
puts(" = VL_RAND_RESET_");
emitIQW(varp);
puts("(");
puts(cvtToStr(varp->widthMin()));
puts(");\n");
}
}
for (int v=0; v<vects; ++v) puts( "}}\n");
}
splitSizeInc(1);
}
void EmitCImp::emitCoverageDecl(AstNodeModule* modp) {
if (v3Global.opt.coverage()) {
ofp()->putsPrivate(true);

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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 "<<nodep<<endl);
if (nodep->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