void EmitCSyms::emitDpiImp() { UINFO(6,__FUNCTION__<<": "<<endl); string filename = v3Global.opt.makeDir()+"/"+topClassName()+"__Dpi.cpp"; AstCFile* cfilep = newCFile(filename, false/*slow*/, true/*source*/); cfilep->support(true); V3OutCFile hf (filename); m_ofp = &hf; m_ofp->putsHeader(); puts("// DESCR" "IPTION: Verilator output: Implementation of DPI export functions.\n"); puts("//\n"); puts("// Verilator compiles this file in when DPI functions are used.\n"); puts("// If you have multiple Verilated designs with the same DPI exported\n"); puts("// function names, you will get multiple definition link errors from here.\n"); puts("// This is an unfortunate result of the DPI specification.\n"); puts("// To solve this, either\n"); puts("// 1. Call "+topClassName()+"::{export_function} instead,\n"); puts("// and do not even bother to compile this file\n"); puts("// or 2. Compile all __Dpi.cpp files in the same compiler run,\n"); puts("// and #ifdefs already inserted here will sort everything out.\n"); puts("\n"); puts("#include \""+topClassName()+"__Dpi.h\"\n"); puts("#include \""+topClassName()+".h\"\n"); puts("\n"); for (vector<AstCFunc*>::iterator it = m_dpis.begin(); it != m_dpis.end(); ++it) { AstCFunc* nodep = *it; if (nodep->dpiExportWrapper()) { puts("#ifndef _VL_DPIDECL_"+nodep->name()+"\n"); puts("#define _VL_DPIDECL_"+nodep->name()+"\n"); puts(nodep->rtnTypeVoid()+" "+nodep->name()+" ("+cFuncArgs(nodep)+") {\n"); puts("// DPI Export at "+nodep->fileline()->ascii()+"\n"); puts("return "+topClassName()+"::"+nodep->name()+"("); string args; for (AstNode* stmtp = nodep->argsp(); stmtp; stmtp=stmtp->nextp()) { if (AstVar* portp = stmtp->castVar()) { if (portp->isIO() && !portp->isFuncReturn()) { if (args != "") args+= ", "; args += portp->name(); } } } puts(args+");\n"); puts("}\n"); puts("#endif\n"); puts("\n"); } } }
void EmitCSyms::emitDpiHdr() { UINFO(6,__FUNCTION__<<": "<<endl); string filename = v3Global.opt.makeDir()+"/"+topClassName()+"__Dpi.h"; AstCFile* cfilep = newCFile(filename, false/*slow*/, false/*source*/); cfilep->support(true); V3OutCFile hf (filename); m_ofp = &hf; m_ofp->putsHeader(); puts("// DESCR" "IPTION: Verilator output: Prototypes for DPI import and export functions.\n"); puts("//\n"); puts("// Verilator includes this file in all generated .cpp files that use DPI functions.\n"); puts("// Manually include this file where DPI .c import functions are declared to insure\n"); puts("// the C functions match the expectations of the DPI imports.\n"); puts("\n"); puts("#include \"svdpi.h\"\n"); puts("\n"); puts("#ifdef __cplusplus\n"); puts("extern \"C\" {\n"); puts("#endif\n"); puts("\n"); int firstExp = 0; int firstImp = 0; for (vector<AstCFunc*>::iterator it = m_dpis.begin(); it != m_dpis.end(); ++it) { AstCFunc* nodep = *it; if (nodep->dpiExportWrapper()) { if (!firstExp++) puts("\n// DPI EXPORTS\n"); puts("// DPI Export at "+nodep->fileline()->ascii()+"\n"); puts("extern "+nodep->rtnTypeVoid()+" "+nodep->name()+" ("+cFuncArgs(nodep)+");\n"); } else if (nodep->dpiImport()) { if (!firstImp++) puts("\n// DPI IMPORTS\n"); puts("// DPI Import at "+nodep->fileline()->ascii()+"\n"); puts("extern "+nodep->rtnTypeVoid()+" "+nodep->name()+" ("+cFuncArgs(nodep)+");\n"); } } puts("\n"); puts("#ifdef __cplusplus\n"); puts("}\n"); puts("#endif\n"); }
virtual void visit(AstScopeName* nodep, AstNUser*) { string name = nodep->scopeSymName(); //UINFO(9,"scnameins sp "<<nodep->name()<<" sp "<<nodep->scopePrettyName()<<" ss "<<name<<endl); if (m_scopeNames.find(name) == m_scopeNames.end()) { m_scopeNames.insert(make_pair(name, ScopeNameData(name, nodep->scopePrettyName()))); } if (nodep->dpiExport()) { if (!m_funcp) nodep->v3fatalSrc("ScopeName not under DPI function"); m_scopeFuncs.insert(make_pair(name + " " + m_funcp->name(), ScopeFuncData(nodep, m_funcp, m_modp))); } }
void walkReplace(AstNode* node1p, AstNode* node2p, AstNode* last1p, AstNode* last2p) { // Final node in linked list, maybe null if all statements to be grabbed // Make new function string oldname = m_funcp->name(); string::size_type pos; if ((pos=oldname.find("_common")) != string::npos) { oldname.erase(pos); } if ((pos=oldname.find("__")) != string::npos) { oldname.erase(pos); } AstCFunc* newfuncp = new AstCFunc(node1p->fileline(), oldname+"_common"+cvtToStr(++m_modNFuncs), NULL); m_modp->addStmtp(newfuncp); // Create calls AstCCall* call1p = new AstCCall(node1p->fileline(), newfuncp); AstCCall* call2p = new AstCCall(node2p->fileline(), newfuncp); // Grab statement bodies AstNRelinker relink1Handle; AstNRelinker relink2Handle; for (AstNode* nextp, *walkp = node1p; 1; walkp = nextp) { nextp = walkp->nextp(); if (walkp==node1p) walkp->unlinkFrBack(&relink1Handle); else { walkp->unlinkFrBack(); node1p->addNext(walkp); } if (walkp==last1p) break; } for (AstNode* nextp, *walkp = node2p; 1; walkp = nextp) { nextp = walkp->nextp(); if (walkp==node2p) walkp->unlinkFrBack(&relink2Handle); else { walkp->unlinkFrBack(); node2p->addNext(walkp); } if (walkp==last2p) break; } // Move node1 statements to new function newfuncp->addStmtsp(node1p); //newfuncp->dumpTree(cout," newfunctree: "); // Mark node2 statements as dead CombMarkVisitor visitor(node2p); pushDeletep(node2p); // Delete later // Link in new function relink1Handle.relink(call1p); relink2Handle.relink(call2p); // Hash the new function hashFunctions(newfuncp); m_call.addCall(call1p); m_call.addCall(call2p); // If either new statement makes a func with only a single call, replace // the above callers to call it directly replaceOnlyCallFunc(call1p); VL_DANGLING(call1p); replaceOnlyCallFunc(call2p); VL_DANGLING(call2p); }
AstCFunc* createDeepFunc(AstNode* nodep) { AstNRelinker relinkHandle; nodep->unlinkFrBack(&relinkHandle); // Create function string name = m_funcp->name()+"__deep"+cvtToStr(++m_deepNum); AstCFunc* funcp = new AstCFunc(nodep->fileline(), name, NULL); funcp->argTypes(EmitCBaseVisitor::symClassVar()); funcp->symProlog(true); funcp->slow(m_funcp->slow()); funcp->addStmtsp(nodep); m_modp->addStmtp(funcp); // Call it at the point where the body was removed from AstCCall* callp = new AstCCall(nodep->fileline(), funcp); callp->argTypes("vlSymsp"); UINFO(6," New "<<callp<<endl); // relinkHandle.relink(callp); return funcp; }
void makePublicFuncWrappers() { // We recorded all public functions in m_modFuncs. // If for any given name only one function exists, we can use that function directly. // If multiple functions exist, we need to select the appropriate scope. for (FuncMmap::iterator it = m_modFuncs.begin(); it!=m_modFuncs.end(); ++it) { string name = it->first; AstCFunc* topFuncp = it->second; FuncMmap::iterator nextIt1 = it; ++nextIt1; bool moreOfSame1 = (nextIt1!=m_modFuncs.end() && nextIt1->first == name); if (moreOfSame1) { // Multiple functions under this name, need a wrapper function UINFO(6," Wrapping "<<name<<" multifuncs\n"); AstCFunc* newfuncp = topFuncp->cloneTree(false); if (newfuncp->initsp()) newfuncp->initsp()->unlinkFrBackWithNext()->deleteTree(); if (newfuncp->stmtsp()) newfuncp->stmtsp()->unlinkFrBackWithNext()->deleteTree(); if (newfuncp->finalsp()) newfuncp->finalsp()->unlinkFrBackWithNext()->deleteTree(); newfuncp->name(name); newfuncp->isStatic(false); newfuncp->addInitsp( new AstCStmt(newfuncp->fileline(), EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n")); newfuncp->addInitsp(new AstCStmt(newfuncp->fileline(), EmitCBaseVisitor::symTopAssign()+"\n")); topFuncp->addNextHere(newfuncp); // In the body, call each function if it matches the given scope for (FuncMmap::iterator eachIt = it; eachIt!=m_modFuncs.end() && eachIt->first==name; ++eachIt) { it = eachIt; AstCFunc* funcp = eachIt->second; FuncMmap::iterator nextIt2 = eachIt; ++nextIt2; bool moreOfSame = (nextIt2!=m_modFuncs.end() && nextIt2->first == name); if (!funcp->scopep()) funcp->v3fatalSrc("Not scoped"); UINFO(6," Wrapping "<<name<<" "<<funcp<<endl); UINFO(6," at "<<newfuncp->argTypes()<<" und "<<funcp->argTypes()<<endl); funcp->declPrivate(true); AstNode* argsp = NULL; for (AstNode* stmtp = newfuncp->argsp(); stmtp; stmtp=stmtp->nextp()) { if (AstVar* portp = stmtp->castVar()) { if (portp->isIO() && !portp->isFuncReturn()) { argsp = argsp->addNextNull(new AstVarRef(portp->fileline(), portp, portp->isOutput())); } } } AstNode* returnp = new AstCReturn (funcp->fileline(), new AstCCall (funcp->fileline(), funcp, argsp)); if (moreOfSame) { AstIf* ifp = new AstIf (funcp->fileline(), new AstEq(funcp->fileline(), new AstCMath(funcp->fileline(), "this", 64), new AstCMath(funcp->fileline(), string("&(") +funcp->scopep()->nameVlSym() +")", 64)), returnp, NULL); newfuncp->addStmtsp(ifp); } else { newfuncp->addStmtsp(returnp); } } // Not really any way the user could do this, and we'd need to come up with some return value //newfuncp->addStmtsp(new AstDisplay (newfuncp->fileline(), AstDisplayType::DT_DISPLAY, // string("%%Error: ")+name+"() called with bad scope", NULL)); //newfuncp->addStmtsp(new AstStop (newfuncp->fileline())); if (debug()>=9) newfuncp->dumpTree(cout," newfunc: "); } else { // Only a single function under this name, we can simply rename it UINFO(6," Wrapping "<<name<<" just one "<<topFuncp<<endl); topFuncp->name(name); } } }
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"); } } }