diff --git a/Changes b/Changes index f24a69b70..a92f80239 100644 --- a/Changes +++ b/Changes @@ -5,6 +5,9 @@ indicates the contributor was also the author of the fix; Thanks! * Verilator 3.60** +** Many changes to the pointers used for internal structures. + When used with gcc's -fstrict-aliasing, large models are ~***% faster. + *** Added --inhibit-sim flag for environments using old __Vm_inhibitSim. *** Added `systemc_dtor for destructor extentions. [Allan Cochrane] diff --git a/bin/verilator b/bin/verilator index 98d3268b0..e22ca6dd7 100755 --- a/bin/verilator +++ b/bin/verilator @@ -645,11 +645,14 @@ fast path, mostly code that is executed every cycle. OPT_SLOW specifies optimizations for slow-path files (plus tracing), which execute only rarely, yet take a long time to compile with optimization on. OPT specifies overall optimization and affects all compiles, including those -OPT_FAST and OPT_SLOW affect. For best results, use OPT="-O2". Nearly the -same results can be had with much better compile times with OPT_FAST="-O1". -Unfortunately, using the optimizer with SystemC files can result in -compiles taking several minutes. (The SystemC libraries have many little -inlined functions that drive the compiler nuts.) +OPT_FAST and OPT_SLOW affect. For best results, use OPT="-O2 +-fstrict-aliasing". Nearly the same results can be had with much better +compile times with OPT_FAST="-O1 -fstrict-aliasing". Unfortunately, using +the optimizer with SystemC files can result in compiles taking several +minutes. (The SystemC libraries have many little inlined functions that +drive the compiler nuts.) Also read the manual as to the effects of +-fstrict-aliasing; you may want to compile only the verilated code with +this flag. For best results, use GCC 3.3 or newer. GCC 3.2 and earlier have optimization bugs around pointer aliasing detection, which can result in 2x diff --git a/include/verilated.cpp b/include/verilated.cpp index 709dee963..1e2851a8a 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -30,7 +30,6 @@ //=========================================================================== // Global variables -uint32_t Verilated::s_coverageRequest = false; int Verilated::s_randReset = false; int Verilated::s_debug = 1; bool Verilated::s_calcUnusedSigs = false; diff --git a/include/verilated.h b/include/verilated.h index 7de903128..e99eeb083 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -121,7 +121,6 @@ public: struct Verilated { // Extern Vars // Below two are used as bool, but having as uint32_t avoids conversion time - static uint32_t s_coverageRequest; ///< Collect coverage info now private: static int s_randReset; ///< Random reset: 0=all 0s, 1=all 1s, 2=random static int s_debug; ///< See accessors... only when VL_DEBUG set diff --git a/include/verilated.mk.in b/include/verilated.mk.in index 2cce90b12..c0103e976 100644 --- a/include/verilated.mk.in +++ b/include/verilated.mk.in @@ -52,7 +52,7 @@ CPPFLAGS += $(OPT) # SystemC takes minutes to optimize, thus it is off by default. #OPT_SLOW = # Fast path optimizations. Most time is spent in these classes. -#OPT_FAST = -O2 -funroll-loops +#OPT_FAST = -O2 -fstrict-aliasing #OPT_FAST = -O #OPT_FAST = diff --git a/src/V3Active.cpp b/src/V3Active.cpp index 12a465c0a..47112b181 100644 --- a/src/V3Active.cpp +++ b/src/V3Active.cpp @@ -42,6 +42,7 @@ #include "V3Global.h" #include "V3Active.h" #include "V3Ast.h" +#include "V3EmitCBase.h" //***** See below for main transformation engine @@ -231,6 +232,8 @@ private: } if (!m_scopeFinalp) { m_scopeFinalp = new AstCFunc(nodep->fileline(), "_final", m_namer.scopep()); + m_scopeFinalp->argTypes(EmitCBaseVisitor::symClassVar()); + m_scopeFinalp->addInitsp(new AstCStmt(nodep->fileline()," "+EmitCBaseVisitor::symTopAssign()+"\n")); m_scopeFinalp->dontCombine(true); m_scopeFinalp->formCallTree(true); m_scopeFinalp->slow(true); diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 7dc1bd23d..730a7770f 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -422,7 +422,7 @@ public: virtual string name() const { return m_name; } // * = Scope name void name(const string& name) { m_name = name; } string nameDotless() const; - string nameVlSym() const { return (((string)"VlSym->") + nameDotless()); } + string nameVlSym() const { return (((string)"vlSymsp->") + nameDotless()); } AstModule* modp() const { return m_modp; } void addVarp(AstNode* nodep) { addOp1p(nodep); } AstNode* varsp() const { return op1p()->castNode(); } // op1 = AstVarScope's @@ -586,7 +586,6 @@ struct AstModule : public AstNode { private: string m_name; // Name of the module string m_origName; // Name of the module, ignoring name() changes, for dot lookup - bool m_globalSyms:1; // References global symbol table bool m_modPublic:1; // Module has public references bool m_modTrace:1; // Tracing this module bool m_inLibrary:1; // From a library, no error if not used, never top level @@ -596,7 +595,7 @@ private: public: AstModule(FileLine* fl, const string& name) : AstNode (fl) - ,m_name(name), m_origName(name), m_globalSyms(false), m_modPublic(false) + ,m_name(name), m_origName(name), m_modPublic(false) ,m_modTrace(false), m_inLibrary(false) ,m_level(0), m_varNum(0), m_clkReqVarp(NULL) { } virtual ~AstModule() {} @@ -623,8 +622,6 @@ public: int varNumGetInc() { return ++m_varNum; } AstVar* clkReqVarp() const { return m_clkReqVarp; } void clkReqVarp(AstVar* varp) { m_clkReqVarp = varp; } - void globalSyms(bool flag) { m_globalSyms = flag; } - bool globalSyms() const { return m_globalSyms; } void modPublic(bool flag) { m_modPublic = flag; } bool modPublic() const { return m_modPublic; } void modTrace(bool flag) { m_modTrace = flag; } @@ -2774,6 +2771,7 @@ private: bool m_slow:1; // Slow routine, called once or just at init time bool m_funcPublic:1; // From user public task/function bool m_isStatic:1; // Function is declared static (no this) + bool m_symProlog:1; // Setup symbol table for later instructions public: AstCFunc(FileLine* fl, const string& name, AstScope* scopep, const string& rtnType="") : AstNode(fl) { @@ -2788,6 +2786,7 @@ public: m_slow = false; m_funcPublic = false; m_isStatic = false; + m_symProlog = false; } virtual ~AstCFunc() {} virtual AstType type() const { return AstType::CFUNC;} @@ -2795,7 +2794,9 @@ public: virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); } virtual string name() const { return m_name; } virtual V3Hash sameHash() const { return V3Hash(); } - virtual bool same(AstNode* samep) const { return true; } + virtual bool same(AstNode* samep) const { return ((funcType()==samep->castCFunc()->funcType()) + && (rtnTypeVoid()==samep->castCFunc()->rtnTypeVoid()) + && (argTypes()==samep->castCFunc()->argTypes())); } // void name(const string& flag) { m_name = flag; } AstScope* scopep() const { return m_scopep; } @@ -2819,6 +2820,8 @@ public: AstCFuncType funcType() const { return m_funcType; } bool isStatic() const { return m_isStatic; } void isStatic(bool flag) { m_isStatic = flag; } + bool symProlog() const { return m_symProlog; } + void symProlog(bool flag) { m_symProlog = flag; } // // If adding node accessors, see below AstNode* argsp() const { return op1p()->castNode(); } @@ -2840,6 +2843,7 @@ struct AstCCall : public AstNodeStmt { private: AstCFunc* m_funcp; string m_hiername; + string m_argTypes; public: AstCCall(FileLine* fl, AstCFunc* funcp, AstNode* argsp=NULL) : AstNodeStmt(fl) { @@ -2863,7 +2867,8 @@ public: virtual int instrCount() const { return instrCountCall(); } virtual V3Hash sameHash() const { return V3Hash(funcp()); } virtual bool same(AstNode* samep) const { - return funcp()==samep->castCCall()->funcp(); } + return (funcp()==samep->castCCall()->funcp() + && argTypes()==samep->castCCall()->argTypes()); } AstNode* exprsp() const { return op1p()->castNode(); } // op1= expressions to print virtual bool isGateOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; } @@ -2872,6 +2877,8 @@ public: AstCFunc* funcp() const { return m_funcp; } string hiername() const { return m_hiername; } void hiername(const string& hn) { m_hiername = hn; } + void argTypes(const string& str) { m_argTypes = str; } + string argTypes() const { return m_argTypes; } // AstNode* argsp() const { return op1p()->castNode(); } void addArgsp(AstNode* nodep) { addOp1p(nodep); } diff --git a/src/V3Case.cpp b/src/V3Case.cpp index e2e56433a..b588819cf 100644 --- a/src/V3Case.cpp +++ b/src/V3Case.cpp @@ -393,6 +393,6 @@ void V3Case::caseAll(AstNetlist* nodep) { CaseVisitor visitor (nodep); } void V3Case::caseLint(AstNodeCase* nodep) { - UINFO(2,__FUNCTION__<<": "< #include "V3Global.h" -#include "V3Changed.h" #include "V3Ast.h" +#include "V3Changed.h" +#include "V3EmitCBase.h" //###################################################################### // Changed state, as a visitor of each AstNode @@ -106,6 +107,8 @@ private: m_scopetopp = scopep; // Create change detection function m_chgFuncp = new AstCFunc(nodep->fileline(), "_change_request", scopep, "bool"); + m_chgFuncp->argTypes(EmitCBaseVisitor::symClassVar()); + m_chgFuncp->symProlog(true); m_scopetopp->addActivep(m_chgFuncp); // We need at least one change detect so we know to emit the correct code m_chgFuncp->addStmtsp(new AstChangeDet(nodep->fileline(), NULL, NULL, false)); diff --git a/src/V3Clock.cpp b/src/V3Clock.cpp index 251c6625f..8fed2e292 100644 --- a/src/V3Clock.cpp +++ b/src/V3Clock.cpp @@ -41,6 +41,7 @@ #include "V3Global.h" #include "V3Clock.h" #include "V3Ast.h" +#include "V3EmitCBase.h" //###################################################################### // Clock state, as a visitor of each AstNode @@ -186,30 +187,42 @@ private: AstNode::userClearTree(); // Make top functions { - m_evalFuncp = new AstCFunc(nodep->fileline(), "_eval", m_scopep); - m_evalFuncp->dontCombine(true); - m_scopep->addActivep(m_evalFuncp); + AstCFunc* funcp = new AstCFunc(nodep->fileline(), "_eval", m_scopep); + funcp->argTypes(EmitCBaseVisitor::symClassVar()); + funcp->dontCombine(true); + funcp->symProlog(true); + m_scopep->addActivep(funcp); + m_evalFuncp = funcp; } { - m_initFuncp = new AstCFunc(nodep->fileline(), "_eval_initial", m_scopep); - m_initFuncp->dontCombine(true); - m_initFuncp->slow(true); - m_scopep->addActivep(m_initFuncp); + AstCFunc* funcp = new AstCFunc(nodep->fileline(), "_eval_initial", m_scopep); + funcp->argTypes(EmitCBaseVisitor::symClassVar()); + funcp->dontCombine(true); + funcp->slow(true); + funcp->symProlog(true); + m_scopep->addActivep(funcp); + m_initFuncp = funcp; } { - m_finalFuncp = new AstCFunc(nodep->fileline(), "final", m_scopep); - m_finalFuncp->skipDecl(true); - m_finalFuncp->dontCombine(true); - m_finalFuncp->slow(true); - m_finalFuncp->addStmtsp(new AstCStmt(nodep->fileline(), - " "+v3Global.opt.prefix()+"__Syms::init(this);\n")); - m_scopep->addActivep(m_finalFuncp); + AstCFunc* funcp = new AstCFunc(nodep->fileline(), "final", m_scopep); + funcp->skipDecl(true); + funcp->dontCombine(true); + funcp->slow(true); + funcp->addInitsp( + new AstCStmt(nodep->fileline(), + " "+EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n")); + funcp->addInitsp(new AstCStmt(nodep->fileline()," "+EmitCBaseVisitor::symTopAssign()+"\n")); + m_scopep->addActivep(funcp); + m_finalFuncp = funcp; } { - m_settleFuncp = new AstCFunc(nodep->fileline(), "_eval_settle", m_scopep); - m_settleFuncp->dontCombine(true); - m_settleFuncp->slow(true); - m_scopep->addActivep(m_settleFuncp); + AstCFunc* funcp = new AstCFunc(nodep->fileline(), "_eval_settle", m_scopep); + funcp->argTypes(EmitCBaseVisitor::symClassVar()); + funcp->dontCombine(true); + funcp->slow(true); + funcp->symProlog(true); + m_scopep->addActivep(funcp); + m_settleFuncp = funcp; } // Process the activates nodep->iterateChildren(*this); @@ -273,12 +286,16 @@ private: if (!m_scopep) nodep->v3fatalSrc("Initial Active not under scope\n"); AstCFunc* funcp = new AstCFunc(nodep->fileline(), "_initial__"+m_scopep->nameDotless(), m_scopep); + funcp->argTypes(EmitCBaseVisitor::symClassVar()); + funcp->symProlog(true); funcp->slow(true); stmtsp->unlinkFrBackWithNext(); funcp->addStmtsp(stmtsp); nodep->replaceWith(funcp); // Add top level call to it - m_initFuncp->addStmtsp(new AstCCall(nodep->fileline(), funcp)); + AstCCall* callp = new AstCCall(nodep->fileline(), funcp); + callp->argTypes("vlSymsp"); + m_initFuncp->addStmtsp(callp); } else { nodep->unlinkFrBack(); } @@ -290,7 +307,9 @@ private: if (nodep->formCallTree()) { if (nodep->name() == "_final") { UINFO(4, " formCallTree "<addStmtsp(new AstCCall(nodep->fileline(), nodep)); + AstCCall* callp = new AstCCall(nodep->fileline(), nodep); + callp->argTypes("vlSymsp"); + m_finalFuncp->addStmtsp(callp); } else { nodep->v3fatalSrc("Unknown CFunc name. Make code more generic, with a map of func names"); } diff --git a/src/V3Combine.cpp b/src/V3Combine.cpp index 9d3d8ceec..3ec6d2e42 100644 --- a/src/V3Combine.cpp +++ b/src/V3Combine.cpp @@ -94,6 +94,7 @@ public: if (callp->funcp() != oldfuncp) callp->v3fatalSrc("Call list broken, points to call w/different func"); if (newfuncp) { AstCCall* newp = new AstCCall(callp, newfuncp); + newp->argTypes(callp->argTypes()); callp->replaceWith(newp); addCall(newp); // Fix the table } else { // Just deleting empty function diff --git a/src/V3Descope.cpp b/src/V3Descope.cpp index 31def35b6..425ecec86 100644 --- a/src/V3Descope.cpp +++ b/src/V3Descope.cpp @@ -36,6 +36,7 @@ #include "V3Global.h" #include "V3Descope.h" #include "V3Ast.h" +#include "V3EmitCBase.h" //###################################################################### @@ -61,13 +62,13 @@ private: hierThisr = true; if (varp && varp->isFuncLocal()) { return ""; // Relative to function, not in this - } else if (scopep == m_scopep) { - if (m_modp->isTop()) { - return ""; // Reference to scope we're in, no need to HIER-> it - } else { - m_needThis = true; - return "thisp->"; // this-> but with restricted aliasing - } + } else if (scopep == m_scopep && m_modp->isTop()) { + //return ""; // Reference to scope we're in, no need to HIER-> it + return "vlTOPp->"; + } else if (scopep == m_scopep && !m_modp->isTop() + && 0) { // We no longer thisp-> as still get ambiguation problems + m_needThis = true; + return "thisp->"; // this-> but with restricted aliasing } else if (scopep->aboveScopep() && scopep->aboveScopep()==m_scopep && 0 // DISABLED: GCC considers the pointers ambiguous, so goes ld/store crazy ) { @@ -81,13 +82,12 @@ private: return name+"->"; } else { // Reference to something else, use global variable - m_modp->globalSyms(true); UINFO(8," Descope "<name()<name()<aboveScopep()) { // Top - return "VlSym->TOPp->"; + return "vlTOPp->"; // == "vlSymsp->TOPp->", but GCC would suspect aliases } else { return scopep->nameVlSym()+"."; } @@ -111,6 +111,10 @@ private: if (newfuncp->stmtsp()) newfuncp->stmtsp()->unlinkFrBackWithNext()->deleteTree(); if (newfuncp->finalsp()) newfuncp->finalsp()->unlinkFrBackWithNext()->deleteTree(); newfuncp->name(name); + newfuncp->addInitsp( + new AstCStmt(newfuncp->fileline(), + " "+EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n")); + newfuncp->addInitsp(new AstCStmt(newfuncp->fileline()," "+EmitCBaseVisitor::symTopAssign()+"\n")); topFuncp->addNextHere(newfuncp); // In the body, call each function if it matches the given scope for (FuncMmap::iterator eachIt = it; eachIt!=m_modFuncs.end() && eachIt->first==name; ++eachIt) { @@ -209,6 +213,7 @@ private: nodep->iterateChildren(*this); nodep->user(true); if (m_needThis) { + nodep->v3fatalSrc("old code"); // Really we should have more node types for backend optimization of this stuff string text = " "+v3Global.opt.modPrefix() + "_" + m_modp->name() +"* thisp = &("+m_scopep->nameVlSym()+");\n"; diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 0152d2539..7dd61714c 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -182,9 +182,12 @@ public: puts(nodep->hiername()); puts(nodep->funcp()->name()); puts("("); + puts(nodep->argTypes()); + bool comma = (nodep->argTypes() != ""); for (AstNode* subnodep=nodep->argsp(); subnodep; subnodep = subnodep->nextp()) { + if (comma) puts(", "); subnodep->accept(*this); - if (subnodep->nextp()) puts(", "); + comma = true; } if (nodep->backp()->castNodeMath() || nodep->backp()->castCReturn()) { // We should have a separate CCall for math and statement usage, but... @@ -214,7 +217,7 @@ public: puts(");\n"); } virtual void visit(AstCoverInc* nodep, AstNUser*) { - puts("if (Verilated::s_coverageRequest)"); + puts("if (VL_LIKELY(vlSymsp->__Vm_coverageRequest))"); puts(" ++__Vcoverage["); puts(cvtToStr(m_coverIds.remap(nodep->declp()))); puts("];\n"); } @@ -596,6 +599,8 @@ class EmitCImp : EmitCStmts { +"<symProlog()) puts(EmitCBaseVisitor::symTopAssign()+"\n"); + if (nodep->initsp()) puts("// Variables\n"); ofp()->putAlign(V3OutFile::AL_AUTO, 4); for (AstNode* subnodep=nodep->argsp(); subnodep; subnodep = subnodep->nextp()) { @@ -1023,8 +1028,6 @@ void EmitCImp::emitVarResets(AstModule* modp) { puts("// Reset internal values\n"); if (modp->isTop()) { if (v3Global.opt.inhibitSim()) puts("__Vm_inhibitSim = false;\n"); - puts("__Vm_activity = false;\n"); - puts("__Vm_didInit = false;\n"); puts("\n"); } @@ -1201,7 +1204,8 @@ void EmitCImp::emitTextSection(AstType type) { void EmitCImp::emitCellCtors(AstModule* modp) { if (modp->isTop()) { // Must be before other constructors, as __vlCoverInsert calls it - puts("__VlSymsp = new "+symClassName()+"(this, name());\n"); + puts(EmitCBaseVisitor::symClassVar()+" = __VlSymsp = new "+symClassName()+"(this, name());\n"); + puts(EmitCBaseVisitor::symTopAssign()+"\n"); } for (AstNode* nodep=modp->stmtsp(); nodep; nodep = nodep->nextp()) { if (AstCell* cellp=nodep->castCell()) { @@ -1229,48 +1233,48 @@ void EmitCImp::emitSensitives() { void EmitCImp::emitWrapEval(AstModule* modp) { puts("\nvoid "+modClassName(modp)+"::eval() {\n"); - puts("// Setup global symbol table\n"); - puts(symClassName()); puts("::init(this);\n"); + puts(EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp; // Setup global symbol table\n"); + puts(EmitCBaseVisitor::symTopAssign()+"\n"); puts("// Initialize\n"); - puts("if (!__Vm_didInit) eval_initial_loop();\n"); + puts("if (VL_UNLIKELY(!vlSymsp->__Vm_didInit)) _eval_initial_loop(vlSymsp);\n"); if (v3Global.opt.inhibitSim()) { - puts("if (__Vm_inhibitSim) return;\n"); + puts("if (VL_UNLIKELY(__Vm_inhibitSim)) return;\n"); } puts("// Evaluate till stable\n"); puts("VL_DEBUG_IF(cout<<\"\\n----TOP Evaluate "+modClassName(modp)+"::eval\"<__Vm_coverageRequest = true;\n"); + puts( "vlSymsp->__Vm_activity = true;\n"); + puts( "_eval(vlSymsp);\n"); + if (v3Global.opt.coverage()) puts( "vlSymsp->__Vm_coverageRequest = false;\n"); #ifndef NEW_ORDERING - puts( "__Vchange = _change_request();\n"); + puts( "__Vchange = _change_request(vlSymsp);\n"); puts( "if (++__VclockLoop > 100) vl_fatal(__FILE__,__LINE__,__FILE__,\"Verilated model didn't converge\");\n"); puts("}\n"); #endif puts("}\n"); // - puts("\nvoid "+modClassName(modp)+"::eval_initial_loop() {\n"); - puts("__Vm_didInit = true;\n"); - puts("_eval_initial();\n"); + puts("\nvoid "+modClassName(modp)+"::_eval_initial_loop("+EmitCBaseVisitor::symClassVar()+") {\n"); + puts("vlSymsp->__Vm_didInit = true;\n"); + puts("_eval_initial(vlSymsp);\n"); #ifndef NEW_ORDERING - puts( "__Vm_activity = true;\n"); + puts( "vlSymsp->__Vm_activity = true;\n"); puts( "int __VclockLoop = 0;\n"); - puts( "IData __Vchange;\n"); - puts( "for (__Vchange=1; __Vchange; ) {\n"); + puts( "IData __Vchange=1;\n"); + puts( "while (VL_LIKELY(__Vchange)) {\n"); #endif - puts( "_eval_settle();\n"); - puts( "_eval();\n"); + puts( "_eval_settle(vlSymsp);\n"); + puts( "_eval(vlSymsp);\n"); #ifndef NEW_ORDERING - puts( "__Vchange = _change_request();\n"); + puts( "__Vchange = _change_request(vlSymsp);\n"); puts( "if (++__VclockLoop > 100) vl_fatal(__FILE__,__LINE__,__FILE__,\"Verilated model didn't DC converge\");\n"); puts( "}\n"); #endif @@ -1414,10 +1418,6 @@ void EmitCImp::emitInt(AstModule* modp) { ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(bool)); puts("bool\t__Vm_inhibitSim;\t///< Set true to disable evaluation of module\n"); } - ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(bool)); - puts("bool\t__Vm_activity;\t\t///< Used by trace routines to determine change occurred\n"); - ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(bool)); - puts("bool\t__Vm_didInit;\n"); } ofp()->putAlign(V3OutFile::AL_AUTO, 8); emitCoverageDecl(modp); // may flip public/private @@ -1449,6 +1449,11 @@ void EmitCImp::emitInt(AstModule* modp) { puts("\n// METHODS\n"); ofp()->resetPrivate(); + // We don't need a private copy constructor, as VerilatedModule has one for us. + ofp()->putsPrivate(true); + puts(modClassName(modp)+"& operator= (const "+modClassName(modp)+"&);\t///< Copying not allowed\n"); + puts(modClassName(modp)+"(const "+modClassName(modp)+"&);\t///< Copying not allowed\n"); + ofp()->putsPrivate(false); // public: if (optSystemC() && modp->isTop()) { puts("SC_CTOR("+modClassName(modp)+");\n"); @@ -1466,9 +1471,6 @@ void EmitCImp::emitInt(AstModule* modp) { puts("void\t__Vconfigure("+symClassName()+"* symsp);\n"); if (optSystemPerl()) puts("/*AUTOMETHODS*/\n"); - if (modp->isTop()) { - puts("inline bool\tgetClearActivity() { bool r=__Vm_activity; __Vm_activity=false; return r;}\n"); - } emitTextSection(AstType::SCINT); puts("\n// Sensitivity blocks\n"); @@ -1480,7 +1482,7 @@ void EmitCImp::emitInt(AstModule* modp) { puts("void\tinhibitSim(bool flag) { __Vm_inhibitSim=flag; }\t///< Set true to disable evaluation of module\n"); } ofp()->putsPrivate(true); // private: - puts("void\teval_initial_loop();\n"); + puts("void\t_eval_initial_loop("+EmitCBaseVisitor::symClassVar()+");\n"); #ifndef NEW_ORDERING puts("IData\tchange_request();\n"); #endif @@ -1492,7 +1494,7 @@ void EmitCImp::emitInt(AstModule* modp) { ofp()->putsPrivate(false); // public: puts("static void\ttraceInit (SpTraceVcd* vcdp, void* userthis, uint32_t code);\n"); puts("static void\ttraceFull (SpTraceVcd* vcdp, void* userthis, uint32_t code);\n"); - puts("static void\ttraceChg (SpTraceVcd* vcdp, void* userthis, uint32_t code);\n"); + puts("static void\ttraceChg (SpTraceVcd* vcdp, void* userthis, uint32_t code);\n"); } puts("} VL_ATTR_ALIGNED(8);\n"); @@ -1515,19 +1517,7 @@ void EmitCImp::emitImp(AstModule* modp) { (modClassName(modp)+".h\"").c_str()); // Us - if (modp->globalSyms() || modp->isTop() || 1 /*for thisp*/) { - puts("#include \""+ symClassName() +".h\"\n"); - puts("#define VlSym "+ symClassName() +"::s_thisp\n"); - } else { - // Instantiated modules - for (AstNode* nodep=modp->stmtsp(); nodep; nodep = nodep->nextp()) { - if (AstCell* cellp=nodep->castCell()) { - ofp()->printf("#include \"%-20s", - (modClassName(cellp->modp())+".h\"").c_str()); - puts(" // For "+cellp->name()+"\n"); - } - } - } + puts("#include \""+ symClassName() +".h\"\n"); if (optSystemPerl() && (m_splitFilenum || !m_fast)) { puts("\n"); @@ -1577,9 +1567,6 @@ void EmitCImp::emitImp(AstModule* modp) { } void EmitCImp::emitImpBottom(AstModule* modp) { - if (modp->globalSyms()) { - puts("#undef VlSym\n"); - } } //###################################################################### @@ -1660,7 +1647,6 @@ class EmitCTrace : EmitCStmts { } puts("#include \"SpTraceVcdC.h\"\n"); puts("#include \""+ symClassName() +".h\"\n"); - puts("#define VlSym "+ symClassName() +"::s_thisp\n"); puts("\n"); } @@ -1682,16 +1668,16 @@ class EmitCTrace : EmitCStmts { puts("void "+topClassName()+"::traceInit(SpTraceVcd* vcdp, void* userthis, uint32_t code) {\n"); puts("// Callback from vcd->open()\n"); puts(topClassName()+"* t=("+topClassName()+"*)userthis;\n"); - puts(symClassName()+"::init(t); // Setup global symbol table\n"); + puts(EmitCBaseVisitor::symClassVar()+" = t->__VlSymsp; // Setup global symbol table\n"); puts("if (!Verilated::calcUnusedSigs()) vl_fatal(__FILE__,__LINE__,__FILE__,\"Turning on wave traces requires Verilated::traceEverOn(true) call before time 0.\");\n"); - puts("t->traceInitThis (vcdp, code);\n"); + puts("t->traceInitThis (vlSymsp, vcdp, code);\n"); puts("}\n"); puts("void "+topClassName()+"::traceFull(SpTraceVcd* vcdp, void* userthis, uint32_t code) {\n"); puts("// Callback from vcd->dump()\n"); puts(topClassName()+"* t=("+topClassName()+"*)userthis;\n"); - puts(symClassName()+"::init(t); // Setup global symbol table\n"); - puts("t->traceFullThis (vcdp, code);\n"); + puts(EmitCBaseVisitor::symClassVar()+" = t->__VlSymsp; // Setup global symbol table\n"); + puts("t->traceFullThis (vlSymsp, vcdp, code);\n"); puts("}\n"); puts("\n//======================\n\n"); @@ -1703,9 +1689,9 @@ class EmitCTrace : EmitCStmts { puts("void "+topClassName()+"::traceChg(SpTraceVcd* vcdp, void* userthis, uint32_t code) {\n"); puts("// Callback from vcd->dump()\n"); puts(topClassName()+"* t=("+topClassName()+"*)userthis;\n"); - puts("if (t->getClearActivity()) {\n"); - puts(symClassName()+"::init(t); // Setup global symbol table\n"); - puts("t->traceChgThis (vcdp, code);\n"); + puts(EmitCBaseVisitor::symClassVar()+" = t->__VlSymsp; // Setup global symbol table\n"); + puts("if (vlSymsp->getClearActivity()) {\n"); + puts("t->traceChgThis (vlSymsp, vcdp, code);\n"); puts("}\n"); puts("}\n"); @@ -1879,7 +1865,6 @@ public: v3Global.rootp()->accept(*this); - puts("#undef VlSym\n"); m_ofp = NULL; } }; diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h index ac8fae18d..b14710a15 100644 --- a/src/V3EmitCBase.h +++ b/src/V3EmitCBase.h @@ -108,6 +108,8 @@ public: bool optSystemC() { return v3Global.opt.systemC(); } bool optSystemPerl() { return v3Global.opt.systemPerl(); } static string symClassName() { return v3Global.opt.prefix()+"__Syms"; } + static string symClassVar() { return symClassName()+"* __restrict vlSymsp"; } + static string symTopAssign() { return v3Global.opt.prefix()+"* __restrict vlTOPp = vlSymsp->TOPp;"; } static string modClassName(AstModule* modp) { // Return name of current module being processed if (modp->isTop()) { return v3Global.opt.prefix(); diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 71d7ff4b6..fb69cefdd 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -119,14 +119,23 @@ void EmitCSyms::emitInt() { puts("\n// SYMS CLASS\n"); puts((string)"class "+symClassName()+" {\n"); - puts("public:\n"); + ofp()->putsPrivate(false); // public: - puts("// STATIC STATE\n"); - puts("static "+symClassName()+"* s_thisp;\n"); + //puts("\n// STATIC STATE\n"); puts("\n// LOCAL STATE\n"); + ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(uint64_t)); puts("const char* __Vm_namep;\n"); // Must be before subcells, as constructor order needed before _vlCoverInsert. + ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(bool)); + puts("bool\t__Vm_activity;\t\t///< Used by trace routines to determine change occurred\n"); + ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(bool)); + puts("bool\t__Vm_didInit;\n"); + if (v3Global.opt.coverage()) { + ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(bool)); + puts("bool __Vm_coverageRequest;\n"); + } + ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(uint64_t)); puts("\n// SUBCELL STATE\n"); for (vector::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) { AstScope* scopep = it->first; AstModule* modp = it->second; @@ -143,15 +152,10 @@ void EmitCSyms::emitInt() { puts("\n// CREATORS\n"); puts(symClassName()+"("+topClassName()+"* topp, const char* namep);\n"); puts((string)"~"+symClassName()+"() {};\n"); + puts("\n// METHODS\n"); - puts("/// Called at top of each eval to setup global pointer to top-of-symbol table\n"); - puts((string)"inline static void init ("+symClassName()+"* symsp) {\n"); - puts("s_thisp = symsp;\n"); - puts("}\n"); - puts((string)"inline static void init ("+topClassName()+"* topp) {\n"); - puts("s_thisp = topp->__VlSymsp;\n"); - puts("}\n"); puts("inline const char* name() { return __Vm_namep; }\n"); + puts("inline bool getClearActivity() { bool r=__Vm_activity; __Vm_activity=false; return r;}\n"); puts("\n"); puts("};\n"); puts("#endif /*guard*/\n"); @@ -172,13 +176,15 @@ void EmitCSyms::emitImp() { puts("#include \""+modClassName(nodep)+".h\"\n"); } - puts("\n// GLOBALS\n"); - puts(symClassName()+"* "+symClassName()+"::s_thisp;\n"); + //puts("\n// GLOBALS\n"); puts("\n// FUNCTIONS\n"); puts(symClassName()+"::"+symClassName()+"("+topClassName()+"* topp, const char* namep)\n"); puts("\t// Setup locals\n"); puts("\t: __Vm_namep(namep)\n"); // No leak, as we get destroyed when the top is destroyed + puts("\t, __Vm_activity(false)\n"); + puts("\t, __Vm_didInit(false)\n"); + if (v3Global.opt.coverage()) puts("\t, __Vm_coverageRequest(false)\n"); puts("\t// Setup submodule names\n"); char comma=','; for (vector::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) { diff --git a/src/V3Order.cpp b/src/V3Order.cpp index ee63febc5..bd338bc1c 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -106,6 +106,7 @@ #include "V3List.h" #include "V3SenTree.h" #include "V3Stats.h" +#include "V3EmitCBase.h" #include "V3Order.h" #include "V3OrderGraph.h" @@ -1380,6 +1381,8 @@ void OrderVisitor::processMoveOne(OrderMoveVertex* vertexp, OrderMoveDomScope* d if (!m_pomNewFuncp && domainp != m_deleteDomainp) { string name = cfuncName(modp, domainp, scopep, nodep); m_pomNewFuncp = new AstCFunc(nodep->fileline(), name, scopep); + m_pomNewFuncp->argTypes(EmitCBaseVisitor::symClassVar()); + m_pomNewFuncp->symProlog(true); if (domainp->hasInitial() || domainp->hasSettle()) m_pomNewFuncp->slow(true); scopep->addActivep(m_pomNewFuncp); // Where will we be adding the call? @@ -1387,6 +1390,7 @@ void OrderVisitor::processMoveOne(OrderMoveVertex* vertexp, OrderMoveDomScope* d processMoveLoopStmt(callunderp); // Add a top call to it AstCCall* callp = new AstCCall(nodep->fileline(), m_pomNewFuncp); + callp->argTypes("vlSymsp"); callunderp->addStmtsp(callp); UINFO(6," New "<funcPublic(true); // We need to get a pointer to all of our variables (may have eval'ed something else earlier) - funcp->addInitsp(new AstCStmt(nodep->fileline(), - string(" ")+v3Global.opt.prefix()+"__Syms::init(__VlSymsp);\n")); + funcp->addInitsp( + new AstCStmt(nodep->fileline(), + " "+EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n")); + funcp->addInitsp(new AstCStmt(nodep->fileline()," "+EmitCBaseVisitor::symTopAssign()+"\n")); // Create list of arguments and move to function for (AstNode* nextp, *stmtp = nodep->stmtsp(); stmtp; stmtp=nextp) { diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp index fd4f23aaf..b6ec597b7 100644 --- a/src/V3TraceDecl.cpp +++ b/src/V3TraceDecl.cpp @@ -76,8 +76,9 @@ private: { AstCFunc* funcp = new AstCFunc(nodep->fileline(), "traceInitThis", m_scopetopp); funcp->slow(true); - funcp->argTypes("SpTraceVcd* vcdp, uint32_t code"); + funcp->argTypes(EmitCBaseVisitor::symClassVar()+", SpTraceVcd* vcdp, uint32_t code"); funcp->funcType(AstCFuncType::TRACE_INIT); + funcp->symProlog(true); m_scopetopp->addActivep(funcp); m_initFuncp = funcp; UINFO(5," Newfunc "<fileline(), "traceFullThis", m_scopetopp); funcp->slow(true); - funcp->argTypes("SpTraceVcd* vcdp, uint32_t code"); + funcp->argTypes(EmitCBaseVisitor::symClassVar()+", SpTraceVcd* vcdp, uint32_t code"); funcp->funcType(AstCFuncType::TRACE_FULL); + funcp->symProlog(true); m_scopetopp->addActivep(funcp); m_fullFuncp = funcp; } { AstCFunc* funcp = new AstCFunc(nodep->fileline(), "traceChgThis", m_scopetopp); - funcp->argTypes("SpTraceVcd* vcdp, uint32_t code"); + funcp->argTypes(EmitCBaseVisitor::symClassVar()+", SpTraceVcd* vcdp, uint32_t code"); funcp->funcType(AstCFuncType::TRACE_CHANGE); + funcp->symProlog(true); m_scopetopp->addActivep(funcp); m_chgFuncp = funcp; }