diff --git a/include/verilated_fst_c.cpp b/include/verilated_fst_c.cpp index 670b78b6b..62623dbd8 100644 --- a/include/verilated_fst_c.cpp +++ b/include/verilated_fst_c.cpp @@ -222,35 +222,38 @@ void VerilatedFst::declare(uint32_t code, const char* name, int dtypenum, fstVar } } -void VerilatedFst::declEvent(uint32_t code, const char* name, int dtypenum, fstVarDir vardir, - fstVarType vartype, bool array, int arraynum) { +void VerilatedFst::declEvent(uint32_t code, uint32_t fidx, const char* name, int dtypenum, + fstVarDir vardir, fstVarType vartype, bool array, int arraynum) { declare(code, name, dtypenum, vardir, vartype, array, arraynum, false, 0, 0); } -void VerilatedFst::declBit(uint32_t code, const char* name, int dtypenum, fstVarDir vardir, - fstVarType vartype, bool array, int arraynum) { +void VerilatedFst::declBit(uint32_t code, uint32_t fidx, const char* name, int dtypenum, + fstVarDir vardir, fstVarType vartype, bool array, int arraynum) { declare(code, name, dtypenum, vardir, vartype, array, arraynum, false, 0, 0); } -void VerilatedFst::declBus(uint32_t code, const char* name, int dtypenum, fstVarDir vardir, - fstVarType vartype, bool array, int arraynum, int msb, int lsb) { +void VerilatedFst::declBus(uint32_t code, uint32_t fidx, const char* name, int dtypenum, + fstVarDir vardir, fstVarType vartype, bool array, int arraynum, int msb, + int lsb) { declare(code, name, dtypenum, vardir, vartype, array, arraynum, true, msb, lsb); } -void VerilatedFst::declQuad(uint32_t code, const char* name, int dtypenum, fstVarDir vardir, - fstVarType vartype, bool array, int arraynum, int msb, int lsb) { +void VerilatedFst::declQuad(uint32_t code, uint32_t fidx, const char* name, int dtypenum, + fstVarDir vardir, fstVarType vartype, bool array, int arraynum, + int msb, int lsb) { declare(code, name, dtypenum, vardir, vartype, array, arraynum, true, msb, lsb); } -void VerilatedFst::declArray(uint32_t code, const char* name, int dtypenum, fstVarDir vardir, - fstVarType vartype, bool array, int arraynum, int msb, int lsb) { +void VerilatedFst::declArray(uint32_t code, uint32_t fidx, const char* name, int dtypenum, + fstVarDir vardir, fstVarType vartype, bool array, int arraynum, + int msb, int lsb) { declare(code, name, dtypenum, vardir, vartype, array, arraynum, true, msb, lsb); } -void VerilatedFst::declDouble(uint32_t code, const char* name, int dtypenum, fstVarDir vardir, - fstVarType vartype, bool array, int arraynum) { +void VerilatedFst::declDouble(uint32_t code, uint32_t fidx, const char* name, int dtypenum, + fstVarDir vardir, fstVarType vartype, bool array, int arraynum) { declare(code, name, dtypenum, vardir, vartype, array, arraynum, false, 63, 0); } //============================================================================= // Get/commit trace buffer -VerilatedFst::Buffer* VerilatedFst::getTraceBuffer() { +VerilatedFst::Buffer* VerilatedFst::getTraceBuffer(uint32_t fidx) { if (offload()) return new OffloadBuffer{*this}; return new Buffer{*this}; } diff --git a/include/verilated_fst_c.h b/include/verilated_fst_c.h index 57671e0d7..2f659db91 100644 --- a/include/verilated_fst_c.h +++ b/include/verilated_fst_c.h @@ -74,7 +74,7 @@ protected: bool preChangeDump() override { return isOpen(); } // Trace buffer management - Buffer* getTraceBuffer() override; + Buffer* getTraceBuffer(uint32_t fidx) override; void commitTraceBuffer(Buffer*) override; // Configure sub-class @@ -101,17 +101,17 @@ public: //========================================================================= // Internal interface to Verilator generated code - void declEvent(uint32_t code, const char* name, int dtypenum, fstVarDir vardir, + void declEvent(uint32_t code, uint32_t fidx, const char* name, int dtypenum, fstVarDir vardir, fstVarType vartype, bool array, int arraynum); - void declBit(uint32_t code, const char* name, int dtypenum, fstVarDir vardir, + void declBit(uint32_t code, uint32_t fidx, const char* name, int dtypenum, fstVarDir vardir, fstVarType vartype, bool array, int arraynum); - void declBus(uint32_t code, const char* name, int dtypenum, fstVarDir vardir, + void declBus(uint32_t code, uint32_t fidx, const char* name, int dtypenum, fstVarDir vardir, fstVarType vartype, bool array, int arraynum, int msb, int lsb); - void declQuad(uint32_t code, const char* name, int dtypenum, fstVarDir vardir, + void declQuad(uint32_t code, uint32_t fidx, const char* name, int dtypenum, fstVarDir vardir, fstVarType vartype, bool array, int arraynum, int msb, int lsb); - void declArray(uint32_t code, const char* name, int dtypenum, fstVarDir vardir, + void declArray(uint32_t code, uint32_t fidx, const char* name, int dtypenum, fstVarDir vardir, fstVarType vartype, bool array, int arraynum, int msb, int lsb); - void declDouble(uint32_t code, const char* name, int dtypenum, fstVarDir vardir, + void declDouble(uint32_t code, uint32_t fidx, const char* name, int dtypenum, fstVarDir vardir, fstVarType vartype, bool array, int arraynum); void declDTypeEnum(int dtypenum, const char* name, uint32_t elements, unsigned int minValbits, diff --git a/include/verilated_trace.h b/include/verilated_trace.h index 6b053e776..61e52cdd5 100644 --- a/include/verilated_trace.h +++ b/include/verilated_trace.h @@ -162,24 +162,29 @@ private: // (the one in Ubuntu 14.04 with GCC 4.8.4 in particular) use the // assignment operator on inserting into collections, so they don't work // with const fields... - union { // The callback + const union { // The callback initCb_t m_initCb; dumpCb_t m_dumpCb; dumpOffloadCb_t m_dumpOffloadCb; cleanupCb_t m_cleanupCb; }; - void* m_userp; // The user pointer to pass to the callback (the symbol table) + const uint32_t m_fidx; // The index of the tracing function + void* const m_userp; // The user pointer to pass to the callback (the symbol table) CallbackRecord(initCb_t cb, void* userp) : m_initCb{cb} + , m_fidx{0} , m_userp{userp} {} - CallbackRecord(dumpCb_t cb, void* userp) + CallbackRecord(dumpCb_t cb, uint32_t fidx, void* userp) : m_dumpCb{cb} + , m_fidx{fidx} , m_userp{userp} {} - CallbackRecord(dumpOffloadCb_t cb, void* userp) + CallbackRecord(dumpOffloadCb_t cb, uint32_t fidx, void* userp) : m_dumpOffloadCb{cb} + , m_fidx{fidx} , m_userp{userp} {} CallbackRecord(cleanupCb_t cb, void* userp) : m_cleanupCb{cb} + , m_fidx{0} , m_userp{userp} {} }; @@ -329,7 +334,7 @@ protected: virtual bool preChangeDump() = 0; // Trace buffer management - virtual Buffer* getTraceBuffer() = 0; + virtual Buffer* getTraceBuffer(uint32_t fidx) = 0; virtual void commitTraceBuffer(Buffer*) = 0; // Configure sub-class @@ -363,12 +368,12 @@ public: void addModel(VerilatedModel*) VL_MT_SAFE_EXCLUDES(m_mutex); void addInitCb(initCb_t cb, void* userp) VL_MT_SAFE; - void addConstCb(dumpCb_t cb, void* userp) VL_MT_SAFE; - void addConstCb(dumpOffloadCb_t cb, void* userp) VL_MT_SAFE; - void addFullCb(dumpCb_t cb, void* userp) VL_MT_SAFE; - void addFullCb(dumpOffloadCb_t cb, void* userp) VL_MT_SAFE; - void addChgCb(dumpCb_t cb, void* userp) VL_MT_SAFE; - void addChgCb(dumpOffloadCb_t cb, void* userp) VL_MT_SAFE; + void addConstCb(dumpCb_t cb, uint32_t fidx, void* userp) VL_MT_SAFE; + void addConstCb(dumpOffloadCb_t cb, uint32_t fidx, void* userp) VL_MT_SAFE; + void addFullCb(dumpCb_t cb, uint32_t fidx, void* userp) VL_MT_SAFE; + void addFullCb(dumpOffloadCb_t cb, uint32_t fidx, void* userp) VL_MT_SAFE; + void addChgCb(dumpCb_t cb, uint32_t fidx, void* userp) VL_MT_SAFE; + void addChgCb(dumpOffloadCb_t cb, uint32_t fidx, void* userp) VL_MT_SAFE; void addCleanupCb(cleanupCb_t cb, void* userp) VL_MT_SAFE; void scopeEscape(char flag) { m_scopeEscape = flag; } diff --git a/include/verilated_trace_imp.h b/include/verilated_trace_imp.h index 2d473e905..183117521 100644 --- a/include/verilated_trace_imp.h +++ b/include/verilated_trace_imp.h @@ -498,16 +498,15 @@ void VerilatedTrace::runCallbacks(const std::vector mainThreadWorkerData; // Enqueue all the jobs - for (unsigned i = 0; i < cbVec.size(); ++i) { - const CallbackRecord& cbr = cbVec[i]; + for (const CallbackRecord& cbr : cbVec) { // Always get the trace buffer on the main thread - Buffer* const bufp = getTraceBuffer(); + Buffer* const bufp = getTraceBuffer(cbr.m_fidx); // Create new work item workerData.emplace_back(cbr.m_dumpCb, cbr.m_userp, bufp); // Grab the new work item ParallelWorkerData* const itemp = &workerData.back(); // Enqueue task to thread pool, or main thread - if (unsigned rem = i % threads) { + if (unsigned rem = cbr.m_fidx % threads) { threadPoolp->workerp(rem - 1)->addTask(parallelWorkerTask, itemp); } else { mainThreadWorkerData.push_back(itemp); @@ -530,7 +529,7 @@ void VerilatedTrace::runCallbacks(const std::vector::runOffloadedCallbacks( const std::vector& cbVec) { // Fall back on sequential execution for (const CallbackRecord& cbr : cbVec) { - Buffer* traceBufferp = getTraceBuffer(); + Buffer* traceBufferp = getTraceBuffer(cbr.m_fidx); cbr.m_dumpOffloadCb(cbr.m_userp, static_cast(traceBufferp)); commitTraceBuffer(traceBufferp); } @@ -704,28 +703,34 @@ void VerilatedTrace::addInitCb(initCb_t cb, void* userp) VL_ addCallbackRecord(m_initCbs, CallbackRecord{cb, userp}); } template <> -void VerilatedTrace::addConstCb(dumpCb_t cb, void* userp) VL_MT_SAFE { - addCallbackRecord(m_constCbs, CallbackRecord{cb, userp}); +void VerilatedTrace::addConstCb(dumpCb_t cb, uint32_t fidx, + void* userp) VL_MT_SAFE { + addCallbackRecord(m_constCbs, CallbackRecord{cb, fidx, userp}); } template <> -void VerilatedTrace::addConstCb(dumpOffloadCb_t cb, void* userp) VL_MT_SAFE { - addCallbackRecord(m_constOffloadCbs, CallbackRecord{cb, userp}); +void VerilatedTrace::addConstCb(dumpOffloadCb_t cb, uint32_t fidx, + void* userp) VL_MT_SAFE { + addCallbackRecord(m_constOffloadCbs, CallbackRecord{cb, fidx, userp}); } template <> -void VerilatedTrace::addFullCb(dumpCb_t cb, void* userp) VL_MT_SAFE { - addCallbackRecord(m_fullCbs, CallbackRecord{cb, userp}); +void VerilatedTrace::addFullCb(dumpCb_t cb, uint32_t fidx, + void* userp) VL_MT_SAFE { + addCallbackRecord(m_fullCbs, CallbackRecord{cb, fidx, userp}); } template <> -void VerilatedTrace::addFullCb(dumpOffloadCb_t cb, void* userp) VL_MT_SAFE { - addCallbackRecord(m_fullOffloadCbs, CallbackRecord{cb, userp}); +void VerilatedTrace::addFullCb(dumpOffloadCb_t cb, uint32_t fidx, + void* userp) VL_MT_SAFE { + addCallbackRecord(m_fullOffloadCbs, CallbackRecord{cb, fidx, userp}); } template <> -void VerilatedTrace::addChgCb(dumpCb_t cb, void* userp) VL_MT_SAFE { - addCallbackRecord(m_chgCbs, CallbackRecord{cb, userp}); +void VerilatedTrace::addChgCb(dumpCb_t cb, uint32_t fidx, + void* userp) VL_MT_SAFE { + addCallbackRecord(m_chgCbs, CallbackRecord{cb, fidx, userp}); } template <> -void VerilatedTrace::addChgCb(dumpOffloadCb_t cb, void* userp) VL_MT_SAFE { - addCallbackRecord(m_chgOffloadCbs, CallbackRecord{cb, userp}); +void VerilatedTrace::addChgCb(dumpOffloadCb_t cb, uint32_t fidx, + void* userp) VL_MT_SAFE { + addCallbackRecord(m_chgOffloadCbs, CallbackRecord{cb, fidx, userp}); } template <> void VerilatedTrace::addCleanupCb(cleanupCb_t cb, void* userp) VL_MT_SAFE { diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index fc0b438cb..282052528 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -520,32 +520,35 @@ void VerilatedVcd::declare(uint32_t code, const char* name, const char* wirep, b m_namemapp->emplace(hiername, decl); } -void VerilatedVcd::declEvent(uint32_t code, const char* name, bool array, int arraynum) { +void VerilatedVcd::declEvent(uint32_t code, uint32_t fidx, const char* name, bool array, + int arraynum) { declare(code, name, "event", array, arraynum, false, false, 0, 0); } -void VerilatedVcd::declBit(uint32_t code, const char* name, bool array, int arraynum) { +void VerilatedVcd::declBit(uint32_t code, uint32_t fidx, const char* name, bool array, + int arraynum) { declare(code, name, "wire", array, arraynum, false, false, 0, 0); } -void VerilatedVcd::declBus(uint32_t code, const char* name, bool array, int arraynum, int msb, - int lsb) { +void VerilatedVcd::declBus(uint32_t code, uint32_t fidx, const char* name, bool array, + int arraynum, int msb, int lsb) { declare(code, name, "wire", array, arraynum, false, true, msb, lsb); } -void VerilatedVcd::declQuad(uint32_t code, const char* name, bool array, int arraynum, int msb, - int lsb) { +void VerilatedVcd::declQuad(uint32_t code, uint32_t fidx, const char* name, bool array, + int arraynum, int msb, int lsb) { declare(code, name, "wire", array, arraynum, false, true, msb, lsb); } -void VerilatedVcd::declArray(uint32_t code, const char* name, bool array, int arraynum, int msb, - int lsb) { +void VerilatedVcd::declArray(uint32_t code, uint32_t fidx, const char* name, bool array, + int arraynum, int msb, int lsb) { declare(code, name, "wire", array, arraynum, false, true, msb, lsb); } -void VerilatedVcd::declDouble(uint32_t code, const char* name, bool array, int arraynum) { +void VerilatedVcd::declDouble(uint32_t code, uint32_t fidx, const char* name, bool array, + int arraynum) { declare(code, name, "real", array, arraynum, false, false, 63, 0); } //============================================================================= // Get/commit trace buffer -VerilatedVcd::Buffer* VerilatedVcd::getTraceBuffer() { +VerilatedVcd::Buffer* VerilatedVcd::getTraceBuffer(uint32_t fidx) { VerilatedVcd::Buffer* const bufp = new Buffer{*this}; if (parallel()) { // Note: This is called from VerilatedVcd::dump, which already holds the lock diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h index 9ffceaa87..1e0ddcec4 100644 --- a/include/verilated_vcd_c.h +++ b/include/verilated_vcd_c.h @@ -107,7 +107,7 @@ protected: bool preChangeDump() override; // Trace buffer management - Buffer* getTraceBuffer() override; + Buffer* getTraceBuffer(uint32_t fidx) override; void commitTraceBuffer(Buffer*) override; // Configure sub-class @@ -140,12 +140,15 @@ public: //========================================================================= // Internal interface to Verilator generated code - void declEvent(uint32_t code, const char* name, bool array, int arraynum); - void declBit(uint32_t code, const char* name, bool array, int arraynum); - void declBus(uint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); - void declQuad(uint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); - void declArray(uint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); - void declDouble(uint32_t code, const char* name, bool array, int arraynum); + void declEvent(uint32_t code, uint32_t fidx, const char* name, bool array, int arraynum); + void declBit(uint32_t code, uint32_t fidx, const char* name, bool array, int arraynum); + void declBus(uint32_t code, uint32_t fidx, const char* name, bool array, int arraynum, int msb, + int lsb); + void declQuad(uint32_t code, uint32_t fidx, const char* name, bool array, int arraynum, + int msb, int lsb); + void declArray(uint32_t code, uint32_t fidx, const char* name, bool array, int arraynum, + int msb, int lsb); + void declDouble(uint32_t code, uint32_t fidx, const char* name, bool array, int arraynum); }; #ifndef DOXYGEN diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 25508a230..e8eabda41 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -3192,7 +3192,8 @@ class AstTraceDecl final : public AstNodeStmt { // Expression being traced - Moved to AstTraceInc by V3Trace // @astgen op1 := valuep : Optional[AstNodeExpr] private: - uint32_t m_code = 0; // Trace identifier code; converted to ASCII by trace routines + uint32_t m_code{0}; // Trace identifier code + uint32_t m_fidx{0}; // Trace function index const string m_showname; // Name of variable const VNumRange m_bitRange; // Property of var the trace details const VNumRange m_arrayRange; // Property of var the trace details @@ -3228,6 +3229,8 @@ public: // Details on what we're tracing uint32_t code() const { return m_code; } void code(uint32_t code) { m_code = code; } + uint32_t fidx() const { return m_fidx; } + void fidx(uint32_t fidx) { m_fidx = fidx; } uint32_t codeInc() const { return m_codeInc; } const VNumRange& bitRange() const { return m_bitRange; } const VNumRange& arrayRange() const { return m_arrayRange; } diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp index 6d2a6bca5..687af5568 100644 --- a/src/V3EmitCImp.cpp +++ b/src/V3EmitCImp.cpp @@ -649,6 +649,8 @@ class EmitCTrace final : EmitCFunc { puts("(c+" + cvtToStr(nodep->code())); if (nodep->arrayRange().ranged()) puts("+i*" + cvtToStr(nodep->widthWords())); puts(","); + puts(cvtToStr(nodep->fidx())); + puts(","); putsQuoted(VIdProtect::protectWordsIf(nodep->showname(), nodep->protect())); // Direction if (v3Global.opt.traceFormat().fst()) { diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index 58cbad724..a7bc4fa42 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -477,22 +477,28 @@ private: } } - AstCFunc* newCFunc(VTraceType traceType, AstCFunc* topFuncp, unsigned funcNum, + AstCFunc* newCFunc(VTraceType traceType, AstCFunc* topFuncp, uint32_t funcNum, uint32_t baseCode = 0) { // Create new function const bool isTopFunc = topFuncp == nullptr; - std::string baseName = "trace_"; - if (traceType == VTraceType::CONSTANT) { - baseName += "const_"; - } else if (traceType == VTraceType::FULL) { - baseName += "full_"; + std::string funcName; + if (isTopFunc) { + if (traceType == VTraceType::CONSTANT) { + funcName = "trace_const"; + } else if (traceType == VTraceType::FULL) { + funcName = "trace_full"; + } else { + funcName = "trace_chg"; + } } else { - baseName += "chg_"; + funcName = topFuncp->name(); + funcName += "_sub"; } - baseName += isTopFunc ? "top_" : "sub_"; + funcName += "_"; + funcName += cvtToStr(funcNum); FileLine* const flp = m_topScopep->fileline(); - AstCFunc* const funcp = new AstCFunc{flp, baseName + cvtToStr(funcNum), m_topScopep}; + AstCFunc* const funcp = new AstCFunc{flp, funcName, m_topScopep}; funcp->isTrace(true); funcp->dontCombine(true); funcp->isLoose(true); @@ -526,6 +532,8 @@ private: } m_regFuncp->addStmtsp(new AstText{flp, str, true}); m_regFuncp->addStmtsp(new AstAddrOfCFunc{flp, funcp}); + m_regFuncp->addStmtsp(new AstText{flp, ", ", true}); + m_regFuncp->addStmtsp(new AstConst{flp, funcNum}); m_regFuncp->addStmtsp(new AstText{flp, ", vlSelf);\n", true}); } else { // Sub functions @@ -565,7 +573,7 @@ private: : std::numeric_limits::max(); AstCFunc* const topFuncp = newCFunc(VTraceType::CONSTANT, nullptr, 0); - unsigned subFuncNum = 0; + uint32_t subFuncNum = 0; AstCFunc* subFuncp = nullptr; int subStmts = 0; for (auto it = traces.cbegin(); it != traces.end(); ++it) { @@ -612,14 +620,16 @@ private: uint32_t parallelism) { const int splitLimit = v3Global.opt.outputSplitCTrace() ? v3Global.opt.outputSplitCTrace() : std::numeric_limits::max(); - unsigned topFuncNum = 0; - unsigned subFuncNum = 0; + + // pre-incremented, so starts at 0 + uint32_t topFuncNum = std::numeric_limits::max(); TraceVec::const_iterator it = traces.begin(); while (it != traces.end()) { AstCFunc* topFulFuncp = nullptr; AstCFunc* topChgFuncp = nullptr; AstCFunc* subFulFuncp = nullptr; AstCFunc* subChgFuncp = nullptr; + uint32_t subFuncNum = 0; int subStmts = 0; const uint32_t maxCodes = std::max((nAllCodes + parallelism - 1) / parallelism, 1U); uint32_t nCodes = 0; @@ -627,20 +637,25 @@ private: AstIf* ifp = nullptr; uint32_t baseCode = 0; for (; nCodes < maxCodes && it != traces.end(); ++it) { - const TraceTraceVertex* const vtxp = it->second; - // This is a duplicate decl, no need to add it - if (vtxp->duplicatep()) continue; const ActCodeSet& actSet = it->first; // Traced value never changes, no need to add it if (actSet.count(TraceActivityVertex::ACTIVITY_NEVER)) continue; + const TraceTraceVertex* const vtxp = it->second; AstTraceDecl* const declp = vtxp->nodep(); + // This is a duplicate decl, no need to add it, but must set the + // function index to the same as the canonical node. + if (const TraceTraceVertex* const canonVtxp = vtxp->duplicatep()) { + declp->fidx(canonVtxp->nodep()->fidx()); + continue; + } + // Create top function if not yet created if (!topFulFuncp) { + ++topFuncNum; topFulFuncp = newCFunc(VTraceType::FULL, nullptr, topFuncNum); topChgFuncp = newCFunc(VTraceType::CHANGE, nullptr, topFuncNum); - ++topFuncNum; } // Create new sub function if required @@ -682,6 +697,9 @@ private: = new AstTraceInc{flp, declp, VTraceType::CHANGE, baseCode}; ifp->addThensp(incChgp); + // Set the function index of the decl + declp->fidx(topFuncNum); + // Track splitting due to size UASSERT_OBJ(incFulp->nodeCount() == incChgp->nodeCount(), declp, "Should have equal cost");