diff --git a/Changes b/Changes index 623ff057f..9a21bb638 100644 --- a/Changes +++ b/Changes @@ -21,6 +21,7 @@ Verilator 4.217 devel * Support lower dimension looping in foreach loops (#3172). [Ehab Ibrahim] * Support up to 64 bit enums for .next/.prev/.name (#3244). [Alexander Grobman] +* Reduce .rodata footpring of trace initializatoin (#3250). [Geza Lore, Shunyao CAD] * Fix MSWIN compile error (#2681). [Unai Martinez-Corral] * Fix break under foreach loop (#3230). * Fix VL_STREAML_FAST_QQI with 64 bit left-hand-side (#3232) (#3235) diff --git a/include/verilated.cpp b/include/verilated.cpp index 40c51f000..ae76d93a1 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -2625,14 +2625,11 @@ void Verilated::debug(int level) VL_MT_SAFE { } } -const char* Verilated::catName(const char* n1, const char* n2, int scopet, - const char* delimiter) VL_MT_SAFE { - // Returns new'ed data +const char* Verilated::catName(const char* n1, const char* n2, const char* delimiter) VL_MT_SAFE { // Used by symbol table creation to make module names static VL_THREAD_LOCAL char* t_strp = nullptr; static VL_THREAD_LOCAL size_t t_len = 0; - const size_t newlen - = std::strlen(n1) + std::strlen(n2) + std::strlen(delimiter) + (scopet > 0 ? 2 : 1); + const size_t newlen = std::strlen(n1) + std::strlen(n2) + std::strlen(delimiter) + 1; if (VL_UNLIKELY(!t_strp || newlen > t_len)) { if (t_strp) delete[] t_strp; t_strp = new char[newlen]; @@ -2640,8 +2637,6 @@ const char* Verilated::catName(const char* n1, const char* n2, int scopet, } char* dp = t_strp; for (const char* sp = n1; *sp;) *dp++ = *sp++; - // Add scope type - if (scopet) *dp++ = (char)(0x80 + scopet); for (const char* sp = delimiter; *sp;) *dp++ = *sp++; for (const char* sp = n2; *sp;) *dp++ = *sp++; *dp++ = '\0'; diff --git a/include/verilated.h b/include/verilated.h index 8e502fd08..e9c6a6dde 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -823,8 +823,8 @@ public: public: // METHODS - INTERNAL USE ONLY (but public due to what uses it) // Internal: Create a new module name by concatenating two strings - static const char* catName(const char* n1, const char* n2, int scopet = 0, - const char* delimiter = "."); // Returns static data + // Returns pointer to thread-local static data (overwritten on next call) + static const char* catName(const char* n1, const char* n2, const char* delimiter = "."); // Internal: Throw signal assertion static void nullPointerError(const char* filename, int linenum) VL_ATTR_NORETURN VL_MT_SAFE; diff --git a/include/verilated_fst_c.cpp b/include/verilated_fst_c.cpp index 73275f9c7..3a5066f5a 100644 --- a/include/verilated_fst_c.cpp +++ b/include/verilated_fst_c.cpp @@ -163,13 +163,13 @@ void VerilatedFst::declare(vluint32_t code, const char* name, int dtypenum, fstV VerilatedTrace::declCode(code, bits, false); - std::istringstream nameiss{name}; + std::string nameasstr = namePrefix() + name; + std::istringstream nameiss{nameasstr}; std::istream_iterator beg(nameiss); std::istream_iterator end; std::list tokens(beg, end); // Split name std::string symbol_name{tokens.back()}; tokens.pop_back(); // Remove symbol name from hierarchy - tokens.insert(tokens.begin(), moduleName()); // Add current module to the hierarchy std::string tmpModName; // Find point where current and new scope diverge diff --git a/include/verilated_trace.h b/include/verilated_trace.h index 6e7d6c59e..ce303be47 100644 --- a/include/verilated_trace.h +++ b/include/verilated_trace.h @@ -150,7 +150,7 @@ private: vluint32_t m_nextCode; // Next code number to assign vluint32_t m_numSignals; // Number of distinct signals vluint32_t m_maxBits; // Number of bits in the widest signal - std::string m_moduleName; // Name of module being trace initialized now + std::vector m_namePrefixStack{""}; // Path prefixes to add to signal names char m_scopeEscape; double m_timeRes; // Time resolution (ns/ms etc) double m_timeUnit; // Time units (ns/ms etc) @@ -213,7 +213,6 @@ protected: vluint32_t nextCode() const { return m_nextCode; } vluint32_t numSignals() const { return m_numSignals; } vluint32_t maxBits() const { return m_maxBits; } - const std::string& moduleName() const { return m_moduleName; } void fullDump(bool value) { m_fullDump = value; } vluint64_t timeLastDump() { return m_timeLastDump; } @@ -229,6 +228,8 @@ protected: bool isScopeEscape(char c) { return std::isspace(c) || c == m_scopeEscape; } // Character that splits scopes. Note whitespace are ALWAYS escapes. char scopeEscape() { return m_scopeEscape; } + // Prefix to assume in signal declarations + const std::string& namePrefix() const { return m_namePrefixStack.back(); } void closeBase(); void flushBase(); @@ -269,9 +270,11 @@ public: void addChgCb(dumpCb_t cb, void* userp) VL_MT_SAFE; void addCleanupCb(dumpCb_t cb, void* userp) VL_MT_SAFE; - void module(const std::string& name) VL_MT_UNSAFE; void scopeEscape(char flag) { m_scopeEscape = flag; } + void pushNamePrefix(const std::string&); + void popNamePrefix(unsigned count = 1); + //========================================================================= // Hot path internal interface to Verilator generated code diff --git a/include/verilated_trace_imp.cpp b/include/verilated_trace_imp.cpp index 84225ed98..925e30580 100644 --- a/include/verilated_trace_imp.cpp +++ b/include/verilated_trace_imp.cpp @@ -504,9 +504,14 @@ template <> void VerilatedTrace::addCleanupCb(dumpCb_t cb, void* u CallbackRecord cbr{cb, userp}; addCallbackRecord(m_cleanupCbs, cbr); } -template <> void VerilatedTrace::module(const std::string& name) VL_MT_UNSAFE { - // Called via callbacks way above in call stack, which already hold m_mutex - m_moduleName = name; + +template <> void VerilatedTrace::pushNamePrefix(const std::string& prefix) { + m_namePrefixStack.push_back(m_namePrefixStack.back() + prefix); +} + +template <> void VerilatedTrace::popNamePrefix(unsigned count) { + while (count--) m_namePrefixStack.pop_back(); + assert(!m_namePrefixStack.empty()); } //========================================================================= diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index 860c9de41..7b44148db 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -477,10 +477,7 @@ void VerilatedVcd::declare(vluint32_t code, const char* name, const char* wirep, // Tab separates final scope from signal name // Tab sorts before spaces, so signals nicely will print before scopes // Note the hiername may be nothing, if so we'll add "\t{name}" - std::string nameasstr = name; - if (!moduleName().empty()) { - nameasstr = moduleName() + scopeEscape() + nameasstr; // Optional ->module prefix - } + std::string nameasstr = namePrefix() + name; std::string hiername; std::string basename; for (const char* cp = nameasstr.c_str(); *cp; cp++) { @@ -830,16 +827,19 @@ float flo = 0.0f; void vcdInit(void*, VerilatedVcd* vcdp, vluint32_t) { vcdp->scopeEscape('.'); - vcdp->module("top"); + vcdp->pushNamePrefix("top."); /**/ vcdp->declBus(0x2, "v1", -1, 0, 5, 1); /**/ vcdp->declBus(0x3, "v2", -1, 0, 6, 1); - /**/ vcdp->module("top.sub1"); + /**/ vcdp->pushNamePrefix("sub1."); /***/ vcdp->declBit(0x4, "s1", -1, 0); /***/ vcdp->declBit(0x5, "ch", -1, 0); - /**/ vcdp->module("top.sub2"); + /**/ vcdp->popNamePrefix(); + /**/ vcdp->pushNamePrefix("sub2."); /***/ vcdp->declArray(0x6, "s2", -1, 0, 40, 3); + /**/ vcdp->popNamePrefix(); + vcdp->popNamePrefix(); // Note need to add 3 for next code. - vcdp->module("top2"); + vcdp->pushNamePrefix("top2."); /**/ vcdp->declBus(0x2, "t2v1", -1, 0, 4, 1); /**/ vcdp->declTriBit(0x10, "io1", -1, 0); /**/ vcdp->declTriBus(0x12, "io5", -1, 0, 4, 0); @@ -851,6 +851,7 @@ void vcdInit(void*, VerilatedVcd* vcdp, vluint32_t) { /**/ // Note need to add 4 for next code. /**/ vcdp->declTriQuad(0x24, "tq", -1, 0, 63, 0); /**/ // Note need to add 4 for next code. + vcdp->popNamePrefix(); } void vcdFull(void*, VerilatedVcd* vcdp) { diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index b67e03b22..baf36bb7d 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -5257,6 +5257,28 @@ public: AstNode* widthp() const { return op4p(); } }; +class AstTracePushNamePrefix final : public AstNodeStmt { + const string m_prefix; // Prefix to add to signal names +public: + AstTracePushNamePrefix(FileLine* fl, const string& prefix) + : ASTGEN_SUPER_TracePushNamePrefix(fl) + , m_prefix{prefix} {} + ASTNODE_NODE_FUNCS(TracePushNamePrefix) + virtual bool same(const AstNode* samep) const override { return false; } + string prefix() const { return m_prefix; } +}; + +class AstTracePopNamePrefix final : public AstNodeStmt { + const unsigned m_count; // How many levels to pop +public: + AstTracePopNamePrefix(FileLine* fl, unsigned count) + : ASTGEN_SUPER_TracePopNamePrefix(fl) + , m_count{count} {} + ASTNODE_NODE_FUNCS(TracePopNamePrefix) + virtual bool same(const AstNode* samep) const override { return false; } + unsigned count() const { return m_count; } +}; + class AstTraceDecl final : public AstNodeStmt { // Trace point declaration // Separate from AstTraceInc; as a declaration can't be deleted @@ -5271,12 +5293,10 @@ private: const AstVarType m_varType; // Type of variable (for localparam vs. param) const AstBasicDTypeKwd m_declKwd; // Keyword at declaration time const VDirection m_declDirection; // Declared direction input/output etc - const bool m_isScoped; // Uses run-time scope (for interfaces) public: AstTraceDecl(FileLine* fl, const string& showname, AstVar* varp, // For input/output state etc - AstNode* valuep, const VNumRange& bitRange, const VNumRange& arrayRange, - bool isScoped) + AstNode* valuep, const VNumRange& bitRange, const VNumRange& arrayRange) : ASTGEN_SUPER_TraceDecl(fl) , m_showname{showname} , m_bitRange{bitRange} @@ -5286,8 +5306,7 @@ public: * (VL_EDATASIZE / 32))) // A code is always 32-bits , m_varType{varp->varType()} , m_declKwd{varp->declKwd()} - , m_declDirection{varp->declDirection()} - , m_isScoped{isScoped} { + , m_declDirection{varp->declDirection()} { dtypeFrom(valuep); addNOp1p(valuep); } @@ -5307,7 +5326,6 @@ public: AstVarType varType() const { return m_varType; } AstBasicDTypeKwd declKwd() const { return m_declKwd; } VDirection declDirection() const { return m_declDirection; } - bool isScoped() const { return m_isScoped; } AstNode* valuep() const { return op1p(); } }; diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 67a68d6db..dc2e4bf02 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -441,9 +441,6 @@ public: iterateAndNextNull(nodep->exprp()); puts("; }\n"); } - virtual void visit(AstIntfRef* nodep) override { - putsQuoted(VIdProtect::protectWordsIf(AstNode::vcdName(nodep->name()), nodep->protect())); - } virtual void visit(AstNodeCase* nodep) override { // LCOV_EXCL_LINE // In V3Case... nodep->v3fatalSrc("Case statements should have been reduced out"); diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp index 2b471b6f1..54d3141a0 100644 --- a/src/V3EmitCImp.cpp +++ b/src/V3EmitCImp.cpp @@ -631,9 +631,7 @@ class EmitCTrace final : EmitCFunc { puts("(c+" + cvtToStr(nodep->code())); if (nodep->arrayRange().ranged()) puts("+i*" + cvtToStr(nodep->widthWords())); puts(","); - if (nodep->isScoped()) puts("Verilated::catName(scopep,"); putsQuoted(VIdProtect::protectWordsIf(nodep->showname(), nodep->protect())); - if (nodep->isScoped()) puts(",(int)scopet,\" \")"); // Direction if (v3Global.opt.traceFormat().fst()) { puts("," + cvtToStr(enumNum)); @@ -836,12 +834,22 @@ class EmitCTrace final : EmitCFunc { EmitCFunc::visit(nodep); } + virtual void visit(AstTracePushNamePrefix* nodep) override { + puts("tracep->pushNamePrefix("); + putsQuoted(VIdProtect::protectWordsIf(nodep->prefix(), nodep->protect())); + puts(");\n"); + } + virtual void visit(AstTracePopNamePrefix* nodep) override { // + puts("tracep->popNamePrefix("); + puts(cvtToStr(nodep->count())); + puts(");\n"); + } virtual void visit(AstTraceDecl* nodep) override { const int enumNum = emitTraceDeclDType(nodep->dtypep()); if (nodep->arrayRange().ranged()) { - puts("{int i; for (i=0; i<" + cvtToStr(nodep->arrayRange().elements()) + "; i++) {\n"); + puts("for (int i = 0; i < " + cvtToStr(nodep->arrayRange().elements()) + "; ++i) {\n"); emitTraceInitOne(nodep, enumNum); - puts("}}\n"); + puts("\n}\n"); } else { emitTraceInitOne(nodep, enumNum); puts("\n"); diff --git a/src/V3EmitCModel.cpp b/src/V3EmitCModel.cpp index 93d84d292..eb87de72c 100644 --- a/src/V3EmitCModel.cpp +++ b/src/V3EmitCModel.cpp @@ -563,9 +563,10 @@ class EmitCModel final : public EmitCFunc { "0.\");\n"); puts("}\n"); puts("vlSymsp->__Vm_baseCode = code;\n"); - puts("tracep->module(vlSymsp->name());\n"); puts("tracep->scopeEscape(' ');\n"); + puts("tracep->pushNamePrefix(std::string{vlSymsp->name()} + ' ');\n"); puts(topModNameProtected + "__" + protect("trace_init_top") + "(vlSelf, tracep);\n"); + puts("tracep->popNamePrefix();\n"); puts("tracep->scopeEscape('.');\n"); // Restore so later traced files won't break puts("}\n"); diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp index db1d60667..55f73e7d4 100644 --- a/src/V3TraceDecl.cpp +++ b/src/V3TraceDecl.cpp @@ -29,6 +29,62 @@ #include "V3EmitCBase.h" #include "V3Stats.h" +#include +#include +#include +#include + +//###################################################################### +// Utility class to emit path adjustments + +class PathAdjustor final { + FileLine* const m_flp; // FileLine used for created nodes + std::function m_emit; // Function called with adjustment statements + std::vector m_stack{""}; // Stack of current paths + + static constexpr char SEPARATOR = ' '; + +public: + explicit PathAdjustor(FileLine* flp, std::function emit) + : m_flp{flp} + , m_emit{emit} {} + + // Emit Prefix adjustments until the current path is 'newPath' + void adjust(const string& newPath) { + // Move up to enclosing path + unsigned toPop = 0; + while (!VString::startsWith(newPath, m_stack.back())) { + ++toPop; + m_stack.pop_back(); + } + if (toPop) m_emit(new AstTracePopNamePrefix{m_flp, toPop}); + // Move down, one path element at a time + if (newPath != m_stack.back()) { + const string& extraPrefix = newPath.substr(m_stack.back().size()); + size_t begin = 0; + while (true) { + const size_t end = extraPrefix.find(SEPARATOR, begin); + if (end == string::npos) break; + const string& extra = extraPrefix.substr(begin, end + 1 - begin); + m_emit(new AstTracePushNamePrefix{m_flp, extra}); + m_stack.push_back(m_stack.back() + extra); + begin = end + 1; + } + const string& extra = extraPrefix.substr(begin); + if (!extra.empty()) { + m_emit(new AstTracePushNamePrefix{m_flp, extra + SEPARATOR}); + m_stack.push_back(m_stack.back() + extra); + } + } + } + + // Emit Prefix adjustments to unwind the path back to its original state + void unwind() { + const unsigned toPop = m_stack.size() - 1; + if (toPop) m_emit(new AstTracePopNamePrefix{m_flp, toPop}); + } +}; + //###################################################################### // TraceDecl state, as a visitor of each AstNode @@ -37,15 +93,38 @@ private: // NODE STATE // STATE - AstScope* const m_topScopep = v3Global.rootp()->topScopep()->scopep(); // The top AstScope - AstCFunc* m_initFuncp = nullptr; // Trace function being built - AstCFunc* m_initSubFuncp = nullptr; // Trace function being built (under m_init) - int m_initSubStmts = 0; // Number of statements in function - int m_funcNum = 0; // Function number being built - const AstVarScope* m_traVscp = nullptr; // Signal being trace constructed - AstNode* m_traValuep = nullptr; // Signal being traced's value to trace in it - string m_traShowname; // Signal being traced's component name - bool m_interface = false; // Currently tracing an interface + AstTopScope* const m_topScopep; // The singleton AstTopScope + const AstScope* m_currScopep = nullptr; // Current scope being visited + + std::vector m_topFuncps; // Top level trace initialization functions + std::vector m_subFuncps; // Trace sub functions for this scope + int m_topFuncSize = 0; // Size of the top function currently being built + int m_subFuncSize = 0; // Size of the sub function currently being built + const int m_funcSizeLimit // Maximum size of a function + = v3Global.opt.outputSplitCTrace() ? v3Global.opt.outputSplitCTrace() + : std::numeric_limits::max(); + // Trace init sub functions to invoke for path names in the hierarchy. Note path names and + // AstScope instances are not one to one due to the presence of AstIntfRef. + std::map> m_scopeSubFuncps; + + struct Signal final { + AstVarScope* m_vscp; // AstVarScope being traced (non const to allow copy during sorting) + std::string m_path; // Path to enclosing module in hierarchy + std::string m_name; // Name of signal + Signal(AstVarScope* vscp) + : m_vscp{vscp} { + // Compute path in hierarchy and signal name + const string& vcdName = AstNode::vcdName(vscp->varp()->name()); + const size_t pos = vcdName.rfind(' '); + const size_t pathLen = pos == string::npos ? 0 : pos + 1; + m_path = vcdName.substr(0, pathLen); + m_name = vcdName.substr(pathLen); + } + }; + std::vector m_signals; // Signals under current scope + AstVarScope* m_traVscp = nullptr; // Current AstVarScope we are constructing AstTraceDecls for + AstNode* m_traValuep = nullptr; // Value expression for current signal + string m_traName; // Name component for current signal VDouble0 m_statSigs; // Statistic tracking VDouble0 m_statIgnSigs; // Statistic tracking @@ -69,38 +148,44 @@ private: return nullptr; } - AstCFunc* newCFunc(const string& name) { - FileLine* const flp = m_topScopep->fileline(); - AstCFunc* const funcp = new AstCFunc(flp, name, m_topScopep); - string argTypes = v3Global.opt.traceClassBase() + "* tracep"; - if (m_interface) argTypes += ", int scopet, const char* scopep"; - funcp->argTypes(argTypes); + AstCFunc* newCFunc(FileLine* flp, const string& name) { + AstScope* const topScopep = m_topScopep->scopep(); + AstCFunc* const funcp = new AstCFunc{flp, name, topScopep}; + funcp->argTypes(v3Global.opt.traceClassBase() + "* tracep"); funcp->isTrace(true); funcp->isStatic(false); funcp->isLoose(true); funcp->slow(true); - m_topScopep->addActivep(funcp); - UINFO(5, " Newfunc " << funcp << endl); + topScopep->addActivep(funcp); return funcp; } - void callCFuncSub(AstCFunc* basep, AstCFunc* funcp, AstIntfRef* irp) { - AstCCall* const callp = new AstCCall(funcp->fileline(), funcp); - if (irp) { - callp->argTypes("tracep, VLT_TRACE_SCOPE_INTERFACE"); - callp->addArgsp(irp->unlinkFrBack()); - } else { - callp->argTypes("tracep"); + + void addToTopFunc(AstNodeStmt* stmtp) { + if (m_topFuncSize > m_funcSizeLimit || m_topFuncps.empty()) { + m_topFuncSize = 0; + // + const string n = cvtToStr(m_topFuncps.size()); + const string name{"trace_init_top__" + n}; + AstCFunc* const funcp = newCFunc(m_topScopep->fileline(), name); + m_topFuncps.push_back(funcp); } - basep->addStmtsp(callp); + m_topFuncps.back()->addStmtsp(stmtp); + m_topFuncSize += EmitCBaseCounterVisitor{stmtp}.count(); } - AstCFunc* newCFuncSub(AstCFunc* basep) { - FileLine* const fl = basep->fileline(); - const string name = "trace_init_sub_" + cvtToStr(m_funcNum++); - AstCFunc* const funcp = newCFunc(name); - funcp->addInitsp(new AstCStmt(fl, "const int c = vlSymsp->__Vm_baseCode;\n")); - funcp->addInitsp(new AstCStmt(fl, "if (false && tracep && c) {} // Prevent unused\n")); - if (!m_interface) callCFuncSub(basep, funcp, nullptr); - return funcp; + + void addToSubFunc(AstNodeStmt* stmtp) { + if (m_subFuncSize > m_funcSizeLimit || m_subFuncps.empty()) { + m_subFuncSize = 0; + // + FileLine* const flp = m_currScopep->fileline(); + const string n = cvtToStr(m_subFuncps.size()); + const string name{"trace_init_sub__" + m_currScopep->nameDotless() + "__" + n}; + AstCFunc* const funcp = newCFunc(flp, name); + funcp->addInitsp(new AstCStmt{flp, "const int c = vlSymsp->__Vm_baseCode;\n"}); + m_subFuncps.push_back(funcp); + } + m_subFuncps.back()->addStmtsp(stmtp); + m_subFuncSize += EmitCBaseCounterVisitor{stmtp}.count(); } std::string getScopeChar(VltTraceScope sct) { return std::string(1, (char)(0x80 + sct)); } @@ -114,114 +199,124 @@ private: } else if (const AstBasicDType* const bdtypep = m_traValuep->dtypep()->basicp()) { bitRange = bdtypep->nrange(); } - AstTraceDecl* const declp - = new AstTraceDecl(m_traVscp->fileline(), m_traShowname, m_traVscp->varp(), - m_traValuep->cloneTree(true), bitRange, arrayRange, m_interface); - UINFO(9, "Decl " << declp << endl); - - if (!m_interface && v3Global.opt.outputSplitCTrace() - && m_initSubStmts > v3Global.opt.outputSplitCTrace()) { - m_initSubFuncp = newCFuncSub(m_initFuncp); - m_initSubStmts = 0; - } - - m_initSubFuncp->addStmtsp(declp); - m_initSubStmts += EmitCBaseCounterVisitor(declp).count(); + addToSubFunc(new AstTraceDecl{m_traVscp->fileline(), m_traName, m_traVscp->varp(), + m_traValuep->cloneTree(false), bitRange, arrayRange}); } + void addIgnore(const char* why) { ++m_statIgnSigs; - m_initSubFuncp->addStmtsp(new AstComment( - m_traVscp->fileline(), "Tracing: " + m_traShowname + " // Ignored: " + why, true)); + addToSubFunc(new AstComment{m_traVscp->fileline(), + "Tracing: " + m_traName + " // Ignored: " + why, true}); } // VISITORS - virtual void visit(AstTopScope* nodep) override { - // Create the trace init function - m_initFuncp = newCFunc("trace_init_top"); - // Create initial sub function - m_initSubFuncp = newCFuncSub(m_initFuncp); - // And find variables - iterateChildren(nodep); - } virtual void visit(AstScope* nodep) override { - const AstCell* const cellp = nodep->aboveCellp(); - if (cellp && VN_IS(cellp->modp(), Iface)) { - AstCFunc* const origSubFunc = m_initSubFuncp; - int origSubStmts = m_initSubStmts; - { - m_interface = true; - m_initSubFuncp = newCFuncSub(origSubFunc); - string scopeName = nodep->prettyName(); - const size_t lastDot = scopeName.find_last_of('.'); - UASSERT_OBJ(lastDot != string::npos, nodep, - "Expected an interface scope name to have at least one dot"); - scopeName = scopeName.substr(0, lastDot + 1); - const size_t scopeLen = scopeName.length(); + UASSERT_OBJ(!m_currScopep, nodep, "Should not nest"); + UASSERT_OBJ(m_subFuncps.empty(), nodep, "Should not nest"); + UASSERT_OBJ(m_signals.empty(), nodep, "Should not nest"); + UASSERT_OBJ(!m_traVscp, nodep, "Should not nest"); + UASSERT_OBJ(m_traName.empty(), nodep, "Should not nest"); - AstIntfRef* nextIrp = cellp->intfRefp(); - // While instead of for loop because interface references will - // be unlinked as we go - while (nextIrp) { - AstIntfRef* const irp = nextIrp; - nextIrp = VN_AS(irp->nextp(), IntfRef); + FileLine* const flp = nodep->fileline(); + m_currScopep = nodep; - const string irpName = irp->prettyName(); - if (scopeLen > irpName.length()) continue; - const string intfScopeName = irpName.substr(0, scopeLen); - if (scopeName != intfScopeName) continue; - callCFuncSub(origSubFunc, m_initSubFuncp, irp); - ++origSubStmts; - } - iterateChildren(nodep); - } - m_initSubFuncp = origSubFunc; - m_initSubStmts = origSubStmts; - m_interface = false; - } else { - iterateChildren(nodep); + // Gather all signals under this AstScope + iterateChildrenConst(nodep); + + // If nothing to trace in this scope, then job done + if (m_signals.empty()) { + m_currScopep = nullptr; + return; } - } - virtual void visit(AstVarScope* nodep) override { - iterateChildren(nodep); - // Prefilter - things that get through this if will either get - // traced or get a comment as to why not traced. - // Generally this equation doesn't need updating, instead use - // varp->isTrace() and/or vscIgnoreTrace. - if ((!nodep->varp()->isTemp() || nodep->varp()->isTrace()) - && !nodep->varp()->isClassMember() && !nodep->varp()->isFuncLocal()) { - UINFO(5, " vsc " << nodep << endl); - const AstVar* const varp = nodep->varp(); - const AstScope* const scopep = nodep->scopep(); - // Compute show name - // This code assumes SPTRACEVCDC_VERSION >= 1330; - // it uses spaces to separate hierarchy components. - if (m_interface) { - m_traShowname = AstNode::vcdName(varp->name()); - } else { - m_traShowname = AstNode::vcdName(scopep->name() + " " + varp->name()); - if (m_traShowname.substr(0, 4) == "TOP ") m_traShowname.erase(0, 4); - } - UASSERT_OBJ(m_initSubFuncp, nodep, "nullptr"); - m_traVscp = nodep; - if (const char* const ignoreReasonp = vscIgnoreTrace(nodep)) { + // Sort signals, first by enclosing instance, then by source location, then by name + std::stable_sort(m_signals.begin(), m_signals.end(), [](const Signal& a, const Signal& b) { + if (const int cmp = a.m_path.compare(b.m_path)) return cmp < 0; + const FileLine* const aflp = a.m_vscp->fileline(); + const FileLine* const bflp = b.m_vscp->fileline(); + if (const int cmp = aflp->operatorCompare(*bflp)) return cmp < 0; + return a.m_name < b.m_name; + }); + + // Build trace initialization functions for this AstScope + PathAdjustor pathAdjustor{flp, [&](AstNodeStmt* stmtp) { addToSubFunc(stmtp); }}; + for (const Signal& signal : m_signals) { + // Adjust name prefix based on path in hierarchy + pathAdjustor.adjust(signal.m_path); + + // Build AstTraceDecl for this signal + m_traVscp = signal.m_vscp; + m_traName = signal.m_name; + if (const char* const ignoreReasonp = vscIgnoreTrace(m_traVscp)) { addIgnore(ignoreReasonp); } else { ++m_statSigs; - if (nodep->valuep()) { - m_traValuep = nodep->valuep()->cloneTree(true); + if (AstNode* const valuep = m_traVscp->valuep()) { + m_traValuep = valuep->cloneTree(false); } else { - m_traValuep = new AstVarRef(nodep->fileline(), nodep, VAccess::READ); + m_traValuep = new AstVarRef{m_traVscp->fileline(), m_traVscp, VAccess::READ}; } - // Recurse into data type of the signal; the visitors will call addTraceDecl() - iterate(varp->dtypep()->skipRefToEnump()); + // Recurse into data type of the signal. The visit methods will add AstTraceDecls. + iterate(m_traVscp->varp()->dtypep()->skipRefToEnump()); // Cleanup - if (m_traValuep) VL_DO_CLEAR(m_traValuep->deleteTree(), m_traValuep = nullptr); + if (m_traValuep) VL_DO_DANGLING(m_traValuep->deleteTree(), m_traValuep); } - m_traVscp = nullptr; - m_traShowname = ""; } + pathAdjustor.unwind(); + m_traVscp = nullptr; + m_traName.clear(); + UASSERT_OBJ(!m_traValuep, nodep, "Should have been deleted"); + m_signals.clear(); + + // Add sub functions to m_scopeSubFuncps + const AstCell* const cellp = nodep->aboveCellp(); + if (cellp && VN_IS(cellp->modp(), Iface)) { + string scopeName = nodep->prettyName(); + const size_t lastDot = scopeName.find_last_of('.'); + UASSERT_OBJ(lastDot != string::npos, nodep, + "Expected an interface scope name to have at least one dot"); + scopeName = scopeName.substr(0, lastDot + 1); + const size_t scopeLen = scopeName.length(); + + for (AstIntfRef *irp = cellp->intfRefp(), *nextIrp; irp; irp = nextIrp) { + nextIrp = VN_AS(irp->nextp(), IntfRef); + + const string irpName = irp->prettyName(); + if (scopeLen > irpName.length()) continue; + const string intfScopeName = irpName.substr(0, scopeLen); + if (scopeName != intfScopeName) continue; + + string scopeName = AstNode::vcdName(irp->name()); + if (scopeName.substr(0, 4) == "TOP ") scopeName.erase(0, 4); + scopeName += getScopeChar(VLT_TRACE_SCOPE_INTERFACE) + ' '; + m_scopeSubFuncps.emplace(scopeName, m_subFuncps); + + VL_DO_DANGLING(irp->unlinkFrBack(), irp); + } + + m_subFuncps.clear(); + } else { + string scopeName = AstNode::vcdName(nodep->name()) + ' '; + if (VString::startsWith(scopeName, "TOP ")) scopeName.erase(0, 4); + m_scopeSubFuncps.emplace(scopeName, std::move(m_subFuncps)); + } + + m_currScopep = nullptr; } + virtual void visit(AstVarScope* nodep) override { + UASSERT_OBJ(m_currScopep, nodep, "AstVarScope not under AstScope"); + + // Prefilter - things that get added to m_vscps will either get traced or get a comment as + // to why they are not traced. Generally these conditions doesn't need updating, instead + // use varp->isTrace() and/or vscIgnoreTrace. + if (nodep->varp()->isTemp() && !nodep->varp()->isTrace()) return; + if (nodep->varp()->isClassMember()) return; + if (nodep->varp()->isFuncLocal()) return; + + // Add to traced signal list + m_signals.emplace_back(nodep); + } + // VISITORS - Data types when tracing virtual void visit(AstConstDType* nodep) override { if (m_traVscp) iterate(nodep->subDTypep()->skipRefToEnump()); @@ -247,20 +342,20 @@ private: } } else { // Unroll now, as have no other method to get right signal names + FileLine* const flp = nodep->fileline(); AstNodeDType* const subtypep = nodep->subDTypep()->skipRefToEnump(); + VL_RESTORER(m_traName); + addToSubFunc(new AstTracePushNamePrefix{flp, m_traName}); for (int i = nodep->lo(); i <= nodep->hi(); ++i) { - VL_RESTORER(m_traShowname); VL_RESTORER(m_traValuep); - { - m_traShowname += string("[") + cvtToStr(i) + string("]"); - m_traValuep = new AstArraySel( - nodep->fileline(), m_traValuep->cloneTree(true), i - nodep->lo()); - - m_traValuep->dtypep(subtypep); - iterate(subtypep); - VL_DO_CLEAR(m_traValuep->deleteTree(), m_traValuep = nullptr); - } + m_traName = string{"["} + cvtToStr(i) + string{"]"}; + m_traValuep = m_traValuep->cloneTree(false); + m_traValuep = new AstArraySel{flp, m_traValuep, i - nodep->lo()}; + m_traValuep->dtypep(subtypep); + iterate(subtypep); + VL_DO_CLEAR(m_traValuep->deleteTree(), m_traValuep = nullptr); } + addToSubFunc(new AstTracePopNamePrefix{flp, 1}); } } } @@ -272,20 +367,21 @@ private: // a much faster way to trace addTraceDecl(VNumRange(), nodep->width()); } else { + FileLine* const flp = nodep->fileline(); AstNodeDType* const subtypep = nodep->subDTypep()->skipRefToEnump(); + VL_RESTORER(m_traName); + addToSubFunc(new AstTracePushNamePrefix{flp, m_traName}); for (int i = nodep->lo(); i <= nodep->hi(); ++i) { - VL_RESTORER(m_traShowname); VL_RESTORER(m_traValuep); - { - m_traShowname += string("[") + cvtToStr(i) + string("]"); - m_traValuep - = new AstSel(nodep->fileline(), m_traValuep->cloneTree(true), - (i - nodep->lo()) * subtypep->width(), subtypep->width()); - m_traValuep->dtypep(subtypep); - iterate(subtypep); - VL_DO_CLEAR(m_traValuep->deleteTree(), m_traValuep = nullptr); - } + m_traName = string{"["} + cvtToStr(i) + string{"]"}; + const int lsb = (i - nodep->lo()) * subtypep->width(); + m_traValuep = m_traValuep->cloneTree(false); + m_traValuep = new AstSel{flp, m_traValuep, lsb, subtypep->width()}; + m_traValuep->dtypep(subtypep); + iterate(subtypep); + VL_DO_CLEAR(m_traValuep->deleteTree(), m_traValuep = nullptr); } + addToSubFunc(new AstTracePopNamePrefix{flp, 1}); } } } @@ -299,31 +395,30 @@ private: } else if (!nodep->packed()) { addIgnore("Unsupported: Unpacked struct/union"); } else { + FileLine* const flp = nodep->fileline(); + const bool isStruct = VN_IS(nodep, StructDType); // Otherwise union + VL_RESTORER(m_traName); + string prefix{m_traName}; + prefix += isStruct ? getScopeChar(VLT_TRACE_SCOPE_STRUCT) // Mark scope type + : getScopeChar(VLT_TRACE_SCOPE_UNION); + addToSubFunc(new AstTracePushNamePrefix{flp, prefix + ' '}); for (const AstMemberDType* itemp = nodep->membersp(); itemp; itemp = VN_AS(itemp->nextp(), MemberDType)) { AstNodeDType* const subtypep = itemp->subDTypep()->skipRefToEnump(); - VL_RESTORER(m_traShowname); - VL_RESTORER(m_traValuep); - { - if (VN_IS(nodep, StructDType)) { - // Mark scope as a struct by setting the last char to 0x80 + the - // fstScopeType - m_traShowname += getScopeChar(VLT_TRACE_SCOPE_STRUCT) + " " - + itemp->prettyName(); - - m_traValuep - = new AstSel(nodep->fileline(), m_traValuep->cloneTree(true), - itemp->lsb(), subtypep->width()); - m_traValuep->dtypep(subtypep); - iterate(subtypep); - VL_DO_CLEAR(m_traValuep->deleteTree(), m_traValuep = nullptr); - } else { // Else union, replicate fields - m_traShowname - += getScopeChar(VLT_TRACE_SCOPE_UNION) + " " + itemp->prettyName(); - iterate(subtypep); - } + m_traName = itemp->prettyName(); + if (isStruct) { + VL_RESTORER(m_traValuep); + m_traValuep = m_traValuep->cloneTree(false); + m_traValuep + = new AstSel{flp, m_traValuep, itemp->lsb(), subtypep->width()}; + m_traValuep->dtypep(subtypep); + iterate(subtypep); + VL_DO_CLEAR(m_traValuep->deleteTree(), m_traValuep = nullptr); + } else { // Else union, replicate fields + iterate(subtypep); } } + addToSubFunc(new AstTracePopNamePrefix{flp, 1}); } } } @@ -348,7 +443,48 @@ private: public: // CONSTRUCTORS - explicit TraceDeclVisitor(AstNetlist* nodep) { iterate(nodep); } + explicit TraceDeclVisitor(AstNetlist* nodep) + : m_topScopep{nodep->topScopep()} { + FileLine* const flp = nodep->fileline(); + + // Iterate modules to build per scope initialization sub functions + iterateAndNextConstNull(nodep->modulesp()); + UASSERT_OBJ(m_subFuncps.empty(), nodep, "Should have been emptied"); + + // Build top level trace initialization functions + PathAdjustor pathAdjustor{flp, [&](AstNodeStmt* stmtp) { addToTopFunc(stmtp); }}; + for (const auto& item : m_scopeSubFuncps) { + // Adjust name prefix based on path in hierarchy + pathAdjustor.adjust(item.first); + + // Call all sub functions for this path + for (AstCFunc* const subFuncp : item.second) { + AstCCall* const callp = new AstCCall{flp, subFuncp}; + callp->argTypes("tracep"); + addToTopFunc(callp); + } + } + pathAdjustor.unwind(); + + // Ensure a top function exists, in case there was nothing to trace at all + if (m_topFuncps.empty()) addToTopFunc(new AstComment{flp, "Empty"}); + + // Create single top level function, if more than one exists + if (m_topFuncps.size() > 1) { + AstCFunc* const topFuncp = newCFunc(flp, ""); + for (AstCFunc* funcp : m_topFuncps) { + AstCCall* const callp = new AstCCall{flp, funcp}; + callp->argTypes("tracep"); + topFuncp->addStmtsp(callp); + } + m_topFuncps.clear(); + m_topFuncps.push_back(topFuncp); + } + + // Set name of top level function + AstCFunc* const topFuncp = m_topFuncps.front(); + topFuncp->name("trace_init_top"); + } virtual ~TraceDeclVisitor() override { V3Stats::addStat("Tracing, Traced signals", m_statSigs); V3Stats::addStat("Tracing, Ignored signals", m_statIgnSigs); diff --git a/test_regress/t/t_cover_line_trace.out b/test_regress/t/t_cover_line_trace.out index 56c0bd1d1..9c6365e91 100644 --- a/test_regress/t/t_cover_line_trace.out +++ b/test_regress/t/t_cover_line_trace.out @@ -1,7 +1,6 @@ $version Generated by VerilatedVcd $end -$date Sun May 31 15:48:42 2020 - $end -$timescale 1ps $end +$date Sat Dec 18 13:32:31 2021 $end +$timescale 1ps $end $scope module top $end $var wire 1 W clk $end @@ -11,31 +10,31 @@ $timescale 1ps $end $var wire 8 ' cyc_copy [7:0] $end $var wire 1 % toggle $end $var wire 32 ; vlCoverageLineTrace_t_cover_line__102_elsif [31:0] $end - $var wire 32 : vlCoverageLineTrace_t_cover_line__105_elsif [31:0] $end - $var wire 32 9 vlCoverageLineTrace_t_cover_line__112_else [31:0] $end - $var wire 32 8 vlCoverageLineTrace_t_cover_line__112_if [31:0] $end + $var wire 32 < vlCoverageLineTrace_t_cover_line__105_elsif [31:0] $end + $var wire 32 = vlCoverageLineTrace_t_cover_line__112_else [31:0] $end + $var wire 32 > vlCoverageLineTrace_t_cover_line__112_if [31:0] $end $var wire 32 X vlCoverageLineTrace_t_cover_line__119_block [31:0] $end $var wire 32 # vlCoverageLineTrace_t_cover_line__15_block [31:0] $end $var wire 32 $ vlCoverageLineTrace_t_cover_line__18_block [31:0] $end - $var wire 32 > vlCoverageLineTrace_t_cover_line__47_block [31:0] $end - $var wire 32 = vlCoverageLineTrace_t_cover_line__48_else [31:0] $end - $var wire 32 < vlCoverageLineTrace_t_cover_line__48_if [31:0] $end - $var wire 32 ) vlCoverageLineTrace_t_cover_line__52_else [31:0] $end - $var wire 32 ( vlCoverageLineTrace_t_cover_line__52_if [31:0] $end - $var wire 32 + vlCoverageLineTrace_t_cover_line__53_else [31:0] $end - $var wire 32 * vlCoverageLineTrace_t_cover_line__53_if [31:0] $end - $var wire 32 - vlCoverageLineTrace_t_cover_line__58_else [31:0] $end - $var wire 32 , vlCoverageLineTrace_t_cover_line__58_if [31:0] $end - $var wire 32 / vlCoverageLineTrace_t_cover_line__59_else [31:0] $end - $var wire 32 . vlCoverageLineTrace_t_cover_line__59_if [31:0] $end - $var wire 32 1 vlCoverageLineTrace_t_cover_line__65_else [31:0] $end - $var wire 32 0 vlCoverageLineTrace_t_cover_line__65_if [31:0] $end - $var wire 32 3 vlCoverageLineTrace_t_cover_line__66_else [31:0] $end - $var wire 32 2 vlCoverageLineTrace_t_cover_line__66_if [31:0] $end + $var wire 32 ( vlCoverageLineTrace_t_cover_line__47_block [31:0] $end + $var wire 32 ) vlCoverageLineTrace_t_cover_line__48_else [31:0] $end + $var wire 32 * vlCoverageLineTrace_t_cover_line__48_if [31:0] $end + $var wire 32 + vlCoverageLineTrace_t_cover_line__52_else [31:0] $end + $var wire 32 , vlCoverageLineTrace_t_cover_line__52_if [31:0] $end + $var wire 32 - vlCoverageLineTrace_t_cover_line__53_else [31:0] $end + $var wire 32 . vlCoverageLineTrace_t_cover_line__53_if [31:0] $end + $var wire 32 / vlCoverageLineTrace_t_cover_line__58_else [31:0] $end + $var wire 32 0 vlCoverageLineTrace_t_cover_line__58_if [31:0] $end + $var wire 32 1 vlCoverageLineTrace_t_cover_line__59_else [31:0] $end + $var wire 32 2 vlCoverageLineTrace_t_cover_line__59_if [31:0] $end + $var wire 32 3 vlCoverageLineTrace_t_cover_line__65_else [31:0] $end + $var wire 32 4 vlCoverageLineTrace_t_cover_line__65_if [31:0] $end + $var wire 32 5 vlCoverageLineTrace_t_cover_line__66_else [31:0] $end + $var wire 32 6 vlCoverageLineTrace_t_cover_line__66_if [31:0] $end $var wire 32 7 vlCoverageLineTrace_t_cover_line__75_elsif [31:0] $end - $var wire 32 6 vlCoverageLineTrace_t_cover_line__79_elsif [31:0] $end - $var wire 32 5 vlCoverageLineTrace_t_cover_line__83_else [31:0] $end - $var wire 32 4 vlCoverageLineTrace_t_cover_line__83_if [31:0] $end + $var wire 32 8 vlCoverageLineTrace_t_cover_line__79_elsif [31:0] $end + $var wire 32 9 vlCoverageLineTrace_t_cover_line__83_else [31:0] $end + $var wire 32 : vlCoverageLineTrace_t_cover_line__83_if [31:0] $end $var wire 32 ] vlCoverageLineTrace_t_cover_line__92_block [31:0] $end $var wire 32 ^ vlCoverageLineTrace_t_cover_line__93_block [31:0] $end $var wire 32 _ vlCoverageLineTrace_t_cover_line__96_block [31:0] $end @@ -43,57 +42,57 @@ $timescale 1ps $end $scope module a1 $end $var wire 1 W clk $end $var wire 1 % toggle $end - $var wire 32 B vlCoverageLineTrace_t_cover_line__132_block [31:0] $end + $var wire 32 ? vlCoverageLineTrace_t_cover_line__132_block [31:0] $end $var wire 32 @ vlCoverageLineTrace_t_cover_line__133_else [31:0] $end - $var wire 32 ? vlCoverageLineTrace_t_cover_line__133_if [31:0] $end - $var wire 32 A vlCoverageLineTrace_t_cover_line__137_else [31:0] $end + $var wire 32 A vlCoverageLineTrace_t_cover_line__133_if [31:0] $end + $var wire 32 B vlCoverageLineTrace_t_cover_line__137_else [31:0] $end $upscope $end $scope module a2 $end $var wire 1 W clk $end $var wire 1 % toggle $end - $var wire 32 F vlCoverageLineTrace_t_cover_line__132_block [31:0] $end + $var wire 32 C vlCoverageLineTrace_t_cover_line__132_block [31:0] $end $var wire 32 D vlCoverageLineTrace_t_cover_line__133_else [31:0] $end - $var wire 32 C vlCoverageLineTrace_t_cover_line__133_if [31:0] $end - $var wire 32 E vlCoverageLineTrace_t_cover_line__137_else [31:0] $end + $var wire 32 E vlCoverageLineTrace_t_cover_line__133_if [31:0] $end + $var wire 32 F vlCoverageLineTrace_t_cover_line__137_else [31:0] $end $upscope $end $scope module b1 $end $var wire 1 W clk $end $var wire 1 % toggle $end - $var wire 32 O vlCoverageLineTrace_t_cover_line__156_block [31:0] $end - $var wire 32 K vlCoverageLineTrace_t_cover_line__158_else [31:0] $end + $var wire 32 K vlCoverageLineTrace_t_cover_line__156_block [31:0] $end + $var wire 32 L vlCoverageLineTrace_t_cover_line__158_else [31:0] $end $var wire 32 b vlCoverageLineTrace_t_cover_line__158_if [31:0] $end $var wire 32 M vlCoverageLineTrace_t_cover_line__162_else [31:0] $end - $var wire 32 L vlCoverageLineTrace_t_cover_line__162_if [31:0] $end - $var wire 32 N vlCoverageLineTrace_t_cover_line__166_else [31:0] $end + $var wire 32 N vlCoverageLineTrace_t_cover_line__162_if [31:0] $end + $var wire 32 O vlCoverageLineTrace_t_cover_line__166_else [31:0] $end $upscope $end $scope module b2 $end $var wire 1 W clk $end $var wire 1 % toggle $end - $var wire 32 T vlCoverageLineTrace_t_cover_line__156_block [31:0] $end - $var wire 32 P vlCoverageLineTrace_t_cover_line__158_else [31:0] $end + $var wire 32 P vlCoverageLineTrace_t_cover_line__156_block [31:0] $end + $var wire 32 Q vlCoverageLineTrace_t_cover_line__158_else [31:0] $end $var wire 32 c vlCoverageLineTrace_t_cover_line__158_if [31:0] $end $var wire 32 R vlCoverageLineTrace_t_cover_line__162_else [31:0] $end - $var wire 32 Q vlCoverageLineTrace_t_cover_line__162_if [31:0] $end - $var wire 32 S vlCoverageLineTrace_t_cover_line__166_else [31:0] $end + $var wire 32 S vlCoverageLineTrace_t_cover_line__162_if [31:0] $end + $var wire 32 T vlCoverageLineTrace_t_cover_line__166_else [31:0] $end $upscope $end $scope module o1 $end $var wire 1 W clk $end $var wire 1 % toggle $end - $var wire 32 J vlCoverageLineTrace_t_cover_line__220_block [31:0] $end - $var wire 32 I vlCoverageLineTrace_t_cover_line__221_else [31:0] $end - $var wire 32 H vlCoverageLineTrace_t_cover_line__221_if [31:0] $end - $var wire 32 G vlCoverageLineTrace_t_cover_line__224_else [31:0] $end + $var wire 32 G vlCoverageLineTrace_t_cover_line__220_block [31:0] $end + $var wire 32 H vlCoverageLineTrace_t_cover_line__221_else [31:0] $end + $var wire 32 I vlCoverageLineTrace_t_cover_line__221_if [31:0] $end + $var wire 32 J vlCoverageLineTrace_t_cover_line__224_else [31:0] $end $var wire 32 a vlCoverageLineTrace_t_cover_line__224_if [31:0] $end $upscope $end $scope module t1 $end $var wire 1 W clk $end $var wire 1 % toggle $end $var wire 32 U vlCoverageLineTrace_t_cover_line__187_block [31:0] $end - $var wire 32 \ vlCoverageLineTrace_t_cover_line__191_block [31:0] $end + $var wire 32 Y vlCoverageLineTrace_t_cover_line__191_block [31:0] $end $var wire 32 Z vlCoverageLineTrace_t_cover_line__194_else [31:0] $end - $var wire 32 Y vlCoverageLineTrace_t_cover_line__194_if [31:0] $end + $var wire 32 [ vlCoverageLineTrace_t_cover_line__194_if [31:0] $end $var wire 32 V vlCoverageLineTrace_t_cover_line__197_else [31:0] $end - $var wire 32 [ vlCoverageLineTrace_t_cover_line__197_if [31:0] $end + $var wire 32 \ vlCoverageLineTrace_t_cover_line__197_if [31:0] $end $upscope $end $upscope $end $upscope $end @@ -169,7 +168,8 @@ b00000000000000000000000000000000 c #10 b00000000000000000000000000000010 & b00000010 ' -b00000000000000000000000000000001 ) +b00000000000000000000000000000001 ( +b00000000000000000000000000000001 * b00000000000000000000000000000001 + b00000000000000000000000000000001 - b00000000000000000000000000000001 / @@ -177,35 +177,35 @@ b00000000000000000000000000000001 1 b00000000000000000000000000000001 3 b00000000000000000000000000000001 5 b00000000000000000000000000000001 9 -b00000000000000000000000000000001 < -b00000000000000000000000000000001 > +b00000000000000000000000000000001 = +b00000000000000000000000000000001 ? b00000000000000000000000000000001 @ -b00000000000000000000000000000001 A b00000000000000000000000000000001 B +b00000000000000000000000000000001 C b00000000000000000000000000000001 D -b00000000000000000000000000000001 E b00000000000000000000000000000001 F -b00000000000000000000000000000001 I -b00000000000000000000000000000001 J +b00000000000000000000000000000001 G +b00000000000000000000000000000001 H b00000000000000000000000000000001 K +b00000000000000000000000000000001 L b00000000000000000000000000000001 M -b00000000000000000000000000000001 N b00000000000000000000000000000001 O b00000000000000000000000000000001 P +b00000000000000000000000000000001 Q b00000000000000000000000000000001 R -b00000000000000000000000000000001 S b00000000000000000000000000000001 T b00000000000000000000000000000001 U b00000000000000000000000000000001 V 1W +b00000000000000000000000000000001 Y b00000000000000000000000000000001 Z -b00000000000000000000000000000001 \ #15 0W #20 b00000000000000000000000000000011 & b00000011 ' -b00000000000000000000000000000010 ) +b00000000000000000000000000000010 ( +b00000000000000000000000000000010 * b00000000000000000000000000000010 + b00000000000000000000000000000010 - b00000000000000000000000000000010 / @@ -213,315 +213,314 @@ b00000000000000000000000000000010 1 b00000000000000000000000000000010 3 b00000000000000000000000000000010 5 b00000000000000000000000000000010 9 -b00000000000000000000000000000010 < -b00000000000000000000000000000010 > +b00000000000000000000000000000010 = +b00000000000000000000000000000010 ? b00000000000000000000000000000010 @ -b00000000000000000000000000000010 A b00000000000000000000000000000010 B +b00000000000000000000000000000010 C b00000000000000000000000000000010 D -b00000000000000000000000000000010 E b00000000000000000000000000000010 F -b00000000000000000000000000000010 I -b00000000000000000000000000000010 J +b00000000000000000000000000000010 G +b00000000000000000000000000000010 H b00000000000000000000000000000010 K +b00000000000000000000000000000010 L b00000000000000000000000000000010 M -b00000000000000000000000000000010 N b00000000000000000000000000000010 O b00000000000000000000000000000010 P +b00000000000000000000000000000010 Q b00000000000000000000000000000010 R -b00000000000000000000000000000010 S b00000000000000000000000000000010 T b00000000000000000000000000000010 U b00000000000000000000000000000010 V 1W +b00000000000000000000000000000010 Y b00000000000000000000000000000010 Z -b00000000000000000000000000000010 \ #25 0W #30 1% b00000000000000000000000000000100 & b00000100 ' -b00000000000000000000000000000001 ( -b00000000000000000000000000000001 * +b00000000000000000000000000000011 ( +b00000000000000000000000000000011 * b00000000000000000000000000000001 , b00000000000000000000000000000001 . b00000000000000000000000000000001 0 b00000000000000000000000000000001 2 +b00000000000000000000000000000001 4 +b00000000000000000000000000000001 6 b00000000000000000000000000000001 7 b00000000000000000000000000000001 ; -b00000000000000000000000000000011 < -b00000000000000000000000000000011 > +b00000000000000000000000000000011 ? b00000000000000000000000000000011 @ -b00000000000000000000000000000011 A b00000000000000000000000000000011 B +b00000000000000000000000000000011 C b00000000000000000000000000000011 D -b00000000000000000000000000000011 E b00000000000000000000000000000011 F -b00000000000000000000000000000011 I -b00000000000000000000000000000011 J +b00000000000000000000000000000011 G +b00000000000000000000000000000011 H b00000000000000000000000000000011 K +b00000000000000000000000000000011 L b00000000000000000000000000000011 M -b00000000000000000000000000000011 N b00000000000000000000000000000011 O b00000000000000000000000000000011 P +b00000000000000000000000000000011 Q b00000000000000000000000000000011 R -b00000000000000000000000000000011 S b00000000000000000000000000000011 T b00000000000000000000000000000011 U b00000000000000000000000000000011 V 1W +b00000000000000000000000000000011 Y b00000000000000000000000000000011 Z -b00000000000000000000000000000011 \ #35 0W #40 0% b00000000000000000000000000000101 & b00000101 ' -b00000000000000000000000000000011 ) +b00000000000000000000000000000100 ( +b00000000000000000000000000000100 * b00000000000000000000000000000011 + b00000000000000000000000000000011 - b00000000000000000000000000000011 / b00000000000000000000000000000011 1 b00000000000000000000000000000011 3 -b00000000000000000000000000000001 6 -b00000000000000000000000000000011 9 -b00000000000000000000000000000100 < -b00000000000000000000000000000100 > -b00000000000000000000000000000001 ? -b00000000000000000000000000000100 B -b00000000000000000000000000000001 C -b00000000000000000000000000000100 F -b00000000000000000000000000000001 G -b00000000000000000000000000000001 H -b00000000000000000000000000000100 J +b00000000000000000000000000000011 5 +b00000000000000000000000000000001 8 +b00000000000000000000000000000011 = +b00000000000000000000000000000100 ? +b00000000000000000000000000000001 A +b00000000000000000000000000000100 C +b00000000000000000000000000000001 E +b00000000000000000000000000000100 G +b00000000000000000000000000000001 I +b00000000000000000000000000000001 J b00000000000000000000000000000100 K -b00000000000000000000000000000001 L -b00000000000000000000000000000100 O +b00000000000000000000000000000100 L +b00000000000000000000000000000001 N b00000000000000000000000000000100 P -b00000000000000000000000000000001 Q -b00000000000000000000000000000100 T +b00000000000000000000000000000100 Q +b00000000000000000000000000000001 S b00000000000000000000000000000100 U b00000000000000000000000000000100 V 1W -b00000000000000000000000000000001 Y -b00000000000000000000000000000100 \ +b00000000000000000000000000000100 Y +b00000000000000000000000000000001 [ #45 0W #50 b00000000000000000000000000000110 & b00000110 ' -b00000000000000000000000000000100 ) +b00000000000000000000000000000101 ( +b00000000000000000000000000000101 * b00000000000000000000000000000100 + b00000000000000000000000000000100 - b00000000000000000000000000000100 / b00000000000000000000000000000100 1 b00000000000000000000000000000100 3 -b00000000000000000000000000000001 4 +b00000000000000000000000000000100 5 b00000000000000000000000000000001 : -b00000000000000000000000000000101 < -b00000000000000000000000000000101 > +b00000000000000000000000000000001 < +b00000000000000000000000000000101 ? b00000000000000000000000000000100 @ -b00000000000000000000000000000100 A -b00000000000000000000000000000101 B +b00000000000000000000000000000100 B +b00000000000000000000000000000101 C b00000000000000000000000000000100 D -b00000000000000000000000000000100 E -b00000000000000000000000000000101 F -b00000000000000000000000000000100 I -b00000000000000000000000000000101 J +b00000000000000000000000000000100 F +b00000000000000000000000000000101 G +b00000000000000000000000000000100 H b00000000000000000000000000000101 K +b00000000000000000000000000000101 L b00000000000000000000000000000100 M -b00000000000000000000000000000100 N -b00000000000000000000000000000101 O +b00000000000000000000000000000100 O b00000000000000000000000000000101 P +b00000000000000000000000000000101 Q b00000000000000000000000000000100 R -b00000000000000000000000000000100 S -b00000000000000000000000000000101 T +b00000000000000000000000000000100 T b00000000000000000000000000000101 U b00000000000000000000000000000101 V 1W b00000000000000000000000000000001 X +b00000000000000000000000000000110 Y b00000000000000000000000000000101 Z -b00000000000000000000000000000001 [ -b00000000000000000000000000000110 \ +b00000000000000000000000000000001 \ #55 0W #60 b00000000000000000000000000000111 & b00000111 ' -b00000000000000000000000000000101 ) +b00000000000000000000000000000110 ( +b00000000000000000000000000000110 * b00000000000000000000000000000101 + b00000000000000000000000000000101 - b00000000000000000000000000000101 / b00000000000000000000000000000101 1 b00000000000000000000000000000101 3 -b00000000000000000000000000000011 5 -b00000000000000000000000000000100 9 -b00000000000000000000000000000110 < -b00000000000000000000000000000110 > +b00000000000000000000000000000101 5 +b00000000000000000000000000000011 9 +b00000000000000000000000000000100 = +b00000000000000000000000000000110 ? b00000000000000000000000000000101 @ -b00000000000000000000000000000101 A -b00000000000000000000000000000110 B +b00000000000000000000000000000101 B +b00000000000000000000000000000110 C b00000000000000000000000000000101 D -b00000000000000000000000000000101 E -b00000000000000000000000000000110 F -b00000000000000000000000000000101 I -b00000000000000000000000000000110 J +b00000000000000000000000000000101 F +b00000000000000000000000000000110 G +b00000000000000000000000000000101 H b00000000000000000000000000000110 K +b00000000000000000000000000000110 L b00000000000000000000000000000101 M -b00000000000000000000000000000101 N -b00000000000000000000000000000110 O +b00000000000000000000000000000101 O b00000000000000000000000000000110 P +b00000000000000000000000000000110 Q b00000000000000000000000000000101 R -b00000000000000000000000000000101 S -b00000000000000000000000000000110 T +b00000000000000000000000000000101 T b00000000000000000000000000000110 U b00000000000000000000000000000110 V 1W +b00000000000000000000000000000111 Y b00000000000000000000000000000110 Z -b00000000000000000000000000000111 \ #65 0W #70 b00000000000000000000000000001000 & b00001000 ' -b00000000000000000000000000000110 ) +b00000000000000000000000000000111 ( +b00000000000000000000000000000111 * b00000000000000000000000000000110 + b00000000000000000000000000000110 - b00000000000000000000000000000110 / b00000000000000000000000000000110 1 b00000000000000000000000000000110 3 -b00000000000000000000000000000100 5 -b00000000000000000000000000000101 9 -b00000000000000000000000000000111 < -b00000000000000000000000000000111 > +b00000000000000000000000000000110 5 +b00000000000000000000000000000100 9 +b00000000000000000000000000000101 = +b00000000000000000000000000000111 ? b00000000000000000000000000000110 @ -b00000000000000000000000000000110 A -b00000000000000000000000000000111 B +b00000000000000000000000000000110 B +b00000000000000000000000000000111 C b00000000000000000000000000000110 D -b00000000000000000000000000000110 E -b00000000000000000000000000000111 F -b00000000000000000000000000000110 I -b00000000000000000000000000000111 J +b00000000000000000000000000000110 F +b00000000000000000000000000000111 G +b00000000000000000000000000000110 H b00000000000000000000000000000111 K +b00000000000000000000000000000111 L b00000000000000000000000000000110 M -b00000000000000000000000000000110 N -b00000000000000000000000000000111 O +b00000000000000000000000000000110 O b00000000000000000000000000000111 P +b00000000000000000000000000000111 Q b00000000000000000000000000000110 R -b00000000000000000000000000000110 S -b00000000000000000000000000000111 T +b00000000000000000000000000000110 T b00000000000000000000000000000111 U b00000000000000000000000000000111 V 1W +b00000000000000000000000000001000 Y b00000000000000000000000000000111 Z -b00000000000000000000000000001000 \ #75 0W #80 b00000000000000000000000000001001 & b00001001 ' -b00000000000000000000000000000111 ) +b00000000000000000000000000001000 ( +b00000000000000000000000000001000 * b00000000000000000000000000000111 + b00000000000000000000000000000111 - b00000000000000000000000000000111 / b00000000000000000000000000000111 1 b00000000000000000000000000000111 3 -b00000000000000000000000000000101 5 -b00000000000000000000000000000110 9 -b00000000000000000000000000001000 < -b00000000000000000000000000001000 > +b00000000000000000000000000000111 5 +b00000000000000000000000000000101 9 +b00000000000000000000000000000110 = +b00000000000000000000000000001000 ? b00000000000000000000000000000111 @ -b00000000000000000000000000000111 A -b00000000000000000000000000001000 B +b00000000000000000000000000000111 B +b00000000000000000000000000001000 C b00000000000000000000000000000111 D -b00000000000000000000000000000111 E -b00000000000000000000000000001000 F -b00000000000000000000000000000111 I -b00000000000000000000000000001000 J +b00000000000000000000000000000111 F +b00000000000000000000000000001000 G +b00000000000000000000000000000111 H b00000000000000000000000000001000 K +b00000000000000000000000000001000 L b00000000000000000000000000000111 M -b00000000000000000000000000000111 N -b00000000000000000000000000001000 O +b00000000000000000000000000000111 O b00000000000000000000000000001000 P +b00000000000000000000000000001000 Q b00000000000000000000000000000111 R -b00000000000000000000000000000111 S -b00000000000000000000000000001000 T +b00000000000000000000000000000111 T b00000000000000000000000000001000 U b00000000000000000000000000001000 V 1W +b00000000000000000000000000001001 Y b00000000000000000000000000001000 Z -b00000000000000000000000000001001 \ #85 0W #90 b00000000000000000000000000001010 & b00001010 ' -b00000000000000000000000000001000 ) +b00000000000000000000000000001001 ( +b00000000000000000000000000001001 * b00000000000000000000000000001000 + b00000000000000000000000000001000 - b00000000000000000000000000001000 / b00000000000000000000000000001000 1 b00000000000000000000000000001000 3 -b00000000000000000000000000000110 5 -b00000000000000000000000000000111 9 -b00000000000000000000000000001001 < -b00000000000000000000000000001001 > +b00000000000000000000000000001000 5 +b00000000000000000000000000000110 9 +b00000000000000000000000000000111 = +b00000000000000000000000000001001 ? b00000000000000000000000000001000 @ -b00000000000000000000000000001000 A -b00000000000000000000000000001001 B +b00000000000000000000000000001000 B +b00000000000000000000000000001001 C b00000000000000000000000000001000 D -b00000000000000000000000000001000 E -b00000000000000000000000000001001 F -b00000000000000000000000000001000 I -b00000000000000000000000000001001 J +b00000000000000000000000000001000 F +b00000000000000000000000000001001 G +b00000000000000000000000000001000 H b00000000000000000000000000001001 K +b00000000000000000000000000001001 L b00000000000000000000000000001000 M -b00000000000000000000000000001000 N -b00000000000000000000000000001001 O +b00000000000000000000000000001000 O b00000000000000000000000000001001 P +b00000000000000000000000000001001 Q b00000000000000000000000000001000 R -b00000000000000000000000000001000 S -b00000000000000000000000000001001 T +b00000000000000000000000000001000 T b00000000000000000000000000001001 U b00000000000000000000000000001001 V 1W +b00000000000000000000000000001010 Y b00000000000000000000000000001001 Z -b00000000000000000000000000001010 \ #95 0W #100 b00000000000000000000000000001011 & b00001011 ' -b00000000000000000000000000001001 ) +b00000000000000000000000000001010 ( +b00000000000000000000000000001010 * b00000000000000000000000000001001 + b00000000000000000000000000001001 - b00000000000000000000000000001001 / b00000000000000000000000000001001 1 b00000000000000000000000000001001 3 -b00000000000000000000000000000111 5 -b00000000000000000000000000000001 8 -b00000000000000000000000000001010 < -b00000000000000000000000000001010 > +b00000000000000000000000000001001 5 +b00000000000000000000000000000111 9 +b00000000000000000000000000000001 > +b00000000000000000000000000001010 ? b00000000000000000000000000001001 @ -b00000000000000000000000000001001 A -b00000000000000000000000000001010 B +b00000000000000000000000000001001 B +b00000000000000000000000000001010 C b00000000000000000000000000001001 D -b00000000000000000000000000001001 E -b00000000000000000000000000001010 F -b00000000000000000000000000001001 I -b00000000000000000000000000001010 J +b00000000000000000000000000001001 F +b00000000000000000000000000001010 G +b00000000000000000000000000001001 H b00000000000000000000000000001010 K +b00000000000000000000000000001010 L b00000000000000000000000000001001 M -b00000000000000000000000000001001 N -b00000000000000000000000000001010 O +b00000000000000000000000000001001 O b00000000000000000000000000001010 P +b00000000000000000000000000001010 Q b00000000000000000000000000001001 R -b00000000000000000000000000001001 S -b00000000000000000000000000001010 T +b00000000000000000000000000001001 T b00000000000000000000000000001010 U b00000000000000000000000000001010 V 1W +b00000000000000000000000000001011 Y b00000000000000000000000000001010 Z -b00000000000000000000000000001011 \ diff --git a/test_regress/t/t_trace_empty.pl b/test_regress/t/t_trace_empty.pl new file mode 100755 index 000000000..314b65d45 --- /dev/null +++ b/test_regress/t/t_trace_empty.pl @@ -0,0 +1,26 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2021 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + verilator_flags2 => ['--trace'], + ); + +execute( + check_finished => 1, + ); + +file_grep_not("$Self->{obj_dir}/simx.vcd", qr/scope/); +file_grep_not("$Self->{obj_dir}/simx.vcd", qr/upscope/); +file_grep_not("$Self->{obj_dir}/simx.vcd", qr/var/); + +ok(1); +1; diff --git a/test_regress/t/t_trace_empty.v b/test_regress/t/t_trace_empty.v new file mode 100644 index 000000000..132598f8a --- /dev/null +++ b/test_regress/t/t_trace_empty.v @@ -0,0 +1,26 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2021 by Geza Lore. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/ + // Inputs + clk + ); + + /* verilator tracing_off */ + + input clk; + + reg [7:0] cyc = 8'd0; + + always @(posedge clk) begin + cyc <= cyc + 1; + if (cyc == 20) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule