Example #1
0
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");
	}
    }
}
Example #2
0
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");
}
Example #3
0
    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)));
	}
    }
Example #4
0
    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);
    }
Example #5
0
    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;
    }
Example #6
0
    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);
	    }
	}
    }
Example #7
0
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");
	}
    }
}