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(AstCFunc* nodep, AstNUser*) { if (!nodep->user1()) { m_needThis = false; nodep->iterateChildren(*this); nodep->user1(true); if (m_needThis) { nodep->v3fatalSrc("old code"); // Really we should have more node types for backend optimization of this stuff string text = v3Global.opt.modPrefix() + "_" + m_modp->name() +"* thisp = &("+m_scopep->nameVlSym()+");\n"; nodep->addInitsp(new AstCStmt(nodep->fileline(), text)); } // If it's under a scope, move it up to the top if (m_scopep) { nodep->unlinkFrBack(); m_modp->addStmtp(nodep); if (nodep->funcPublic()) { // There may be multiple public functions by the same name; // record for later correction or making of shells m_modFuncs.insert(make_pair(nodep->name(), nodep)); nodep->name(m_scopep->nameDotless() +"__" + nodep->name()); } } } }
AstCFunc* newCFunc(AstCFuncType type, const string& name, bool slow) { AstCFunc* funcp = new AstCFunc(m_scopetopp->fileline(), name, m_scopetopp); funcp->slow(slow); funcp->argTypes(EmitCBaseVisitor::symClassVar()+", "+v3Global.opt.traceClassBase()+"* vcdp, uint32_t code"); funcp->funcType(type); funcp->symProlog(true); m_scopetopp->addActivep(funcp); UINFO(5," Newfunc "<<funcp<<endl); return funcp; }
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))); } } } }
AstVarScope* getCreateLastClk(AstVarScope* vscp) { if (vscp->user1p()) return ((AstVarScope*)vscp->user1p()); AstVar* varp = vscp->varp(); if (!varp->width1()) varp->v3error("Unsupported: Clock edge on non-single bit signal: "<<varp->prettyName()); string newvarname = ((string)"__Vclklast__"+vscp->scopep()->nameDotless()+"__"+varp->name()); AstVar* newvarp = new AstVar(vscp->fileline(), AstVarType::MODULETEMP, newvarname, VFlagLogicPacked(), 1); newvarp->noReset(true); // Reset by below assign m_modp->addStmtp(newvarp); AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopep, newvarp); vscp->user1p(newvscp); m_scopep->addVarp(newvscp); // Add init AstNode* fromp = new AstVarRef(newvarp->fileline(), vscp, false); if (v3Global.opt.xInitialEdge()) fromp = new AstNot(fromp->fileline(), fromp); AstNode* newinitp = new AstAssign(vscp->fileline(), new AstVarRef(newvarp->fileline(), newvscp, true), fromp); addToInitial(newinitp); // At bottom, assign them AstAssign* finalp = new AstAssign(vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, true), new AstVarRef(vscp->fileline(), vscp, false)); m_evalFuncp->addFinalsp(finalp); // UINFO(4,"New Last: "<<newvscp<<endl); return newvscp; }
virtual void visit(AstCoverToggle* nodep, AstNUser*) { // Add to list of blocks under this scope UINFO(4," Move "<<nodep<<endl); AstNode* clonep = nodep->cloneTree(false); nodep->user2p(clonep); m_scopep->addActivep(clonep); clonep->iterateChildren(*this); // We iterate under the *clone* }
virtual void visit(AstAssignVarScope* nodep, AstNUser*) { // Copy under the scope but don't recurse UINFO(4," Move "<<nodep<<endl); AstNode* clonep = nodep->cloneTree(false); nodep->user2p(clonep); m_scopep->addActivep(clonep); clonep->iterateChildren(*this); // We iterate under the *clone* }
virtual void visit(AstVar* nodep, AstNUser*) { // Make new scope variable if (!nodep->user1p()) { AstVarScope* varscp = new AstVarScope(nodep->fileline(), m_scopep, nodep); UINFO(6," New scope "<<varscp<<endl); nodep->user1p(varscp); m_scopep->addVarp(varscp); } }
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); }
AstVarScope* getCreateLocalVar(FileLine* fl, const string& name, AstVar* examplep, int width) { AstVar* newvarp; if (width) { newvarp = new AstVar (fl, AstVarType::BLOCKTEMP, name, VFlagLogicPacked(), width); } else { newvarp = new AstVar (fl, AstVarType::BLOCKTEMP, name, examplep); // No range; 1 bit. } m_modp->addStmtp(newvarp); AstVarScope* newvscp = new AstVarScope(fl, m_scopep, newvarp); m_scopep->addVarp(newvscp); return newvscp; }
// METHODS AstVarScope* genInpClk(AstVarScope* vscp) { if (vscp->user2p()) { return VN_CAST(vscp->user2p(), VarScope); } else { AstVar* varp = vscp->varp(); string newvarname = "__VinpClk__"+vscp->scopep()->nameDotless()+"__"+varp->name(); // Create: VARREF(inpclk) // ... // ASSIGN(VARREF(inpclk), VARREF(var)) AstVar* newvarp = new AstVar(varp->fileline(), AstVarType::MODULETEMP, newvarname, varp); m_topModp->addStmtp(newvarp); AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopetopp, newvarp); m_scopetopp->addVarp(newvscp); AstAssign* asninitp = new AstAssign(vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, true), new AstVarRef(vscp->fileline(), vscp, false)); m_scopetopp->addFinalClkp(asninitp); // vscp->user2p(newvscp); return newvscp; } }
void genChangeDet(AstVarScope* vscp) { #ifdef NEW_ORDERING vscp->v3fatalSrc("Not applicable\n"); #endif AstVar* varp = vscp->varp(); vscp->v3warn(IMPERFECTSCH,"Imperfect scheduling of variable: "<<vscp); AstUnpackArrayDType* arrayp = varp->dtypeSkipRefp()->castUnpackArrayDType(); AstStructDType *structp = varp->dtypeSkipRefp()->castStructDType(); bool isArray = arrayp; bool isStruct = structp && structp->packedUnsup(); int elements = isArray ? arrayp->elementsConst() : 1; if (isArray && (elements > DETECTARRAY_MAX_INDEXES)) { vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect more than "<<cvtToStr(DETECTARRAY_MAX_INDEXES) <<" array indexes (probably with UNOPTFLAT warning suppressed): "<<varp->prettyName()<<endl <<vscp->warnMore() <<"... Could recompile with DETECTARRAY_MAX_INDEXES increased to at least "<<cvtToStr(elements)); } else if (!isArray && !isStruct && !varp->dtypeSkipRefp()->castBasicDType()) { if (debug()) varp->dumpTree(cout,"-DETECTARRAY-"); vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable (probably with UNOPTFLAT warning suppressed): "<<varp->prettyName()); } else { string newvarname = "__Vchglast__"+vscp->scopep()->nameDotless()+"__"+varp->shortName(); // Create: VARREF(_last) // ASSIGN(VARREF(_last), VARREF(var)) // ... // CHANGEDET(VARREF(_last), VARREF(var)) AstVar* newvarp = new AstVar (varp->fileline(), AstVarType::MODULETEMP, newvarname, varp); m_topModp->addStmtp(newvarp); AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopetopp, newvarp); m_scopetopp->addVarp(newvscp); for (int index=0; index<elements; ++index) { AstChangeDet* changep = new AstChangeDet (vscp->fileline(), aselIfNeeded(isArray, index, new AstVarRef(vscp->fileline(), vscp, false)), aselIfNeeded(isArray, index, new AstVarRef(vscp->fileline(), newvscp, false)), false); m_chgFuncp->addStmtsp(changep); AstAssign* initp = new AstAssign (vscp->fileline(), aselIfNeeded(isArray, index, new AstVarRef(vscp->fileline(), newvscp, true)), aselIfNeeded(isArray, index, new AstVarRef(vscp->fileline(), vscp, false))); m_chgFuncp->addFinalsp(initp); } } }
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) }
virtual void visit(AstTopScope* nodep, AstNUser*) { UINFO(4," TS "<<nodep<<endl); // Clearing AstNode::user1ClearTree(); // Create the change detection function AstScope* scopep = nodep->scopep(); if (!scopep) nodep->v3fatalSrc("No scope found on top level, perhaps you have no statements?\n"); m_scopetopp = scopep; // Create change detection function m_chgFuncp = new AstCFunc(nodep->fileline(), "_change_request", scopep, "IData"); m_chgFuncp->argTypes(EmitCBaseVisitor::symClassVar()); m_chgFuncp->symProlog(true); m_chgFuncp->declPrivate(true); m_scopetopp->addActivep(m_chgFuncp); // We need at least one change detect so we know to emit the correct code m_chgFuncp->addStmtsp(new AstChangeDet(nodep->fileline(), NULL, NULL, false)); // nodep->iterateChildren(*this); }
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()+"."; } } }
// VISITORS virtual void visit(AstTopScope* nodep) { UINFO(4," TOPSCOPE "<<nodep<<endl); m_topScopep=nodep; m_scopep = nodep->scopep(); if (!m_scopep) nodep->v3fatalSrc("No scope found on top level, perhaps you have no statements?"); //VV***** We reset all user1p() AstNode::user1ClearTree(); // Make top functions { AstCFunc* funcp = new AstCFunc(nodep->fileline(), "_eval", m_scopep); funcp->argTypes(EmitCBaseVisitor::symClassVar()); funcp->dontCombine(true); funcp->symProlog(true); funcp->isStatic(true); funcp->entryPoint(true); m_scopep->addActivep(funcp); m_evalFuncp = funcp; } { AstCFunc* funcp = new AstCFunc(nodep->fileline(), "_eval_initial", m_scopep); funcp->argTypes(EmitCBaseVisitor::symClassVar()); funcp->dontCombine(true); funcp->slow(true); funcp->symProlog(true); funcp->isStatic(true); funcp->entryPoint(true); m_scopep->addActivep(funcp); m_initFuncp = funcp; } { AstCFunc* funcp = new AstCFunc(nodep->fileline(), "final", m_scopep); funcp->skipDecl(true); funcp->dontCombine(true); funcp->slow(true); funcp->isStatic(false); funcp->entryPoint(true); funcp->addInitsp(new AstCStmt(nodep->fileline(), EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n")); funcp->addInitsp(new AstCStmt(nodep->fileline(), EmitCBaseVisitor::symTopAssign()+"\n")); m_scopep->addActivep(funcp); m_finalFuncp = funcp; } { AstCFunc* funcp = new AstCFunc(nodep->fileline(), "_eval_settle", m_scopep); funcp->argTypes(EmitCBaseVisitor::symClassVar()); funcp->dontCombine(true); funcp->slow(true); funcp->isStatic(true); funcp->symProlog(true); funcp->entryPoint(true); m_scopep->addActivep(funcp); m_settleFuncp = funcp; } // Process the activates iterateChildren(nodep); // Done, clear so we can detect errors UINFO(4," TOPSCOPEDONE "<<nodep<<endl); clearLastSen(); m_topScopep=NULL; m_scopep = NULL; }
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"); } } }
void EmitCSyms::emitSymHdr() { UINFO(6,__FUNCTION__<<": "<<endl); string filename = v3Global.opt.makeDir()+"/"+symClassName()+".h"; newCFile(filename, true/*slow*/, false/*source*/); V3OutCFile hf (filename); m_ofp = &hf; ofp()->putsHeader(); puts("// DESCR" "IPTION: Verilator output: Symbol table internal header\n"); puts("//\n"); puts("// Internal details; most calling programs do not need this header\n"); puts("\n"); puts("#ifndef _"+symClassName()+"_H_\n"); puts("#define _"+symClassName()+"_H_\n"); puts("\n"); if (optSystemPerl()) puts("#include \"systemperl.h\"\n"); else if (optSystemC()) puts("#include \"systemc.h\"\n"); if (optSystemPerl() || optSystemC()) { puts("#include \"verilated_sc.h\"\n"); } if (v3Global.needHeavy()) { puts("#include \"verilated_heavy.h\"\n"); } else { puts("#include \"verilated.h\"\n"); } // for puts("\n// INCLUDE MODULE CLASSES\n"); for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep; nodep=nodep->nextp()->castNodeModule()) { puts("#include \""+modClassName(nodep)+".h\"\n"); } if (v3Global.dpi()) { puts ("\n// DPI TYPES for DPI Export callbacks (Internal use)\n"); map<string,int> types; // Remove duplicates and sort for (ScopeFuncs::iterator it = m_scopeFuncs.begin(); it != m_scopeFuncs.end(); ++it) { AstCFunc* funcp = it->second.m_funcp; if (funcp->dpiExport()) { string cbtype = v3Global.opt.prefix()+"__Vcb_"+funcp->cname()+"_t"; types["typedef void (*"+cbtype+") ("+cFuncArgs(funcp)+");\n"] = 1; } } for (map<string,int>::iterator it = types.begin(); it != types.end(); ++it) { puts(it->first); } } puts("\n// SYMS CLASS\n"); puts((string)"class "+symClassName()+" : public VerilatedSyms {\n"); ofp()->putsPrivate(false); // public: puts("\n// LOCAL STATE\n"); ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(vluint64_t)); puts("const char* __Vm_namep;\n"); // Must be before subcells, as constructor order needed before _vlCoverInsert. ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(bool)); puts("bool\t__Vm_activity;\t\t///< Used by trace routines to determine change occurred\n"); ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(bool)); puts("bool\t__Vm_didInit;\n"); ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(vluint64_t)); puts("\n// 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()) { ofp()->printf("%-30s ", (modClassName(modp)+"*").c_str()); puts(scopep->nameDotless()+"p;\n"); } else { ofp()->printf("%-30s ", (modClassName(modp)+"").c_str()); puts(scopep->nameDotless()+";\n"); } } puts("\n// COVERAGE\n"); if (m_coverBins) { ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(uint32_t)); puts("uint32_t\t__Vcoverage["); puts(cvtToStr(m_coverBins)); puts("];\n"); } puts("\n// SCOPE NAMES\n"); for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) { puts("VerilatedScope __Vscope_"+it->second.m_symName+";\n"); } puts("\n// CREATORS\n"); puts(symClassName()+"("+topClassName()+"* topp, const char* namep);\n"); puts((string)"~"+symClassName()+"() {};\n"); puts("\n// METHODS\n"); puts("inline const char* name() { return __Vm_namep; }\n"); puts("inline bool getClearActivity() { bool r=__Vm_activity; __Vm_activity=false; return r;}\n"); if (v3Global.opt.savable() ) { puts("void __Vserialize(VerilatedSerialize& os);\n"); puts("void __Vdeserialize(VerilatedDeserialize& os);\n"); } puts("\n"); puts("} VL_ATTR_ALIGNED(64);\n"); puts("\n"); puts("#endif /*guard*/\n"); }
// METHODS void addActive(AstActive* nodep) { if (!m_scopep) nodep->v3fatalSrc("NULL scope"); m_scopep->addActivep(nodep); }