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