virtual void visit(AstVarScope* nodep, AstNUser*) { nodep->iterateChildren(*this); // Avoid updating this if (), instead see varp->isTrace() if (!nodep->varp()->isTemp() && !nodep->varp()->isFuncLocal()) { UINFO(5, " vsc "<<nodep<<endl); AstVar* varp = nodep->varp(); AstScope* scopep = nodep->scopep(); // Compute show name // This code assumes SPTRACEVCDC_VERSION >= 1330; // it uses spaces to separate hierarchy components. m_traShowname = AstNode::vcdName(scopep->name() + " " + varp->name()); if (m_traShowname.substr(0,4) == "TOP ") m_traShowname.replace(0,4,""); if (!m_initSubFuncp) nodep->v3fatalSrc("NULL"); m_traVscp = nodep; m_traValuep = NULL; if (varIgnoreTrace(varp)) { addIgnore(varIgnoreTrace(varp)); } else { ++m_statSigs; if (nodep->valuep()) m_traValuep = nodep->valuep()->cloneTree(true); else m_traValuep = new AstVarRef(nodep->fileline(), nodep, false); { // Recurse into data type of the signal; the visitors will call addTraceDecl() varp->dtypeSkipRefp()->accept(*this); } // Cleanup if (m_traValuep) { m_traValuep->deleteTree(); m_traValuep=NULL; } } m_traVscp = NULL; m_traValuep = NULL; m_traShowname = ""; } }
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() string prefix = (string)("__DOT__")+m_scopep->name(); // TOP and above will be the user's name(). // Note 'TOP.' is stripped by scopePrettyName // To keep correct visual order, must add before other Text's AstNode* afterp = nodep->scopeAttrp(); if (afterp) afterp->unlinkFrBackWithNext(); nodep->scopeAttrp(new AstText(nodep->fileline(), prefix)); if (afterp) nodep->scopeAttrp(afterp); nodep->iterateChildren(*this); }
void varsExpand() { // We didn'e have all m_scopes loaded when we encountered variables, so expand them now // It would be less code if each module inserted its own variables. // Someday. For now public isn't common. for (vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) { AstScope* scopep = it->first; AstNodeModule* smodp = it->second; for (vector<ModVarPair>::iterator it = m_modVars.begin(); it != m_modVars.end(); ++it) { AstNodeModule* modp = it->first; AstVar* varp = it->second; if (modp == smodp) { // Need to split the module + var name into the original-ish full scope and variable name under that scope. // The module instance name is included later, when we know the scopes this module is under string whole = scopep->name()+"__DOT__"+varp->name(); string scpName; string varBase; if (whole.substr(0,10) == "__DOT__TOP") whole.replace(0,10,""); string::size_type pos = whole.rfind("__DOT__"); if (pos != string::npos) { scpName = whole.substr(0,pos); varBase = whole.substr(pos+strlen("__DOT__")); } else { varBase = whole; } //UINFO(9,"For "<<scopep->name()<<" - "<<varp->name()<<" Scp "<<scpName<<" Var "<<varBase<<endl); string varBasePretty = AstNode::prettyName(varBase); string scpPretty = AstNode::prettyName(scpName); string scpSym; { string out = scpName; string::size_type pos; while ((pos=out.find("__PVT__")) != string::npos) { out.replace(pos, 7, ""); } if (out.substr(0,10) == "TOP__DOT__") out.replace(0,10,""); if (out.substr(0,4) == "TOP.") out.replace(0,4,""); while ((pos=out.find(".")) != string::npos) { out.replace(pos, 1, "__"); } while ((pos=out.find("__DOT__")) != string::npos) { out.replace(pos, 7, "__"); } scpSym = out; } //UINFO(9," scnameins sp "<<scpName<<" sp "<<scpPretty<<" ss "<<scpSym<<endl); if (m_scopeNames.find(scpSym) == m_scopeNames.end()) { m_scopeNames.insert(make_pair(scpSym, ScopeNameData(scpSym, scpPretty))); } m_scopeVars.insert(make_pair(scpSym + " " + varp->name(), ScopeVarData(scpSym, varBasePretty, varp, modp, scopep))); } } } }
virtual void visit(AstNodeModule* nodep, AstNUser*) { // Create required blocks and add to module string scopename; if (!m_aboveScopep) scopename = "TOP"; else scopename = m_aboveScopep->name()+"."+m_aboveCellp->name(); UINFO(4," MOD AT "<<scopename<<" "<<nodep<<endl); AstNode::user1ClearTree(); m_scopep = new AstScope((m_aboveCellp?(AstNode*)m_aboveCellp:(AstNode*)nodep)->fileline(), nodep, scopename, m_aboveScopep, m_aboveCellp); // Now for each child cell, iterate the module this cell points to for (AstNode* cellnextp = nodep->stmtsp(); cellnextp; cellnextp=cellnextp->nextp()) { if (AstCell* cellp = cellnextp->castCell()) { AstScope* oldScopep = m_scopep; AstCell* oldAbCellp = m_aboveCellp; AstScope* oldAbScopep = m_aboveScopep; { m_aboveCellp = cellp; m_aboveScopep = m_scopep; AstNodeModule* modp = cellp->modp(); if (!modp) cellp->v3fatalSrc("Unlinked mod"); modp->accept(*this); // Recursive call to visit(AstNodeModule) } // Done, restore vars m_scopep = oldScopep; m_aboveCellp = oldAbCellp; m_aboveScopep = oldAbScopep; } } // Create scope for the current usage of this module UINFO(4," back AT "<<scopename<<" "<<nodep<<endl); AstNode::user1ClearTree(); m_modp = nodep; if (m_modp->isTop()) { AstTopScope* topscp = new AstTopScope(nodep->fileline(), m_scopep); m_modp->addStmtp(topscp); } else { m_modp->addStmtp(m_scopep); } // Copy blocks into this scope // If this is the first usage of the block ever, we can simply move the reference nodep->iterateChildren(*this); // ***Note m_scopep is passed back to the caller of the routine (above) }
string descopedName(AstScope* scopep, bool& hierThisr, AstVar* varp=NULL) { UASSERT(scopep, "Var/Func not scoped\n"); hierThisr = true; if (varp && varp->isFuncLocal()) { return ""; // Relative to function, not in this } else if (scopep == m_scopep && m_modp->isTop()) { //return ""; // Reference to scope we're in, no need to HIER-> it return "vlTOPp->"; } else if (scopep == m_scopep && !m_modp->isTop() && 0) { // We no longer thisp-> as still get ambiguation problems m_needThis = true; return "thisp->"; // this-> but with restricted aliasing } else if (scopep->aboveScopep() && scopep->aboveScopep()==m_scopep && 0 // DISABLED: GCC considers the pointers ambiguous, so goes ld/store crazy ) { // Reference to scope of cell directly under this module, can just "cell->" string name = scopep->name(); string::size_type pos; if ((pos = name.rfind(".")) != string::npos) { name.erase(0,pos+1); } hierThisr = false; return name+"->"; } else { // Reference to something else, use global variable UINFO(8," Descope "<<scopep<<endl); UINFO(8," to "<<scopep->name()<<endl); UINFO(8," under "<<m_scopep->name()<<endl); hierThisr = false; if (!scopep->aboveScopep()) { // Top return "vlTOPp->"; // == "vlSymsp->TOPp->", but GCC would suspect aliases } else { return scopep->nameVlSym()+"."; } } }
void EmitCSyms::emitSymImp() { UINFO(6,__FUNCTION__<<": "<<endl); string filename = v3Global.opt.makeDir()+"/"+symClassName()+".cpp"; AstCFile* cfilep = newCFile(filename, true/*slow*/, true/*source*/); cfilep->support(true); V3OutCFile cf (filename); m_ofp = &cf; ofp()->putsHeader(); puts("// DESCR" "IPTION: Verilator output: Symbol table implementation internals\n"); puts("\n"); // Includes puts("#include \""+symClassName()+".h\"\n"); for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep; nodep=nodep->nextp()->castNodeModule()) { puts("#include \""+modClassName(nodep)+".h\"\n"); } //puts("\n// GLOBALS\n"); puts("\n// FUNCTIONS\n"); puts(symClassName()+"::"+symClassName()+"("+topClassName()+"* topp, const char* namep)\n"); puts("\t// Setup locals\n"); puts("\t: __Vm_namep(namep)\n"); // No leak, as we get destroyed when the top is destroyed puts("\t, __Vm_activity(false)\n"); puts("\t, __Vm_didInit(false)\n"); puts("\t// Setup submodule names\n"); char comma=','; for (vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) { AstScope* scopep = it->first; AstNodeModule* modp = it->second; if (modp->isTop()) { } else { ofp()->printf("\t%c %-30s ", comma, scopep->nameDotless().c_str()); puts("(Verilated::catName(topp->name(),"); // The "." is added by catName putsQuoted(scopep->prettyName()); puts("))\n"); comma=','; } } puts("{\n"); puts("// Pointer to top level\n"); puts("TOPp = topp;\n"); puts("// Setup each module's pointers to their submodules\n"); for (vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) { AstScope* scopep = it->first; AstNodeModule* modp = it->second; if (!modp->isTop()) { string arrow = scopep->name(); string::size_type pos; while ((pos=arrow.find(".")) != string::npos) { arrow.replace(pos, 1, "->"); } if (arrow.substr(0,5) == "TOP->") arrow.replace(0,5,"TOPp->"); ofp()->printf("%-30s ", arrow.c_str()); puts(" = &"); puts(scopep->nameDotless()+";\n"); } } puts("// Setup each module's pointer back to symbol table (for public functions)\n"); puts("TOPp->__Vconfigure(this, true);\n"); for (vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) { AstScope* scopep = it->first; AstNodeModule* modp = it->second; if (!modp->isTop()) { // first is used by AstCoverDecl's call to __vlCoverInsert bool first = !modp->user1(); modp->user1(true); puts(scopep->nameDotless()+".__Vconfigure(this, " +(first?"true":"false") +");\n"); } } puts("// Setup scope names\n"); for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) { puts("__Vscope_"+it->second.m_symName+".configure(this,name(),"); putsQuoted(it->second.m_prettyName); puts(");\n"); } if (v3Global.dpi()) { puts("// Setup export functions\n"); puts("for (int __Vfinal=0; __Vfinal<2; __Vfinal++) {\n"); for (ScopeFuncs::iterator it = m_scopeFuncs.begin(); it != m_scopeFuncs.end(); ++it) { AstScopeName* scopep = it->second.m_scopep; AstCFunc* funcp = it->second.m_funcp; AstNodeModule* modp = it->second.m_modp; if (funcp->dpiExport()) { puts("__Vscope_"+scopep->scopeSymName()+".exportInsert(__Vfinal,"); putsQuoted(funcp->cname()); puts(", (void*)(&"); puts(modClassName(modp)); puts("::"); puts(funcp->name()); puts("));\n"); } } // It would be less code if each module inserted its own variables. // Someday. For now public isn't common. for (ScopeVars::iterator it = m_scopeVars.begin(); it != m_scopeVars.end(); ++it) { AstNodeModule* modp = it->second.m_modp; AstScope* scopep = it->second.m_scopep; AstVar* varp = it->second.m_varp; // int pdim=0; int udim=0; string bounds; if (AstBasicDType* basicp = varp->basicp()) { // Range is always first, it's not in "C" order if (basicp->isRanged()) { bounds += " ,"; bounds += cvtToStr(basicp->msb()); bounds += ","; bounds += cvtToStr(basicp->lsb()); pdim++; } for (AstNodeDType* dtypep=varp->dtypep(); dtypep; ) { dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node if (AstNodeArrayDType* adtypep = dtypep->castNodeArrayDType()) { bounds += " ,"; bounds += cvtToStr(adtypep->msb()); bounds += ","; bounds += cvtToStr(adtypep->lsb()); if (dtypep->castPackArrayDType()) pdim++; else udim++; dtypep = adtypep->subDTypep(); } else break; // AstBasicDType - nothing below, 1 } } // if (pdim>1 || udim>1) { puts("//UNSUP "); // VerilatedImp can't deal with >2d or packed arrays } puts("__Vscope_"+it->second.m_scopeName+".varInsert(__Vfinal,"); putsQuoted(it->second.m_varBasePretty); puts(", &("); if (modp->isTop()) { puts(scopep->nameDotless()); puts("p->"); } else { puts(scopep->nameDotless()); puts("."); } puts(varp->name()); puts("), "); puts(varp->vlEnumType()); // VLVT_UINT32 etc puts(","); puts(varp->vlEnumDir()); // VLVD_IN etc if (varp->isSigUserRWPublic()) puts("|VLVF_PUB_RW"); else if (varp->isSigUserRdPublic()) puts("|VLVF_PUB_RD"); puts(","); puts(cvtToStr(pdim+udim)); puts(bounds); puts(");\n"); } puts("}\n"); } puts("}\n"); if (v3Global.opt.savable() ) { puts("\n"); for (int de=0; de<2; ++de) { string classname = de ? "VerilatedDeserialize" : "VerilatedSerialize"; string funcname = de ? "__Vdeserialize" : "__Vserialize"; string op = de ? ">>" : "<<"; puts("void "+symClassName()+"::"+funcname+"("+classname+"& os) {\n"); puts( "// LOCAL STATE\n"); // __Vm_namep presumably already correct puts( "os"+op+"__Vm_activity;\n"); puts( "os"+op+"__Vm_didInit;\n"); puts( "// SUBCELL STATE\n"); for (vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) { AstScope* scopep = it->first; AstNodeModule* modp = it->second; if (!modp->isTop()) { puts( scopep->nameDotless()+"."+funcname+"(os);\n"); } } puts("}\n"); } } }