diff --git a/src/V3Ast.h b/src/V3Ast.h index afa26f75d..b569d76a9 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -238,39 +238,6 @@ inline bool operator==(AstPragmaType::en lhs, const AstPragmaType& rhs) { return //###################################################################### -class AstCFuncType final { -public: - enum en : uint8_t { - FT_NORMAL, - TRACE_REGISTER, - TRACE_INIT, - TRACE_INIT_SUB, - TRACE_FULL, - TRACE_FULL_SUB, - TRACE_CHANGE, - TRACE_CHANGE_SUB, - TRACE_CLEANUP - }; - enum en m_e; - inline AstCFuncType() - : m_e{FT_NORMAL} {} - // cppcheck-suppress noExplicitConstructor - inline AstCFuncType(en _e) - : m_e{_e} {} - explicit inline AstCFuncType(int _e) - : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning - operator en() const { return m_e; } - // METHODS - bool isTrace() const { return m_e != FT_NORMAL; } -}; -inline bool operator==(const AstCFuncType& lhs, const AstCFuncType& rhs) { - return lhs.m_e == rhs.m_e; -} -inline bool operator==(const AstCFuncType& lhs, AstCFuncType::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(AstCFuncType::en lhs, const AstCFuncType& rhs) { return lhs == rhs.m_e; } - -//###################################################################### - class VEdgeType final { public: // REMEMBER to edit the strings below too diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 731bcc1dc..f75c67a82 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -5244,11 +5244,14 @@ class AstTraceInc final : public AstNodeStmt { private: AstTraceDecl* m_declp; // Pointer to declaration const bool m_full; // Is this a full vs incremental dump + const uint32_t m_baseCode; // Trace code base value in function containing this AstTraceInc + public: - AstTraceInc(FileLine* fl, AstTraceDecl* declp, bool full) + AstTraceInc(FileLine* fl, AstTraceDecl* declp, bool full, uint32_t baseCode = 0) : ASTGEN_SUPER_TraceInc(fl) , m_declp{declp} - , m_full{full} { + , m_full{full} + , m_baseCode{baseCode} { dtypeFrom(declp); addOp2p(declp->valuep()->cloneTree(true)); } @@ -5276,6 +5279,7 @@ public: AstNode* valuep() const { return op2p(); } AstTraceDecl* declp() const { return m_declp; } bool full() const { return m_full; } + uint32_t baseCode() const { return m_baseCode; } }; class AstActive final : public AstNode { @@ -8728,7 +8732,6 @@ class AstCFunc final : public AstNode { // Parents: MODULE/SCOPE // Children: VAR/statements private: - AstCFuncType m_funcType; AstScope* m_scopep; string m_name; string m_cname; // C name, for dpiExports @@ -8738,6 +8741,7 @@ private: string m_ifdef; // #ifdef symbol around this function VBoolOrUnknown m_isConst; // Function is declared const (*this not changed) bool m_isStatic : 1; // Function is static (no need for a 'this' pointer) + bool m_isTrace : 1; // Function is related to tracing bool m_dontCombine : 1; // V3Combine shouldn't compare this func tree, it's special bool m_declPrivate : 1; // Declare it private bool m_formCallTree : 1; // Make a global function to call entire tree of functions @@ -8759,12 +8763,12 @@ private: public: AstCFunc(FileLine* fl, const string& name, AstScope* scopep, const string& rtnType = "") : ASTGEN_SUPER_CFunc(fl) { - m_funcType = AstCFuncType::FT_NORMAL; m_isConst = VBoolOrUnknown::BU_UNKNOWN; // Unknown until analyzed m_scopep = scopep; m_name = name; m_rtnType = rtnType; m_isStatic = false; + m_isTrace = false; m_dontCombine = false; m_declPrivate = false; m_formCallTree = false; @@ -8793,7 +8797,7 @@ public: virtual void dump(std::ostream& str = std::cout) const override; virtual bool same(const AstNode* samep) const override { const AstCFunc* asamep = static_cast(samep); - return ((funcType() == asamep->funcType()) && (rtnTypeVoid() == asamep->rtnTypeVoid()) + return ((isTrace() == asamep->isTrace()) && (rtnTypeVoid() == asamep->rtnTypeVoid()) && (argTypes() == asamep->argTypes()) && (ctorInits() == asamep->ctorInits()) && isLoose() == asamep->isLoose() && (!(dpiImportPrototype() || dpiExportImpl()) || name() == asamep->name())); @@ -8806,12 +8810,14 @@ public: void isConst(VBoolOrUnknown flag) { m_isConst = flag; } bool isStatic() const { return m_isStatic; } void isStatic(bool flag) { m_isStatic = flag; } + bool isTrace() const { return m_isTrace; } + void isTrace(bool flag) { m_isTrace = flag; } void cname(const string& name) { m_cname = name; } string cname() const { return m_cname; } AstScope* scopep() const { return m_scopep; } void scopep(AstScope* nodep) { m_scopep = nodep; } string rtnTypeVoid() const { return ((m_rtnType == "") ? "void" : m_rtnType); } - bool dontCombine() const { return m_dontCombine || funcType() != AstCFuncType::FT_NORMAL; } + bool dontCombine() const { return m_dontCombine || isTrace(); } void dontCombine(bool flag) { m_dontCombine = flag; } bool dontInline() const { return dontCombine() || slow() || funcPublic(); } bool declPrivate() const { return m_declPrivate; } @@ -8828,8 +8834,6 @@ public: string ctorInits() const { return m_ctorInits; } void ifdef(const string& str) { m_ifdef = str; } string ifdef() const { return m_ifdef; } - void funcType(AstCFuncType flag) { m_funcType = flag; } - AstCFuncType funcType() const { return m_funcType; } bool isConstructor() const { return m_isConstructor; } void isConstructor(bool flag) { m_isConstructor = flag; } bool isDestructor() const { return m_isDestructor; } diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index fc8cb08fa..4e7f7cdae 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -74,7 +74,7 @@ class EmitCImp final : EmitCFunc { using EmitCFunc::visit; // Suppress hidden overloaded virtual function warning virtual void visit(AstCFunc* nodep) override { // TRACE_* and DPI handled elsewhere - if (nodep->funcType().isTrace()) return; + if (nodep->isTrace()) return; if (nodep->dpiImportPrototype()) return; if (nodep->dpiExportDispatcher()) return; if (!(nodep->slow() ? m_slow : m_fast)) return; @@ -675,10 +675,8 @@ class EmitCTrace final : EmitCFunc { AstUser1InUse m_inuser1; // MEMBERS - AstCFunc* m_cfuncp = nullptr; // Function we're in now - bool m_slow; // Making slow file + const bool m_slow; // Making slow file int m_enumNum = 0; // Enumeration number (whole netlist) - int m_baseCode = -1; // Code of first AstTraceInc in this function // METHODS void newOutCFile(int filenum) { @@ -703,10 +701,6 @@ class EmitCTrace final : EmitCFunc { m_ofp->puts("// DESCR" "IPTION: Verilator output: Tracing implementation internals\n"); - emitTraceHeader(); - } - - void emitTraceHeader() { // Includes puts("#include \"" + v3Global.opt.traceSourceLang() + ".h\"\n"); puts("#include \"" + symClassName() + ".h\"\n"); @@ -895,12 +889,13 @@ class EmitCTrace final : EmitCFunc { const uint32_t offset = (arrayindex < 0) ? 0 : (arrayindex * nodep->declp()->widthWords()); const uint32_t code = nodep->declp()->code() + offset; puts(v3Global.opt.trueTraceThreads() && !nodep->full() ? "(base+" : "(oldp+"); - puts(cvtToStr(code - m_baseCode)); + puts(cvtToStr(code - nodep->baseCode())); puts(","); emitTraceValue(nodep, arrayindex); if (emitWidth) puts("," + cvtToStr(nodep->declp()->widthMin())); puts(");\n"); } + void emitTraceValue(AstTraceInc* nodep, int arrayindex) { if (AstVarRef* const varrefp = VN_CAST(nodep->valuep(), VarRef)) { AstVar* varp = varrefp->varp(); @@ -939,92 +934,20 @@ class EmitCTrace final : EmitCFunc { // VISITORS using EmitCFunc::visit; // Suppress hidden overloaded virtual function warning - virtual void visit(AstNetlist* nodep) override { - // Top module only - iterate(nodep->topModulep()); - } - virtual void visit(AstNodeModule* nodep) override { - m_modp = nodep; - iterateChildren(nodep); - m_modp = nullptr; - } virtual void visit(AstCFunc* nodep) override { + if (!nodep->isTrace()) return; if (nodep->slow() != m_slow) return; - VL_RESTORER(m_cfuncp); - VL_RESTORER(m_useSelfForThis); - if (nodep->funcType().isTrace()) { // TRACE_* - m_cfuncp = nodep; - if (splitNeeded()) { - // Splitting file, so using parallel build. - v3Global.useParallelBuild(true); - // Close old file - VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); - // Open a new file - newOutCFile(splitFilenumInc()); - } - - splitSizeInc(nodep); - - puts("\n"); - m_lazyDecls.emit(nodep); - emitCFuncHeader(nodep, m_modp, /* withScope: */ true); - puts(" {\n"); - - if (nodep->isLoose()) { - m_lazyDecls.declared(nodep); // Defined here, so no longer needs declaration - if (!nodep->isStatic()) { // Standard prologue - puts("if (false && vlSelf) {} // Prevent unused\n"); - m_useSelfForThis = true; - puts(symClassAssign()); - } - } - - if (nodep->initsp()) { - string section; - emitVarList(nodep->initsp(), EVL_FUNC_ALL, "", section /*ref*/); - iterateAndNextNull(nodep->initsp()); - } - - m_baseCode = -1; - - if (nodep->funcType() == AstCFuncType::TRACE_CHANGE_SUB) { - const AstNode* const stmtp = nodep->stmtsp(); - const AstIf* const ifp = VN_CAST_CONST(stmtp, If); - const AstTraceInc* const tracep - = VN_CAST_CONST(ifp ? ifp->ifsp() : stmtp, TraceInc); - // On rare occasions we can end up with an empty sub function - m_baseCode = tracep ? tracep->declp()->code() : 0; - if (v3Global.opt.trueTraceThreads()) { - puts("const vluint32_t base = vlSymsp->__Vm_baseCode + " + cvtToStr(m_baseCode) - + ";\n"); - puts("if (false && tracep && base) {} // Prevent unused\n"); - } else { - puts("vluint32_t* const oldp = tracep->oldp(vlSymsp->__Vm_baseCode + " - + cvtToStr(m_baseCode) + ");\n"); - puts("if (false && oldp) {} // Prevent unused\n"); - } - } else if (nodep->funcType() == AstCFuncType::TRACE_FULL_SUB) { - m_baseCode = 0; - puts("vluint32_t* const oldp = tracep->oldp(vlSymsp->__Vm_baseCode);\n"); - puts("if (false && oldp) {} // Prevent unused\n"); - } else if (nodep->funcType() == AstCFuncType::TRACE_INIT_SUB) { - puts("const int c = vlSymsp->__Vm_baseCode;\n"); - puts("if (false && tracep && c) {} // Prevent unused\n"); - } - - if (nodep->stmtsp()) { - putsDecoration("// Body\n"); - puts("{\n"); - iterateAndNextNull(nodep->stmtsp()); - puts("}\n"); - } - if (nodep->finalsp()) { - putsDecoration("// Final\n"); - iterateAndNextNull(nodep->finalsp()); - } - puts("}\n"); + if (splitNeeded()) { + // Splitting file, so using parallel build. + v3Global.useParallelBuild(true); + // Close old file + VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); + // Open a new file + newOutCFile(splitFilenumInc()); } + + EmitCFunc::visit(nodep); } virtual void visit(AstTraceDecl* nodep) override { const int enumNum = emitTraceDeclDType(nodep->dtypep()); @@ -1047,28 +970,32 @@ class EmitCTrace final : EmitCFunc { emitTraceChangeOne(nodep, -1); } } - virtual void visit(AstCoverDecl* nodep) override {} - virtual void visit(AstCoverInc* nodep) override {} -public: - explicit EmitCTrace(bool slow) - : m_slow{slow} {} - virtual ~EmitCTrace() override = default; - void main() { - // Put out the file + explicit EmitCTrace(AstNodeModule* modp, bool slow) + : m_slow{slow} { + m_modp = modp; + // Open output file newOutCFile(0); - - iterate(v3Global.rootp()); - + // Emit functions + for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { + if (AstCFunc* const funcp = VN_CAST(nodep, CFunc)) { iterate(funcp); } + } + // Close output file VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); } + virtual ~EmitCTrace() override = default; + +public: + static void main(AstNodeModule* modp, bool slow) { EmitCTrace(modp, slow); } }; //###################################################################### // EmitC class functions -static void setParentClassPointers() { +void V3EmitC::emitc() { + UINFO(2, __FUNCTION__ << ": " << endl); // Set user4p in all CFunc and Var to point to the containing AstNodeModule + AstUser4InUse user4InUse; const auto setAll = [](AstNodeModule* modp) -> void { for (AstNode* nodep = VN_CAST(modp, NodeModule)->stmtsp(); nodep; nodep = nodep->nextp()) { if (VN_IS(nodep, CFunc) || VN_IS(nodep, Var)) nodep->user4p(modp); @@ -1078,13 +1005,7 @@ static void setParentClassPointers() { setAll(VN_CAST(modp, NodeModule)); } setAll(v3Global.rootp()->constPoolp()->modp()); -} -void V3EmitC::emitc() { - UINFO(2, __FUNCTION__ << ": " << endl); - // Set user4 to parent module - AstUser4InUse user4InUse; - setParentClassPointers(); // Process each module in turn for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep; nodep = VN_CAST(nodep->nextp(), NodeModule)) { @@ -1099,22 +1020,11 @@ void V3EmitC::emitc() { fast.mainImp(nodep, false); } } -} -void V3EmitC::emitcTrace() { - UINFO(2, __FUNCTION__ << ": " << endl); + // Emit trace routines (currently they can only exist in the top module) if (v3Global.opt.trace()) { - // Set user4 to parent module - AstUser4InUse user4InUse; - setParentClassPointers(); - { - EmitCTrace slow(true); - slow.main(); - } - { - EmitCTrace fast(false); - fast.main(); - } + EmitCTrace::main(v3Global.rootp()->topModulep(), /* slow: */ true); + EmitCTrace::main(v3Global.rootp()->topModulep(), /* slow: */ false); } } diff --git a/src/V3EmitC.h b/src/V3EmitC.h index 406a00429..e52552734 100644 --- a/src/V3EmitC.h +++ b/src/V3EmitC.h @@ -32,7 +32,6 @@ public: static void emitcInlines(); static void emitcModel(); static void emitcSyms(bool dpiHdrOnly = false); - static void emitcTrace(); static void emitcFiles(); }; diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index bee0293a4..38f18a00e 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -1223,8 +1223,6 @@ public: virtual void visit(AstCell*) override {} // Handled outside the Visit class virtual void visit(AstVar*) override {} // Handled outside the Visit class virtual void visit(AstNodeText*) override {} // Handled outside the Visit class - virtual void visit(AstTraceDecl*) override {} // Handled outside the Visit class - virtual void visit(AstTraceInc*) override {} // Handled outside the Visit class virtual void visit(AstCFile*) override {} // Handled outside the Visit class virtual void visit(AstCellInline*) override {} // Handled outside visit (in EmitCSyms) virtual void visit(AstCUse*) override {} // Handled outside the Visit class diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index 062cd2ea1..a5901d1e8 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -171,6 +171,7 @@ private: AstNodeModule* m_topModp = nullptr; // Module to add variables to AstScope* m_topScopep = nullptr; // Scope to add variables to AstCFunc* m_cfuncp = nullptr; // C function adding to graph + AstCFunc* m_regFuncp = nullptr; // Trace registration function AstTraceDecl* m_tracep = nullptr; // Trace function adding to graph AstVarScope* m_activityVscp = nullptr; // Activity variable uint32_t m_activityNumber = 0; // Count of fields in activity variable @@ -472,69 +473,77 @@ private: } } - AstCFunc* newCFunc(AstCFuncType type, AstCFunc* callfromp, AstCFunc* regp, int& funcNump) { + AstCFunc* newCFunc(bool full, AstCFunc* topFuncp, int& funcNump, uint32_t baseCode = 0) { // Create new function - string name; - switch (type) { - case AstCFuncType::TRACE_FULL: name = "trace_full_top_"; break; - case AstCFuncType::TRACE_FULL_SUB: name = "trace_full_sub_"; break; - case AstCFuncType::TRACE_CHANGE: name = "trace_chg_top_"; break; - case AstCFuncType::TRACE_CHANGE_SUB: name = "trace_chg_sub_"; break; - default: m_topScopep->v3fatalSrc("Bad trace function type"); - } - name += cvtToStr(funcNump++); - FileLine* const flp = m_topScopep->fileline(); - AstCFunc* const funcp = new AstCFunc(flp, name, m_topScopep); - funcp->funcType(type); - funcp->dontCombine(true); - const bool isTopFunc - = type == AstCFuncType::TRACE_FULL || type == AstCFuncType::TRACE_CHANGE; - if (isTopFunc) { - funcp->argTypes("void* voidSelf, " + v3Global.opt.traceClassBase() + "* tracep"); - funcp->isStatic(true); - funcp->addInitsp(new AstCStmt( - flp, prefixNameProtect(m_topModp) + "* const __restrict vlSelf = static_cast<" - + prefixNameProtect(m_topModp) + "*>(voidSelf);\n")); - funcp->addInitsp(new AstCStmt(flp, symClassAssign())); + const bool isTopFunc = topFuncp == nullptr; + const string baseName = full && isTopFunc ? "trace_full_top_" + : full ? "trace_full_sub_" + : isTopFunc ? "trace_chg_top_" + : "trace_chg_sub_"; - } else { - funcp->argTypes(v3Global.opt.traceClassBase() + "* tracep"); - funcp->isStatic(false); - } + FileLine* const flp = m_topScopep->fileline(); + AstCFunc* const funcp = new AstCFunc(flp, baseName + cvtToStr(funcNump++), m_topScopep); + funcp->isTrace(true); + funcp->dontCombine(true); funcp->isLoose(true); - funcp->slow(type == AstCFuncType::TRACE_FULL || type == AstCFuncType::TRACE_FULL_SUB); + funcp->slow(full); + funcp->isStatic(isTopFunc); // Add it to top scope m_topScopep->addActivep(funcp); - // Add call to new function - if (callfromp) { + const auto addInitStr = [funcp, flp](const string& str) -> void { + funcp->addInitsp(new AstCStmt(flp, str)); + }; + if (isTopFunc) { + // Top functions + funcp->argTypes("void* voidSelf, " + v3Global.opt.traceClassBase() + "* tracep"); + addInitStr(voidSelfAssign(m_topModp)); + addInitStr(symClassAssign()); + // Add global activity check to change dump functions + if (!full) { // + addInitStr("if (VL_UNLIKELY(!vlSymsp->__Vm_activity)) return;\n"); + } + // Register function + if (full) { + m_regFuncp->addStmtsp(new AstText(flp, "tracep->addFullCb(", true)); + } else { + m_regFuncp->addStmtsp(new AstText(flp, "tracep->addChgCb(", true)); + } + m_regFuncp->addStmtsp(new AstAddrOfCFunc(flp, funcp)); + m_regFuncp->addStmtsp(new AstText(flp, ", vlSelf);\n", true)); + } else { + // Sub functions + funcp->argTypes(v3Global.opt.traceClassBase() + "* tracep"); + // Setup base references. Note in rare occasions we can end up with an empty trace + // sub function, hence the VL_ATTR_UNUSED attributes. + if (full) { + // Full dump sub function + addInitStr("vluint32_t* const oldp VL_ATTR_UNUSED = " + "tracep->oldp(vlSymsp->__Vm_baseCode);\n"); + } else { + // Change dump sub function + if (v3Global.opt.trueTraceThreads()) { + addInitStr("const vluint32_t base VL_ATTR_UNUSED = " + "vlSymsp->__Vm_baseCode + " + + cvtToStr(baseCode) + ";\n"); + addInitStr("if (false && tracep) {} // Prevent unused\n"); + } else { + addInitStr("vluint32_t* const oldp VL_ATTR_UNUSED = " + "tracep->oldp(vlSymsp->__Vm_baseCode + " + + cvtToStr(baseCode) + ");\n"); + } + } + // Add call to top function AstCCall* callp = new AstCCall(funcp->fileline(), funcp); callp->argTypes("tracep"); - callfromp->addStmtsp(callp); - } - // Register function - if (regp) { - if (type == AstCFuncType::TRACE_FULL) { - regp->addStmtsp(new AstText(flp, "tracep->addFullCb(", true)); - } else if (type == AstCFuncType::TRACE_CHANGE) { - regp->addStmtsp(new AstText(flp, "tracep->addChgCb(", true)); - } else { - funcp->v3fatalSrc("Don't know how to register this type of function"); - } - regp->addStmtsp(new AstAddrOfCFunc(flp, funcp)); - regp->addStmtsp(new AstText(flp, ", vlSelf);\n", true)); - } - // Add global activity check to TRACE_CHANGE functions - if (type == AstCFuncType::TRACE_CHANGE) { - funcp->addInitsp( - new AstCStmt(flp, string("if (VL_UNLIKELY(!vlSymsp->__Vm_activity)) return;\n"))); + topFuncp->addStmtsp(callp); } // Done UINFO(5, " newCFunc " << funcp << endl); return funcp; } - void createFullTraceFunction(const TraceVec& traces, uint32_t nAllCodes, uint32_t parallelism, - AstCFunc* regFuncp) { + void createFullTraceFunction(const TraceVec& traces, uint32_t nAllCodes, + uint32_t parallelism) { const int splitLimit = v3Global.opt.outputSplitCTrace() ? v3Global.opt.outputSplitCTrace() : std::numeric_limits::max(); @@ -571,20 +580,17 @@ private: ++m_statUniqSigs; // Create top function if not yet created - if (!topFuncp) { - topFuncp - = newCFunc(AstCFuncType::TRACE_FULL, nullptr, regFuncp, topFuncNum); - } + if (!topFuncp) { topFuncp = newCFunc(/* full: */ true, nullptr, topFuncNum); } // Crate new sub function if required if (!subFuncp || subStmts > splitLimit) { subStmts = 0; - subFuncp = newCFunc(AstCFuncType::TRACE_FULL_SUB, topFuncp, nullptr, - subFuncNum); + subFuncp = newCFunc(/* full: */ true, topFuncp, subFuncNum); } // Add TraceInc node - AstTraceInc* const incp = new AstTraceInc(declp->fileline(), declp, true); + AstTraceInc* const incp + = new AstTraceInc(declp->fileline(), declp, /* full: */ true); subFuncp->addStmtsp(incp); subStmts += EmitCBaseCounterVisitor(incp).count(); @@ -599,8 +605,8 @@ private: } } - void createChgTraceFunctions(const TraceVec& traces, uint32_t nAllCodes, uint32_t parallelism, - AstCFunc* regFuncp) { + void createChgTraceFunctions(const TraceVec& traces, uint32_t nAllCodes, + uint32_t parallelism) { const int splitLimit = v3Global.opt.outputSplitCTrace() ? v3Global.opt.outputSplitCTrace() : std::numeric_limits::max(); int topFuncNum = 0; @@ -615,6 +621,7 @@ private: uint32_t nCodes = 0; const ActCodeSet* prevActSet = nullptr; 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 to incremental dump @@ -623,16 +630,16 @@ private: // Traced value never changes, no need to add it to incremental dump if (actSet.count(TraceActivityVertex::ACTIVITY_NEVER)) continue; - // Create top function if not yet created - if (!topFuncp) { - topFuncp = newCFunc(AstCFuncType::TRACE_CHANGE, nullptr, regFuncp, topFuncNum); - } + AstTraceDecl* const declp = vtxp->nodep(); - // Crate new sub function if required + // Create top function if not yet created + if (!topFuncp) { topFuncp = newCFunc(/* full: */ false, nullptr, topFuncNum); } + + // Create new sub function if required if (!subFuncp || subStmts > splitLimit) { + baseCode = declp->code(); subStmts = 0; - subFuncp - = newCFunc(AstCFuncType::TRACE_CHANGE_SUB, topFuncp, nullptr, subFuncNum); + subFuncp = newCFunc(/* full: */ false, topFuncp, subFuncNum, baseCode); prevActSet = nullptr; ifp = nullptr; } @@ -658,8 +665,8 @@ private: } // Add TraceInc node - AstTraceDecl* const declp = vtxp->nodep(); - AstTraceInc* const incp = new AstTraceInc(declp->fileline(), declp, VAccess::READ); + AstTraceInc* const incp + = new AstTraceInc(declp->fileline(), declp, /* full: */ false, baseCode); ifp->addIfsp(incp); subStmts += EmitCBaseCounterVisitor(incp).count(); @@ -673,25 +680,23 @@ private: } } - void createCleanupFunction(AstCFunc* regFuncp) { + void createCleanupFunction() { FileLine* const fl = m_topScopep->fileline(); AstCFunc* const cleanupFuncp = new AstCFunc(fl, "trace_cleanup", m_topScopep); cleanupFuncp->argTypes("void* voidSelf, " + v3Global.opt.traceClassBase() + "* /*unused*/"); - cleanupFuncp->funcType(AstCFuncType::TRACE_CLEANUP); + cleanupFuncp->isTrace(true); cleanupFuncp->slow(false); cleanupFuncp->isStatic(true); cleanupFuncp->isLoose(true); m_topScopep->addActivep(cleanupFuncp); - cleanupFuncp->addInitsp(new AstCStmt( - fl, prefixNameProtect(m_topModp) + "* const __restrict vlSelf = static_cast<" - + prefixNameProtect(m_topModp) + "*>(voidSelf);\n")); + cleanupFuncp->addInitsp(new AstCStmt(fl, voidSelfAssign(m_topModp))); cleanupFuncp->addInitsp(new AstCStmt(fl, symClassAssign())); // Register it - regFuncp->addStmtsp(new AstText(fl, "tracep->addCleanupCb(", true)); - regFuncp->addStmtsp(new AstAddrOfCFunc(fl, cleanupFuncp)); - regFuncp->addStmtsp(new AstText(fl, ", vlSelf);\n", true)); + m_regFuncp->addStmtsp(new AstText(fl, "tracep->addCleanupCb(", true)); + m_regFuncp->addStmtsp(new AstAddrOfCFunc(fl, cleanupFuncp)); + m_regFuncp->addStmtsp(new AstText(fl, ", vlSelf);\n", true)); // Clear global activity flag cleanupFuncp->addStmtsp( @@ -735,22 +740,21 @@ private: // last value vector is more compact // Create the trace registration function - AstCFunc* const regFuncp - = new AstCFunc(m_topScopep->fileline(), "trace_register", m_topScopep); - regFuncp->argTypes(v3Global.opt.traceClassBase() + "* tracep"); - regFuncp->funcType(AstCFuncType::TRACE_REGISTER); - regFuncp->slow(true); - regFuncp->isStatic(false); - regFuncp->isLoose(true); - m_topScopep->addActivep(regFuncp); + m_regFuncp = new AstCFunc(m_topScopep->fileline(), "trace_register", m_topScopep); + m_regFuncp->argTypes(v3Global.opt.traceClassBase() + "* tracep"); + m_regFuncp->isTrace(true); + m_regFuncp->slow(true); + m_regFuncp->isStatic(false); + m_regFuncp->isLoose(true); + m_topScopep->addActivep(m_regFuncp); const int parallelism = 1; // Note: will bump this later, code below works for any value // Create the full dump functions, also allocates signal numbers - createFullTraceFunction(traces, nFullCodes, parallelism, regFuncp); + createFullTraceFunction(traces, nFullCodes, parallelism); // Create the incremental dump functions - createChgTraceFunctions(traces, nChgCodes, parallelism, regFuncp); + createChgTraceFunctions(traces, nChgCodes, parallelism); // Remove refs to traced values from TraceDecl nodes, these have now moved under // TraceInc @@ -761,7 +765,7 @@ private: } // Create the trace cleanup function clearing the activity flags - createCleanupFunction(regFuncp); + createCleanupFunction(); } TraceCFuncVertex* getCFuncVertexp(AstCFunc* nodep) { diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp index b7f61a01f..07a62629d 100644 --- a/src/V3TraceDecl.cpp +++ b/src/V3TraceDecl.cpp @@ -69,13 +69,13 @@ private: return nullptr; } - AstCFunc* newCFunc(AstCFuncType type, const string& name) { + 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); - funcp->funcType(type); + funcp->isTrace(true); funcp->isStatic(false); funcp->isLoose(true); funcp->slow(true); @@ -94,8 +94,11 @@ private: basep->addStmtsp(callp); } AstCFunc* newCFuncSub(AstCFunc* basep) { + FileLine* const fl = basep->fileline(); const string name = "trace_init_sub_" + cvtToStr(m_funcNum++); - AstCFunc* const funcp = newCFunc(AstCFuncType::TRACE_INIT_SUB, name); + 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; } @@ -135,7 +138,7 @@ private: virtual void visit(AstTopScope* nodep) override { m_topScopep = nodep->scopep(); // Create the trace init function - m_initFuncp = newCFunc(AstCFuncType::TRACE_INIT, "trace_init_top"); + m_initFuncp = newCFunc("trace_init_top"); // Create initial sub function m_initSubFuncp = newCFuncSub(m_initFuncp); // And find variables diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 9a742cafd..842fa04a9 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -512,7 +512,6 @@ static void process() { V3EmitC::emitcSyms(); V3EmitC::emitcConstPool(); V3EmitC::emitcModel(); - V3EmitC::emitcTrace(); } else if (v3Global.opt.dpiHdrOnly()) { V3EmitC::emitcSyms(true); }