diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index 9618840c6..04d1ff0f8 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -180,6 +180,7 @@ RAW_OBJS = \ V3Descope.o \ V3DupFinder.o \ V3EmitC.o \ + V3EmitCBase.o \ V3EmitCConstPool.o \ V3EmitCInlines.o \ V3EmitCSyms.o \ diff --git a/src/V3EmitCBase.cpp b/src/V3EmitCBase.cpp new file mode 100644 index 000000000..8552b69b9 --- /dev/null +++ b/src/V3EmitCBase.cpp @@ -0,0 +1,108 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Emit C++ for tree +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2021 by Wilson Snyder. This program is free software; you +// can redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* + +#include "config_build.h" +#include "verilatedos.h" + +#include "V3EmitCBase.h" + +//###################################################################### +// EmitCBaseVisitor implementation + +string EmitCBaseVisitor::funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp) { + modp = modp ? modp : VN_CAST(nodep->user4p(), NodeModule); + string name; + if (nodep->isConstructor()) { + name += prefixNameProtect(modp); + } else if (nodep->isDestructor()) { + name += "~"; + name += prefixNameProtect(modp); + } else { + if (nodep->isLoose()) { + name += prefixNameProtect(modp); + name += "__"; + } + name += nodep->nameProtect(); + } + return name; +} + +AstCFile* EmitCBaseVisitor::newCFile(const string& filename, bool slow, bool source) { + AstCFile* cfilep = new AstCFile(v3Global.rootp()->fileline(), filename); + cfilep->slow(slow); + cfilep->source(source); + v3Global.rootp()->addFilesp(cfilep); + return cfilep; +} + +string EmitCBaseVisitor::cFuncArgs(const AstCFunc* nodep) { + // Return argument list for given C function + string args; + if (nodep->isLoose() && !nodep->isStatic()) { + if (nodep->isConst().trueKnown()) args += "const "; + AstNodeModule* modp = VN_CAST(nodep->user4p(), NodeModule); + args += prefixNameProtect(modp); + args += "* vlSelf"; + } + if (!nodep->argTypes().empty()) { + if (!args.empty()) args += ", "; + args += nodep->argTypes(); + } + // Might be a user function with argument list. + for (const AstNode* stmtp = nodep->argsp(); stmtp; stmtp = stmtp->nextp()) { + if (const AstVar* portp = VN_CAST_CONST(stmtp, Var)) { + if (portp->isIO() && !portp->isFuncReturn()) { + if (args != "") args += ", "; + if (nodep->dpiImportPrototype() || nodep->dpiExportDispatcher()) { + args += portp->dpiArgType(true, false); + } else if (nodep->funcPublic()) { + args += portp->cPubArgType(true, false); + } else { + args += portp->vlArgType(true, false, true); + } + } + } + } + return args; +} + +void EmitCBaseVisitor::emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp, + bool withScope) { + if (!funcp->isConstructor() && !funcp->isDestructor()) { + puts(funcp->rtnTypeVoid()); + puts(" "); + } + if (withScope && funcp->isProperMethod()) puts(prefixNameProtect(modp) + "::"); + puts(funcNameProtect(funcp, modp)); + puts("(" + cFuncArgs(funcp) + ")"); + if (funcp->isConst().trueKnown() && funcp->isProperMethod()) puts(" const"); +} + +void EmitCBaseVisitor::emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp, + bool cLinkage) { + ensureNewLine(); + if (!funcp->ifdef().empty()) puts("#ifdef " + funcp->ifdef() + "\n"); + if (cLinkage) puts("extern \"C\" "); + if (funcp->isStatic() && funcp->isProperMethod()) puts("static "); + if (funcp->isVirtual()) { + UASSERT_OBJ(funcp->isProperMethod(), funcp, "Virtual function is not a proper method"); + puts("virtual "); + } + emitCFuncHeader(funcp, modp, /* withScope: */ false); + if (funcp->slow()) puts(" VL_ATTR_COLD"); + puts(";\n"); + if (!funcp->ifdef().empty()) puts("#endif // " + funcp->ifdef() + "\n"); +} diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h index e3d32d827..144c0f921 100644 --- a/src/V3EmitCBase.h +++ b/src/V3EmitCBase.h @@ -62,23 +62,7 @@ public: static string symClassAssign() { return symClassName() + "* const __restrict vlSymsp VL_ATTR_UNUSED = vlSelf->vlSymsp;\n"; } - static string funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp = nullptr) { - modp = modp ? modp : VN_CAST(nodep->user4p(), NodeModule); - string name; - if (nodep->isConstructor()) { - name += prefixNameProtect(modp); - } else if (nodep->isDestructor()) { - name += "~"; - name += prefixNameProtect(modp); - } else { - if (nodep->isLoose()) { - name += prefixNameProtect(modp); - name += "__"; - } - name += nodep->nameProtect(); - } - return name; - } + static string funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp = nullptr); static string prefixNameProtect(const AstNode* nodep) { // C++ name with prefix const AstNodeModule* modp = VN_CAST_CONST(nodep, NodeModule); if (modp && modp->isTop()) { @@ -95,69 +79,10 @@ public: return modp == v3Global.rootp()->constPoolp()->modp(); } - static AstCFile* newCFile(const string& filename, bool slow, bool source) { - AstCFile* cfilep = new AstCFile(v3Global.rootp()->fileline(), filename); - cfilep->slow(slow); - cfilep->source(source); - v3Global.rootp()->addFilesp(cfilep); - return cfilep; - } - string cFuncArgs(const AstCFunc* nodep) { - // Return argument list for given C function - string args; - if (nodep->isLoose() && !nodep->isStatic()) { - if (nodep->isConst().trueKnown()) args += "const "; - AstNodeModule* modp = VN_CAST(nodep->user4p(), NodeModule); - args += prefixNameProtect(modp); - args += "* vlSelf"; - } - if (!nodep->argTypes().empty()) { - if (!args.empty()) args += ", "; - args += nodep->argTypes(); - } - // Might be a user function with argument list. - for (const AstNode* stmtp = nodep->argsp(); stmtp; stmtp = stmtp->nextp()) { - if (const AstVar* portp = VN_CAST_CONST(stmtp, Var)) { - if (portp->isIO() && !portp->isFuncReturn()) { - if (args != "") args += ", "; - if (nodep->dpiImportPrototype() || nodep->dpiExportDispatcher()) { - args += portp->dpiArgType(true, false); - } else if (nodep->funcPublic()) { - args += portp->cPubArgType(true, false); - } else { - args += portp->vlArgType(true, false, true); - } - } - } - } - return args; - } - - void emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp, bool withScope) { - if (!funcp->isConstructor() && !funcp->isDestructor()) { - puts(funcp->rtnTypeVoid()); - puts(" "); - } - if (withScope && funcp->isProperMethod()) puts(prefixNameProtect(modp) + "::"); - puts(funcNameProtect(funcp, modp)); - puts("(" + cFuncArgs(funcp) + ")"); - if (funcp->isConst().trueKnown() && funcp->isProperMethod()) puts(" const"); - } - - void emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp, bool cLinkage = false) { - ensureNewLine(); - if (!funcp->ifdef().empty()) puts("#ifdef " + funcp->ifdef() + "\n"); - if (cLinkage) puts("extern \"C\" "); - if (funcp->isStatic() && funcp->isProperMethod()) puts("static "); - if (funcp->isVirtual()) { - UASSERT_OBJ(funcp->isProperMethod(), funcp, "Virtual function is not a proper method"); - puts("virtual "); - } - emitCFuncHeader(funcp, modp, /* withScope: */ false); - if (funcp->slow()) puts(" VL_ATTR_COLD"); - puts(";\n"); - if (!funcp->ifdef().empty()) puts("#endif // " + funcp->ifdef() + "\n"); - } + static AstCFile* newCFile(const string& filename, bool slow, bool source); + string cFuncArgs(const AstCFunc* nodep); + void emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp, bool withScope); + void emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp, bool cLinkage = false); // CONSTRUCTORS EmitCBaseVisitor() = default;