diff --git a/src/V3EmitCBase.cpp b/src/V3EmitCBase.cpp index 681193265..afce95b18 100644 --- a/src/V3EmitCBase.cpp +++ b/src/V3EmitCBase.cpp @@ -92,21 +92,6 @@ string EmitCBaseVisitorConst::funcNameProtect(const AstCFunc* nodep, const AstNo return name; } -AstCFile* EmitCBaseVisitorConst::newCFile(const string& filename, bool slow, bool source) { - AstCFile* const cfilep = createCFile(filename, slow, source); - v3Global.rootp()->addFilesp(cfilep); - return cfilep; -} - -AstCFile* EmitCBaseVisitorConst::createCFile(const string& filename, bool slow, - bool source) VL_MT_SAFE { - AstCFile* const cfilep = new AstCFile{v3Global.rootp()->fileline(), filename}; - cfilep->slow(slow); - cfilep->source(source); - if (source) V3Stats::addStatSum(V3Stats::STAT_CPP_FILES, 1); - return cfilep; -} - string EmitCBaseVisitorConst::cFuncArgs(const AstCFunc* nodep) { // Return argument list for given C function string args; diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h index dc5886ce8..129d7f271 100644 --- a/src/V3EmitCBase.h +++ b/src/V3EmitCBase.h @@ -85,40 +85,89 @@ public: // Base Visitor class -- holds output file pointer class EmitCBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst { -public: // STATE - V3OutCFile* m_ofp = nullptr; - AstCFile* m_outFileNodep = nullptr; - int m_splitSize = 0; // # of cfunc nodes placed into output file + V3OutCFile* m_ofp = nullptr; // File handle to emit to + AstCFile* m_cfilep = nullptr; // Current AstCFile being emitted + std::vector m_newCfileps; // AstCFiles created + size_t m_splitSize = 0; // Complexity of this file + const size_t m_splitLimit = v3Global.opt.outputSplit() + ? static_cast(v3Global.opt.outputSplit()) + : std::numeric_limits::max(); + // METHODS + // Create new AstCFile and open it for writing + void openNewOutputFile(const std::string& baseName, bool slow, bool support, bool source, + const char* const descriptionp) { + std::string fileName = v3Global.opt.makeDir() + "/" + baseName; + if (source) { + if (slow) fileName += "__Slow"; + fileName += ".cpp"; + } else { + fileName += ".h"; + } + AstCFile* const cfilep = new AstCFile{v3Global.rootp()->fileline(), fileName}; + cfilep->slow(slow); + cfilep->source(source); + cfilep->support(support); + m_newCfileps.emplace_back(cfilep); + openOutputFile(cfilep, descriptionp); + } + +public: + // Create new source AstCFile and open it for writing + void openNewOutputSourceFile(const std::string& baseName, bool slow, bool support, + const char* descriptionp) { + V3Stats::addStatSum(V3Stats::STAT_CPP_FILES, 1); + openNewOutputFile(baseName, slow, support, true, descriptionp); + } + + // Create new header AstCFile and open it for writing + void openNewOutputHeaderFile(const std::string& baseName, const char* descriptionp) { + openNewOutputFile(baseName, false, false, false, descriptionp); + } + + // Open exisitng AstCFile for writing + void openOutputFile(AstCFile* cfilep, const char* descriptionp) { + UASSERT(!m_ofp, "Output file is already open"); + m_cfilep = cfilep; + m_splitSize = 0; + if (v3Global.opt.lintOnly()) { + // Unfortunately we have some lint checks in EmitCImp, so we can't + // just skip processing. TODO: Move them to an earlier stage. + m_ofp = new V3OutCFile{VL_DEV_NULL}; + return; + } + m_ofp = new V3OutCFile{cfilep->name()}; + putsHeader(); + // Emit description + m_ofp->putsNoTracking("// DESCR" /* keep this comment */ "IPTION: Verilator output: "); + m_ofp->putsNoTracking(descriptionp); + m_ofp->putsNoTracking("\n"); + } + + // Close current output file. Sets ofp() and outFileNodep() to nullptr. + void closeOutputFile() { + UASSERT(m_ofp, "No currently open output file"); + VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); + m_cfilep->complexityScore(m_splitSize); + m_cfilep = nullptr; + } + + std::vector getAndClearCfileps() { + UASSERT(!m_ofp, "Output file is open"); + return std::move(m_newCfileps); + } + + void splitSizeInc(size_t count) { m_splitSize += count; } + void splitSizeInc(const AstNode* nodep) { + splitSizeInc(static_cast(nodep->nodeCount())); + } + bool splitNeeded(size_t splitLimit) const { return m_splitSize >= splitLimit; } + bool splitNeeded() const { return splitNeeded(m_splitLimit); } + // Returns pointer to current output file object. V3OutCFile* ofp() const VL_MT_SAFE { return m_ofp; } - // Returns pointer to the AST node that represents the output file (`ofp()`) - AstCFile* outFileNodep() const VL_MT_SAFE { return m_outFileNodep; } - - // Sets ofp() and outFileNodep() to the given pointers, without closing a file these pointers - // currently point to. - void setOutputFile(V3OutCFile* ofp, AstCFile* nodep) { - // cppcheck-suppress danglingLifetime // ofp is often on stack in caller, it's fine. - m_ofp = ofp; - m_outFileNodep = nodep; - } - - // Sets ofp() and outFileNodep() to null, without closing a file these pointers currently point - // to. NOTE: Dummy nullptr argument is taken to make function calls more explicit. - void setOutputFile(std::nullptr_t nullp) { - UASSERT(nullp == nullptr, "Expected nullptr as the argument"); - m_ofp = nullp; - m_outFileNodep = nullp; - } - - // Closes current output file. Sets ofp() and outFileNodep() to nullptr. - void closeOutputFile() { - VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); - m_outFileNodep->complexityScore(m_splitSize); - m_outFileNodep = nullptr; - } void puts(const string& str) { ofp()->puts(str); } void putns(const AstNode* nodep, const string& str) { ofp()->putns(nodep, str); } @@ -133,8 +182,6 @@ public: bool optSystemC() { return v3Global.opt.systemC(); } static string protect(const string& name) VL_MT_SAFE { return VIdProtect::protect(name); } static string funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp = nullptr); - static AstCFile* newCFile(const string& filename, bool slow, bool source); - static AstCFile* createCFile(const string& filename, bool slow, bool source) VL_MT_SAFE; 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); @@ -163,7 +210,11 @@ public: // CONSTRUCTORS EmitCBaseVisitorConst() = default; - ~EmitCBaseVisitorConst() override = default; + ~EmitCBaseVisitorConst() override { + UASSERT(!m_ofp, "Did not close output file"); + // Add files cerated to the netlist (unless retrieved before destruction) + for (AstCFile* const cfilep : m_newCfileps) v3Global.rootp()->addFilesp(cfilep); + } }; #endif // guard diff --git a/src/V3EmitCConstPool.cpp b/src/V3EmitCConstPool.cpp index 6dc2043c0..bd9db79b8 100644 --- a/src/V3EmitCConstPool.cpp +++ b/src/V3EmitCConstPool.cpp @@ -20,6 +20,7 @@ #include "V3EmitCConstInit.h" #include "V3File.h" #include "V3Stats.h" +#include "V3UniqueNames.h" #include #include @@ -34,40 +35,15 @@ class EmitCConstPool final : public EmitCConstInit { using OutCFilePair = std::pair; // MEMBERS - uint32_t m_outFileCount = 0; - int m_outFileSize = 0; VDouble0 m_tablesEmitted; VDouble0 m_constsEmitted; + V3UniqueNames m_uniqueNames; // Generates unique file names + const std::string m_fileBaseName = EmitCUtil::topClassName() + "__ConstPool"; // METHODS - - OutCFilePair newOutCFile() const { - const string fileName = v3Global.opt.makeDir() + "/" + EmitCUtil::topClassName() - + "__ConstPool_" + cvtToStr(m_outFileCount) + ".cpp"; - AstCFile* const cfilep = newCFile(fileName, /* slow: */ true, /* source: */ true); - V3OutCFile* const ofp = new V3OutCFile{fileName}; - ofp->putsHeader(); - ofp->puts("// DESCRIPTION: Verilator output: Constant pool\n"); - ofp->puts("//\n"); - ofp->puts("\n"); - ofp->puts("#include \"verilated.h\"\n"); - return {ofp, cfilep}; - } - - void maybeSplitCFile() { - if (v3Global.opt.outputSplit() && m_outFileSize < v3Global.opt.outputSplit()) return; - // Splitting file, so using parallel build. - v3Global.useParallelBuild(true); - // Close current file - closeOutputFile(); - // Open next file - m_outFileSize = 0; - ++m_outFileCount; - const OutCFilePair outFileAndNodePair = newOutCFile(); - setOutputFile(outFileAndNodePair.first, outFileAndNodePair.second); - } - void emitVars(const AstConstPool* poolp) { + UASSERT(!ofp(), "Output file should not be open"); + std::vector varps; for (AstNode* nodep = poolp->modp()->stmtsp(); nodep; nodep = nodep->nextp()) { if (const AstVar* const varp = VN_CAST(nodep, Var)) varps.push_back(varp); @@ -79,12 +55,22 @@ class EmitCConstPool final : public EmitCConstInit { return ap->name() < bp->name(); }); - const OutCFilePair outFileAndNodePair = newOutCFile(); - setOutputFile(outFileAndNodePair.first, outFileAndNodePair.second); - for (const AstVar* varp : varps) { - maybeSplitCFile(); - const string nameProtect + if (splitNeeded()) { + // Splitting file, so using parallel build. + v3Global.useParallelBuild(true); + // Close old file + closeOutputFile(); + } + + if (!ofp()) { + openNewOutputSourceFile(m_uniqueNames.get(m_fileBaseName), true, false, + "Constant pool"); + puts("\n"); + puts("#include \"verilated.h\"\n"); + } + + const std::string nameProtect = EmitCUtil::topClassName() + "__ConstPool__" + varp->nameProtect(); puts("\n"); putns(varp, "extern const "); @@ -101,12 +87,18 @@ class EmitCConstPool final : public EmitCConstInit { } } - closeOutputFile(); + if (ofp()) closeOutputFile(); } // VISITORS void visit(AstConst* nodep) override { - m_outFileSize += nodep->num().isString() ? 10 : nodep->isWide() ? nodep->widthWords() : 1; + if (nodep->num().isString()) { + splitSizeInc(AstNode::INSTR_COUNT_STR); + } else if (nodep->isWide()) { + splitSizeInc(nodep->widthWords()); + } else { + splitSizeInc(1); + } EmitCConstInit::visit(nodep); } diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index f1538d230..ade7cf0e2 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -144,7 +144,7 @@ class EmitCFunc VL_NOT_FINAL : public EmitCConstInit { } m_emitDispState; protected: - EmitCLazyDecls m_lazyDecls; // Visitor for emitting lazy declarations + EmitCLazyDecls m_lazyDecls{*this}; // Visitor for emitting lazy declarations bool m_useSelfForThis = false; // Replace "this" with "vlSelf" bool m_usevlSelfRef = false; // Use vlSelfRef reference instead of vlSelf pointer const AstNodeModule* m_modp = nullptr; // Current module being emitted @@ -169,16 +169,6 @@ protected: } public: - // METHODS - - // ACCESSORS - void splitSizeInc(int count) { m_splitSize += count; } - void splitSizeInc(const AstNode* nodep) { splitSizeInc(nodep->nodeCount()); } - void splitSizeReset() { m_splitSize = 0; } - bool splitNeeded() const { - return v3Global.opt.outputSplit() && m_splitSize >= v3Global.opt.outputSplit(); - } - // METHODS void displayNode(AstNode* nodep, AstScopeName* scopenamep, const string& vformat, AstNode* exprsp, bool isScan); @@ -1730,13 +1720,8 @@ public: } } // LCOV_EXCL_STOP - EmitCFunc() - : m_lazyDecls{*this} {} - EmitCFunc(AstNode* nodep, V3OutCFile* ofp, AstCFile* cfilep) - : EmitCFunc{} { - setOutputFile(ofp, cfilep); - iterateConst(nodep); - } +protected: + EmitCFunc() = default; ~EmitCFunc() override = default; }; diff --git a/src/V3EmitCHeaders.cpp b/src/V3EmitCHeaders.cpp index 2b42fe78f..825b3c474 100644 --- a/src/V3EmitCHeaders.cpp +++ b/src/V3EmitCHeaders.cpp @@ -635,16 +635,7 @@ class EmitCHeader final : public EmitCConstInit { UINFO(5, " Emitting header for " << EmitCUtil::prefixNameProtect(modp)); // Open output file - const string filename - = v3Global.opt.makeDir() + "/" + EmitCUtil::prefixNameProtect(modp) + ".h"; - AstCFile* const cfilep = newCFile(filename, /* slow: */ false, /* source: */ false); - V3OutCFile* const ofilep - = v3Global.opt.systemC() ? new V3OutScFile{filename} : new V3OutCFile{filename}; - - setOutputFile(ofilep, cfilep); - - ofp()->putsHeader(); - puts("// DESCRIPTION: Verilator output: Design internal header\n"); + openNewOutputHeaderFile(EmitCUtil::prefixNameProtect(modp), "Design internal header"); puts("// See " + EmitCUtil::topClassName() + ".h for the primary calling header\n"); ofp()->putsGuard(); @@ -653,6 +644,7 @@ class EmitCHeader final : public EmitCConstInit { puts("\n"); ofp()->putsIntTopInclude(); puts("#include \"verilated.h\"\n"); + if (modp->isTop() && optSystemC()) puts("#include \"verilated_sc.h\"\n"); if (v3Global.opt.mtasks()) puts("#include \"verilated_threads.h\"\n"); if (v3Global.opt.savable()) puts("#include \"verilated_save.h\"\n"); if (v3Global.opt.coverage()) puts("#include \"verilated_cov.h\"\n"); diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp index 3855dbe2e..55cc93ad0 100644 --- a/src/V3EmitCImp.cpp +++ b/src/V3EmitCImp.cpp @@ -30,47 +30,23 @@ VL_DEFINE_DEBUG_FUNCTIONS; //###################################################################### // Internal EmitC implementation -class EmitCImp final : EmitCFunc { +class EmitCImp final : public EmitCFunc { // MEMBERS - const AstNodeModule* const m_fileModp; // Files names/headers constructed using this module + // Base module (For non-classes, same as m_modp. For classes, it's the ClassPackage.) + const AstNodeModule* const m_fileModp; const bool m_slow; // Creating __Slow file - size_t m_nSplitFiles = 0; // Sequence number for file splitting - std::deque& m_cfilesr; // cfiles generated by this emit + V3UniqueNames m_uniqueNames; // Generates unique file names + const std::string m_fileBaseName = EmitCUtil::prefixNameProtect(m_fileModp); // METHODS - void openNextOutputFile(bool canBeSplit) { - UASSERT(!ofp(), "Output file already open"); - - splitSizeReset(); // Reset file size tracking - m_lazyDecls.reset(); // Need to emit new lazy declarations - - AstCFile* filep = nullptr; - V3OutCFile* ofilep = nullptr; - if (v3Global.opt.lintOnly()) { - // Unfortunately we have some lint checks here, so we can't just skip processing. - // We should move them to a different stage. - const std::string filename = VL_DEV_NULL; - filep = createCFile(filename, /* slow: */ m_slow, /* source: */ true); - ofilep = new V3OutCFile{filename}; - } else { - std::string filename = v3Global.opt.makeDir(); - filename += "/" + EmitCUtil::prefixNameProtect(m_fileModp); - if (canBeSplit) filename += "__" + std::to_string(m_nSplitFiles++); - if (m_slow) filename += "__Slow"; - filename += ".cpp"; - filep = createCFile(filename, /* slow: */ m_slow, /* source: */ true); - ofilep = v3Global.opt.systemC() ? new V3OutScFile{filename} : new V3OutCFile{filename}; - } - m_cfilesr.push_back(filep); - setOutputFile(ofilep, filep); - - putsHeader(); - puts("// DESCRIPTION: Verilator output: Design implementation internals\n"); + void openNextOutputFile(const std::string& fileName) { + openNewOutputSourceFile(fileName, m_slow, false, "Design implementation internals"); puts("// See " + EmitCUtil::topClassName() + ".h for the primary calling header\n"); puts("\n"); puts("#include \"" + EmitCUtil::pchClassName() + ".h\"\n"); - - emitSystemCSection(m_modp, VSystemCSectionType::IMP_HDR); + emitSystemCSection(m_fileModp, VSystemCSectionType::IMP_HDR); + // Need to emit new lazy declarations + m_lazyDecls.reset(); } void emitStaticVarDefns(const AstNodeModule* modp) { @@ -402,7 +378,7 @@ class EmitCImp final : EmitCFunc { = VN_IS(modp, ClassPackage) ? VN_AS(modp, ClassPackage)->classp() : nullptr; if (hasCommonImp(modp) || hasCommonImp(classp)) { - openNextOutputFile(/* canBeSplit: */ false); + openNextOutputFile(m_fileBaseName); doCommonImp(modp); if (classp) { @@ -442,7 +418,7 @@ class EmitCImp final : EmitCFunc { if (funcps.empty()) return; // Open output file - openNextOutputFile(/* canBeSplit: */ true); + openNextOutputFile(m_uniqueNames.get(m_fileBaseName)); // Emit all functions for (AstCFunc* const funcp : funcps) { VL_RESTORER(m_modp); @@ -461,16 +437,15 @@ class EmitCImp final : EmitCFunc { // Close old file closeOutputFile(); // Open a new file - openNextOutputFile(/* canBeSplit: */ true); + openNextOutputFile(m_uniqueNames.get(m_fileBaseName)); } EmitCFunc::visit(nodep); } - explicit EmitCImp(const AstNodeModule* modp, bool slow, std::deque& cfilesr) + explicit EmitCImp(const AstNodeModule* modp, bool slow) : m_fileModp{modp} - , m_slow{slow} - , m_cfilesr{cfilesr} { + , m_slow{slow} { UINFO(5, " Emitting implementation of " << EmitCUtil::prefixNameProtect(modp)); m_modp = modp; @@ -489,121 +464,142 @@ class EmitCImp final : EmitCFunc { ~EmitCImp() override = default; public: - static void main(const AstNodeModule* modp, bool slow, - std::deque& cfilesr) VL_MT_STABLE { - EmitCImp{modp, slow, cfilesr}; + static std::vector main(const AstNodeModule* modp, bool slow) VL_MT_STABLE { + EmitCImp emitCImp{modp, slow}; + return emitCImp.getAndClearCfileps(); } }; //###################################################################### // Tracing routines -class EmitCTrace final : EmitCFunc { +// Trace type descriptors go in a different file as it needs to be written in +// parallel with the actual trace function source files +class EmitCTraceTypes final : public EmitCFunc { + // NODE STATE/TYPES + // None allowed to support threaded emitting + + // STATE + int m_enumNum = 0; // Enumeration number (whole netlist) + std::unordered_map m_enumNumMap; // EnumDType to enumeration number + int m_traceTypeSubs = 0; // Number of trace type declaration sub-functions + V3UniqueNames m_uniqueNames; // Generates unique file names + const std::string m_fileBaseName = EmitCUtil::topClassName() + "_" + protect("_TraceDecls"); + // This one uses CSplitTrace for file splitting, which is incorrect but historically accurates + const size_t m_splitLimit = v3Global.opt.outputSplitCTrace() + ? static_cast(v3Global.opt.outputSplitCTrace()) + : std::numeric_limits::max(); + + void openNextOutputFile() { + openNewOutputSourceFile(m_uniqueNames.get(m_fileBaseName), true, true, + "Tracing declarations"); + puts("\n"); + for (const std::string& base : v3Global.opt.traceSourceLangs()) { + puts("#include \"" + base + ".h\"\n"); + } + puts("\n"); + puts("\nvoid " + EmitCUtil::prefixNameProtect(m_modp) + "__" + + protect("traceDeclTypesSub" + std::to_string(m_traceTypeSubs++)) + "(" + + v3Global.opt.traceClassBase() + "* tracep) {\n"); + } + +public: + // METHODS + int getEnumMapNum(AstEnumDType* nodep) { + int& enumNumr = m_enumNumMap[nodep]; + if (!enumNumr) { + if (splitNeeded(m_splitLimit)) { + // Splitting file, so using parallel build. + v3Global.useParallelBuild(true); + puts("}\n"); + closeOutputFile(); + openNextOutputFile(); + } + + enumNumr = ++m_enumNum; + int nvals = 0; + puts("{\n"); + putns(nodep, "const char* " + protect("__VenumItemNames") + "[]\n"); + puts("= {"); + for (AstEnumItem* itemp = nodep->itemsp(); itemp; + itemp = VN_AS(itemp->nextp(), EnumItem)) { + if (++nvals > 1) puts(", "); + putbs("\"" + itemp->prettyName() + "\""); + } + puts("};\n"); + nvals = 0; + puts("const char* " + protect("__VenumItemValues") + "[]\n"); + puts("= {"); + for (AstEnumItem* itemp = nodep->itemsp(); itemp; + itemp = VN_AS(itemp->nextp(), EnumItem)) { + AstConst* const constp = VN_AS(itemp->valuep(), Const); + if (++nvals > 1) puts(", "); + putbs("\"" + constp->num().displayed(nodep, "%0b") + "\""); + } + puts("};\n"); + puts("tracep->declDTypeEnum(" + std::to_string(enumNumr) + ", \"" + nodep->prettyName() + + "\", " + std::to_string(nvals) + ", " + std::to_string(nodep->widthMin()) + ", " + + protect("__VenumItemNames") + ", " + protect("__VenumItemValues") + ");\n"); + puts("}\n"); + splitSizeInc(AstNode::INSTR_COUNT_CALL); + } + return enumNumr; + } + + // Close output file + void finalize() { + // Close function definition + puts("}\n"); + + const std::string modName = EmitCUtil::prefixNameProtect(m_modp); + const std::string args = v3Global.opt.traceClassBase() + "* tracep"; + + // Forward declarations for subs in other files + for (int i = 0; i < m_traceTypeSubs - 1; ++i) { + puts("void " + modName + "__" + protect("traceDeclTypesSub" + std::to_string(i)) + "(" + + args + ");\n"); + } + + // Create top level trace_decl_types function and call each sub-function + puts("\nvoid " + modName + "__" + protect("trace_decl_types") + "(" + args + ") {\n"); + for (int i = 0; i < m_traceTypeSubs; ++i) { + puts(modName + "__" + protect("traceDeclTypesSub" + std::to_string(i)) + + "(tracep);\n"); + } + puts("}\n"); + + closeOutputFile(); + } + + EmitCTraceTypes() { + m_modp = v3Global.rootp()->topModulep(); + openNextOutputFile(); + } + ~EmitCTraceTypes() override = default; +}; + +class EmitCTrace final : public EmitCFunc { // NODE STATE/TYPES // None allowed to support threaded emitting // MEMBERS const bool m_slow; // Making slow file - int m_enumNum = 0; // Enumeration number (whole netlist) - V3UniqueNames m_uniqueNames; // For generating unique file names - std::unordered_map m_enumNumMap; // EnumDType to enumeration number - std::deque& m_cfilesr; // cfiles generated by this emit - V3OutCFile* m_typesFp = nullptr; // File for type declarations - int m_traceTypeSubs = 0; // Number of trace type declaration sub-functions - int m_typeSplitSize = 0; // # of cfunc nodes placed into output file + const std::unique_ptr m_emitTypesp{m_slow ? new EmitCTraceTypes{} : nullptr}; + V3UniqueNames m_uniqueNames; // Generates unique file names + const std::string m_fileBaseName = EmitCUtil::topClassName() + "_" + protect("_Trace"); // METHODS void openNextOutputFile() { - UASSERT(!ofp(), "Output file already open"); - - splitSizeReset(); // Reset file size tracking - m_lazyDecls.reset(); // Need to emit new lazy declarations - - string filename - = (v3Global.opt.makeDir() + "/" + EmitCUtil::topClassName() + "_" + protect("_Trace")); - filename = m_uniqueNames.get(filename); - if (m_slow) filename += "__Slow"; - filename += ".cpp"; - - AstCFile* const cfilep = createCFile(filename, m_slow, true /*source*/); - cfilep->support(true); - m_cfilesr.push_back(cfilep); - - V3OutCFile* const ofilep - = optSystemC() ? new V3OutScFile{filename} : new V3OutCFile{filename}; - setOutputFile(ofilep, cfilep); - - putsHeader(); - puts("// DESCR" - "IPTION: Verilator output: Tracing implementation internals\n"); - - // Includes - for (const string& base : v3Global.opt.traceSourceLangs()) + openNewOutputSourceFile(m_uniqueNames.get(m_fileBaseName), m_slow, true, + "Tracing implementation internals"); + puts("\n"); + for (const std::string& base : v3Global.opt.traceSourceLangs()) { puts("#include \"" + base + ".h\"\n"); + } puts("#include \"" + EmitCUtil::symClassName() + ".h\"\n"); puts("\n"); - } - - V3OutCFile* typesFp() const VL_MT_SAFE { return m_typesFp; } - - void openNextTypesFile() { - UASSERT(!m_typesFp, "Declarations output file already open"); - - string filename = (v3Global.opt.makeDir() + "/" + EmitCUtil::topClassName() + "_" - + protect("_TraceDecls")); - filename = m_uniqueNames.get(filename); - filename += "__Slow.cpp"; - - AstCFile* const cfilep = createCFile(filename, m_slow, true /*source*/); - cfilep->support(true); - m_cfilesr.push_back(cfilep); - - if (optSystemC()) { - m_typesFp = new V3OutScFile{filename}; - } else { - m_typesFp = new V3OutCFile{filename}; - } - typesFp()->putsHeader(); - typesFp()->puts("// DESCR" - "IPTION: Verilator output: Tracing declarations\n"); - - // Includes - for (const string& base : v3Global.opt.traceSourceLangs()) - typesFp()->puts("#include \"" + base + ".h\"\n"); - typesFp()->puts("\n"); - - typesFp()->puts("\nvoid " + EmitCUtil::prefixNameProtect(m_modp) + "__" - + protect("traceDeclTypesSub" + cvtToStr(m_traceTypeSubs++)) + "(" - + v3Global.opt.traceClassBase() + "* tracep) {\n"); - } - - void closeTypesFile() { - typesFp()->puts("}\n"); - VL_DO_CLEAR(delete m_typesFp, m_typesFp = nullptr); - } - - void callTypeSubs() { - typesFp()->puts("}\n"); - - // Forward declarations for subs in other files - for (int i = 0; i < m_traceTypeSubs - 1; ++i) { - typesFp()->puts("void " + EmitCUtil::prefixNameProtect(m_modp) + "__" - + protect("traceDeclTypesSub" + cvtToStr(i)) + "(" - + v3Global.opt.traceClassBase() + "* tracep);\n"); - } - - typesFp()->puts("\nvoid " + EmitCUtil::prefixNameProtect(m_modp) + "__" - + protect("trace_decl_types") + "(" + v3Global.opt.traceClassBase() - + "* tracep) {\n"); - for (int i = 0; i < m_traceTypeSubs; ++i) { - typesFp()->puts(EmitCUtil::prefixNameProtect(m_modp) + "__" - + protect("traceDeclTypesSub" + cvtToStr(i)) + "(tracep);\n"); - } - } - - bool typesSplitNeeded() { - return v3Global.opt.outputSplitCTrace() - && m_typeSplitSize >= v3Global.opt.outputSplitCTrace(); + // Need to emit new lazy declarations + m_lazyDecls.reset(); } bool emitTraceIsScBv(const AstTraceInc* nodep) { @@ -693,54 +689,13 @@ class EmitCTrace final : EmitCFunc { puts(");"); } - int getEnumMapNum(AstEnumDType* nodep) { - int enumNum = m_enumNumMap[nodep]; - if (!enumNum) { - if (typesSplitNeeded()) { - // Splitting file, so using parallel build. - v3Global.useParallelBuild(true); - closeTypesFile(); - openNextTypesFile(); - } - enumNum = ++m_enumNum; - m_enumNumMap[nodep] = enumNum; - int nvals = 0; - typesFp()->puts("{\n"); - typesFp()->putns(nodep, "const char* " + protect("__VenumItemNames") + "[]\n"); - typesFp()->puts("= {"); - for (AstEnumItem* itemp = nodep->itemsp(); itemp; - itemp = VN_AS(itemp->nextp(), EnumItem)) { - if (++nvals > 1) typesFp()->puts(", "); - typesFp()->putbs("\"" + itemp->prettyName() + "\""); - } - typesFp()->puts("};\n"); - nvals = 0; - typesFp()->puts("const char* " + protect("__VenumItemValues") + "[]\n"); - typesFp()->puts("= {"); - for (AstEnumItem* itemp = nodep->itemsp(); itemp; - itemp = VN_AS(itemp->nextp(), EnumItem)) { - AstConst* const constp = VN_AS(itemp->valuep(), Const); - if (++nvals > 1) typesFp()->puts(", "); - typesFp()->putbs("\"" + constp->num().displayed(nodep, "%0b") + "\""); - } - typesFp()->puts("};\n"); - typesFp()->puts("tracep->declDTypeEnum(" + cvtToStr(enumNum) + ", \"" - + nodep->prettyName() + "\", " + cvtToStr(nvals) + ", " - + cvtToStr(nodep->widthMin()) + ", " + protect("__VenumItemNames") - + ", " + protect("__VenumItemValues") + ");\n"); - typesFp()->puts("}\n"); - m_typeSplitSize += 3; - } - return enumNum; - } - int emitTraceDeclDType(AstNodeDType* nodep) { // Return enum number or -1 for none if (v3Global.opt.traceEnabledFst()) { // Skip over refs-to-refs, but stop before final ref so can get data type name // Alternatively back in V3Width we could push enum names from upper typedefs if (AstEnumDType* const enump = VN_CAST(nodep->skipRefToEnump(), EnumDType)) { - return getEnumMapNum(enump); + return m_emitTypesp->getEnumMapNum(enump); } } return -1; @@ -873,29 +828,49 @@ class EmitCTrace final : EmitCFunc { } } - explicit EmitCTrace(AstNodeModule* modp, bool slow, std::deque& cfilesr) - : m_slow{slow} - , m_cfilesr{cfilesr} { - m_modp = modp; + explicit EmitCTrace(bool slow) + : m_slow{slow} { + m_modp = v3Global.rootp()->topModulep(); // Open output file openNextOutputFile(); - if (m_slow) openNextTypesFile(); // Emit functions - for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { + for (AstNode* nodep = m_modp->stmtsp(); nodep; nodep = nodep->nextp()) { if (AstCFunc* const funcp = VN_CAST(nodep, CFunc)) iterateConst(funcp); } // Close output file closeOutputFile(); - if (m_slow) { - callTypeSubs(); - closeTypesFile(); - } + if (m_slow) m_emitTypesp->finalize(); } ~EmitCTrace() override = default; public: - static void main(AstNodeModule* modp, bool slow, std::deque& cfilesr) VL_MT_STABLE { - EmitCTrace{modp, slow, cfilesr}; + static std::vector main(bool slow) VL_MT_STABLE { + EmitCTrace emitCTrace{slow}; + std::vector cfileps = emitCTrace.getAndClearCfileps(); + if (slow) { + for (AstCFile* const cfilep : emitCTrace.m_emitTypesp->getAndClearCfileps()) { + cfileps.emplace_back(cfilep); + } + } + return cfileps; + } +}; + +//###################################################################### +// Existing AstCFile emitter + +class EmitCFile final : public EmitCFunc { + explicit EmitCFile(AstCFile* cfilep) { + openOutputFile(cfilep, "Generated C++"); + iterateConst(cfilep->tblockp()); + closeOutputFile(); + } + ~EmitCFile() override = default; + +public: + static void main(AstCFile* cfilep) VL_MT_STABLE { + if (!cfilep->tblockp()) return; + EmitCFile{cfilep}; } }; @@ -904,42 +879,37 @@ public: void V3EmitC::emitcImp() { UINFO(2, __FUNCTION__ << ":"); - // Make parent module pointers available. - const EmitCParentModule emitCParentModule; - std::list> cfiles; - V3ThreadScope threadScope; + std::list> cfiles; + { + // Make parent module pointers available. + const EmitCParentModule emitCParentModule; + V3ThreadScope threadScope; - // Process each module in turn - for (const AstNode* nodep = v3Global.rootp()->modulesp(); nodep; nodep = nodep->nextp()) { - if (VN_IS(nodep, Class)) continue; // Imped with ClassPackage - const AstNodeModule* const modp = VN_AS(nodep, NodeModule); - cfiles.emplace_back(); - auto& slowCfilesr = cfiles.back(); - threadScope.enqueue( - [modp, &slowCfilesr] { EmitCImp::main(modp, /* slow: */ true, slowCfilesr); }); - cfiles.emplace_back(); - auto& fastCfilesr = cfiles.back(); - threadScope.enqueue( - [modp, &fastCfilesr] { EmitCImp::main(modp, /* slow: */ false, fastCfilesr); }); - } + // Process each module in turn + for (const AstNode* nodep = v3Global.rootp()->modulesp(); nodep; nodep = nodep->nextp()) { + if (VN_IS(nodep, Class)) continue; // Imped with ClassPackage + const AstNodeModule* const modp = VN_AS(nodep, NodeModule); + cfiles.emplace_back(); + std::vector& slow = cfiles.back(); + threadScope.enqueue([modp, &slow] { slow = EmitCImp::main(modp, /* slow: */ true); }); + cfiles.emplace_back(); + std::vector& fast = cfiles.back(); + threadScope.enqueue([modp, &fast] { fast = EmitCImp::main(modp, /* slow: */ false); }); + } - // Emit trace routines (currently they can only exist in the top module) - if (v3Global.opt.trace() && !v3Global.opt.lintOnly()) { - cfiles.emplace_back(); - auto& slowCfilesr = cfiles.back(); - threadScope.enqueue([&slowCfilesr] { - EmitCTrace::main(v3Global.rootp()->topModulep(), /* slow: */ true, slowCfilesr); - }); - cfiles.emplace_back(); - auto& fastCfilesr = cfiles.back(); - threadScope.enqueue([&fastCfilesr] { - EmitCTrace::main(v3Global.rootp()->topModulep(), /* slow: */ false, fastCfilesr); - }); + // Emit trace routines (currently they can only exist in the top module) + if (v3Global.opt.trace() && !v3Global.opt.lintOnly()) { + cfiles.emplace_back(); + std::vector& slow = cfiles.back(); + threadScope.enqueue([&slow] { slow = EmitCTrace::main(/* slow: */ true); }); + cfiles.emplace_back(); + std::vector& fast = cfiles.back(); + threadScope.enqueue([&fast] { fast = EmitCTrace::main(/* slow: */ false); }); + } } - // Wait for futures - threadScope.wait(); - for (const auto& collr : cfiles) { - for (const auto cfilep : collr) v3Global.rootp()->addFilesp(cfilep); + // Add files to netlist + for (const std::vector& cfileps : cfiles) { + for (AstCFile* const cfilep : cfileps) v3Global.rootp()->addFilesp(cfilep); } } @@ -947,12 +917,6 @@ void V3EmitC::emitcFiles() { UINFO(2, __FUNCTION__ << ":"); for (AstNodeFile *filep = v3Global.rootp()->filesp(), *nextp; filep; filep = nextp) { nextp = VN_AS(filep->nextp(), NodeFile); - AstCFile* const cfilep = VN_CAST(filep, CFile); - if (cfilep && cfilep->tblockp()) { - V3OutCFile of{cfilep->name()}; - of.puts("// DESCR" - "IPTION: Verilator generated C++\n"); - EmitCFunc{cfilep->tblockp(), &of, cfilep}; - } + if (AstCFile* const cfilep = VN_CAST(filep, CFile)) EmitCFile::main(cfilep); } } diff --git a/src/V3EmitCMain.cpp b/src/V3EmitCMain.cpp index 0648d4564..ef42341e6 100644 --- a/src/V3EmitCMain.cpp +++ b/src/V3EmitCMain.cpp @@ -41,12 +41,6 @@ public: private: // MAIN METHOD void emitInt() { - const string filename - = v3Global.opt.makeDir() + "/" + EmitCUtil::topClassName() + "__main.cpp"; - AstCFile* const cfilep = newCFile(filename, false /*slow*/, true /*source*/); - V3OutCFile cf{filename}; - setOutputFile(&cf, cfilep); - // Not defining main_time/vl_time_stamp, so v3Global.opt.addCFlags("-DVL_TIME_CONTEXT"); // On MSVC++ anyways @@ -54,11 +48,12 @@ private: string topName = v3Global.opt.mainTopName(); if (topName == "-") topName = ""; - // Heavily commented output, as users are likely to look at or copy this code - ofp()->putsHeader(); - puts("// DESCRIPTION: main() calling loop, created with Verilator --main\n"); + openNewOutputSourceFile(EmitCUtil::topClassName() + "__main", false, false, + "main() simulation loop, created with --main"); puts("\n"); + // Heavily commented output, as users are likely to look at or copy this code + puts("#include \"verilated.h\"\n"); puts("#include \"" + EmitCUtil::topClassName() + ".h\"\n"); @@ -116,7 +111,7 @@ private: puts("return 0;\n"); puts("}\n"); - setOutputFile(nullptr); + closeOutputFile(); } }; diff --git a/src/V3EmitCModel.cpp b/src/V3EmitCModel.cpp index 51226334c..07a223a2b 100644 --- a/src/V3EmitCModel.cpp +++ b/src/V3EmitCModel.cpp @@ -53,15 +53,7 @@ class EmitCModel final : public EmitCFunc { } void emitHeader(AstNodeModule* modp) { - UASSERT(!ofp(), "Output file should not be open"); - - const string filename = v3Global.opt.makeDir() + "/" + EmitCUtil::topClassName() + ".h"; - setOutputFile(v3Global.opt.systemC() ? new V3OutScFile{filename} - : new V3OutCFile{filename}, - newCFile(filename, /* slow: */ false, /* source: */ false)); - - ofp()->putsHeader(); - puts("// DESCRIPTION: Verilator output: Primary model header\n"); + openNewOutputHeaderFile(EmitCUtil::topClassName(), "Primary model header"); puts("//\n"); puts("// This header should be included by all source files instantiating the design.\n"); puts("// The class here is then constructed to instantiate the design.\n"); @@ -72,7 +64,9 @@ class EmitCModel final : public EmitCFunc { // Include files puts("\n"); ofp()->putsIntTopInclude(); + puts("#include \"verilated.h\"\n"); + if (v3Global.opt.systemC()) puts("#include \"verilated_sc.h\"\n"); if (v3Global.opt.mtasks()) puts("#include \"verilated_threads.h\"\n"); if (v3Global.opt.savable()) puts("#include \"verilated_save.h\"\n"); if (v3Global.opt.coverage()) puts("#include \"verilated_cov.h\"\n"); @@ -614,17 +608,8 @@ class EmitCModel final : public EmitCFunc { } void emitImplementation(AstNodeModule* modp) { - UASSERT(!ofp(), "Output file should not be open"); - - const string filename = v3Global.opt.makeDir() + "/" + EmitCUtil::topClassName() + ".cpp"; - setOutputFile(v3Global.opt.systemC() ? new V3OutScFile{filename} - : new V3OutCFile{filename}, - newCFile(filename, /* slow: */ false, /* source: */ true)); - - ofp()->putsHeader(); - puts("// DESCRIPTION: Verilator output: " - "Model implementation (design independent parts)\n"); - + openNewOutputSourceFile(EmitCUtil::topClassName(), false, false, + "Model implementation (design independent parts)"); puts("\n"); puts("#include \"" + EmitCUtil::pchClassName() + ".h\"\n"); for (const string& base : v3Global.opt.traceSourceLangs()) @@ -643,6 +628,10 @@ class EmitCModel final : public EmitCFunc { void emitDpiExportDispatchers(AstNodeModule* modp) { UASSERT(!ofp(), "Output file should not be open"); + // File name utils + V3UniqueNames uniqueNames; + const std::string fileBaseName = EmitCUtil::topClassName() + "__Dpi_Export"; + // Emit DPI Export dispatchers for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { AstCFunc* const funcp = VN_CAST(nodep, CFunc); @@ -656,23 +645,14 @@ class EmitCModel final : public EmitCFunc { } if (!ofp()) { - string filename - = v3Global.opt.makeDir() + "/" + EmitCUtil::topClassName() + "__Dpi_Export"; - filename = m_uniqueNames.get(filename); - filename += ".cpp"; - setOutputFile(v3Global.opt.systemC() ? new V3OutScFile{filename} - : new V3OutCFile{filename}, - newCFile(filename, /* slow: */ false, /* source: */ true)); - splitSizeReset(); // Reset file size tracking - m_lazyDecls.reset(); - ofp()->putsHeader(); - puts( - "// DESCRIPTION: Verilator output: Implementation of DPI export functions.\n"); - puts("//\n"); + openNewOutputSourceFile(uniqueNames.get(fileBaseName), false, false, + "Implementation of DPI export functions."); + puts("\n"); puts("#include \"" + EmitCUtil::topClassName() + ".h\"\n"); puts("#include \"" + EmitCUtil::symClassName() + ".h\"\n"); puts("#include \"verilated_dpi.h\"\n"); puts("\n"); + m_lazyDecls.reset(); } iterateConst(funcp); diff --git a/src/V3EmitCPch.cpp b/src/V3EmitCPch.cpp index fdac954d1..7673f625f 100644 --- a/src/V3EmitCPch.cpp +++ b/src/V3EmitCPch.cpp @@ -23,48 +23,49 @@ VL_DEFINE_DEBUG_FUNCTIONS; //###################################################################### // Precompiled header emitter -class EmitCPch final { +class EmitCPch final : public EmitCBaseVisitorConst { public: // METHODS void emitPch() { - // Generate the makefile - V3OutCFile of{v3Global.opt.makeDir() + "/" + EmitCUtil::pchClassName() + ".h"}; - of.putsHeader(); - of.puts("// DESCRIPTION: Verilator output: Precompiled header\n"); - of.puts("//\n"); - of.puts("// Internal details; most user sources do not need this header,\n"); - of.puts("// unless using verilator public meta comments.\n"); - of.puts("// Suggest use " + EmitCUtil::topClassName() + ".h instead.\n"); - of.puts("\n"); + openNewOutputHeaderFile(EmitCUtil::pchClassName(), "Precompiled header"); + puts("//\n"); + puts("// Internal details; most user sources do not need this header,\n"); + puts("// unless using verilator public meta comments.\n"); + puts("// Suggest use " + EmitCUtil::topClassName() + ".h instead.\n"); - of.putsGuard(); + ofp()->putsGuard(); - of.puts("\n"); - of.puts("// GCC and Clang only will precompile headers (PCH) for the first header.\n"); - of.puts("// So, make sure this is the one and only PCH.\n"); - of.puts("// If multiple module's includes are needed, use individual includes.\n"); - of.puts("#ifdef VL_PCH_INCLUDED\n"); - of.puts("# error \"Including multiple precompiled header files\"\n"); - of.puts("#endif\n"); - of.puts("#define VL_PCH_INCLUDED\n"); + puts("\n"); + puts("// GCC and Clang only will precompile headers (PCH) for the first header.\n"); + puts("// So, make sure this is the one and only PCH.\n"); + puts("// If multiple module's includes are needed, use individual includes.\n"); + puts("#ifdef VL_PCH_INCLUDED\n"); + puts("# error \"Including multiple precompiled header files\"\n"); + puts("#endif\n"); + puts("#define VL_PCH_INCLUDED\n"); - of.puts("\n"); - of.puts("\n#include \"verilated.h\"\n"); - if (v3Global.dpi()) of.puts("#include \"verilated_dpi.h\"\n"); + puts("\n"); + puts("\n#include \"verilated.h\"\n"); + if (v3Global.dpi()) puts("#include \"verilated_dpi.h\"\n"); - of.puts("\n"); - of.puts("#include \"" + EmitCUtil::symClassName() + ".h\"\n"); - of.puts("#include \"" + EmitCUtil::topClassName() + ".h\"\n"); + puts("\n"); + puts("#include \"" + EmitCUtil::symClassName() + ".h\"\n"); + puts("#include \"" + EmitCUtil::topClassName() + ".h\"\n"); - of.puts("\n// Additional include files added using '--compiler-include'\n"); + puts("\n// Additional include files added using '--compiler-include'\n"); for (const string& filename : v3Global.opt.compilerIncludes()) { - of.puts("#include \"" + filename + "\"\n"); + puts("#include \"" + filename + "\"\n"); } - of.putsEndGuard(); + ofp()->putsEndGuard(); + + closeOutputFile(); } + // VISITOR + void visit(AstNode* nodep) { nodep->v3fatalSrc("Unused"); } + public: explicit EmitCPch() { emitPch(); } }; diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 2ea514206..929c04f91 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -103,16 +103,8 @@ class EmitCSyms final : EmitCBaseVisitorConst { const bool m_dpiHdrOnly; // Only emit the DPI header std::vector m_splitFuncNames; // Split file names VDouble0 m_statVarScopeBytes; // Statistic tracking - const std::string m_symsFileBase = v3Global.opt.makeDir() + "/" + symClassName(); // METHODS - void openOutputFile(const std::string fileName) { - V3OutCFile* const fp = optSystemC() ? new V3OutScFile{fileName} : new V3OutCFile{fileName}; - AstCFile* const cfilep = newCFile(fileName, true /*slow*/, true /*source*/); - cfilep->support(true); - setOutputFile(fp, cfilep); - } - void emitSymHdr(); void emitSymImpPreamble(); void emitScopeHier(std::vector& stmts, bool destroy); @@ -415,14 +407,7 @@ public: void EmitCSyms::emitSymHdr() { UINFO(6, __FUNCTION__ << ": "); - const std::string filename = m_symsFileBase + ".h"; - AstCFile* const cfilep = newCFile(filename, true /*slow*/, false /*source*/); - V3OutCFile* const ofilep = optSystemC() ? new V3OutScFile{filename} : new V3OutCFile{filename}; - setOutputFile(ofilep, cfilep); - - ofp()->putsHeader(); - puts("// DESCR" - "IPTION: Verilator output: Symbol table internal header\n"); + openNewOutputHeaderFile(symClassName(), "Symbol table internal header"); puts("//\n"); puts("// Internal details; most calling programs do not need this header,\n"); puts("// unless using verilator public meta comments.\n"); @@ -596,9 +581,6 @@ void EmitCSyms::emitSymHdr() { } void EmitCSyms::emitSymImpPreamble() { - ofp()->putsHeader(); - puts("// DESCR" - "IPTION: Verilator output: Symbol table implementation internals\n"); puts("\n"); // Includes @@ -883,7 +865,6 @@ std::vector EmitCSyms::getSymDtorStmts() { void EmitCSyms::emitSplit(std::vector& stmts, const std::string name, size_t maxCost) { - const std::string baseName = m_symsFileBase + "__" + name; size_t nSubFunctions = 0; // Reduce into a balanced tree of sub-function calls until we end up with a single statement while (stmts.size() > 1) { @@ -905,7 +886,7 @@ void EmitCSyms::emitSplit(std::vector& stmts, const std::string nam const std::string funcName = symClassName() + "__" + name + "__" + nStr; m_splitFuncNames.emplace_back(funcName); // Open split file - openOutputFile(baseName + "__" + nStr + "__Slow.cpp"); + openNewOutputSourceFile(funcName, true, true, "Symbol table implementation internals"); // Emit header emitSymImpPreamble(); // Open sub-function definition in the split file @@ -913,9 +894,9 @@ void EmitCSyms::emitSplit(std::vector& stmts, const std::string nam // Emit statements for (size_t j = splitStart; j < splitEnd; ++j) { - m_ofp->putsNoTracking(" "); - m_ofp->putsNoTracking(stmts[j]); - m_ofp->putsNoTracking("\n"); + ofp()->putsNoTracking(" "); + ofp()->putsNoTracking(stmts[j]); + ofp()->putsNoTracking("\n"); } // Close sub-function @@ -961,7 +942,7 @@ void EmitCSyms::emitSymImp(AstNetlist* netlistp) { } } - openOutputFile(m_symsFileBase + "__Slow.cpp"); + openNewOutputSourceFile(symClassName(), true, true, "Symbol table implementation internals"); emitSymImpPreamble(); // Constructor @@ -988,18 +969,18 @@ void EmitCSyms::emitSymImp(AstNetlist* netlistp) { } puts("{\n"); for (const std::string& stmt : ctorStmts) { - m_ofp->putsNoTracking(" "); - m_ofp->putsNoTracking(stmt); - m_ofp->putsNoTracking("\n"); + ofp()->putsNoTracking(" "); + ofp()->putsNoTracking(stmt); + ofp()->putsNoTracking("\n"); } puts("}\n"); // Destructor puts("\n" + symClassName() + "::~" + symClassName() + "() {\n"); for (const std::string& stmt : dtorStmts) { - m_ofp->putsNoTracking(" "); - m_ofp->putsNoTracking(stmt); - m_ofp->putsNoTracking("\n"); + ofp()->putsNoTracking(" "); + ofp()->putsNoTracking(stmt); + ofp()->putsNoTracking("\n"); } puts("}\n"); @@ -1058,15 +1039,9 @@ void EmitCSyms::emitSymImp(AstNetlist* netlistp) { void EmitCSyms::emitDpiHdr() { UINFO(6, __FUNCTION__ << ": "); - const std::string filename = v3Global.opt.makeDir() + "/" + topClassName() + "__Dpi.h"; - AstCFile* const cfilep = newCFile(filename, false /*slow*/, false /*source*/); - cfilep->support(true); - V3OutCFile hf{filename}; - setOutputFile(&hf, cfilep); - ofp()->putsHeader(); - puts("// DESCR" - "IPTION: Verilator output: Prototypes for DPI import and export functions.\n"); + openNewOutputHeaderFile(topClassName() + "__Dpi", + "Prototypes for DPI import and export functions."); 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 ensure\n"); @@ -1105,22 +1080,16 @@ void EmitCSyms::emitDpiHdr() { puts("#endif\n"); ofp()->putsEndGuard(); - setOutputFile(nullptr); + + closeOutputFile(); } //###################################################################### void EmitCSyms::emitDpiImp() { UINFO(6, __FUNCTION__ << ": "); - const std::string filename = v3Global.opt.makeDir() + "/" + topClassName() + "__Dpi.cpp"; - AstCFile* const cfilep = newCFile(filename, false /*slow*/, true /*source*/); - cfilep->support(true); - V3OutCFile hf(filename); - setOutputFile(&hf, cfilep); - - ofp()->putsHeader(); - puts("// DESCR" - "IPTION: Verilator output: Implementation of DPI export functions.\n"); + openNewOutputSourceFile(topClassName() + "__Dpi", false, true, + "Implementation of DPI export functions"); 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"); @@ -1164,7 +1133,7 @@ void EmitCSyms::emitDpiImp() { puts("#endif\n"); puts("\n"); } - setOutputFile(nullptr); + closeOutputFile(); } //###################################################################### diff --git a/src/V3File.h b/src/V3File.h index e9e740afd..68dd500d9 100644 --- a/src/V3File.h +++ b/src/V3File.h @@ -400,19 +400,6 @@ public: } }; -class V3OutScFile final : public V3OutCFile { -public: - explicit V3OutScFile(const string& filename) - : V3OutCFile{filename} {} - ~V3OutScFile() override = default; - void putsHeader() override { puts("// Verilated -*- SystemC -*-\n"); } - void putsIntTopInclude() override { - putsForceIncs(); - puts("#include \"systemc\"\n"); - puts("#include \"verilated_sc.h\"\n"); - } -}; - class V3OutVFile final : public V3OutCFile { public: explicit V3OutVFile(const string& filename) diff --git a/test_regress/t/t_flag_csplit_groups.py b/test_regress/t/t_flag_csplit_groups.py index a4b61ab1c..1530bf537 100755 --- a/test_regress/t/t_flag_csplit_groups.py +++ b/test_regress/t/t_flag_csplit_groups.py @@ -125,7 +125,7 @@ test.file_grep_not(test.obj_dir + "/" + test.vm_prefix + "_classes.mk", "vm_clas test.file_grep_not(test.obj_dir + "/" + test.vm_prefix + "_classes.mk", "vm_classes_2") # Check combine count -test.file_grep(test.stats, r'Node count, CFILE + (\d+)', (271 if test.vltmt else 254)) +test.file_grep(test.stats, r'Node count, CFILE + (\d+)', (272 if test.vltmt else 255)) test.file_grep(test.stats, r'Makefile targets, VM_CLASSES_FAST + (\d+)', 2) test.file_grep(test.stats, r'Makefile targets, VM_CLASSES_SLOW + (\d+)', 2) diff --git a/test_regress/t/t_json_only_debugcheck.out b/test_regress/t/t_json_only_debugcheck.out index 98c4306c8..414600c30 100644 --- a/test_regress/t/t_json_only_debugcheck.out +++ b/test_regress/t/t_json_only_debugcheck.out @@ -2924,69 +2924,70 @@ ], "filesp": [ {"type":"CFILE","name":"obj_vlt/t_json_only_debugcheck/Vt_json_only_debugcheck__Syms__Slow.cpp","addr":"(ZQB)","loc":"a,0:0,0:0","source":true,"slow":true,"tblockp": []}, - {"type":"CFILE","name":"obj_vlt/t_json_only_debugcheck/Vt_json_only_debugcheck__Syms.h","addr":"(ARB)","loc":"a,0:0,0:0","source":false,"slow":true,"tblockp": []}, + {"type":"CFILE","name":"obj_vlt/t_json_only_debugcheck/Vt_json_only_debugcheck__Syms.h","addr":"(ARB)","loc":"a,0:0,0:0","source":false,"slow":false,"tblockp": []}, {"type":"CFILE","name":"obj_vlt/t_json_only_debugcheck/Vt_json_only_debugcheck.h","addr":"(BRB)","loc":"a,0:0,0:0","source":false,"slow":false,"tblockp": []}, {"type":"CFILE","name":"obj_vlt/t_json_only_debugcheck/Vt_json_only_debugcheck.cpp","addr":"(CRB)","loc":"a,0:0,0:0","source":true,"slow":false,"tblockp": []}, - {"type":"CFILE","name":"obj_vlt/t_json_only_debugcheck/Vt_json_only_debugcheck_$root.h","addr":"(DRB)","loc":"a,0:0,0:0","source":false,"slow":false,"tblockp": []}, - {"type":"CFILE","name":"obj_vlt/t_json_only_debugcheck/Vt_json_only_debugcheck_$unit.h","addr":"(ERB)","loc":"a,0:0,0:0","source":false,"slow":false,"tblockp": []}, - {"type":"CFILE","name":"obj_vlt/t_json_only_debugcheck/Vt_json_only_debugcheck_$root__Slow.cpp","addr":"(FRB)","loc":"a,0:0,0:0","source":true,"slow":true,"tblockp": []}, - {"type":"CFILE","name":"obj_vlt/t_json_only_debugcheck/Vt_json_only_debugcheck_$root__0__Slow.cpp","addr":"(GRB)","loc":"a,0:0,0:0","source":true,"slow":true,"tblockp": []}, - {"type":"CFILE","name":"obj_vlt/t_json_only_debugcheck/Vt_json_only_debugcheck_$root__0.cpp","addr":"(HRB)","loc":"a,0:0,0:0","source":true,"slow":false,"tblockp": []}, - {"type":"CFILE","name":"obj_vlt/t_json_only_debugcheck/Vt_json_only_debugcheck_$unit__Slow.cpp","addr":"(IRB)","loc":"a,0:0,0:0","source":true,"slow":true,"tblockp": []}, - {"type":"CFILE","name":"obj_vlt/t_json_only_debugcheck/Vt_json_only_debugcheck_$unit__0__Slow.cpp","addr":"(JRB)","loc":"a,0:0,0:0","source":true,"slow":true,"tblockp": []} + {"type":"CFILE","name":"obj_vlt/t_json_only_debugcheck/Vt_json_only_debugcheck__pch.h","addr":"(DRB)","loc":"a,0:0,0:0","source":false,"slow":false,"tblockp": []}, + {"type":"CFILE","name":"obj_vlt/t_json_only_debugcheck/Vt_json_only_debugcheck_$root.h","addr":"(ERB)","loc":"a,0:0,0:0","source":false,"slow":false,"tblockp": []}, + {"type":"CFILE","name":"obj_vlt/t_json_only_debugcheck/Vt_json_only_debugcheck_$unit.h","addr":"(FRB)","loc":"a,0:0,0:0","source":false,"slow":false,"tblockp": []}, + {"type":"CFILE","name":"obj_vlt/t_json_only_debugcheck/Vt_json_only_debugcheck_$root__Slow.cpp","addr":"(GRB)","loc":"a,0:0,0:0","source":true,"slow":true,"tblockp": []}, + {"type":"CFILE","name":"obj_vlt/t_json_only_debugcheck/Vt_json_only_debugcheck_$root__0__Slow.cpp","addr":"(HRB)","loc":"a,0:0,0:0","source":true,"slow":true,"tblockp": []}, + {"type":"CFILE","name":"obj_vlt/t_json_only_debugcheck/Vt_json_only_debugcheck_$root__0.cpp","addr":"(IRB)","loc":"a,0:0,0:0","source":true,"slow":false,"tblockp": []}, + {"type":"CFILE","name":"obj_vlt/t_json_only_debugcheck/Vt_json_only_debugcheck_$unit__Slow.cpp","addr":"(JRB)","loc":"a,0:0,0:0","source":true,"slow":true,"tblockp": []}, + {"type":"CFILE","name":"obj_vlt/t_json_only_debugcheck/Vt_json_only_debugcheck_$unit__0__Slow.cpp","addr":"(KRB)","loc":"a,0:0,0:0","source":true,"slow":true,"tblockp": []} ], "miscsp": [ {"type":"TYPETABLE","name":"","addr":"(C)","loc":"a,0:0,0:0","constraintRefp":"UNLINKED","emptyQueuep":"UNLINKED","queueIndexp":"UNLINKED","streamp":"UNLINKED","voidp":"(AB)", "typesp": [ {"type":"BASICDTYPE","name":"logic","addr":"(K)","loc":"d,33:24,33:27","dtypep":"(K)","keyword":"logic","generic":true,"rangep": []}, {"type":"BASICDTYPE","name":"logic","addr":"(EC)","loc":"d,53:16,53:17","dtypep":"(EC)","keyword":"logic","range":"31:0","generic":true,"rangep": []}, - {"type":"BASICDTYPE","name":"logic","addr":"(KRB)","loc":"d,17:17,17:18","dtypep":"(KRB)","keyword":"logic","range":"3:0","generic":true,"rangep": []}, - {"type":"ENUMDTYPE","name":"t.my_t","addr":"(LRB)","loc":"d,17:12,17:16","dtypep":"(LRB)","enum":true,"generic":false,"refDTypep":"(KRB)","childDTypep": [], + {"type":"BASICDTYPE","name":"logic","addr":"(LRB)","loc":"d,17:17,17:18","dtypep":"(LRB)","keyword":"logic","range":"3:0","generic":true,"rangep": []}, + {"type":"ENUMDTYPE","name":"t.my_t","addr":"(MRB)","loc":"d,17:12,17:16","dtypep":"(MRB)","enum":true,"generic":false,"refDTypep":"(LRB)","childDTypep": [], "itemsp": [ - {"type":"ENUMITEM","name":"E01","addr":"(MRB)","loc":"d,18:24,18:27","dtypep":"(RB)","rangep": [], + {"type":"ENUMITEM","name":"E01","addr":"(NRB)","loc":"d,18:24,18:27","dtypep":"(RB)","rangep": [], "valuep": [ - {"type":"CONST","name":"4'h1","addr":"(NRB)","loc":"d,18:30,18:31","dtypep":"(RB)"} + {"type":"CONST","name":"4'h1","addr":"(ORB)","loc":"d,18:30,18:31","dtypep":"(RB)"} ]}, - {"type":"ENUMITEM","name":"E03","addr":"(ORB)","loc":"d,19:24,19:27","dtypep":"(RB)","rangep": [], + {"type":"ENUMITEM","name":"E03","addr":"(PRB)","loc":"d,19:24,19:27","dtypep":"(RB)","rangep": [], "valuep": [ - {"type":"CONST","name":"4'h3","addr":"(PRB)","loc":"d,19:30,19:31","dtypep":"(RB)"} + {"type":"CONST","name":"4'h3","addr":"(QRB)","loc":"d,19:30,19:31","dtypep":"(RB)"} ]}, - {"type":"ENUMITEM","name":"E04","addr":"(QRB)","loc":"d,20:24,20:27","dtypep":"(RB)","rangep": [], + {"type":"ENUMITEM","name":"E04","addr":"(RRB)","loc":"d,20:24,20:27","dtypep":"(RB)","rangep": [], "valuep": [ - {"type":"CONST","name":"4'h4","addr":"(RRB)","loc":"d,20:30,20:31","dtypep":"(RB)"} + {"type":"CONST","name":"4'h4","addr":"(SRB)","loc":"d,20:30,20:31","dtypep":"(RB)"} ]} ]}, {"type":"BASICDTYPE","name":"integer","addr":"(P)","loc":"d,23:4,23:11","dtypep":"(P)","keyword":"integer","range":"31:0","generic":true,"rangep": []}, - {"type":"REFDTYPE","name":"my_t","addr":"(M)","loc":"d,24:4,24:8","dtypep":"(LRB)","generic":false,"typedefp":"UNLINKED","refDTypep":"(LRB)","classOrPackagep":"UNLINKED","typeofp": [],"classOrPackageOpp": [],"paramsp": []}, + {"type":"REFDTYPE","name":"my_t","addr":"(M)","loc":"d,24:4,24:8","dtypep":"(MRB)","generic":false,"typedefp":"UNLINKED","refDTypep":"(MRB)","classOrPackagep":"UNLINKED","typeofp": [],"classOrPackageOpp": [],"paramsp": []}, {"type":"BASICDTYPE","name":"string","addr":"(PB)","loc":"d,28:4,28:10","dtypep":"(PB)","keyword":"string","generic":true,"rangep": []}, - {"type":"UNPACKARRAYDTYPE","name":"","addr":"(ZB)","loc":"d,17:12,17:16","dtypep":"(ZB)","isCompound":false,"declRange":"[7:0]","generic":false,"refDTypep":"(LRB)","childDTypep": [], + {"type":"UNPACKARRAYDTYPE","name":"","addr":"(ZB)","loc":"d,17:12,17:16","dtypep":"(ZB)","isCompound":false,"declRange":"[7:0]","generic":false,"refDTypep":"(MRB)","childDTypep": [], "rangep": [ - {"type":"RANGE","name":"","addr":"(SRB)","loc":"d,17:12,17:16","ascending":false,"fromBracket":false, + {"type":"RANGE","name":"","addr":"(TRB)","loc":"d,17:12,17:16","ascending":false,"fromBracket":false, "leftp": [ - {"type":"CONST","name":"32'h7","addr":"(TRB)","loc":"d,17:12,17:16","dtypep":"(EC)"} + {"type":"CONST","name":"32'h7","addr":"(URB)","loc":"d,17:12,17:16","dtypep":"(EC)"} ], "rightp": [ - {"type":"CONST","name":"32'h0","addr":"(URB)","loc":"d,17:12,17:16","dtypep":"(EC)"} + {"type":"CONST","name":"32'h0","addr":"(VRB)","loc":"d,17:12,17:16","dtypep":"(EC)"} ]} ]}, - {"type":"UNPACKARRAYDTYPE","name":"","addr":"(TI)","loc":"d,17:12,17:16","dtypep":"(TI)","isCompound":false,"declRange":"[7:0]","generic":false,"refDTypep":"(LRB)","childDTypep": [], + {"type":"UNPACKARRAYDTYPE","name":"","addr":"(TI)","loc":"d,17:12,17:16","dtypep":"(TI)","isCompound":false,"declRange":"[7:0]","generic":false,"refDTypep":"(MRB)","childDTypep": [], "rangep": [ - {"type":"RANGE","name":"","addr":"(VRB)","loc":"d,17:12,17:16","ascending":false,"fromBracket":false, + {"type":"RANGE","name":"","addr":"(WRB)","loc":"d,17:12,17:16","ascending":false,"fromBracket":false, "leftp": [ - {"type":"CONST","name":"32'h7","addr":"(WRB)","loc":"d,17:12,17:16","dtypep":"(EC)"} + {"type":"CONST","name":"32'h7","addr":"(XRB)","loc":"d,17:12,17:16","dtypep":"(EC)"} ], "rightp": [ - {"type":"CONST","name":"32'h0","addr":"(XRB)","loc":"d,17:12,17:16","dtypep":"(EC)"} + {"type":"CONST","name":"32'h0","addr":"(YRB)","loc":"d,17:12,17:16","dtypep":"(EC)"} ]} ]}, {"type":"UNPACKARRAYDTYPE","name":"","addr":"(FM)","loc":"d,17:12,17:16","dtypep":"(FM)","isCompound":true,"declRange":"[7:0]","generic":false,"refDTypep":"(PB)","childDTypep": [], "rangep": [ - {"type":"RANGE","name":"","addr":"(YRB)","loc":"d,17:12,17:16","ascending":false,"fromBracket":false, + {"type":"RANGE","name":"","addr":"(ZRB)","loc":"d,17:12,17:16","ascending":false,"fromBracket":false, "leftp": [ - {"type":"CONST","name":"32'h7","addr":"(ZRB)","loc":"d,17:12,17:16","dtypep":"(EC)"} + {"type":"CONST","name":"32'h7","addr":"(ASB)","loc":"d,17:12,17:16","dtypep":"(EC)"} ], "rightp": [ - {"type":"CONST","name":"32'h0","addr":"(ASB)","loc":"d,17:12,17:16","dtypep":"(EC)"} + {"type":"CONST","name":"32'h0","addr":"(BSB)","loc":"d,17:12,17:16","dtypep":"(EC)"} ]} ]}, {"type":"BASICDTYPE","name":"logic","addr":"(IB)","loc":"d,23:23,23:24","dtypep":"(IB)","keyword":"logic","range":"31:0","generic":true,"rangep": []}, @@ -2994,12 +2995,12 @@ {"type":"BASICDTYPE","name":"bit","addr":"(EN)","loc":"a,0:0,0:0","dtypep":"(EN)","keyword":"bit","range":"63:0","generic":true,"rangep": []}, {"type":"UNPACKARRAYDTYPE","name":"","addr":"(T)","loc":"d,11:8,11:9","dtypep":"(T)","isCompound":false,"declRange":"[0:0]","generic":false,"refDTypep":"(EN)","childDTypep": [], "rangep": [ - {"type":"RANGE","name":"","addr":"(BSB)","loc":"d,11:8,11:9","ascending":false,"fromBracket":false, + {"type":"RANGE","name":"","addr":"(CSB)","loc":"d,11:8,11:9","ascending":false,"fromBracket":false, "leftp": [ - {"type":"CONST","name":"32'h0","addr":"(CSB)","loc":"d,11:8,11:9","dtypep":"(EC)"} + {"type":"CONST","name":"32'h0","addr":"(DSB)","loc":"d,11:8,11:9","dtypep":"(EC)"} ], "rightp": [ - {"type":"CONST","name":"32'h0","addr":"(DSB)","loc":"d,11:8,11:9","dtypep":"(EC)"} + {"type":"CONST","name":"32'h0","addr":"(ESB)","loc":"d,11:8,11:9","dtypep":"(EC)"} ]} ]}, {"type":"BASICDTYPE","name":"IData","addr":"(LP)","loc":"a,0:0,0:0","dtypep":"(LP)","keyword":"IData","range":"31:0","generic":true,"rangep": []}, @@ -3013,9 +3014,9 @@ ]}, {"type":"CONSTPOOL","name":"","addr":"(D)","loc":"a,0:0,0:0", "modulep": [ - {"type":"MODULE","name":"@CONST-POOL@","addr":"(ESB)","loc":"a,0:0,0:0","isChecker":false,"isProgram":false,"hasGenericIface":false,"origName":"@CONST-POOL@","level":0,"modPublic":false,"inLibrary":false,"dead":false,"recursiveClone":false,"recursive":false,"timeunit":"NONE","inlinesp": [], + {"type":"MODULE","name":"@CONST-POOL@","addr":"(FSB)","loc":"a,0:0,0:0","isChecker":false,"isProgram":false,"hasGenericIface":false,"origName":"@CONST-POOL@","level":0,"modPublic":false,"inLibrary":false,"dead":false,"recursiveClone":false,"recursive":false,"timeunit":"NONE","inlinesp": [], "stmtsp": [ - {"type":"SCOPE","name":"TOP","addr":"(FSB)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(ESB)","varsp": [],"blocksp": [],"inlinesp": []} + {"type":"SCOPE","name":"TOP","addr":"(GSB)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(FSB)","varsp": [],"blocksp": [],"inlinesp": []} ]} ]} ]} diff --git a/test_regress/t/t_xml_debugcheck.out b/test_regress/t/t_xml_debugcheck.out index 9e5469979..5c6f53cc9 100644 --- a/test_regress/t/t_xml_debugcheck.out +++ b/test_regress/t/t_xml_debugcheck.out @@ -1786,6 +1786,7 @@ +