diff --git a/Changes b/Changes index 5dd935a56..483438765 100644 --- a/Changes +++ b/Changes @@ -16,6 +16,7 @@ Verilator 5.021 devel * Add predicted stack overflow warning (#4799). * Add +verilator+coverage+file runtime option. * Add --main support for dumping coverage. +* Add '--decorations node' for inserting debug comments into emitted code. * Remove deprecated 32-bit pointer mode (`gcc -m32`). * Change zero replication width error to ZEROREPL warning (#4753) (#4762). [Pengcheng Xu] * Support `vpiConstType` in `vpi_get_str()` (#4797). [Marlon James] diff --git a/bin/verilator b/bin/verilator index fd2ad8024..1ed15a16e 100755 --- a/bin/verilator +++ b/bin/verilator @@ -324,7 +324,8 @@ detailed descriptions of these arguments. --no-debug-leak Disable leaking memory in --debug mode --debugi Enable debugging at a specified level --debugi- Enable debugging a source file at a level - --no-decoration Disable comments and symbol decorations + --decorations Set output comment and spacing level + --no-decoration Disable comments and lower spacing level --default-language Default language to parse +define+= Set preprocessor define --dpi-hdr-only Only produce the DPI header file diff --git a/docs/guide/deprecations.rst b/docs/guide/deprecations.rst index 52d396976..6cc5ed6d3 100644 --- a/docs/guide/deprecations.rst +++ b/docs/guide/deprecations.rst @@ -6,7 +6,7 @@ Deprecations The following deprecated items are scheduled for future removal: -C++11 compiler support +C++14 compiler support Verilator currently requires a C++20 or newer compiler for timing, and a C++14 or newer compiler for both compiling Verilator and compiling Verilated models with --no-timing. diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index 3b580d197..7d1c8b984 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -304,12 +304,40 @@ Summary: detailed messages. See :vlopt:`--debug` for other implications of enabling debug. +.. option:: --decorations none + +.. option:: --decorations medium + +.. option:: --decorations node + + When creating output Verilated code, set level of comment and whitespace + decoration. + + With "--decorations none", + Minimize comments, white space, symbol names, and other decorative + items, at the cost of reduced readability. This may assist C++ compile + times. This will not typically change the ultimate model's + performance, but may in some cases. See also :vlopt:`--no-decoration` + option. + + With "--decorations medium", + The default, put a small amount of comments and white space, for + typical level of readability. + + With "--decorations node", + Include comments indicating what caused generation of the following + text, including what node pointer (corresponding to + :vlopt:`--dump-tree` .tree printed data), and the source Verilog + filename and line number. If subsequent following statements etc have + the same filename/line number these comments are omitted. This + enables easy debug when looking at the C++ code to determine what + Verilog source may be related. As node pointers are not stable + between different Verilator runs, this may harm compile caching and + should only be used for debug. + .. option:: --no-decoration - When creating output Verilated code, minimize comments, white space, - symbol names, and other decorative items, at the cost of reduced - readability. This may assist C++ compile times. This will not typically - change the ultimate model's performance, but may in some cases. + Alias for ``--decorations none``. .. option:: --default-language diff --git a/docs/guide/simulating.rst b/docs/guide/simulating.rst index c93decc04..023bf4aef 100644 --- a/docs/guide/simulating.rst +++ b/docs/guide/simulating.rst @@ -524,11 +524,16 @@ with: .. code-block:: bash + --decorations node -CFLAGS -ggdb -LDFLAGS -ggdb -CFLAGS -DVL_DEBUG=1 -CFLAGS -D_GLIBCXX_DEBUG -CFLAGS -fsanitize=address,undefined -LDFLAGS -fsanitize=address,undefined +The :vlopt:`--decorations node` option used here will add comments to the +Verilated C++ code to indicate what Verilog code was responsible, which may +assist debug readability. + The :vlopt:`-CFLAGS` and/or :vlopt:`-LDFLAGS` options used here pass the following argument into the generated Makefile for use as compiler or linker options respectively. If you are using your own Makefiles, adapt diff --git a/src/V3EmitCBase.cpp b/src/V3EmitCBase.cpp index 872af5e68..3c7ebc3d4 100644 --- a/src/V3EmitCBase.cpp +++ b/src/V3EmitCBase.cpp @@ -106,19 +106,19 @@ string EmitCBaseVisitorConst::cFuncArgs(const AstCFunc* nodep) { void EmitCBaseVisitorConst::emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp, bool withScope) { - if (funcp->slow()) puts("VL_ATTR_COLD "); + if (funcp->slow()) putns(funcp, "VL_ATTR_COLD "); if (!funcp->isConstructor() && !funcp->isDestructor()) { - puts(funcp->rtnTypeVoid()); + putns(funcp, funcp->rtnTypeVoid()); puts(" "); } if (withScope) { if (funcp->dpiExportDispatcher()) { - puts(topClassName() + "::"); + putns(funcp, topClassName() + "::"); } else if (funcp->isProperMethod()) { - puts(prefixNameProtect(modp) + "::"); + putns(funcp, prefixNameProtect(modp) + "::"); } } - puts(funcNameProtect(funcp, modp)); + putns(funcp, funcNameProtect(funcp, modp)); puts("(" + cFuncArgs(funcp) + ")"); if (funcp->isConst().trueKnown() && funcp->isProperMethod()) puts(" const"); } @@ -126,16 +126,16 @@ void EmitCBaseVisitorConst::emitCFuncHeader(const AstCFunc* funcp, const AstNode void EmitCBaseVisitorConst::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->ifdef().empty()) putns(funcp, "#ifdef " + funcp->ifdef() + "\n"); + if (cLinkage) putns(funcp, "extern \"C\" "); + if (funcp->isStatic() && funcp->isProperMethod()) putns(funcp, "static "); if (funcp->isVirtual()) { UASSERT_OBJ(funcp->isProperMethod(), funcp, "Virtual function is not a proper method"); - puts("virtual "); + putns(funcp, "virtual "); } emitCFuncHeader(funcp, modp, /* withScope: */ false); - puts(";\n"); - if (!funcp->ifdef().empty()) puts("#endif // " + funcp->ifdef() + "\n"); + putns(funcp, ";\n"); + if (!funcp->ifdef().empty()) putns(funcp, "#endif // " + funcp->ifdef() + "\n"); } void EmitCBaseVisitorConst::emitVarDecl(const AstVar* nodep, bool asRef) { @@ -146,21 +146,21 @@ void EmitCBaseVisitorConst::emitVarDecl(const AstVar* nodep, bool asRef) { // This isn't very robust and may need cleanup for other data types for (const AstUnpackArrayDType* arrayp = VN_CAST(nodep->dtypeSkipRefp(), UnpackArrayDType); arrayp; arrayp = VN_CAST(arrayp->subDTypep()->skipRefp(), UnpackArrayDType)) { - puts("[" + cvtToStr(arrayp->elementsConst()) + "]"); + putns(arrayp, "[" + cvtToStr(arrayp->elementsConst()) + "]"); } }; if (nodep->isIO() && nodep->isSc()) { UASSERT_OBJ(basicp, nodep, "Unimplemented: Outputting this data type"); if (nodep->attrScClocked() && nodep->isReadOnly()) { - puts("sc_core::sc_in_clk "); + putns(nodep, "sc_core::sc_in_clk "); } else { if (nodep->isInoutish()) { - puts("sc_core::sc_inout<"); + putns(nodep, "sc_core::sc_inout<"); } else if (nodep->isWritable()) { - puts("sc_core::sc_out<"); + putns(nodep, "sc_core::sc_out<"); } else if (nodep->isNonOutput()) { - puts("sc_core::sc_in<"); + putns(nodep, "sc_core::sc_in<"); } else { nodep->v3fatalSrc("Unknown type"); } @@ -168,20 +168,20 @@ void EmitCBaseVisitorConst::emitVarDecl(const AstVar* nodep, bool asRef) { puts("> "); } if (asRef) { - if (refNeedParens) puts("("); - puts("&"); + if (refNeedParens) putns(nodep, "("); + putns(nodep, "&"); } - puts(nodep->nameProtect()); + putns(nodep, nodep->nameProtect()); if (asRef && refNeedParens) { puts(")"); } emitDeclArrayBrackets(nodep); puts(";\n"); } else if (nodep->isIO() && basicp && !basicp->isOpaque()) { if (nodep->isInoutish()) { - puts("VL_INOUT"); + putns(nodep, "VL_INOUT"); } else if (nodep->isWritable()) { - puts("VL_OUT"); + putns(nodep, "VL_OUT"); } else if (nodep->isNonOutput()) { - puts("VL_IN"); + putns(nodep, "VL_IN"); } else { nodep->v3fatalSrc("Unknown type"); } @@ -221,7 +221,7 @@ void EmitCBaseVisitorConst::emitVarDecl(const AstVar* nodep, bool asRef) { && name.substr(name.size() - suffix.size()) == suffix; if (beStatic) puts("static thread_local "); } - puts(nodep->vlArgType(true, false, false, "", asRef)); + putns(nodep, nodep->vlArgType(true, false, false, "", asRef)); puts(";\n"); } } @@ -246,10 +246,10 @@ void EmitCBaseVisitorConst::emitTextSection(const AstNodeModule* modp, VNType ty if (nodep->type() == type) { if (last_line != nodep->fileline()->lineno()) { if (last_line < 0) { - puts("\n//*** Below code from `systemc in Verilog file\n"); + putns(nodep, "\n//*** Below code from `systemc in Verilog file\n"); } - putsDecoration( - ifNoProtect("// From `systemc at " + nodep->fileline()->ascii() + "\n")); + putsDecoration(nodep, ifNoProtect("// From `systemc at " + + nodep->fileline()->ascii() + "\n")); last_line = nodep->fileline()->lineno(); } ofp()->putsNoTracking(textp->text()); diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h index 595d007ac..9042c12c1 100644 --- a/src/V3EmitCBase.h +++ b/src/V3EmitCBase.h @@ -89,10 +89,12 @@ public: // METHODS V3OutCFile* ofp() const VL_MT_SAFE { return m_ofp; } void puts(const string& str) { ofp()->puts(str); } + void putns(const AstNode* nodep, const string& str) { ofp()->putns(nodep, str); } void putsHeader() { ofp()->putsHeader(); } void putbs(const string& str) { ofp()->putbs(str); } - void putsDecoration(const string& str) { - if (v3Global.opt.decoration()) puts(str); + void putnbs(const AstNode* nodep, const string& str) { ofp()->putnbs(nodep, str); } + void putsDecoration(const AstNode* nodep, const string& str) { + if (v3Global.opt.decoration()) putns(nodep, str); } void putsQuoted(const string& str) { ofp()->putsQuoted(str); } void ensureNewLine() { ofp()->ensureNewLine(); } diff --git a/src/V3EmitCConstInit.h b/src/V3EmitCConstInit.h index aa490e55f..5905ffc9d 100644 --- a/src/V3EmitCConstInit.h +++ b/src/V3EmitCConstInit.h @@ -60,7 +60,7 @@ protected: const auto& mapr = nodep->map(); for (const auto& itr : mapr) { if (comma++) putbs(",\n"); - puts(cvtToStr(itr.first)); + putns(nodep, cvtToStr(itr.first)); ofp()->printf("%" PRIx64 "ULL", itr.first); ofp()->putsNoTracking(":"); ofp()->putsNoTracking("{"); @@ -102,17 +102,17 @@ protected: UASSERT_OBJ(!num.isFourState(), nodep, "4-state value in constant pool"); const AstNodeDType* const dtypep = nodep->dtypep(); if (num.isNull()) { - puts("VlNull{}"); + putns(nodep, "VlNull{}"); } else if (num.isString()) { // Note: putsQuoted does not track indentation, so we use this instead - puts("\""); + putns(nodep, "\""); puts(num.toString()); puts("\""); } else if (dtypep->isWide()) { const uint32_t size = dtypep->widthWords(); // Note the double {{ initializer. The first { starts the initializer of the VlWide, // and the second starts the initializer of m_storage within the VlWide. - puts("{"); + putns(nodep, "{"); ofp()->putsNoTracking("{"); if (m_inUnpacked) puts(" // VlWide " + cvtToStr(m_unpackedWord)); puts("\n"); @@ -129,11 +129,13 @@ protected: = !m_inUnpacked && (static_cast(dnum) == dnum && -1000 < dnum && dnum < 1000) ? "%3.1f" // Force decimal point : "%.17e"; // %e always yields a float literal + putns(nodep, ""); ofp()->printf(fmt, dnum); } else if (dtypep->isQuad()) { const uint64_t qnum = static_cast(num.toUQuad()); const char* const fmt = !m_inUnpacked && (qnum < 10) ? ("%" PRIx64 "ULL") : ("0x%016" PRIx64 "ULL"); + putns(nodep, ""); ofp()->printf(fmt, qnum); } else { const uint32_t unum = num.toUInt(); @@ -141,6 +143,7 @@ protected: : (dtypep->widthMin() > 16) ? ("0x%08" PRIx32 "U") : (dtypep->widthMin() > 8) ? ("0x%04" PRIx32 "U") : ("0x%02" PRIx32 "U"); + putns(nodep, ""); ofp()->printf(fmt, unum); } } diff --git a/src/V3EmitCConstPool.cpp b/src/V3EmitCConstPool.cpp index 04c973fac..27313bacb 100644 --- a/src/V3EmitCConstPool.cpp +++ b/src/V3EmitCConstPool.cpp @@ -66,7 +66,7 @@ class EmitCConstPool final : public EmitCConstInit { void emitVars(const AstConstPool* poolp) { 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); } + if (const AstVar* const varp = VN_CAST(nodep, Var)) varps.push_back(varp); } if (varps.empty()) return; // Constant pool is empty, so we are done @@ -81,11 +81,11 @@ class EmitCConstPool final : public EmitCConstInit { maybeSplitCFile(); const string nameProtect = topClassName() + "__ConstPool__" + varp->nameProtect(); puts("\n"); - puts("extern const "); - puts(varp->dtypep()->cType(nameProtect, false, false)); - puts(" = "); + putns(varp, "extern const "); + putns(varp, varp->dtypep()->cType(nameProtect, false, false)); + putns(varp, " = "); iterateConst(varp->valuep()); - puts(";\n"); + putns(varp, ";\n"); // Keep track of stats if (VN_IS(varp->dtypep(), UnpackArrayDType)) { ++m_tablesEmitted; diff --git a/src/V3EmitCFunc.cpp b/src/V3EmitCFunc.cpp index d0e51630e..e7cae00a3 100644 --- a/src/V3EmitCFunc.cpp +++ b/src/V3EmitCFunc.cpp @@ -64,7 +64,7 @@ void EmitCFunc::emitOpName(AstNode* nodep, const string& format, AstNode* lhsp, } \ } while (false) - putbs(""); + putnbs(nodep, ""); for (string::const_iterator pos = format.begin(); pos != format.end(); ++pos) { if (pos[0] == ',') { // Remember we need to add one, but don't do yet to avoid ",)" @@ -106,7 +106,8 @@ void EmitCFunc::emitOpName(AstNode* nodep, const string& format, AstNode* lhsp, "Wide Op w/ no temp, perhaps missing op in V3EmitC?"); COMMA; if (!m_wideTempRefp->selfPointer().isEmpty()) { - emitDereference(m_wideTempRefp->selfPointerProtect(m_useSelfForThis)); + emitDereference(m_wideTempRefp, + m_wideTempRefp->selfPointerProtect(m_useSelfForThis)); } puts(m_wideTempRefp->varp()->nameProtect()); m_wideTempRefp = nullptr; @@ -170,13 +171,13 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) { bool isStmt = false; if (const AstFScanF* const dispp = VN_CAST(nodep, FScanF)) { isStmt = false; - puts("VL_FSCANF_IX("); + putns(nodep, "VL_FSCANF_IX("); iterateConst(dispp->filep()); puts(","); } else if (const AstSScanF* const dispp = VN_CAST(nodep, SScanF)) { isStmt = false; checkMaxWords(dispp->fromp()); - puts("VL_SSCANF_I"); + putns(nodep, "VL_SSCANF_I"); emitIQW(dispp->fromp()); puts("X("); puts(cvtToStr(dispp->fromp()->widthMin())); @@ -186,11 +187,11 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) { } else if (const AstDisplay* const dispp = VN_CAST(nodep, Display)) { isStmt = true; if (dispp->filep()) { - puts("VL_FWRITEF("); + putns(nodep, "VL_FWRITEF("); iterateConst(dispp->filep()); puts(","); } else { - puts("VL_WRITEF("); + putns(nodep, "VL_WRITEF("); } } else if (const AstSFormat* const dispp = VN_CAST(nodep, SFormat)) { isStmt = true; @@ -201,7 +202,7 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) { putbs(","); } else if (VN_IS(nodep, SFormatF)) { isStmt = false; - puts("VL_SFORMATF_NX("); + putns(nodep, "VL_SFORMATF_NX("); } else { nodep->v3fatalSrc("Unknown displayEmit node type"); } @@ -409,7 +410,7 @@ void EmitCFunc::displayNode(AstNode* nodep, AstScopeName* scopenamep, const stri void EmitCFunc::emitCCallArgs(const AstNodeCCall* nodep, const string& selfPointer, bool inProcess) { - puts("("); + putns(nodep, "("); bool comma = false; if (nodep->funcp()->isLoose() && !nodep->funcp()->isStatic()) { UASSERT_OBJ(!selfPointer.empty(), nodep, "Call to loose method without self pointer"); @@ -436,29 +437,29 @@ void EmitCFunc::emitCCallArgs(const AstNodeCCall* nodep, const string& selfPoint puts(")"); } -void EmitCFunc::emitDereference(const string& pointer) { +void EmitCFunc::emitDereference(AstNode* nodep, const string& pointer) { if (pointer[0] == '(' && pointer[1] == '&') { // remove "address of" followed by immediate dereference // Note: this relies on only the form '(&OBJECT)' being used by Verilator - puts(pointer.substr(2, pointer.length() - 3)); + putns(nodep, pointer.substr(2, pointer.length() - 3)); puts("."); } else { - puts(pointer); + putns(nodep, pointer); puts("->"); } } void EmitCFunc::emitCvtPackStr(AstNode* nodep) { if (const AstConst* const constp = VN_CAST(nodep, Const)) { - putbs("std::string{"); + putnbs(nodep, "std::string{"); putsQuoted(constp->num().toString()); puts("}"); } else if (VN_IS(nodep->dtypep(), StreamDType)) { - putbs("VL_CVT_PACK_STR_ND("); + putnbs(nodep, "VL_CVT_PACK_STR_ND("); iterateAndNextConstNull(nodep); puts(")"); } else { - putbs("VL_CVT_PACK_STR_N"); + putnbs(nodep, "VL_CVT_PACK_STR_N"); emitIQW(nodep); puts("("); if (nodep->isWide()) { @@ -472,7 +473,7 @@ void EmitCFunc::emitCvtPackStr(AstNode* nodep) { } void EmitCFunc::emitCvtWideArray(AstNode* nodep, AstNode* fromp) { - putbs("VL_CVT_W_A("); + putnbs(nodep, "VL_CVT_W_A("); iterateConst(nodep); puts(", "); iterateConst(fromp); @@ -482,12 +483,13 @@ void EmitCFunc::emitCvtWideArray(AstNode* nodep, AstNode* fromp) { void EmitCFunc::emitConstant(AstConst* nodep, AstVarRef* assigntop, const string& assignString) { // Put out constant set to the specified variable, or given variable in a string + putns(nodep, ""); if (nodep->num().isNull()) { - puts("VlNull{}"); + putns(nodep, "VlNull{}"); } else if (nodep->num().isFourState()) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: 4-state numbers in this context"); } else if (nodep->num().isString()) { - putbs("std::string{"); + putnbs(nodep, "std::string{"); putsQuoted(nodep->num().toString()); puts("}"); } else if (nodep->isWide()) { @@ -501,14 +503,14 @@ void EmitCFunc::emitConstant(AstConst* nodep, AstVarRef* assigntop, const string } { // Upper e.g. 8 words if (chunks) { - putbs("VL_CONSTHI_W_"); + putnbs(nodep, "VL_CONSTHI_W_"); puts(cvtToStr(VL_WORDS_I(upWidth))); puts("X("); puts(cvtToStr(nodep->widthMin())); puts(","); puts(cvtToStr(chunks * EMITC_NUM_CONSTW * VL_EDATASIZE)); } else { - putbs("VL_CONST_W_"); + putnbs(nodep, "VL_CONST_W_"); puts(cvtToStr(VL_WORDS_I(upWidth))); puts("X("); puts(cvtToStr(nodep->widthMin())); @@ -518,7 +520,7 @@ void EmitCFunc::emitConstant(AstConst* nodep, AstVarRef* assigntop, const string puts(assignString); } else { if (!assigntop->selfPointer().isEmpty()) { - emitDereference(assigntop->selfPointerProtect(m_useSelfForThis)); + emitDereference(assigntop, assigntop->selfPointerProtect(m_useSelfForThis)); } puts(assigntop->varp()->nameProtect()); } @@ -540,7 +542,7 @@ void EmitCFunc::emitConstant(AstConst* nodep, AstVarRef* assigntop, const string puts(assignString); } else { if (!assigntop->selfPointer().isEmpty()) { - emitDereference(assigntop->selfPointerProtect(m_useSelfForThis)); + emitDereference(assigntop, assigntop->selfPointerProtect(m_useSelfForThis)); } puts(assigntop->varp()->nameProtect()); } @@ -648,7 +650,7 @@ void EmitCFunc::emitVarReset(AstVar* varp) { varp->v3fatalSrc("InitArray under non-arrayed var"); } } else { - puts(emitVarResetRecurse(varp, varNameProtected, dtypep, 0, "")); + putns(varp, emitVarResetRecurse(varp, varNameProtected, dtypep, 0, "")); } } diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 791621089..3ff35f13f 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -65,7 +65,7 @@ class EmitCLazyDecls final : public VNVisitorConst { if (!declaredOnce(varp)) return; // Already declared const string nameProtect = m_emitter.topClassName() + "__ConstPool__" + varp->nameProtect(); - m_emitter.puts("extern const "); + m_emitter.putns(varp, "extern const "); m_emitter.puts(varp->dtypep()->cType(nameProtect, false, false)); m_emitter.puts(";\n"); m_needsBlankLine = true; @@ -205,7 +205,7 @@ public: void emitOpName(AstNode* nodep, const string& format, AstNode* lhsp, AstNode* rhsp, AstNode* thsp); void emitCCallArgs(const AstNodeCCall* nodep, const string& selfPointer, bool inProcess); - void emitDereference(const string& pointer); + void emitDereference(AstNode* nodep, const string& pointer); void emitCvtPackStr(AstNode* nodep); void emitCvtWideArray(AstNode* nodep, AstNode* fromp); void emitConstant(AstConst* nodep, AstVarRef* assigntop, const string& assignString); @@ -290,8 +290,8 @@ public: puts("\n"); m_lazyDecls.emit(nodep); - if (nodep->ifdef() != "") puts("#ifdef " + nodep->ifdef() + "\n"); - if (nodep->isInline()) puts("VL_INLINE_OPT "); + if (nodep->ifdef() != "") putns(nodep, "#ifdef " + nodep->ifdef() + "\n"); + if (nodep->isInline()) putns(nodep, "VL_INLINE_OPT "); emitCFuncHeader(nodep, m_modp, /* withScope: */ true); if (nodep->isConstructor()) { @@ -344,17 +344,17 @@ public: } if (nodep->initsp()) { - putsDecoration("// Init\n"); + putsDecoration(nodep, "// Init\n"); iterateAndNextConstNull(nodep->initsp()); } if (nodep->stmtsp()) { - putsDecoration("// Body\n"); + putsDecoration(nodep, "// Body\n"); iterateAndNextConstNull(nodep->stmtsp()); } if (nodep->finalsp()) { - putsDecoration("// Final\n"); + putsDecoration(nodep, "// Final\n"); iterateAndNextConstNull(nodep->finalsp()); } @@ -368,15 +368,15 @@ public: } void visit(AstCvtDynArrayToPacked* nodep) override { - puts("VL_DYN_TO_"); + putns(nodep, "VL_DYN_TO_"); emitIQW(nodep); - puts("<"); const AstNodeDType* const elemDTypep = nodep->fromp()->dtypep()->subDTypep(); + putns(elemDTypep, "<"); putbs(elemDTypep->cType("", false, false)); puts(">("); iterateAndNextConstNull(nodep->fromp()); puts(", "); - puts(cvtToStr(elemDTypep->widthMin())); + putns(elemDTypep, cvtToStr(elemDTypep->widthMin())); puts(")"); } @@ -386,7 +386,7 @@ public: bool rhs = true; if (AstSel* const selp = VN_CAST(nodep->lhsp(), Sel)) { if (selp->widthMin() == 1) { - putbs("VL_ASSIGNBIT_"); + putnbs(nodep, "VL_ASSIGNBIT_"); emitIQW(selp->fromp()); if (nodep->rhsp()->isAllOnesV()) { puts("O("); @@ -399,11 +399,11 @@ public: iterateAndNextConstNull(selp->fromp()); if (rhs) puts(", "); } else { - putbs("VL_ASSIGNSEL_"); + putnbs(nodep, "VL_ASSIGNSEL_"); emitIQW(selp->fromp()); emitIQW(nodep->rhsp()); puts("("); - puts(cvtToStr(selp->fromp()->widthMin()) + ","); + putns(selp->fromp(), cvtToStr(selp->fromp()->widthMin()) + ","); puts(cvtToStr(nodep->widthMin()) + ","); iterateAndNextConstNull(selp->lsbp()); puts(", "); @@ -413,13 +413,13 @@ public: } else if (const AstGetcRefN* const selp = VN_CAST(nodep->lhsp(), GetcRefN)) { iterateAndNextConstNull(selp->lhsp()); puts(" = "); - putbs("VL_PUTC_N("); + putnbs(selp, "VL_PUTC_N("); iterateAndNextConstNull(selp->lhsp()); puts(", "); iterateAndNextConstNull(selp->rhsp()); puts(", "); } else if (AstVar* const varp = AstVar::scVarRecurse(nodep->lhsp())) { - putbs("VL_ASSIGN_"); // Set a systemC variable + putnbs(varp, "VL_ASSIGN_"); // Set a systemC variable emitScIQW(varp); emitIQW(nodep); puts("("); @@ -427,7 +427,7 @@ public: iterateAndNextConstNull(nodep->lhsp()); puts(", "); } else if (AstVar* const varp = AstVar::scVarRecurse(nodep->rhsp())) { - putbs("VL_ASSIGN_"); // Get a systemC variable + putnbs(varp, "VL_ASSIGN_"); // Get a systemC variable emitIQW(nodep); emitScIQW(varp); puts("("); @@ -436,12 +436,12 @@ public: puts(", "); } else if (const AstCvtPackedToDynArray* const castp = VN_CAST(nodep->rhsp(), CvtPackedToDynArray)) { - puts("VL_ASSIGN_DYN_Q<"); + putns(castp, "VL_ASSIGN_DYN_Q<"); putbs(castp->dtypep()->subDTypep()->cType("", false, false)); puts(">("); iterateAndNextConstNull(nodep->lhsp()); puts(", "); - puts(cvtToStr(castp->dtypep()->subDTypep()->widthMin())); + putns(castp->dtypep(), cvtToStr(castp->dtypep()->subDTypep()->widthMin())); puts(", "); puts(cvtToStr(castp->fromp()->widthMin())); puts(", "); @@ -460,7 +460,7 @@ public: m_wideTempRefp = VN_AS(nodep->lhsp(), VarRef); paren = false; } else if (nodep->isWide() && !VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType)) { - putbs("VL_ASSIGN_W("); + putnbs(nodep, "VL_ASSIGN_W("); puts(cvtToStr(nodep->widthMin()) + ","); iterateAndNextConstNull(nodep->lhsp()); puts(", "); @@ -471,7 +471,7 @@ public: ofp()->blockInc(); decind = true; if (!VN_IS(nodep->rhsp(), Const)) ofp()->putBreak(); - puts("= "); + putns(nodep, "= "); } if (rhs) iterateAndNextConstNull(nodep->rhsp()); if (paren) puts(")"); @@ -481,7 +481,7 @@ public: void visit(AstAlwaysPublic*) override {} void visit(AstAssocSel* nodep) override { iterateAndNextConstNull(nodep->fromp()); - putbs(".at("); + putnbs(nodep, ".at("); AstAssocArrayDType* const adtypep = VN_AS(nodep->fromp()->dtypep()->skipRefp(), AssocArrayDType); UASSERT_OBJ(adtypep, nodep, "Associative select on non-associative type"); @@ -490,7 +490,7 @@ public: } void visit(AstWildcardSel* nodep) override { iterateAndNextConstNull(nodep->fromp()); - putbs(".at("); + putnbs(nodep, ".at("); AstWildcardArrayDType* const adtypep = VN_AS(nodep->fromp()->dtypep()->skipRefp(), WildcardArrayDType); UASSERT_OBJ(adtypep, nodep, "Wildcard select on non-wildcard-associative type"); @@ -500,26 +500,27 @@ public: void visit(AstCCall* nodep) override { const AstCFunc* const funcp = nodep->funcp(); const AstNodeModule* const funcModp = EmitCParentModule::get(funcp); + putnbs(nodep, ""); if (funcp->dpiImportPrototype()) { // Calling DPI import - puts(funcp->name()); + putns(nodep, funcp->name()); } else if (funcp->isProperMethod() && funcp->isStatic()) { // Call static method via the containing class - puts(prefixNameProtect(funcModp) + "::"); - puts(funcp->nameProtect()); + putns(funcModp, prefixNameProtect(funcModp) + "::"); + putns(nodep, funcp->nameProtect()); } else if (nodep->superReference()) { // Calling superclass method - puts(prefixNameProtect(funcModp) + "::"); - puts(funcp->nameProtect()); + putns(funcModp, prefixNameProtect(funcModp) + "::"); + putns(nodep, funcp->nameProtect()); } else if (funcp->isLoose()) { // Calling loose method - puts(funcNameProtect(funcp)); + putns(nodep, funcNameProtect(funcp)); } else { // Calling regular method/function if (!nodep->selfPointer().isEmpty()) { - emitDereference(nodep->selfPointerProtect(m_useSelfForThis)); + emitDereference(nodep, nodep->selfPointerProtect(m_useSelfForThis)); } - puts(funcp->nameProtect()); + putns(nodep, funcp->nameProtect()); } emitCCallArgs(nodep, nodep->selfPointerProtect(m_useSelfForThis), m_cfuncp->needProcess()); } @@ -527,12 +528,12 @@ public: const AstCFunc* const funcp = nodep->funcp(); UASSERT_OBJ(!funcp->isLoose(), nodep, "Loose method called via AstCMethodCall"); iterateConst(nodep->fromp()); - putbs("->"); - puts(funcp->nameProtect()); + putnbs(nodep, "->"); + putns(funcp, funcp->nameProtect()); emitCCallArgs(nodep, "", m_cfuncp->needProcess()); } void visit(AstCAwait* nodep) override { - puts("co_await "); + putns(nodep, "co_await "); iterateConst(nodep->exprp()); } void visit(AstCNew* nodep) override { @@ -541,15 +542,15 @@ public: return; } // assignment case; - puts("VL_NEW(" + prefixNameProtect(nodep->dtypep()) + ", " - + optionalProcArg(nodep->dtypep()) + "vlSymsp"); + putns(nodep, "VL_NEW(" + prefixNameProtect(nodep->dtypep()) + ", " + + optionalProcArg(nodep->dtypep()) + "vlSymsp"); putCommaIterateNext(nodep->argsp(), true); puts(")"); } void visit(AstCMethodHard* nodep) override { iterateConst(nodep->fromp()); - puts("."); - puts(nodep->name()); + putns(nodep, "."); + putns(nodep, nodep->name()); puts("("); bool comma = false; for (AstNode* subnodep = nodep->pinsp(); subnodep; subnodep = subnodep->nextp()) { @@ -567,13 +568,13 @@ public: void visit(AstLambdaArgRef* nodep) override { putbs(nodep->nameProtect()); } void visit(AstWith* nodep) override { // With uses a C++11 lambda - putbs("[&]("); + putnbs(nodep, "[&]("); if (auto* const argrefp = nodep->indexArgRefp()) { - putbs(argrefp->dtypep()->cType(argrefp->nameProtect(), false, false)); + putnbs(argrefp, argrefp->dtypep()->cType(argrefp->nameProtect(), false, false)); puts(","); } if (auto* const argrefp = nodep->valueArgRefp()) { - putbs(argrefp->dtypep()->cType(argrefp->nameProtect(), false, false)); + putnbs(argrefp, argrefp->dtypep()->cType(argrefp->nameProtect(), false, false)); } puts(") {\n"); iterateAndNextConstNull(nodep->exprp()); @@ -591,12 +592,12 @@ public: if (!v3Global.opt.protectIds()) return; } if (!(nodep->protect() && v3Global.opt.protectIds())) { - putsDecoration(string{"// "} + nodep->name() + at + "\n"); + putsDecoration(nodep, string{"// "} + nodep->name() + at + "\n"); } iterateChildrenConst(nodep); } void visit(AstCoverDecl* nodep) override { - puts("vlSelf->__vlCoverInsert("); // As Declared in emitCoverageDecl + putns(nodep, "vlSelf->__vlCoverInsert("); // As Declared in emitCoverageDecl puts("&(vlSymsp->__Vcoverage["); puts(cvtToStr(nodep->dataDeclThisp()->binNum())); puts("])"); @@ -625,18 +626,18 @@ public: } void visit(AstCoverInc* nodep) override { if (v3Global.opt.threads() > 1) { - puts("vlSymsp->__Vcoverage["); + putns(nodep, "vlSymsp->__Vcoverage["); puts(cvtToStr(nodep->declp()->dataDeclThisp()->binNum())); puts("].fetch_add(1, std::memory_order_relaxed);\n"); } else { - puts("++(vlSymsp->__Vcoverage["); + putns(nodep, "++(vlSymsp->__Vcoverage["); puts(cvtToStr(nodep->declp()->dataDeclThisp()->binNum())); puts("]);\n"); } } - void visit(AstDisableFork* nodep) override { puts("vlProcess->disableFork();\n"); } + void visit(AstDisableFork* nodep) override { putns(nodep, "vlProcess->disableFork();\n"); } void visit(AstCReturn* nodep) override { - puts("return ("); + putns(nodep, "return ("); iterateAndNextConstNull(nodep->lhsp()); puts(");\n"); } @@ -648,16 +649,16 @@ public: void visit(AstDumpCtl* nodep) override { switch (nodep->ctlType()) { case VDumpCtlType::FILE: - puts("vlSymsp->_vm_contextp__->dumpfile("); + putns(nodep, "vlSymsp->_vm_contextp__->dumpfile("); emitCvtPackStr(nodep->exprp()); puts(");\n"); break; case VDumpCtlType::VARS: // We ignore number of levels to dump in exprp() if (v3Global.opt.trace()) { - puts("vlSymsp->_traceDumpOpen();\n"); + putns(nodep, "vlSymsp->_traceDumpOpen();\n"); } else { - puts("VL_PRINTF_MT(\"-Info: "); + putns(nodep, "VL_PRINTF_MT(\"-Info: "); puts(V3OutFormatter::quoteNameControls(protect(nodep->fileline()->filename()))); puts(":"); puts(cvtToStr(nodep->fileline()->lineno())); @@ -690,7 +691,7 @@ public: if (!nodep->dpiExport()) { // this is where the DPI import context scope is set const string scope = nodep->scopeDpiName(); - putbs("(&(vlSymsp->" + protect("__Vscope_" + scope) + "))"); + putnbs(nodep, "(&(vlSymsp->" + protect("__Vscope_" + scope) + "))"); } } void visit(AstSFormat* nodep) override { @@ -707,7 +708,7 @@ public: displayNode(nodep, nullptr, nodep->text(), nodep->exprsp(), true); } void visit(AstValuePlusArgs* nodep) override { - puts("VL_VALUEPLUSARGS_IN"); + putns(nodep, "VL_VALUEPLUSARGS_IN"); emitIQW(nodep->outp()); puts("("); puts(cvtToStr(nodep->outp()->widthMin())); @@ -719,12 +720,12 @@ public: puts(")"); } void visit(AstTestPlusArgs* nodep) override { - puts("VL_TESTPLUSARGS_I("); + putns(nodep, "VL_TESTPLUSARGS_I("); emitCvtPackStr(nodep->searchp()); puts(")"); } void visit(AstFError* nodep) override { - puts("VL_FERROR_I"); + putns(nodep, "VL_FERROR_I"); puts(nodep->strp()->isString() ? "N(" : "W("); iterateAndNextConstNull(nodep->filep()); putbs(", "); @@ -749,7 +750,7 @@ public: } } void visit(AstFOpen* nodep) override { - puts("VL_FOPEN_NN("); + putns(nodep, "VL_FOPEN_NN("); emitCvtPackStr(nodep->filenamep()); putbs(", "); if (nodep->modep()->width() > 4 * 8) @@ -758,12 +759,12 @@ public: puts(");\n"); } void visit(AstFOpenMcd* nodep) override { - puts("VL_FOPEN_MCD_N("); + putns(nodep, "VL_FOPEN_MCD_N("); emitCvtPackStr(nodep->filenamep()); puts(");\n"); } void visit(AstNodeReadWriteMem* nodep) override { - puts(nodep->cFuncPrefixp()); + putns(nodep, nodep->cFuncPrefixp()); puts("N("); puts(nodep->isHex() ? "true" : "false"); putbs(", "); @@ -812,23 +813,24 @@ public: puts(");\n"); } void visit(AstFClose* nodep) override { - puts("VL_FCLOSE_I("); + putns(nodep, "VL_FCLOSE_I("); iterateAndNextConstNull(nodep->filep()); puts("); "); } void visit(AstFFlush* nodep) override { if (!nodep->filep()) { - puts("Verilated::runFlushCallbacks();\n"); + putns(nodep, "Verilated::runFlushCallbacks();\n"); } else { - puts("if ("); + putns(nodep, "if ("); iterateAndNextConstNull(nodep->filep()); - puts(") { VL_FFLUSH_I("); + puts(") { "); + putns(nodep, "VL_FFLUSH_I("); iterateAndNextConstNull(nodep->filep()); puts("); }\n"); } } void visit(AstFSeek* nodep) override { - puts("(VL_FSEEK_I("); + putns(nodep, "(VL_FSEEK_I("); iterateAndNextConstNull(nodep->filep()); puts(","); iterateAndNextConstNull(nodep->offset()); @@ -837,17 +839,17 @@ public: puts(") == -1 ? -1 : 0)"); } void visit(AstFTell* nodep) override { - puts("VL_FTELL_I("); + putns(nodep, "VL_FTELL_I("); iterateAndNextConstNull(nodep->filep()); puts(")"); } void visit(AstFRewind* nodep) override { - puts("(VL_FSEEK_I("); + putns(nodep, "(VL_FSEEK_I("); iterateAndNextConstNull(nodep->filep()); puts(", 0, 0) == -1 ? -1 : 0)"); } void visit(AstFRead* nodep) override { - puts("VL_FREAD_I("); + putns(nodep, "VL_FREAD_I("); puts(cvtToStr(nodep->memp()->widthMin())); // Need real storage width putbs(","); uint32_t array_lo = 0; @@ -890,14 +892,14 @@ public: puts(")"); } void visit(AstSysFuncAsTask* nodep) override { - if (!nodep->lhsp()->isWide()) puts("(void)"); + if (!nodep->lhsp()->isWide()) putns(nodep, "(void)"); iterateAndNextConstNull(nodep->lhsp()); - if (!nodep->lhsp()->isWide()) puts(";\n"); + if (!nodep->lhsp()->isWide()) putns(nodep, ";\n"); } - void visit(AstStackTraceF* nodep) override { puts("VL_STACKTRACE_N()"); } - void visit(AstStackTraceT* nodep) override { puts("VL_STACKTRACE();\n"); } + void visit(AstStackTraceF* nodep) override { putns(nodep, "VL_STACKTRACE_N()"); } + void visit(AstStackTraceT* nodep) override { putns(nodep, "VL_STACKTRACE();\n"); } void visit(AstSystemT* nodep) override { - puts("(void)VL_SYSTEM_I"); + putns(nodep, "(void)VL_SYSTEM_I"); emitIQW(nodep->lhsp()); puts("("); if (nodep->lhsp()->isWide()) { @@ -909,7 +911,7 @@ public: puts(");\n"); } void visit(AstSystemF* nodep) override { - puts("VL_SYSTEM_I"); + putns(nodep, "VL_SYSTEM_I"); emitIQW(nodep->lhsp()); puts("("); if (nodep->lhsp()->isWide()) { @@ -920,31 +922,32 @@ public: iterateAndNextConstNull(nodep->lhsp()); puts(")"); } - void visit(AstStmtExpr* node) override { - iterateConst(node->exprp()); + void visit(AstStmtExpr* nodep) override { + putns(nodep, ""); + iterateConst(nodep->exprp()); puts(";\n"); } void visit(AstJumpBlock* nodep) override { nodep->labelNum(++m_labelNum); - puts("{\n"); // Make it visually obvious label jumps outside these + putns(nodep, "{\n"); // Make it visually obvious label jumps outside these iterateAndNextConstNull(nodep->stmtsp()); iterateAndNextConstNull(nodep->endStmtsp()); puts("}\n"); } void visit(AstCLocalScope* nodep) override { - puts("{\n"); + putns(nodep, "{\n"); iterateAndNextConstNull(nodep->stmtsp()); puts("}\n"); } void visit(AstJumpGo* nodep) override { - puts("goto __Vlabel" + cvtToStr(nodep->labelp()->blockp()->labelNum()) + ";\n"); + putns(nodep, "goto __Vlabel" + cvtToStr(nodep->labelp()->blockp()->labelNum()) + ";\n"); } void visit(AstJumpLabel* nodep) override { - puts("__Vlabel" + cvtToStr(nodep->blockp()->labelNum()) + ": ;\n"); + putns(nodep, "__Vlabel" + cvtToStr(nodep->blockp()->labelNum()) + ": ;\n"); } void visit(AstWhile* nodep) override { iterateAndNextConstNull(nodep->precondsp()); - puts("while ("); + putns(nodep, "while ("); iterateAndNextConstNull(nodep->condp()); puts(") {\n"); iterateAndNextConstNull(nodep->stmtsp()); @@ -953,7 +956,7 @@ public: puts("}\n"); } void visit(AstNodeIf* nodep) override { - puts("if ("); + putns(nodep, "if ("); if (!nodep->branchPred().unknown()) { puts(nodep->branchPred().ascii()); puts("("); @@ -979,14 +982,14 @@ public: void visit(AstExprStmt* nodep) override { // GCC allows compound statements in expressions, but this is not standard. // So we use an immediate-evaluation lambda and comma operator - putbs("([&]() {\n"); + putnbs(nodep, "([&]() {\n"); iterateAndNextConstNull(nodep->stmtsp()); puts("}(), "); iterateAndNextConstNull(nodep->resultp()); puts(")"); } void visit(AstStop* nodep) override { - puts("VL_STOP_MT("); + putns(nodep, "VL_STOP_MT("); putsQuoted(protect(nodep->fileline()->filename())); puts(", "); puts(cvtToStr(nodep->fileline()->lineno())); @@ -994,14 +997,14 @@ public: puts(");\n"); } void visit(AstFinish* nodep) override { - puts("VL_FINISH_MT("); + putns(nodep, "VL_FINISH_MT("); putsQuoted(protect(nodep->fileline()->filename())); puts(", "); puts(cvtToStr(nodep->fileline()->lineno())); puts(", \"\");\n"); } void visit(AstPrintTimeScale* nodep) override { - puts("VL_PRINTTIMESCALE("); + putns(nodep, "VL_PRINTTIMESCALE("); putsQuoted(protect(nodep->prettyName())); puts(", "); putsQuoted(nodep->timeunit().ascii()); @@ -1014,21 +1017,21 @@ public: emitOpName(nodep, nodep->emitC(), nullptr, nullptr, nullptr); } void visit(AstTime* nodep) override { - puts("VL_TIME_UNITED_Q("); + putns(nodep, "VL_TIME_UNITED_Q("); UASSERT_OBJ(!nodep->timeunit().isNone(), nodep, "$time has no units"); puts(cvtToStr(nodep->timeunit().multiplier() / v3Global.rootp()->timeprecision().multiplier())); puts(")"); } void visit(AstTimeD* nodep) override { - puts("VL_TIME_UNITED_D("); + putns(nodep, "VL_TIME_UNITED_D("); UASSERT_OBJ(!nodep->timeunit().isNone(), nodep, "$realtime has no units"); puts(cvtToStr(nodep->timeunit().multiplier() / v3Global.rootp()->timeprecision().multiplier())); puts(")"); } void visit(AstTimeFormat* nodep) override { - puts("VL_TIMEFORMAT_IINI("); + putns(nodep, "VL_TIMEFORMAT_IINI("); iterateAndNextConstNull(nodep->unitsp()); puts(", "); iterateAndNextConstNull(nodep->precisionp()); @@ -1039,7 +1042,7 @@ public: puts(", vlSymsp->_vm_contextp__);\n"); } void visit(AstTimePrecision* nodep) override { - puts("vlSymsp->_vm_contextp__->timeprecision()"); + putns(nodep, "vlSymsp->_vm_contextp__->timeprecision()"); } void visit(AstNodeSimpleText* nodep) override { const string text = m_inUC && m_useSelfForThis @@ -1059,17 +1062,19 @@ public: } } void visit(AstCStmt* nodep) override { - putbs(""); + putnbs(nodep, ""); iterateAndNextConstNull(nodep->exprsp()); } void visit(AstCExpr* nodep) override { - putbs(""); + putnbs(nodep, ""); iterateAndNextConstNull(nodep->exprsp()); } void visit(AstUCStmt* nodep) override { VL_RESTORER(m_inUC); m_inUC = true; - putsDecoration(ifNoProtect("// $c statement at " + nodep->fileline()->ascii() + "\n")); + putnbs(nodep, ""); + putsDecoration(nodep, + ifNoProtect("// $c statement at " + nodep->fileline()->ascii() + "\n")); iterateAndNextConstNull(nodep->exprsp()); puts("\n"); } @@ -1077,7 +1082,9 @@ public: VL_RESTORER(m_inUC); m_inUC = true; puts("\n"); - putsDecoration(ifNoProtect("// $c function at " + nodep->fileline()->ascii() + "\n")); + putnbs(nodep, ""); + putsDecoration(nodep, + ifNoProtect("// $c function at " + nodep->fileline()->ascii() + "\n")); iterateAndNextConstNull(nodep->exprsp()); puts("\n"); } @@ -1097,7 +1104,7 @@ public: << " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); } if (emitSimpleOk(nodep)) { - putbs("("); + putnbs(nodep, "("); puts(nodep->emitSimpleOperator()); puts(" "); iterateAndNextConstNull(nodep->lhsp()); @@ -1115,7 +1122,7 @@ public: << " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); } if (emitSimpleOk(nodep)) { - putbs("("); + putnbs(nodep, "("); iterateAndNextConstNull(nodep->lhsp()); puts(" "); putbs(nodep->emitSimpleOperator()); @@ -1140,7 +1147,7 @@ public: : nodep->lhsp()->dtypep()->widthPow2(); UASSERT_OBJ(widthPow2 > 1, nodep, "Reduction over single bit value should have been folded"); - putbs("VL_REDXOR_"); + putnbs(nodep, "VL_REDXOR_"); puts(cvtToStr(widthPow2)); puts("("); iterateAndNextConstNull(nodep->lhsp()); @@ -1150,15 +1157,15 @@ public: void visit(AstCCast* nodep) override { // Extending a value of the same word width is just a NOP. if (const AstClassRefDType* const classDtypep = VN_CAST(nodep->dtypep(), ClassRefDType)) { - puts("(" + classDtypep->cType("", false, false) + ")("); + putns(nodep, "(" + classDtypep->cType("", false, false) + ")("); } else if (nodep->size() <= VL_BYTESIZE) { - puts("(CData)("); + putns(nodep, "(CData)("); } else if (nodep->size() <= VL_SHORTSIZE) { - puts("(SData)("); + putns(nodep, "(SData)("); } else if (nodep->size() <= VL_IDATASIZE) { - puts("(IData)("); + putns(nodep, "(IData)("); } else { - puts("(QData)("); + putns(nodep, "(QData)("); } iterateAndNextConstNull(nodep->lhsp()); puts(")"); @@ -1168,7 +1175,7 @@ public: if (nodep->thenp()->isWide()) { emitOpName(nodep, nodep->emitC(), nodep->condp(), nodep->thenp(), nodep->elsep()); } else { - putbs("("); + putnbs(nodep, "("); iterateAndNextConstNull(nodep->condp()); putbs(" ? "); iterateAndNextConstNull(nodep->thenp()); @@ -1179,16 +1186,16 @@ public: } void visit(AstMemberSel* nodep) override { iterateAndNextConstNull(nodep->fromp()); - putbs("->"); + putnbs(nodep, "->"); puts(nodep->varp()->nameProtect()); } void visit(AstStructSel* nodep) override { iterateAndNextConstNull(nodep->fromp()); - putbs("."); + putnbs(nodep, "."); puts(nodep->nameProtect()); } void visit(AstNullCheck* nodep) override { - puts("VL_NULL_CHECK("); + putns(nodep, "VL_NULL_CHECK("); iterateAndNextConstNull(nodep->lhsp()); puts(", "); putsQuoted(protect(nodep->fileline()->filename())); @@ -1197,8 +1204,8 @@ public: puts(")"); } void visit(AstNewCopy* nodep) override { - puts("VL_NEW(" + prefixNameProtect(nodep->dtypep()) + ", " - + optionalProcArg(nodep->dtypep())); + putns(nodep, "VL_NEW(" + prefixNameProtect(nodep->dtypep()) + ", " + + optionalProcArg(nodep->dtypep())); puts("*"); // i.e. make into a reference iterateAndNextConstNull(nodep->rhsp()); puts(")"); @@ -1213,7 +1220,7 @@ public: * nodep->srcp()->widthMin()) == nodep->widthMin(), nodep, "Replicate non-constant or width miscomputed"); - puts("VL_REPLICATE_"); + putns(nodep, "VL_REPLICATE_"); emitIQW(nodep); puts("OI("); if (nodep->srcp()) puts(cvtToStr(nodep->srcp()->widthMin())); @@ -1232,7 +1239,7 @@ public: const uint32_t isPow2 = VN_AS(nodep->rhsp(), Const)->num().countOnes() == 1; const uint32_t sliceSize = VN_AS(nodep->rhsp(), Const)->toUInt(); if (isPow2 && sliceSize <= (nodep->isQuad() ? sizeof(uint64_t) : sizeof(uint32_t))) { - puts("VL_STREAML_FAST_"); + putns(nodep, "VL_STREAML_FAST_"); emitIQW(nodep); emitIQW(nodep->lhsp()); puts("I("); @@ -1249,14 +1256,14 @@ public: nullptr); } void visit(AstCastDynamic* nodep) override { - putbs("VL_CAST_DYNAMIC("); + putnbs(nodep, "VL_CAST_DYNAMIC("); iterateAndNextConstNull(nodep->fromp()); puts(", "); iterateAndNextConstNull(nodep->top()); puts(")"); } void visit(AstCountBits* nodep) override { - putbs("VL_COUNTBITS_"); + putnbs(nodep, "VL_COUNTBITS_"); emitIQW(nodep->lhsp()); puts("("); puts(cvtToStr(nodep->lhsp()->widthMin())); @@ -1282,26 +1289,26 @@ public: const AstNodeModule* const varModp = EmitCParentModule::get(varp); if (isConstPoolMod(varModp)) { // Reference to constant pool variable - puts(topClassName() + "__ConstPool__"); + putns(nodep, topClassName() + "__ConstPool__"); } else if (varp->isStatic()) { // Access static variable via the containing class - puts(prefixNameProtect(varModp) + "::"); + putns(nodep, prefixNameProtect(varModp) + "::"); } else if (VN_IS(varModp, Class) && varModp != m_modp) { // Superclass member reference - puts(prefixNameProtect(varModp) + "::"); + putns(nodep, prefixNameProtect(varModp) + "::"); } else if (varp->isIfaceRef()) { - puts(nodep->selfPointerProtect(m_useSelfForThis)); + putns(nodep, nodep->selfPointerProtect(m_useSelfForThis)); return; } else if (!nodep->selfPointer().isEmpty()) { - emitDereference(nodep->selfPointerProtect(m_useSelfForThis)); + emitDereference(nodep, nodep->selfPointerProtect(m_useSelfForThis)); } - puts(nodep->varp()->nameProtect()); + putns(nodep, nodep->varp()->nameProtect()); } void visit(AstAddrOfCFunc* nodep) override { // Note: Can be thought to handle more, but this is all that is needed right now const AstCFunc* const funcp = nodep->funcp(); UASSERT_OBJ(funcp->isLoose(), nodep, "Cannot take address of non-loose method"); - puts("&"); + putns(nodep, "&"); puts(funcNameProtect(funcp)); } void visit(AstConst* nodep) override { @@ -1316,7 +1323,7 @@ public: } } void visit(AstThisRef* nodep) override { - putbs(nodep->dtypep()->cType("", false, false)); + putnbs(nodep, nodep->dtypep()->cType("", false, false)); puts("{"); puts(m_useSelfForThis ? "vlSelf" : "this"); puts("}"); @@ -1329,7 +1336,7 @@ public: iterateChildrenConst(nodep); } void visit(AstConsAssoc* nodep) override { - putbs(nodep->dtypep()->cType("", false, false)); + putnbs(nodep, nodep->dtypep()->cType("", false, false)); puts("()"); if (nodep->defaultp()) { putbs(".setDefault("); @@ -1339,7 +1346,7 @@ public: } void visit(AstSetAssoc* nodep) override { iterateAndNextConstNull(nodep->lhsp()); - putbs(".set("); + putnbs(nodep, ".set("); iterateAndNextConstNull(nodep->keyp()); puts(", "); putbs(""); @@ -1347,7 +1354,7 @@ public: puts(")"); } void visit(AstConsWildcard* nodep) override { - putbs(nodep->dtypep()->cType("", false, false)); + putnbs(nodep, nodep->dtypep()->cType("", false, false)); puts("()"); if (nodep->defaultp()) { putbs(".setDefault("); @@ -1357,7 +1364,7 @@ public: } void visit(AstSetWildcard* nodep) override { iterateAndNextConstNull(nodep->lhsp()); - putbs(".set("); + putnbs(nodep, ".set("); iterateAndNextConstNull(nodep->keyp()); puts(", "); putbs(""); @@ -1365,11 +1372,11 @@ public: puts(")"); } void visit(AstConsDynArray* nodep) override { - putbs(nodep->dtypep()->cType("", false, false)); + putnbs(nodep, nodep->dtypep()->cType("", false, false)); if (!nodep->lhsp()) { - puts("()"); + putns(nodep, "()"); } else { - puts("::cons("); + putns(nodep, "::cons("); iterateAndNextConstNull(nodep->lhsp()); if (nodep->rhsp()) { puts(", "); @@ -1380,23 +1387,23 @@ public: } } void visit(AstConsPackUOrStruct* nodep) override { - putbs(nodep->dtypep()->cType("", false, false)); + putnbs(nodep, nodep->dtypep()->cType("", false, false)); puts("{"); for (AstNode* memberp = nodep->membersp(); memberp; memberp = memberp->nextp()) { iterateConst(memberp); - if (memberp->nextp()) { puts(", "); } + if (memberp->nextp()) puts(", "); } puts("}"); } void visit(AstConsPackMember* nodep) override { auto* const vdtypep = VN_AS(nodep->dtypep(), MemberDType); - putbs("."); + putnbs(nodep, "."); puts(vdtypep->name()); puts(" = "); iterateConst(nodep->rhsp()); } void visit(AstConsQueue* nodep) override { - putbs(nodep->dtypep()->cType("", false, false)); + putnbs(nodep, nodep->dtypep()->cType("", false, false)); if (!nodep->lhsp()) { puts("()"); } else { @@ -1423,7 +1430,7 @@ public: // Default void visit(AstNode* nodep) override { - puts(string{"\n???? // "} + nodep->prettyTypeName() + "\n"); + putns(nodep, string{"\n???? // "} + nodep->prettyTypeName() + "\n"); iterateChildrenConst(nodep); // LCOV_EXCL_START if (!v3Global.opt.lintOnly()) { // An internal problem, so suppress diff --git a/src/V3EmitCHeaders.cpp b/src/V3EmitCHeaders.cpp index 499f1e6d4..2c52f28dd 100644 --- a/src/V3EmitCHeaders.cpp +++ b/src/V3EmitCHeaders.cpp @@ -35,7 +35,7 @@ class EmitCHeader final : public EmitCConstInit { void decorateFirst(bool& first, const string& str) { if (first) { - putsDecoration(str); + putsDecoration(nullptr, str); first = false; } } @@ -44,7 +44,8 @@ class EmitCHeader final : public EmitCConstInit { for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { if (const AstCell* const cellp = VN_CAST(nodep, Cell)) { decorateFirst(first, "// CELLS\n"); - puts(prefixNameProtect(cellp->modp()) + "* " + cellp->nameProtect() + ";\n"); + putns(cellp, + prefixNameProtect(cellp->modp()) + "* " + cellp->nameProtect() + ";\n"); } } } @@ -120,11 +121,11 @@ class EmitCHeader final : public EmitCConstInit { void emitInternalVarDecls(const AstNodeModule* modp) { if (const AstClass* const classp = VN_CAST(modp, Class)) { if (classp->needRNG()) { - putsDecoration("\n// INTERNAL VARIABLES\n"); + putsDecoration(nullptr, "\n// INTERNAL VARIABLES\n"); puts("VlRNG __Vm_rng;\n"); } } else { // not class - putsDecoration("\n// INTERNAL VARIABLES\n"); + putsDecoration(nullptr, "\n// INTERNAL VARIABLES\n"); puts(symClassName() + "* const vlSymsp;\n"); } } @@ -137,7 +138,7 @@ class EmitCHeader final : public EmitCConstInit { UASSERT_OBJ(varp->valuep(), nodep, "No init for a param?"); // Only C++ LiteralTypes can be constexpr const bool canBeConstexpr = varp->dtypep()->isLiteralType(); - puts("static "); + putns(varp, "static "); puts(canBeConstexpr ? "constexpr " : "const "); puts(varp->dtypep()->cType(varp->nameProtect(), false, false)); if (canBeConstexpr) { @@ -152,10 +153,10 @@ class EmitCHeader final : public EmitCConstInit { void emitCtorDtorDecls(const AstNodeModule* modp) { if (!VN_IS(modp, Class)) { // Classes use CFuncs with isConstructor/isDestructor const string& name = prefixNameProtect(modp); - putsDecoration("\n// CONSTRUCTORS\n"); - puts(name + "(" + symClassName() + "* symsp, const char* v__name);\n"); - puts("~" + name + "();\n"); - puts("VL_UNCOPYABLE(" + name + ");\n"); + putsDecoration(nullptr, "\n// CONSTRUCTORS\n"); + putns(modp, name + "(" + symClassName() + "* symsp, const char* v__name);\n"); + putns(modp, "~" + name + "();\n"); + putns(modp, "VL_UNCOPYABLE(" + name + ");\n"); } } void emitInternalMethodDecls(const AstNodeModule* modp) { @@ -193,18 +194,19 @@ class EmitCHeader final : public EmitCConstInit { if (!edtypep) continue; decorateFirst(first, "\n// ENUMS (that were declared public)\n"); if (edtypep->width() > 64) { - putsDecoration("// enum " + tdefp->nameProtect() + " ignored: Too wide for C++\n"); + putsDecoration(tdefp, + "// enum " + tdefp->nameProtect() + " ignored: Too wide for C++\n"); } else { - puts("enum " + tdefp->name() + " {\n"); + putns(tdefp, "enum " + tdefp->name() + " {\n"); for (const AstEnumItem* itemp = edtypep->itemsp(); itemp; itemp = VN_AS(itemp->nextp(), EnumItem)) { if (const AstConst* const constp = VN_CAST(itemp->valuep(), Const)) { if (constp->num().isFourState()) { - puts("// " + itemp->nameProtect() + " is four-state\n"); + putns(itemp, "// " + itemp->nameProtect() + " is four-state\n"); continue; } } - puts(itemp->nameProtect()); + putns(itemp, itemp->nameProtect()); puts(" = "); iterateConst(itemp->valuep()); if (VN_IS(itemp->nextp(), EnumItem)) puts(","); @@ -229,26 +231,26 @@ class EmitCHeader final : public EmitCConstInit { } } } - puts(sdtypep->verilogKwd()); // "struct"/"union" + putns(sdtypep, sdtypep->verilogKwd()); // "struct"/"union" puts(" " + EmitCBase::prefixNameProtect(sdtypep) + " {\n"); for (const AstMemberDType* itemp = sdtypep->membersp(); itemp; itemp = VN_AS(itemp->nextp(), MemberDType)) { - puts(itemp->dtypep()->cType(itemp->nameProtect(), false, false)); + putns(itemp, itemp->dtypep()->cType(itemp->nameProtect(), false, false)); puts(";\n"); } - puts("\nbool operator==(const " + EmitCBase::prefixNameProtect(sdtypep) - + "& rhs) const {\n"); + putns(sdtypep, "\nbool operator==(const " + EmitCBase::prefixNameProtect(sdtypep) + + "& rhs) const {\n"); puts("return "); for (const AstMemberDType* itemp = sdtypep->membersp(); itemp; itemp = VN_AS(itemp->nextp(), MemberDType)) { if (itemp != sdtypep->membersp()) puts("\n && "); - puts(itemp->nameProtect() + " == " + "rhs." + itemp->nameProtect()); + putns(itemp, itemp->nameProtect() + " == " + "rhs." + itemp->nameProtect()); } puts(";\n"); puts("}\n"); - puts("bool operator!=(const " + EmitCBase::prefixNameProtect(sdtypep) - + "& rhs) const {\n"); + putns(sdtypep, "bool operator!=(const " + EmitCBase::prefixNameProtect(sdtypep) + + "& rhs) const {\n"); puts("return !(*this == rhs);\n}\n"); puts("};\n"); } @@ -298,8 +300,8 @@ class EmitCHeader final : public EmitCConstInit { if (const AstClass* const classp = VN_CAST(modp, Class)) { for (const AstClassExtends* extp = classp->extendsp(); extp; extp = VN_AS(extp->nextp(), ClassExtends)) { - puts("#include \"" + prefixNameProtect(extp->classp()->classOrPackagep()) - + ".h\"\n"); + putns(extp, "#include \"" + prefixNameProtect(extp->classp()->classOrPackagep()) + + ".h\"\n"); } } @@ -312,7 +314,8 @@ class EmitCHeader final : public EmitCConstInit { emitStructs(modp); // Open class body {{{ - puts("\nclass "); + puts("\n"); + putns(modp, "class "); if (!VN_IS(modp, Class)) puts("alignas(VL_CACHE_LINE_BYTES) "); puts(prefixNameProtect(modp)); if (const AstClass* const classp = VN_CAST(modp, Class)) { @@ -321,7 +324,7 @@ class EmitCHeader final : public EmitCConstInit { if (classp->extendsp()) { for (const AstClassExtends* extp = classp->extendsp(); extp; extp = VN_AS(extp->nextp(), ClassExtends)) { - puts(prefixNameProtect(extp->classp())); + putns(extp, prefixNameProtect(extp->classp())); if (extp->nextp()) puts(", " + virtpub); } } else { diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp index d33c172e2..3daa693cd 100644 --- a/src/V3EmitCImp.cpp +++ b/src/V3EmitCImp.cpp @@ -203,7 +203,7 @@ class EmitCImp final : EmitCFunc { for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { if (const AstVar* const varp = VN_CAST(nodep, Var)) { if (varp->isStatic()) { - puts(varp->vlArgType(true, false, false, modName)); + putns(varp, varp->vlArgType(true, false, false, modName)); puts(";\n"); } } @@ -217,15 +217,15 @@ class EmitCImp final : EmitCFunc { if (varp->isParam()) { if (first) { puts("\n"); - putsDecoration("// Parameter definitions for " + modName + "\n"); + putsDecoration(modp, "// Parameter definitions for " + modName + "\n"); first = false; } UASSERT_OBJ(varp->valuep(), nodep, "No init for a param?"); // Only C++ LiteralTypes can be constexpr const bool canBeConstexpr = varp->dtypep()->isLiteralType(); - puts(canBeConstexpr ? "constexpr " : "const "); + putns(varp, canBeConstexpr ? "constexpr " : "const "); const string scopedName = modName + "::" + varp->nameProtect(); - puts(varp->dtypep()->cType(scopedName, false, false)); + putns(varp, varp->dtypep()->cType(scopedName, false, false)); if (!canBeConstexpr) { puts(" = "); emitConstInit(varp->valuep()); @@ -244,7 +244,8 @@ class EmitCImp final : EmitCFunc { "(" + modName + "* vlSelf);"); puts("\n"); - puts(modName + "::" + modName + "(" + symClassName() + "* symsp, const char* v__name)\n"); + putns(modp, + modName + "::" + modName + "(" + symClassName() + "* symsp, const char* v__name)\n"); puts(" : VerilatedModule{v__name}\n"); ofp()->indentInc(); @@ -254,19 +255,19 @@ class EmitCImp final : EmitCFunc { = VN_CAST(varp->dtypeSkipRefp(), BasicDType)) { if (dtypep->keyword().isMTaskState()) { puts(", "); - puts(varp->nameProtect()); + putns(varp, varp->nameProtect()); puts("("); iterateConst(varp->valuep()); puts(")\n"); } else if (varp->isIO() && varp->isSc()) { puts(", "); - puts(varp->nameProtect()); + putns(varp, varp->nameProtect()); puts("("); putsQuoted(varp->nameProtect()); puts(")\n"); } else if (dtypep->isDelayScheduler()) { puts(", "); - puts(varp->nameProtect()); + putns(varp, varp->nameProtect()); puts("{*symsp->_vm_contextp__}\n"); } } @@ -277,7 +278,7 @@ class EmitCImp final : EmitCFunc { puts(" {\n"); - putsDecoration("// Reset structure values\n"); + putsDecoration(modp, "// Reset structure values\n"); puts(modName + "__" + protect("_ctor_var_reset") + "(this);\n"); emitTextSection(modp, VNType::atScCtor); @@ -339,7 +340,7 @@ class EmitCImp final : EmitCFunc { } void emitDestructorImp(const AstNodeModule* modp) { puts("\n"); - puts(prefixNameProtect(modp) + "::~" + prefixNameProtect(modp) + "() {\n"); + putns(modp, prefixNameProtect(modp) + "::~" + prefixNameProtect(modp) + "() {\n"); emitTextSection(modp, VNType::atScDtor); puts("}\n"); splitSizeInc(10); @@ -352,8 +353,8 @@ class EmitCImp final : EmitCFunc { const string funcname = de ? "__Vdeserialize" : "__Vserialize"; const string op = de ? ">>" : "<<"; // NOLINTNEXTLINE(performance-inefficient-string-concatenation) - puts("void " + prefixNameProtect(modp) + "::" + protect(funcname) + "(" + classname - + "& os) {\n"); + putns(modp, "void " + prefixNameProtect(modp) + "::" + protect(funcname) + "(" + + classname + "& os) {\n"); // Place a computed checksum to ensure proper structure save/restore formatting // OK if this hash includes some things we won't dump, since // just looking for loading the wrong model @@ -414,7 +415,7 @@ class EmitCImp final : EmitCFunc { puts("; " + ivar + " < " + cvtToStr(elementp->widthWords())); puts("; ++" + ivar + ") {\n"); } - puts("os" + op + varp->nameProtect()); + putns(varp, "os" + op + varp->nameProtect()); for (int v = 0; v < vects; ++v) puts("[__Vi" + cvtToStr(v) + "]"); puts(";\n"); for (int v = 0; v < vects; ++v) puts("}\n"); @@ -773,7 +774,7 @@ class EmitCTrace final : EmitCFunc { m_enumNumMap[nodep] = enumNum; int nvals = 0; typesFp()->puts("{\n"); - typesFp()->puts("const char* " + protect("__VenumItemNames") + "[]\n"); + typesFp()->putns(nodep, "const char* " + protect("__VenumItemNames") + "[]\n"); typesFp()->puts("= {"); for (AstEnumItem* itemp = nodep->itemsp(); itemp; itemp = VN_AS(itemp->nextp(), EnumItem)) { @@ -817,26 +818,28 @@ class EmitCTrace final : EmitCFunc { // Note: Both VTraceType::CHANGE and VTraceType::FULL use the 'full' methods const std::string func = nodep->traceType() == VTraceType::CHANGE ? "chg" : "full"; bool emitWidth = true; + string stype; if (nodep->dtypep()->basicp()->isDouble()) { - puts("bufp->" + func + "Double"); + stype = "Double"; emitWidth = false; } else if (nodep->isWide() || emitTraceIsScBv(nodep) || emitTraceIsScBigUint(nodep)) { - puts("bufp->" + func + "WData"); + stype = "WData"; } else if (nodep->isQuad()) { - puts("bufp->" + func + "QData"); + stype = "QData"; } else if (nodep->declp()->widthMin() > 16) { - puts("bufp->" + func + "IData"); + stype = "IData"; } else if (nodep->declp()->widthMin() > 8) { - puts("bufp->" + func + "SData"); + stype = "SData"; } else if (nodep->declp()->widthMin() > 1) { - puts("bufp->" + func + "CData"); + stype = "CData"; } else if (nodep->dtypep()->basicp()->isEvent()) { - puts("bufp->" + func + "Event"); + stype = "Event"; emitWidth = false; } else { - puts("bufp->" + func + "Bit"); + stype = "Bit"; emitWidth = false; } + putns(nodep, "bufp->" + func + stype); const uint32_t offset = (arrayindex < 0) ? 0 : (arrayindex * nodep->declp()->widthWords()); const uint32_t code = nodep->declp()->code() + offset; @@ -906,17 +909,18 @@ class EmitCTrace final : EmitCFunc { EmitCFunc::visit(nodep); } void visit(AstTracePushPrefix* nodep) override { - puts("tracep->pushPrefix("); + putns(nodep, "tracep->pushPrefix("); putsQuoted(VIdProtect::protectWordsIf(nodep->prefix(), nodep->protect())); puts(", VerilatedTracePrefixType::"); puts(nodep->prefixType().ascii()); puts(");\n"); } void visit(AstTracePopPrefix* nodep) override { // - puts("tracep->popPrefix();\n"); + putns(nodep, "tracep->popPrefix();\n"); } void visit(AstTraceDecl* nodep) override { const int enumNum = emitTraceDeclDType(nodep->dtypep()); + putns(nodep, ""); if (nodep->arrayRange().ranged()) { puts("for (int i = 0; i < " + cvtToStr(nodep->arrayRange().elements()) + "; ++i) {\n"); emitTraceInitOne(nodep, enumNum); @@ -946,7 +950,7 @@ class EmitCTrace final : EmitCFunc { if (m_slow) openNextTypesFile(); // Emit functions for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { - if (AstCFunc* const funcp = VN_CAST(nodep, CFunc)) { iterateConst(funcp); } + if (AstCFunc* const funcp = VN_CAST(nodep, CFunc)) iterateConst(funcp); } // Close output file VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); diff --git a/src/V3EmitCModel.cpp b/src/V3EmitCModel.cpp index 90ccd80fc..c4334fd21 100644 --- a/src/V3EmitCModel.cpp +++ b/src/V3EmitCModel.cpp @@ -87,7 +87,7 @@ class EmitCModel final : public EmitCFunc { puts("\n"); puts("// This class is the main interface to the Verilated model\n"); - puts("class alignas(VL_CACHE_LINE_BYTES) " + topClassName() + " VL_NOT_FINAL : "); + putns(modp, "class alignas(VL_CACHE_LINE_BYTES) " + topClassName() + " VL_NOT_FINAL : "); if (optSystemC()) { // SC_MODULE, but with multiple-inheritance of VerilatedModel puts("public ::sc_core::sc_module, "); @@ -120,7 +120,8 @@ class EmitCModel final : public EmitCFunc { "// Otherwise the application code can consider these internals.\n"); for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { if (const AstCell* const cellp = VN_CAST(nodep, Cell)) { - puts(prefixNameProtect(cellp->modp()) + "* const " + cellp->nameProtect() + ";\n"); + putns(cellp, prefixNameProtect(cellp->modp()) + "* const " + cellp->nameProtect() + + ";\n"); } } @@ -253,7 +254,7 @@ class EmitCModel final : public EmitCFunc { putSectionDelimiter("Constructors"); puts("\n"); - puts(topClassName() + "::" + topClassName()); + putns(modp, topClassName() + "::" + topClassName()); if (optSystemC()) { puts("(sc_core::sc_module_name /* unused */)\n"); puts(" : VerilatedModel{*Verilated::threadContextp()}\n"); @@ -269,7 +270,8 @@ class EmitCModel final : public EmitCFunc { if (const AstVar* const varp = VN_CAST(nodep, Var)) { if (varp->isPrimaryIO()) { const string protName = varp->nameProtect(); - puts(" , " + protName + "{vlSymsp->TOP." + protName + "}\n"); + puts(" , "); + putns(varp, protName + "{vlSymsp->TOP." + protName + "}\n"); } } } @@ -278,7 +280,8 @@ class EmitCModel final : public EmitCFunc { for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { if (const AstCell* const cellp = VN_CAST(nodep, Cell)) { const string protName = cellp->nameProtect(); - puts(" , " + protName + "{vlSymsp->TOP." + protName + "}\n"); + puts(" , "); + putns(cellp, protName + "{vlSymsp->TOP." + protName + "}\n"); } } @@ -291,7 +294,7 @@ class EmitCModel final : public EmitCFunc { if (optSystemC()) { // Create sensitivity list for when to evaluate the model. - putsDecoration("// Sensitivities on all clocks and combinational inputs\n"); + putsDecoration(nullptr, "// Sensitivities on all clocks and combinational inputs\n"); puts("SC_METHOD(eval);\n"); if (v3Global.usesTiming()) puts("SC_METHOD(eval_sens);\n"); for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { @@ -307,12 +310,12 @@ class EmitCModel final : public EmitCFunc { UASSERT_OBJ(arrayp->hi() >= arrayp->lo(), varp, "Should have swapped msb & lsb earlier."); const string ivar = std::string{"__Vi"} + cvtToStr(vecnum); - puts("for (int __Vi" + cvtToStr(vecnum) + " = " - + cvtToStr(arrayp->lo())); + putns(varp, "for (int __Vi" + cvtToStr(vecnum) + " = " + + cvtToStr(arrayp->lo())); puts("; " + ivar + " <= " + cvtToStr(arrayp->hi())); puts("; ++" + ivar + ") {\n"); } - puts("sensitive << " + varp->nameProtect()); + putns(varp, "sensitive << " + varp->nameProtect()); for (int v = 0; v < vects; ++v) puts("[__Vi" + cvtToStr(v) + "]"); puts(";\n"); for (int v = 0; v < vects; ++v) puts("}\n"); @@ -384,7 +387,7 @@ class EmitCModel final : public EmitCFunc { + "::eval_step\\n\"); );\n"); puts("#ifdef VL_DEBUG\n"); - putsDecoration("// Debug assertions\n"); + putsDecoration(nullptr, "// Debug assertions\n"); puts(topModNameProtected + "__" + protect("_eval_debug_assertions") + "(&(vlSymsp->TOP));\n"); puts("#endif // VL_DEBUG\n"); @@ -407,7 +410,7 @@ class EmitCModel final : public EmitCFunc { puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+ Eval\\n\"););\n"); puts(topModNameProtected + "__" + protect("_eval") + "(&(vlSymsp->TOP));\n"); - putsDecoration("// Evaluate cleanup\n"); + putsDecoration(nullptr, "// Evaluate cleanup\n"); puts("Verilated::endOfEval(vlSymsp->__Vm_evalMsgQp);\n"); puts("}\n"); @@ -419,11 +422,12 @@ class EmitCModel final : public EmitCFunc { // ::eval_end_step if (v3Global.needTraceDumper() && !optSystemC()) { - puts("\nvoid " + topClassName() + "::eval_end_step() {\n"); + puts("\n"); + putns(modp, "void " + topClassName() + "::eval_end_step() {\n"); puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+eval_end_step " + topClassName() + "::eval_end_step\\n\"); );\n"); puts("#ifdef VM_TRACE\n"); - putsDecoration("// Tracing\n"); + putsDecoration(nullptr, "// Tracing\n"); // SystemC's eval loop deals with calling trace, not us puts("if (VL_UNLIKELY(vlSymsp->__Vm_dumping)) vlSymsp->_traceDump();\n"); puts("#endif // VM_TRACE\n"); @@ -432,14 +436,15 @@ class EmitCModel final : public EmitCFunc { putSectionDelimiter("Events and timing"); if (auto* const delaySchedp = v3Global.rootp()->delaySchedulerp()) { - puts("bool " + topClassName() + "::eventsPending() { return !vlSymsp->TOP."); + putns(modp, "bool " + topClassName() + "::eventsPending() { return !vlSymsp->TOP."); puts(delaySchedp->nameProtect()); puts(".empty(); }\n\n"); - puts("uint64_t " + topClassName() + "::nextTimeSlot() { return vlSymsp->TOP."); + + putns(modp, "uint64_t " + topClassName() + "::nextTimeSlot() { return vlSymsp->TOP."); puts(delaySchedp->nameProtect()); puts(".nextTimeSlot(); }\n"); } else { - puts("bool " + topClassName() + "::eventsPending() { return false; }\n\n"); + putns(modp, "bool " + topClassName() + "::eventsPending() { return false; }\n\n"); puts("uint64_t " + topClassName() + "::nextTimeSlot() {\n"); puts("VL_FATAL_MT(__FILE__, __LINE__, \"\", \"%Error: No delays in the " "design\");\n"); @@ -450,7 +455,8 @@ class EmitCModel final : public EmitCFunc { if (!optSystemC()) { // ::name - puts("\nconst char* " + topClassName() + "::name() const {\n"); + puts("\n"); + putns(modp, "const char* " + topClassName() + "::name() const {\n"); puts(/**/ "return vlSymsp->name();\n"); puts("}\n"); } @@ -458,21 +464,23 @@ class EmitCModel final : public EmitCFunc { putSectionDelimiter("Invoke final blocks"); // Forward declarations puts("\n"); - puts("void " + topModNameProtected + "__" + protect("_eval_final") + selfDecl + ";\n"); + putns(modp, + "void " + topModNameProtected + "__" + protect("_eval_final") + selfDecl + ";\n"); // ::final puts("\nVL_ATTR_COLD void " + topClassName() + "::final() {\n"); puts(/**/ topModNameProtected + "__" + protect("_eval_final") + "(&(vlSymsp->TOP));\n"); puts("}\n"); putSectionDelimiter("Implementations of abstract methods from VerilatedModel\n"); - puts("const char* " + topClassName() + "::hierName() const { return vlSymsp->name(); }\n"); - puts("const char* " + topClassName() + "::modelName() const { return \"" + topClassName() - + "\"; }\n"); - puts("unsigned " + topClassName() + "::threads() const { return " - + cvtToStr(v3Global.opt.threads()) + "; }\n"); - puts("void " + topClassName() - + "::prepareClone() const { contextp()->prepareClone(); }\n"); - puts("void " + topClassName() + "::atClone() const {\n"); + putns(modp, "const char* " + topClassName() + + "::hierName() const { return vlSymsp->name(); }\n"); + putns(modp, "const char* " + topClassName() + "::modelName() const { return \"" + + topClassName() + "\"; }\n"); + putns(modp, "unsigned " + topClassName() + "::threads() const { return " + + cvtToStr(v3Global.opt.threads()) + "; }\n"); + putns(modp, "void " + topClassName() + + "::prepareClone() const { contextp()->prepareClone(); }\n"); + putns(modp, "void " + topClassName() + "::atClone() const {\n"); if (v3Global.opt.threads() > 1) { puts("vlSymsp->__Vm_threadPoolp = static_cast("); } @@ -481,8 +489,8 @@ class EmitCModel final : public EmitCFunc { puts(";\n}\n"); if (v3Global.opt.trace()) { - puts("std::unique_ptr " + topClassName() - + "::traceConfig() const {\n"); + putns(modp, "std::unique_ptr " + topClassName() + + "::traceConfig() const {\n"); puts("return std::unique_ptr{new VerilatedTraceConfig{"); puts(v3Global.opt.useTraceParallel() ? "true" : "false"); puts(v3Global.opt.useTraceOffload() ? ", true" : ", false"); @@ -498,16 +506,17 @@ class EmitCModel final : public EmitCFunc { putSectionDelimiter("Trace configuration"); // Forward declaration - puts("\nvoid " + topModNameProtected + "__" + protect("trace_decl_types") + "(" - + v3Global.opt.traceClassBase() + "* tracep);\n"); - puts("\nvoid " + topModNameProtected + "__" + protect("trace_init_top") + "(" - + topModNameProtected + "* vlSelf, " + v3Global.opt.traceClassBase() - + "* tracep);\n"); + putns(modp, "\nvoid " + topModNameProtected + "__" + protect("trace_decl_types") + "(" + + v3Global.opt.traceClassBase() + "* tracep);\n"); + putns(modp, "\nvoid " + topModNameProtected + "__" + protect("trace_init_top") + "(" + + topModNameProtected + "* vlSelf, " + v3Global.opt.traceClassBase() + + "* tracep);\n"); // Static helper function - puts("\nVL_ATTR_COLD static void " + protect("trace_init") + "(void* voidSelf, " - + v3Global.opt.traceClassBase() + "* tracep, uint32_t code) {\n"); - putsDecoration("// Callback from tracep->open()\n"); + puts("\n"); + putns(modp, "VL_ATTR_COLD static void " + protect("trace_init") + "(void* voidSelf, " + + v3Global.opt.traceClassBase() + "* tracep, uint32_t code) {\n"); + putsDecoration(modp, "// Callback from tracep->open()\n"); puts(voidSelfAssign(modp)); puts(symClassAssign()); puts("if (!vlSymsp->_vm_contextp__->calcUnusedSigs()) {\n"); @@ -524,16 +533,18 @@ class EmitCModel final : public EmitCFunc { puts("}\n"); // Forward declaration - puts("\nVL_ATTR_COLD void " + topModNameProtected + "__" + protect("trace_register") + "(" - + topModNameProtected + "* vlSelf, " + v3Global.opt.traceClassBase() - + "* tracep);\n"); + puts("\n"); + putns(modp, "VL_ATTR_COLD void " + topModNameProtected + "__" + protect("trace_register") + + "(" + topModNameProtected + "* vlSelf, " + v3Global.opt.traceClassBase() + + "* tracep);\n"); const CFuncVector traceInitFuncps = findFuncps([](const AstCFunc* nodep) { return nodep->dpiTraceInit(); }); for (const AstCFunc* const funcp : traceInitFuncps) emitCFuncDecl(funcp, modp); // ::trace - puts("\nVL_ATTR_COLD void " + topClassName() + "::trace("); + puts("\n"); + putns(modp, "VL_ATTR_COLD void " + topClassName() + "::trace("); puts(v3Global.opt.traceClassBase() + "C* tfp, int levels, int options) {\n"); if (optSystemC()) { puts(/**/ "if (!sc_core::sc_get_curr_simcontext()->elaboration_done()) {\n"); @@ -579,7 +590,8 @@ class EmitCModel final : public EmitCFunc { void emitTraceOffMethods(AstNodeModule* modp) { putSectionDelimiter("Trace configuration"); // ::trace - puts("\nVL_ATTR_COLD void " + topClassName() + "::trace("); + puts("\n"); + putns(modp, "VL_ATTR_COLD void " + topClassName() + "::trace("); puts(v3Global.opt.traceClassBase() + "C* tfp, int levels, int options) {\n"); puts(/**/ "vl_fatal(__FILE__, __LINE__, __FILE__,\"'" + topClassName() + +"::trace()' called on model that was Verilated without --trace option\");\n"); diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 38af0222a..ba18bc400 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -40,13 +40,15 @@ class EmitCSyms final : EmitCBaseVisitorConst { // TYPES struct ScopeData final { + const AstNode* m_nodep; const string m_symName; const string m_prettyName; const int m_timeunit; string m_type; - ScopeData(const string& symName, const string& prettyName, int timeunit, - const string& type) - : m_symName{symName} + ScopeData(const AstNode* nodep, const string& symName, const string& prettyName, + int timeunit, const string& type) + : m_nodep{nodep} + , m_symName{symName} , m_prettyName{prettyName} , m_timeunit{timeunit} , m_type{type} {} @@ -100,9 +102,9 @@ class EmitCSyms final : EmitCBaseVisitorConst { std::vector m_scopes; // Every scope by module std::vector m_dpis; // DPI functions std::vector m_modVars; // Each public {mod,var} - ScopeNames m_scopeNames; // Each unique AstScopeName std::map m_scopeFuncs; // Each {scope,dpi-export-func} std::map m_scopeVars; // Each {scope,public-var} + ScopeNames m_scopeNames; // Each unique AstScopeName ScopeNames m_vpiScopeCandidates; // All scopes for VPI ScopeNameHierarchy m_vpiScopeHierarchy; // The actual hierarchy of scopes int m_coverBins = 0; // Coverage bin number @@ -239,7 +241,7 @@ class EmitCSyms final : EmitCBaseVisitorConst { if (m_scopeNames.find(scpSym) == m_scopeNames.end()) { // cppcheck-suppress stlFindInsert m_scopeNames.emplace(scpSym, - ScopeData{scpSym, scpPretty, 0, "SCOPE_OTHER"}); + ScopeData{varp, scpSym, scpPretty, 0, "SCOPE_OTHER"}); } m_scopeVars.emplace(scpSym + " " + varp->name(), ScopeVarData{scpSym, varBasePretty, varp, modp, scopep}); @@ -311,7 +313,7 @@ class EmitCSyms final : EmitCBaseVisitorConst { const int timeunit = m_modp->timeunit().powerOfTen(); m_vpiScopeCandidates.emplace( scopeSymString(name), - ScopeData{scopeSymString(name), name_pretty, timeunit, type}); + ScopeData{nodep, scopeSymString(name), name_pretty, timeunit, type}); } } void visit(AstScope* nodep) override { @@ -326,7 +328,7 @@ class EmitCSyms final : EmitCBaseVisitorConst { const int timeunit = m_modp->timeunit().powerOfTen(); m_vpiScopeCandidates.emplace( scopeSymString(nodep->name()), - ScopeData{scopeSymString(nodep->name()), name_pretty, timeunit, type}); + ScopeData{nodep, scopeSymString(nodep->name()), name_pretty, timeunit, type}); } } void visit(AstScopeName* nodep) override { @@ -335,7 +337,7 @@ class EmitCSyms final : EmitCBaseVisitorConst { // << " ss" << name << endl); const int timeunit = m_modp ? m_modp->timeunit().powerOfTen() : 0; m_scopeNames.emplace( - name, ScopeData{name, nodep->scopePrettySymName(), timeunit, "SCOPE_OTHER"}); + name, ScopeData{nodep, name, nodep->scopePrettySymName(), timeunit, "SCOPE_OTHER"}); if (nodep->dpiExport()) { UASSERT_OBJ(m_cfuncp, nodep, "ScopeName not under DPI function"); m_scopeFuncs.emplace(name + " " + m_cfuncp->name(), @@ -343,9 +345,9 @@ class EmitCSyms final : EmitCBaseVisitorConst { } else { if (m_scopeNames.find(nodep->scopeDpiName()) == m_scopeNames.end()) { // cppcheck-suppress stlFindInsert - m_scopeNames.emplace(nodep->scopeDpiName(), - ScopeData{nodep->scopeDpiName(), nodep->scopePrettyDpiName(), - timeunit, "SCOPE_OTHER"}); + m_scopeNames.emplace(nodep->scopeDpiName(), ScopeData{nodep, nodep->scopeDpiName(), + nodep->scopePrettyDpiName(), + timeunit, "SCOPE_OTHER"}); } } } @@ -415,7 +417,7 @@ void EmitCSyms::emitSymHdr() { for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep; nodep = VN_AS(nodep->nextp(), NodeModule)) { if (VN_IS(nodep, Class)) continue; // Class included earlier - puts("#include \"" + prefixNameProtect(nodep) + ".h\"\n"); + putns(nodep, "#include \"" + prefixNameProtect(nodep) + ".h\"\n"); } if (v3Global.dpi()) { @@ -486,7 +488,7 @@ void EmitCSyms::emitSymHdr() { if (VN_IS(modp, Class)) continue; const string name = prefixNameProtect(modp); ofp()->printf("%-30s ", name.c_str()); - puts(protectIf(scopep->nameDotless(), scopep->protect()) + ";\n"); + putns(scopep, protectIf(scopep->nameDotless(), scopep->protect()) + ";\n"); } if (m_coverBins) { @@ -506,7 +508,8 @@ void EmitCSyms::emitSymHdr() { if (!m_scopeNames.empty()) { // Scope names puts("\n// SCOPE NAMES\n"); for (const auto& itr : m_scopeNames) { - puts("VerilatedScope " + protect("__Vscope_" + itr.second.m_symName) + ";\n"); + putns(itr.second.m_nodep, + "VerilatedScope " + protect("__Vscope_" + itr.second.m_symName) + ";\n"); } } @@ -522,7 +525,7 @@ void EmitCSyms::emitSymHdr() { for (const auto& i : m_usesVfinal) { puts("void " + symClassName() + "_" + cvtToStr(i.first) + "("); - if (i.second) { puts("int __Vfinal"); } + if (i.second) puts("int __Vfinal"); puts(");\n"); } @@ -604,12 +607,12 @@ void EmitCSyms::checkSplit(bool usesVfinal) { } m_ofpBase->puts(symClassName() + "_" + cvtToStr(m_funcNum) + "("); - if (usesVfinal) { m_ofpBase->puts("__Vfinal"); } + if (usesVfinal) m_ofpBase->puts("__Vfinal"); m_ofpBase->puts(");\n"); emitSymImpPreamble(); puts("void " + symClassName() + "::" + symClassName() + "_" + cvtToStr(m_funcNum) + "("); - if (usesVfinal) { puts("int __Vfinal"); } + if (usesVfinal) puts("int __Vfinal"); puts(") {\n"); } @@ -625,7 +628,7 @@ void EmitCSyms::emitSymImpPreamble() { for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep; nodep = VN_AS(nodep->nextp(), NodeModule)) { if (VN_IS(nodep, Class)) continue; // Class included earlier - puts("#include \"" + prefixNameProtect(nodep) + ".h\"\n"); + putns(nodep, "#include \"" + prefixNameProtect(nodep) + ".h\"\n"); } puts("\n"); // Declarations for DPI Export implementation functions @@ -651,8 +654,9 @@ void EmitCSyms::emitScopeHier(bool destroy) { const string scopeType = it->second.m_type; if ((name.find('.') == string::npos) && (scopeType == "SCOPE_MODULE" || scopeType == "SCOPE_PACKAGE")) { - puts("__Vhier." + method + "(0, &" + protect("__Vscope_" + it->second.m_symName) - + ");\n"); + putns(it->second.m_nodep, "__Vhier." + method + "(0, &" + + protect("__Vscope_" + it->second.m_symName) + + ");\n"); } } @@ -799,7 +803,7 @@ void EmitCSyms::emitSymImp() { const AstScope* const scopep = i.first; const AstNodeModule* const modp = i.second; puts(" , "); - puts(protect(scopep->nameDotless())); + putns(scopep, protect(scopep->nameDotless())); puts("{this"); if (modp->isTop()) { puts(", namep"); @@ -857,9 +861,9 @@ void EmitCSyms::emitSymImp() { const string protName = protectWordsIf(scopep->name(), scopep->protect()); if (VN_IS(modp, ClassPackage)) { // ClassPackage modules seem to be a bit out of place, so hard code... - puts("TOP"); + putns(scopep, "TOP"); } else { - puts(protectIf(aboveScopep->nameDotless(), aboveScopep->protect())); + putns(scopep, protectIf(aboveScopep->nameDotless(), aboveScopep->protect())); } puts("."); puts(protName.substr(protName.rfind('.') + 1)); @@ -877,8 +881,8 @@ void EmitCSyms::emitSymImp() { // first is used by AstCoverDecl's call to __vlCoverInsert const bool first = !modp->user1(); modp->user1(true); - puts(protectIf(scopep->nameDotless(), scopep->protect()) + "." + protect("__Vconfigure") - + "(" + (first ? "true" : "false") + ");\n"); + putns(scopep, protectIf(scopep->nameDotless(), scopep->protect()) + "." + + protect("__Vconfigure") + "(" + (first ? "true" : "false") + ");\n"); ++m_numStmts; } @@ -886,7 +890,8 @@ void EmitCSyms::emitSymImp() { puts("// Setup scopes\n"); for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) { checkSplit(false); - puts(protect("__Vscope_" + it->second.m_symName) + ".configure(this, name(), "); + putns(it->second.m_nodep, + protect("__Vscope_" + it->second.m_symName) + ".configure(this, name(), "); putsQuoted(protectWordsIf(it->second.m_prettyName, true)); puts(", "); putsQuoted(protect(scopeDecodeIdentifier(it->second.m_prettyName))); @@ -911,7 +916,8 @@ void EmitCSyms::emitSymImp() { AstNodeModule* const modp = it->second.m_modp; if (funcp->dpiExportImpl()) { checkSplit(true); - puts(protect("__Vscope_" + scopep->scopeSymName()) + ".exportInsert(__Vfinal, "); + putns(scopep, + protect("__Vscope_" + scopep->scopeSymName()) + ".exportInsert(__Vfinal, "); putsQuoted(funcp->cname()); // Not protected - user asked for import/export puts(", (void*)(&"); puts(prefixNameProtect(modp)); @@ -972,7 +978,8 @@ void EmitCSyms::emitSymImp() { if (pdim > 1 || udim > 1) { puts("//UNSUP "); // VerilatedImp can't deal with >2d or packed arrays } - puts(protect("__Vscope_" + it->second.m_scopeName) + ".varInsert(__Vfinal,"); + putns(scopep, protect("__Vscope_" + it->second.m_scopeName)); + putns(varp, ".varInsert(__Vfinal,"); putsQuoted(protect(it->second.m_varBasePretty)); std::string varName; @@ -1049,16 +1056,16 @@ void EmitCSyms::emitDpiHdr() { for (AstCFunc* nodep : m_dpis) { if (nodep->dpiExportDispatcher()) { if (!firstExp++) puts("\n// DPI EXPORTS\n"); - putsDecoration("// DPI export" + ifNoProtect(" at " + nodep->fileline()->ascii()) - + "\n"); - puts("extern " + nodep->rtnTypeVoid() + " " + nodep->nameProtect() + "(" - + cFuncArgs(nodep) + ");\n"); + putsDecoration(nodep, "// DPI export" + + ifNoProtect(" at " + nodep->fileline()->ascii()) + "\n"); + putns(nodep, "extern " + nodep->rtnTypeVoid() + " " + nodep->nameProtect() + "(" + + cFuncArgs(nodep) + ");\n"); } else if (nodep->dpiImportPrototype()) { if (!firstImp++) puts("\n// DPI IMPORTS\n"); - putsDecoration("// DPI import" + ifNoProtect(" at " + nodep->fileline()->ascii()) - + "\n"); - puts("extern " + nodep->rtnTypeVoid() + " " + nodep->nameProtect() + "(" - + cFuncArgs(nodep) + ");\n"); + putsDecoration(nodep, "// DPI import" + + ifNoProtect(" at " + nodep->fileline()->ascii()) + "\n"); + putns(nodep, "extern " + nodep->rtnTypeVoid() + " " + nodep->nameProtect() + "(" + + cFuncArgs(nodep) + ");\n"); } } @@ -1105,19 +1112,21 @@ void EmitCSyms::emitDpiImp() { // Prevent multi-definition if used by multiple models puts("#ifndef VL_DPIDECL_" + nodep->name() + "_\n"); puts("#define VL_DPIDECL_" + nodep->name() + "_\n"); - puts(nodep->rtnTypeVoid() + " " + nodep->name() + "(" + cFuncArgs(nodep) + ") {\n"); + putns(nodep, + nodep->rtnTypeVoid() + " " + nodep->name() + "(" + cFuncArgs(nodep) + ") {\n"); puts("// DPI export" + ifNoProtect(" at " + nodep->fileline()->ascii()) + "\n"); - puts("return " + topClassName() + "::" + nodep->name() + "("); - string args; + putns(nodep, "return " + topClassName() + "::" + nodep->name() + "("); + string comma; for (AstNode* stmtp = nodep->argsp(); stmtp; stmtp = stmtp->nextp()) { if (const AstVar* const portp = VN_CAST(stmtp, Var)) { if (portp->isIO() && !portp->isFuncReturn()) { - if (args != "") args += ", "; - args += portp->name(); + puts(comma); + comma = ", "; + putns(portp, portp->name()); } } } - puts(args + ");\n"); + puts(");\n"); puts("}\n"); puts("#endif\n"); puts("\n"); diff --git a/src/V3File.cpp b/src/V3File.cpp index 07486c3fb..3e564ab9d 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -695,15 +695,28 @@ int V3OutFormatter::endLevels(const char* strg) { return levels; } -void V3OutFormatter::puts(const char* strg) { +void V3OutFormatter::putns(const AstNode* nodep, const char* strg) { if (!v3Global.opt.decoration()) { putsOutput(strg); return; } + if (m_prependIndent && strg[0] != '\n') { putsNoTracking(indentSpaces(endLevels(strg))); m_prependIndent = false; } + + if (nodep && v3Global.opt.decorationNodes() && !v3Global.opt.protectIds() + && (m_sourceLastFilenameno != nodep->fileline()->filenameno() + || m_sourceLastLineno != nodep->fileline()->firstLineno()) + && FileLine::builtInFilename() != nodep->fileline()->filename()) { + m_sourceLastLineno = nodep->fileline()->firstLineno(); + m_sourceLastFilenameno = nodep->fileline()->filenameno(); + putsNoTracking("/*" + nodep->fileline()->filename() + ":" + + cvtToStr(nodep->fileline()->lineno()) + " " + cvtToStr((void*)nodep) + + "*/"); + } + bool notstart = false; bool wordstart = true; bool equalsForBracket = false; // Looking for "= {" diff --git a/src/V3File.h b/src/V3File.h index 7cdfb0f35..9d1066a82 100644 --- a/src/V3File.h +++ b/src/V3File.h @@ -30,6 +30,8 @@ #include #include +class AstNode; + //============================================================================ // V3File: Create streams, recording dependency information @@ -122,6 +124,8 @@ private: int m_lineno = 1; int m_column = 0; int m_nobreak = false; // Basic operator or begin paren, don't break next + int m_sourceLastLineno = 0; + int m_sourceLastFilenameno = 0; bool m_prependIndent = true; bool m_inStringLiteral = false; int m_indentLevel = 0; // Current {} indentation @@ -141,19 +145,25 @@ public: void blockIndent(int flag) { m_blockIndent = flag; } // METHODS void printf(const char* fmt...) VL_ATTR_PRINTF(2); - void puts(const char* strg); - void puts(const string& strg) { puts(strg.c_str()); } + void puts(const char* strg) { putns(nullptr, strg); } + void puts(const string& strg) { putns(nullptr, strg); } + void putns(const AstNode* nodep, const char* strg); + void putns(const AstNode* nodep, const string& strg) { putns(nodep, strg.c_str()); } void putsNoTracking(const string& strg); void putsQuoted(const string& strg); void putBreak(); // Print linebreak if line is too wide void putBreakExpr(); // Print linebreak in expression if line is too wide void putbs(const char* strg) { putBreakExpr(); - puts(strg); + putns(nullptr, strg); } void putbs(const string& strg) { putBreakExpr(); - puts(strg); + putns(nullptr, strg); + } + void putnbs(const AstNode* nodep, const string& strg) { + putBreakExpr(); + putns(nodep, strg); } bool exceededWidth() const { return m_column > m_commaWidth; } void indentInc() { m_indentLevel += m_blockIndent; } diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 9afd8452e..bcd9de6fc 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -444,6 +444,23 @@ void V3Options::ccSet() { // --cc m_systemC = false; } +void V3Options::decorations(FileLine* fl, const string& arg) { // --decorations + if (arg == "none") { + m_decoration = false; + m_decorationNodes = false; + } else if (arg == "node") { + m_decoration = true; + m_decorationNodes = true; + } else if (arg == "medium") { + m_decoration = true; + m_decorationNodes = false; + } else { + fl->v3fatal("Unknown setting for --decorations: '" + << arg << "'\n" + << fl->warnMore() << "... Suggest 'none', 'medium', or 'node'"); + } +} + //###################################################################### // File searching @@ -1167,7 +1184,9 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, DECL_OPTION("-debug-self-test", OnOff, &m_debugSelfTest).undocumented(); DECL_OPTION("-debug-sigsegv", CbCall, throwSigsegv).undocumented(); // See also --debug-abort DECL_OPTION("-debug-stack-check", OnOff, &m_debugStackCheck).undocumented(); - DECL_OPTION("-decoration", OnOff, &m_decoration); + DECL_OPTION("-decoration", CbCall, [this, fl]() { decorations(fl, "medium"); }); + DECL_OPTION("-decorations", CbVal, [this, fl](const char* optp) { decorations(fl, optp); }); + DECL_OPTION("-no-decoration", CbCall, [this, fl]() { decorations(fl, "none"); }); DECL_OPTION("-dpi-hdr-only", OnOff, &m_dpiHdrOnly); DECL_OPTION("-dump-", CbPartialMatch, [this](const char* optp) { m_dumpLevel[optp] = 3; }); DECL_OPTION("-no-dump-", CbPartialMatch, [this](const char* optp) { m_dumpLevel[optp] = 0; }); @@ -1383,7 +1402,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, DECL_OPTION("-relative-includes", OnOff, &m_relativeIncludes); DECL_OPTION("-reloop-limit", CbVal, [this, fl](const char* valp) { m_reloopLimit = std::atoi(valp); - if (m_reloopLimit < 2) { fl->v3error("--reloop-limit must be >= 2: " << valp); } + if (m_reloopLimit < 2) fl->v3error("--reloop-limit must be >= 2: " << valp); }); DECL_OPTION("-report-unoptflat", OnOff, &m_reportUnoptflat); DECL_OPTION("-rr", CbCall, []() {}); // Processed only in bin/verilator shell diff --git a/src/V3Options.h b/src/V3Options.h index c80e92875..8361899a0 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -245,6 +245,7 @@ private: bool m_debugSelfTest = false; // main switch: --debug-self-test bool m_debugStackCheck = false; // main switch: --debug-stack-check bool m_decoration = true; // main switch: --decoration + bool m_decorationNodes = false; // main switch: --decoration=nodes bool m_dpiHdrOnly = false; // main switch: --dpi-hdr-only bool m_exe = false; // main switch: --exe bool m_flatten = false; // main switch: --flatten @@ -430,6 +431,7 @@ public: void addForceInc(const string& filename); bool available() const VL_MT_SAFE { return m_available; } void ccSet(); + void decorations(FileLine* fl, const string& filename); void notify() VL_MT_DISABLED; // ACCESSORS (options) @@ -474,6 +476,7 @@ public: bool debugSelfTest() const { return m_debugSelfTest; } bool debugStackCheck() const { return m_debugStackCheck; } bool decoration() const VL_MT_SAFE { return m_decoration; } + bool decorationNodes() const VL_MT_SAFE { return m_decorationNodes; } bool dpiHdrOnly() const { return m_dpiHdrOnly; } bool dumpDefines() const { return m_dumpLevel.count("defines") && m_dumpLevel.at("defines"); } bool dumpTreeDot() const { diff --git a/test_regress/t/t_flag_decoration.pl b/test_regress/t/t_flag_decoration.pl new file mode 100755 index 000000000..82d6aeddc --- /dev/null +++ b/test_regress/t/t_flag_decoration.pl @@ -0,0 +1,24 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 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 + +scenarios(vlt => 1); + +top_filename("t/t_flag_decoration.v"); + +compile( + verilator_flags2 => ["--decoration"], + ); + +file_grep_not("$Self->{obj_dir}/V$Self->{name}.h", qr!\n// CONSTRUCTORS!); +file_grep("$Self->{obj_dir}/V$Self->{name}.h", qr!\n // CONSTRUCTORS!); +file_grep_not("$Self->{obj_dir}/V$Self->{name}.h", qr!/\*t/t_flag_decoration!); + +ok(1); +1; diff --git a/test_regress/t/t_flag_decoration.v b/test_regress/t/t_flag_decoration.v new file mode 100644 index 000000000..d876c9327 --- /dev/null +++ b/test_regress/t/t_flag_decoration.v @@ -0,0 +1,8 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2010 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); +endmodule diff --git a/test_regress/t/t_flag_decoration_no.pl b/test_regress/t/t_flag_decoration_no.pl new file mode 100755 index 000000000..9f2f6a84b --- /dev/null +++ b/test_regress/t/t_flag_decoration_no.pl @@ -0,0 +1,24 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 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 + +scenarios(vlt => 1); + +top_filename("t/t_flag_decoration.v"); + +compile( + verilator_flags2 => ["--no-decoration"], + ); + +file_grep("$Self->{obj_dir}/V$Self->{name}.h", qr!\n// CONSTRUCTORS!); +file_grep_not("$Self->{obj_dir}/V$Self->{name}.h", qr!\n // CONSTRUCTORS!); +file_grep_not("$Self->{obj_dir}/V$Self->{name}.h", qr!/\*t/t_flag_decoration!); + +ok(1); +1; diff --git a/test_regress/t/t_flag_decorations_bad.out b/test_regress/t/t_flag_decorations_bad.out new file mode 100644 index 000000000..be8dbd94e --- /dev/null +++ b/test_regress/t/t_flag_decorations_bad.out @@ -0,0 +1,2 @@ +%Error: Unknown setting for --decorations: 'BAD' + ... Suggest 'none', 'medium', or 'node' diff --git a/test_regress/t/t_flag_decorations_bad.pl b/test_regress/t/t_flag_decorations_bad.pl new file mode 100755 index 000000000..238b5dfc0 --- /dev/null +++ b/test_regress/t/t_flag_decorations_bad.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 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 + +scenarios(vlt => 1); + +top_filename("t/t_flag_decoration.v"); + +lint( + verilator_flags2 => ["-decorations BAD"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_flag_decorations_node.pl b/test_regress/t/t_flag_decorations_node.pl new file mode 100755 index 000000000..e611e91ba --- /dev/null +++ b/test_regress/t/t_flag_decorations_node.pl @@ -0,0 +1,24 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 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 + +scenarios(vlt => 1); + +top_filename("t/t_flag_decoration.v"); + +compile( + verilator_flags2 => ["--decorations node"], + ); + +file_grep_not("$Self->{obj_dir}/V$Self->{name}.h", qr!\n// CONSTRUCTORS!); +file_grep("$Self->{obj_dir}/V$Self->{name}.h", qr!\n // CONSTRUCTORS!); +file_grep("$Self->{obj_dir}/V$Self->{name}.h", qr!/\*t/t_flag_decoration!); + +ok(1); +1;