diff --git a/Changes b/Changes index 981f6211e..9445ee23a 100644 --- a/Changes +++ b/Changes @@ -15,6 +15,12 @@ Verilator 4.205 devel * Generated code is now emitted as global functions rather than methods. '$c' contents might need to be updated, see the docs (#3006). [Geza Lore] +* The generated model class instantiated by the user is now an interface + object and no longer the TOP module instance. User code with direct + C++ member access to model internals, including verilator public_flat + items will likely need to be updated. See the manual for instructions: + https://verilator.org/guide/latest/connecting.html#porting-from-pre-4-206 + (#3036). [Geza Lore] **Minor:** diff --git a/docs/guide/connecting.rst b/docs/guide/connecting.rst index 720ecb8c1..32e1301ae 100644 --- a/docs/guide/connecting.rst +++ b/docs/guide/connecting.rst @@ -7,22 +7,86 @@ Connecting to Verilated Models ****************************** +Structure of the Verilated Model +================================ + +Verilator outputs a :file:`{prefix}.h` header file which defines a class +named :code:`{prefix}` which represents the generated model the user is +supposed to instantiate. This model class defines the interface of the +Verilated model. + +Verilator will additionally create a :file:`{prefix}.cpp` file, together +with additional .h and .cpp files for internals. See the :file:`examples` +directory in the kit for examples. See :ref:`Files Read/Written` for +information on all the files Verilator might output. + +The output of Verilator will contain a :file:`{prefix}.mk` file that may be +used with Make to build a :file:`{prefix}__ALL.a` library with all required +objects in it. + +The generated model class file manages all internal state required by the +model, and exposes the following interface that allows interaction with the +model: + +* Top level IO ports are exposed as references to the appropriate internal + equivalents. + +* Public top level module instances are exposed as pointers to allow access + to :code:`/* verilator public */` items. + +* The root of the design hierarchy (as in SystemVerilog :code:`$root`) is + exposed via the :code:`rootp` member pointer to allow access to model + internals, including :code:`/* verilator public_flat */` items. + + +.. _Porting from pre 4.206: + +Model interface changes in version 4.206 +------------------------------------------ + +Starting from version 4.206, the model class is an interface object. + +Up until Verilator version 4.204 inclusive, the generated model class was +also the instance of the top level instance in the design hierarchy (what +you would refer to with :code:`$root` in SystemVerilog). This meant that +all internal variables that were implemented by Verilator in the root scope +were accessible as members of the model class itself. Note there were often +many such variable due to module inlining, including :code:`/* verilator +public_flat */` items. + +This means that user code that accesses internal signals in the model +(likely including :code:`/* verilator public_flat */` signals, as they are +often inlined into the root scope) will need to be updated as follows: + +* No change required for accessing top level IO signals. These are directly + accessible in the model class via references. + +* No change required for accessing :code:`/* verilator public */` items. + These are directly accessible via sub-module pointers in the model class. + +* Accessing any other internal members, including + :code:`/* verilator public_flat */` items requires the following changes: + + * Additionally include :file:`{prefix}___024root.h`. This header defines + type of the :code:`rootp` pointer within the model class. Note the + :code:`__024` substring is the Verilator escape sequence for the + :code:`$` character, i.e.: :code:`rootp` points to the Verilated + SystemVerilog :code:`$root` scope. + + * Replace :code:`modelp->internal->member->lookup` references with + :code:`modelp->rootp->internal->member->lookup` references, which + contain one additional indirection via the :code:`rootp` pointer. + + .. _Connecting to C++: Connecting to C++ ================= -Verilator creates a :file:`{prefix}.h` and :file:`{prefix}.cpp` file for -the top level module, together with additional .h and .cpp files for -internals. See the :file:`examples` directory in the kit for examples. See -:ref:`Files Read/Written` for information on all the files it writes. - -After the model is created, there will be a :file:`{prefix}.mk` file that -may be used with Make to produce a :file:`{prefix}__ALL.a` file with all -required objects in it. - -The user must write a C++ wrapper and main loop for the simulation, to link -with the Verilated model. Here is a simple example: +In C++ output mode (:vlopt:`--cc`), the Verilator generated model class is a +simple C++ class. The user must write a C++ wrapper and main loop for the +simulation, which instantiates the model class, and link with the Verilated +model. Here is a simple example: .. code-block:: C++ @@ -30,7 +94,7 @@ with the Verilated model. Here is a simple example: #include // Need std::cout #include "Vtop.h" // From Verilating "top.v" - Vtop *top; // Instantiation of module + Vtop *top; // Instantiation of model vluint64_t main_time = 0; // Current simulation time // This is a 64-bit integer to reduce wrap over issues and @@ -45,7 +109,7 @@ with the Verilated model. Here is a simple example: int main(int argc, char** argv) { Verilated::commandArgs(argc, argv); // Remember args - top = new Vtop; // Create instance + top = new Vtop; // Create model top->reset_l = 0; // Set some inputs @@ -70,17 +134,18 @@ with the Verilated model. Here is a simple example: } -Note signals are read and written as member variables of the model. You -call the :code:`eval()` method to evaluate the model. When the simulation -is complete call the :code:`final()` method to execute any SystemVerilog -final blocks, and complete any assertions. See :ref:`Evaluation Loop`. +Note top level IO signals are read and written as members of the model. You +call the :code:`eval()` method to evaluate the model. When the simulation is +complete call the :code:`final()` method to execute any SystemVerilog final +blocks, and complete any assertions. See :ref:`Evaluation Loop`. Connecting to SystemC ===================== -Verilator will convert the top level module to a SC_MODULE. This module -will attach directly into a SystemC netlist as an instantiation. +In SystemC output mode (:vlopt:`--sc`), the Verilator generated model class +is a SystemC SC_MODULE. This module will attach directly into a SystemC +netlist as an instantiation. The SC_MODULE gets the same pinout as the Verilog module, with the following type conversions: Pins of a single bit become bool. Pins 2-32 @@ -88,9 +153,9 @@ bits wide become uint32_t's. Pins 33-64 bits wide become sc_bv's or vluint64_t's depending on the :vlopt:`--no-pins64` option. Wider pins become sc_bv's. (Uints simulate the fastest so are used where possible.) -Lower modules are not pure SystemC code. This is a feature, as using the -SystemC pin interconnect scheme everywhere would reduce performance by an -order of magnitude. +Model internals, including lower level sub-modules are not pure SystemC +code. This is a feature, as using the SystemC pin interconnect scheme +everywhere would reduce performance by an order of magnitude. Direct Programming Interface (DPI) diff --git a/docs/guide/files.rst b/docs/guide/files.rst index cc2dca400..692f3e937 100644 --- a/docs/guide/files.rst +++ b/docs/guide/files.rst @@ -54,32 +54,38 @@ For --cc/--sc, it creates: - Arguments for hierarchical Verilation (from --make gmake) * - *{prefix}*\ _hierCMakeArgs.f - Arguments for hierarchical Verilation (from --make cmake) - * - *{prefix}*\ .cpp - - Top level C++ file - * - *{prefix}{__n}*\ .cpp - - Additional top C++ files (from --output-split) * - *{prefix}*\ .h - - Top level header - * - *{prefix}*\ __Slow\ *{__n}*\ .cpp + - Model header + * - *{prefix}*\ .cpp + - Model C++ file + * - *{prefix}*\ ___024root.h + - Top level (SystemVerilog $root) internal header file + * - *{prefix}*\ ___024root.cpp + - Top level (SystemVerilog $root) internal C++ file + * - *{prefix}*___024root*{__n}*\ .cpp + - Additional top level internal C++ files (from --output-split) + * - *{prefix}*\ ___024root__Slow\ *{__n}*\ .cpp - Infrequent cold routines - * - *{prefix}*\ __Dpi.cpp - - DPI import and export wrappers (from --dpi) + * - *{prefix}*\ ___024root__Trace{__n}*\ .cpp + - Wave file generation code (from --trace) + * - *{prefix}*\ ___024root__Trace__Slow{__n}*\ .cpp + - Wave file generation code (from --trace) * - *{prefix}*\ __Dpi.h - DPI import and export declarations (from --dpi) + * - *{prefix}*\ __Dpi.cpp + - Global DPI export wrappers (from --dpi) + * - *{prefix}*\ __Dpi_Export\ *{__n}\ .cpp + - DPI export wrappers scoped to this particular model (from --dpi) * - *{prefix}*\ __Inlines.h - Inline support functions - * - *{prefix}*\ __Syms.cpp - - Global symbol table C++ * - *{prefix}*\ __Syms.h - Global symbol table header - * - *{prefix}*\ __Trace{__n}*\ .cpp - - Wave file generation code (from --trace) - * - *{prefix}*\ __Trace__Slow{__n}*\ .cpp - - Wave file generation code (from --trace) - * - *{prefix}{each_verilog_module}*\ .cpp - - Lower level internal C++ files + * - *{prefix}*\ __Syms.cpp + - Global symbol table C++ * - *{prefix}{each_verilog_module}*\ .h - Lower level internal header files + * - *{prefix}{each_verilog_module}*\ .cpp + - Lower level internal C++ files * - *{prefix}{each_verilog_module}{__n}*\ .cpp - Additional lower C++ files (from --output-split) diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index 9216ba3ff..47288dec6 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -184,9 +184,10 @@ RAW_OBJS = \ V3EmitCConstPool.o \ V3EmitCFunc.o \ V3EmitCInlines.o \ - V3EmitCSyms.o \ - V3EmitCMake.o \ V3EmitCMain.o \ + V3EmitCMake.o \ + V3EmitCModel.o \ + V3EmitCSyms.o \ V3EmitMk.o \ V3EmitV.o \ V3EmitXml.o \ diff --git a/src/V3Ast.h b/src/V3Ast.h index 3c92a9a3a..afa26f75d 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1880,7 +1880,7 @@ public: virtual void dump(std::ostream& str) const override; virtual bool hasDType() const override { return true; } virtual string emitVerilog() = 0; /// Format string for verilog writing; see V3EmitV - // For documentation on emitC format see EmitCStmts::emitOpName + // For documentation on emitC format see EmitCFunc::emitOpName virtual string emitC() = 0; virtual string emitSimpleOperator() { return ""; } // "" means not ok to use virtual bool emitCheckMaxWords() { return false; } // Check VL_MULS_MAX_WORDS diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 9bb1d5067..d51f70fae 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -337,14 +337,15 @@ string AstVar::verilogKwd() const { } } -string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc) const { +string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc, + bool asRef) const { UASSERT_OBJ(!forReturn, this, "Internal data is never passed as return, but as first argument"); string ostatic; if (isStatic() && namespc.empty()) ostatic = "static "; - const bool isRef - = isDpiOpenArray() || (forFunc && (isWritable() || direction().isRefOrConstRef())); + const bool isRef = isDpiOpenArray() + || (forFunc && (isWritable() || direction().isRefOrConstRef())) || asRef; if (forFunc && isReadOnly() && isRef) ostatic = ostatic + "const "; @@ -641,8 +642,15 @@ public: string render(const string& name, bool isRef) const { string out; out += m_type; - if (name != "") out += " "; - out += isRef ? "(&" + name + ")" : name; + if (!name.empty()) out += " "; + if (isRef) { + if (!m_dims.empty()) out += "("; + out += "&"; + out += name; + if (!m_dims.empty()) out += ")"; + } else { + out += name; + } out += m_dims; return out; } diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 4fe2c3950..731bcc1dc 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -2059,7 +2059,8 @@ public: string dpiArgType(bool named, bool forReturn) const; // Return DPI-C type for argument string dpiTmpVarType(const string& varName) const; // Return Verilator internal type for argument: CData, SData, IData, WData - string vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc = "") const; + string vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc = "", + bool asRef = false) const; string vlEnumType() const; // Return VerilatorVarType: VLVT_UINT32, etc string vlEnumDir() const; // Return VerilatorVarDir: VLVD_INOUT, etc string vlPropDecl(const string& propName) const; // Return VerilatorVarProps declaration diff --git a/src/V3Descope.cpp b/src/V3Descope.cpp index b6057ae85..9b2e2cf76 100644 --- a/src/V3Descope.cpp +++ b/src/V3Descope.cpp @@ -98,11 +98,7 @@ private: } else { // Reference to something elsewhere, or relative references are disabled. Use global // variable - if (scopep->isTop()) { // Top - return "vlSymsp->TOPp"; - } else { - return "(&" + scopep->nameVlSym() + ")"; - } + return "(&" + scopep->nameVlSym() + ")"; } } diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 1532fb7c7..b2f345698 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -24,7 +24,7 @@ #include #include -//###################################################################### > +//###################################################################### // Internal EmitC implementation class EmitCImp final : EmitCFunc { @@ -60,24 +60,12 @@ class EmitCImp final : EmitCFunc { } ofp->putsHeader(); - if (m_fileModp->isTop() && !source) { - ofp->puts("// DESCR" - "IPTION: Verilator output: Primary design header\n"); - ofp->puts("//\n"); - ofp->puts("// This header should be included by all source files instantiating the " - "design.\n"); - ofp->puts("// The class here is then constructed to instantiate the design.\n"); - ofp->puts("// See the Verilator manual for examples.\n"); + if (source) { + ofp->puts("// DESCRIPTION: Verilator output: Design implementation internals\n"); } else { - if (source) { - ofp->puts("// DESCR" - "IPTION: Verilator output: Design implementation internals\n"); - } else { - ofp->puts("// DESCR" - "IPTION: Verilator output: Design internal header\n"); - } - ofp->puts("// See " + v3Global.opt.prefix() + ".h for the primary calling header\n"); + ofp->puts("// DESCRIPTION: Verilator output: Design internal header\n"); } + ofp->puts("// See " + topClassName() + ".h for the primary calling header\n"); return ofp; } @@ -88,6 +76,7 @@ class EmitCImp final : EmitCFunc { // TRACE_* and DPI handled elsewhere if (nodep->funcType().isTrace()) return; if (nodep->dpiImportPrototype()) return; + if (nodep->dpiExportDispatcher()) return; if (!(nodep->slow() ? m_slow : m_fast)) return; maybeSplit(); @@ -192,7 +181,33 @@ class EmitCImp final : EmitCFunc { } if (anyi) puts("\n"); } - void emitSensitives(); + void emitIntFuncDecls(AstNodeModule* modp, bool inClassBody) { + std::vector funcsp; + + for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { + if (const AstCFunc* funcp = VN_CAST(nodep, CFunc)) { + if (funcp->dpiImportPrototype()) // Declared in __Dpi.h + continue; + if (funcp->dpiExportDispatcher()) // Declared in __Dpi.h + continue; + if (funcp->isMethod() != inClassBody) // Only methods go inside class + continue; + if (funcp->isMethod() && funcp->isLoose()) // Loose methods are declared lazily + continue; + funcsp.push_back(funcp); + } + } + + stable_sort(funcsp.begin(), funcsp.end(), [](const AstNode* ap, const AstNode* bp) { // + return ap->name() < bp->name(); + }); + + for (const AstCFunc* funcp : funcsp) { + if (inClassBody) ofp()->putsPrivate(funcp->declPrivate()); + emitCFuncDecl(funcp, modp); + } + } + // Medium level void emitCtorImp(AstNodeModule* modp); void emitConfigureImp(AstNodeModule* modp); @@ -204,11 +219,6 @@ class EmitCImp final : EmitCFunc { // High level void emitImpTop(); void emitImp(AstNodeModule* modp); - void emitSettleLoop(bool initial); - void emitWrapEval(); - void emitWrapFast(); - void emitThreadingState(); - void emitThreadingCtors(bool* firstp); void emitIntTop(const AstNodeModule* modp); void emitInt(AstNodeModule* modp); void maybeSplit(); @@ -236,19 +246,6 @@ void EmitCImp::emitCoverageDecl(AstNodeModule*) { } } -void EmitCImp::emitThreadingCtors(bool* firstp) { - ofp()->indentInc(); - emitCtorSep(firstp); - puts("__Vm_threadPoolp(nullptr)"); - emitCtorSep(firstp); - puts("__Vm_even_cycle(false)"); - if (v3Global.opt.profThreads()) { - emitCtorSep(firstp); - puts("__Vm_profile_cycle_start(0)"); - } - ofp()->indentDec(); -} - void EmitCImp::emitCtorImp(AstNodeModule* modp) { puts("\n"); bool first = true; @@ -264,62 +261,19 @@ void EmitCImp::emitCtorImp(AstNodeModule* modp) { if (VN_IS(modp, Class)) { modp->v3fatalSrc("constructors should be AstCFuncs instead"); - } else if (optSystemC() && modp->isTop()) { - puts(modName + "::" + modName + "(sc_module_name)"); - } else if (modp->isTop()) { - puts(modName + "::" + modName - + "(VerilatedContext* _vcontextp__, const char* _vcname__)\n"); - puts(" : VerilatedModule{_vcname__}\n"); - first = false; // printed the first ':' } else { puts(modName + "::" + modName + "(const char* _vcname__)\n"); puts(" : VerilatedModule(_vcname__)\n"); first = false; // printed the first ':' } emitVarCtors(&first); - if (modp->isTop() && v3Global.opt.mtasks()) emitThreadingCtors(&first); puts(" {\n"); - if (modp->isTop()) { - putsDecoration("// Create Sym instance\n"); - // Must be before other constructors, as __vlCoverInsert calls it. - // Note _vcontextp__ may be nullptr, VerilatedSyms::VerilatedSyms cleans it up - puts(EmitCBaseVisitor::symClassVar() + " = new " + symClassName() + "(" - + (optSystemC() ? "nullptr" : "_vcontextp__") + ", this, name());\n"); - } - - emitSensitives(); - putsDecoration("// Reset structure values\n"); puts(modName + "__" + protect("_ctor_var_reset") + "(this);\n"); emitTextSection(AstType::atScCtor); - if (modp->isTop() && v3Global.opt.mtasks()) { - // TODO-- For now each top module creates its own ThreadPool here, - // and deletes it in the destructor. If A and B are each top level - // modules, each creates a separate thread pool. This allows - // A.eval() and B.eval() to run concurrently without any - // interference -- so long as the physical machine has enough cores - // to support both pools and all testbench threads. - // - // In the future, we might want to let the client provide a - // threadpool to the constructor. This would allow two or more - // models to share a single threadpool. - // - // For example: suppose models A and B are each compiled to run on - // 4 threads. The client might create a single thread pool with 3 - // threads and pass it to both models. If the client can ensure that - // A.eval() and B.eval() do NOT run concurrently, there will be no - // contention for the threads. This mode is missing for now. (Is - // there demand for such a setup?) - puts("__Vm_threadPoolp = new VlThreadPool(" - // Note we create N-1 threads in the thread pool. The thread - // that calls eval() becomes the final Nth thread for the - // duration of the eval call. - + string("vlSymsp->_vm_contextp__, ") + cvtToStr(v3Global.opt.threads() - 1) + ", " - + cvtToStr(v3Global.opt.profThreads()) + ");\n"); - } puts("}\n"); } @@ -382,19 +336,7 @@ void EmitCImp::emitCoverageImp(AstNodeModule*) { void EmitCImp::emitDestructorImp(AstNodeModule* modp) { puts("\n"); puts(prefixNameProtect(modp) + "::~" + prefixNameProtect(modp) + "() {\n"); - if (modp->isTop()) { - if (v3Global.opt.mtasks()) { - puts("VL_DO_CLEAR(delete __Vm_threadPoolp, __Vm_threadPoolp = nullptr);\n"); - } - // Call via function in __Trace.cpp as this .cpp file does not have trace header - if (v3Global.needTraceDumper()) { - puts("#ifdef VM_TRACE\n"); - puts("if (VL_UNLIKELY(vlSymsp->__Vm_dumping)) _traceDumpClose();\n"); - puts("#endif // VM_TRACE\n"); - } - } emitTextSection(AstType::atScDtor); - if (modp->isTop()) puts("VL_DO_CLEAR(delete vlSymsp, vlSymsp = nullptr);\n"); puts("}\n"); splitSizeInc(10); } @@ -476,9 +418,6 @@ void EmitCImp::emitSavableImp(AstNodeModule* modp) { } } - if (modp->isTop()) { // Save the children - puts("vlSymsp->" + protect(funcname) + "(os);\n"); - } puts("}\n"); } } @@ -505,216 +444,6 @@ void EmitCImp::emitTextSection(AstType type) { if (last_line > 0) puts("//*** Above code from `systemc in Verilog file\n\n"); } -void EmitCImp::emitSensitives() { - // Create sensitivity list for when to evaluate the model. - // If C++ code, the user must call this routine themself. - if (m_modp->isTop() && optSystemC()) { - putsDecoration("// Sensitivities on all clocks and combo inputs\n"); - puts("SC_METHOD(eval);\n"); - for (AstNode* nodep = m_modp->stmtsp(); nodep; nodep = nodep->nextp()) { - if (const AstVar* varp = VN_CAST(nodep, Var)) { - if (varp->isNonOutput() && (varp->isScSensitive() || varp->isUsedClock())) { - int vects = 0; - // This isn't very robust and may need cleanup for other data types - for (AstUnpackArrayDType* arrayp - = VN_CAST(varp->dtypeSkipRefp(), UnpackArrayDType); - arrayp; - arrayp = VN_CAST(arrayp->subDTypep()->skipRefp(), UnpackArrayDType)) { - const int vecnum = vects++; - UASSERT_OBJ(arrayp->hi() >= arrayp->lo(), varp, - "Should have swapped msb & lsb earlier."); - const string ivar = string("__Vi") + cvtToStr(vecnum); - puts("for (int __Vi" + cvtToStr(vecnum) + "=" + cvtToStr(arrayp->lo())); - puts("; " + ivar + "<=" + cvtToStr(arrayp->hi())); - puts("; ++" + ivar + ") {\n"); - } - puts("sensitive << " + varp->nameProtect()); - for (int v = 0; v < vects; ++v) puts("[__Vi" + cvtToStr(v) + "]"); - puts(";\n"); - for (int v = 0; v < vects; ++v) puts("}\n"); - } - } - } - puts("\n"); - } -} - -void EmitCImp::emitSettleLoop(bool initial) { - const string self = initial ? "vlSelf" : "this"; - putsDecoration("// Evaluate till stable\n"); - puts("int __VclockLoop = 0;\n"); - puts("QData __Vchange = 1;\n"); - if (v3Global.opt.trace()) puts("vlSymsp->__Vm_activity = true;\n"); - puts("do {\n"); - puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+ "); - puts(initial ? "Initial" : "Clock"); - puts(" loop\\n\"););\n"); - if (initial) puts(topClassName() + "__" + protect("_eval_settle") + "(" + self + ");\n"); - puts(topClassName() + "__" + protect("_eval") + "(" + self + ");\n"); - puts("if (VL_UNLIKELY(++__VclockLoop > " + cvtToStr(v3Global.opt.convergeLimit()) + ")) {\n"); - puts("// About to fail, so enable debug to see what's not settling.\n"); - puts("// Note you must run make with OPT=-DVL_DEBUG for debug prints.\n"); - puts("int __Vsaved_debug = Verilated::debug();\n"); - puts("Verilated::debug(1);\n"); - puts("__Vchange = " + topClassName() + "__" + protect("_change_request") + "(" + self - + ");\n"); - puts("Verilated::debug(__Vsaved_debug);\n"); - puts("VL_FATAL_MT("); - putsQuoted(protect(m_modp->fileline()->filename())); - puts(", "); - puts(cvtToStr(m_modp->fileline()->lineno())); - puts(", \"\",\n"); - puts("\"Verilated model didn't "); - if (initial) puts("DC "); - puts("converge\\n\"\n"); - puts("\"- See https://verilator.org/warn/DIDNOTCONVERGE\");\n"); - puts("} else {\n"); - puts("__Vchange = " + topClassName() + "__" + protect("_change_request") + "(" + self - + ");\n"); - puts("}\n"); - puts("} while (VL_UNLIKELY(__Vchange));\n"); -} - -void EmitCImp::emitWrapFast() { - UASSERT_OBJ(m_modp->isTop(), m_modp, "Attempting to emitWrapFast for non-top class"); - puts("\nVerilatedContext* " + topClassName() + "::contextp() const {\n"); - puts(/**/ "return vlSymsp->_vm_contextp__;\n"); - puts("}\n"); -} - -void EmitCImp::emitWrapEval() { - UASSERT_OBJ(m_modp->isTop(), m_modp, "Attempting to emitWrapEval for non-top class"); - - const string selfDecl = "(" + topClassName() + "* vlSelf)"; - - // Forward declarations - puts("\n"); - m_lazyDecls.emit("void " + topClassName() + "__", protect("_eval_initial"), selfDecl + ";"); - m_lazyDecls.emit("void " + topClassName() + "__", protect("_eval_settle"), selfDecl + ";"); - m_lazyDecls.emit("void " + topClassName() + "__", protect("_eval"), selfDecl + ";"); - m_lazyDecls.emit("QData " + topClassName() + "__", protect("_change_request"), selfDecl + ";"); - puts("#ifdef VL_DEBUG\n"); - m_lazyDecls.emit("void " + topClassName() + "__", protect("_eval_debug_assertions"), - selfDecl + ";"); - puts("#endif // VL_DEBUG\n"); - m_lazyDecls.emit("void " + topClassName() + "__", protect("_final"), selfDecl + ";"); - - // _eval_initial_loop - puts("\nstatic void " + protect("_eval_initial_loop") + selfDecl + " {\n"); - puts(symClassAssign()); - puts("vlSymsp->__Vm_didInit = true;\n"); - puts(topClassName() + "__" + protect("_eval_initial") + "(vlSelf);\n"); - emitSettleLoop(/* initial: */ true); - ensureNewLine(); - puts("}\n"); - - // ::eval_step - puts("\nvoid " + topClassName() + "::eval_step() {\n"); - puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+++++TOP Evaluate " + topClassName() - + "::eval_step\\n\"); );\n"); - puts("#ifdef VL_DEBUG\n"); - putsDecoration("// Debug assertions\n"); - puts(topClassName() + "__" + protect("_eval_debug_assertions") + "(this);\n"); - puts("#endif // VL_DEBUG\n"); - putsDecoration("// Initialize\n"); - puts("if (VL_UNLIKELY(!vlSymsp->__Vm_didInit)) " + protect("_eval_initial_loop") - + "(this);\n"); - - if (v3Global.opt.threads() == 1) { - uint32_t mtaskId = 0; - putsDecoration("// MTask " + cvtToStr(mtaskId) + " start\n"); - puts("VL_DEBUG_IF(VL_DBG_MSGF(\"MTask" + cvtToStr(mtaskId) + " starting\\n\"););\n"); - puts("Verilated::mtaskId(" + cvtToStr(mtaskId) + ");\n"); - } - - if (v3Global.opt.mtasks() && v3Global.opt.profThreads()) { - puts("if (VL_UNLIKELY((vlSymsp->_vm_contextp__->profThreadsStart() != " - "__Vm_profile_time_finished)\n"); - puts(" && (VL_TIME_Q() > vlSymsp->_vm_contextp__->profThreadsStart())\n"); - puts(" && (vlSymsp->_vm_contextp__->profThreadsWindow() >= 1))) {\n"); - // Within a profile (either starting, middle, or end) - puts("if (__Vm_profile_window_ct == 0) {\n"); // Opening file? - // Start profile on this cycle. We'll capture a window worth, then - // only analyze the next window worth. The idea is that the first window - // capture will hit some cache-cold stuff (eg printf) but it'll be warm - // by the time we hit the second window, we hope. - puts("__Vm_profile_cycle_start = VL_RDTSC_Q();\n"); - // "* 2" as first half is warmup, second half is collection - puts("__Vm_profile_window_ct = vlSymsp->_vm_contextp__->profThreadsWindow() * 2 " - "+ " - "1;\n"); - puts("}\n"); - puts("--__Vm_profile_window_ct;\n"); - puts("if (__Vm_profile_window_ct == vlSymsp->_vm_contextp__->profThreadsWindow()) " - "{\n"); - // This barrier record in every threads' profile demarcates the - // cache-warm-up cycles before the barrier from the actual profile - // cycles afterward. - puts("__Vm_threadPoolp->profileAppendAll("); - puts("VlProfileRec(VlProfileRec::Barrier()));\n"); - puts("__Vm_profile_cycle_start = VL_RDTSC_Q();\n"); - puts("}\n"); - puts("else if (__Vm_profile_window_ct == 0) {\n"); - // Ending file. - puts("vluint64_t elapsed = VL_RDTSC_Q() - __Vm_profile_cycle_start;\n"); - puts("__Vm_threadPoolp->profileDump(vlSymsp->_vm_contextp__->profThreadsFilename()." - "c_str(), elapsed);\n"); - // This turns off the test to enter the profiling code, but still - // allows the user to collect another profile by changing - // profThreadsStart - puts("__Vm_profile_time_finished = vlSymsp->_vm_contextp__->profThreadsStart();\n"); - puts("__Vm_profile_cycle_start = 0;\n"); - puts("}\n"); - puts("}\n"); - } - - emitSettleLoop(/* initial: */ false); - if (v3Global.opt.threads() == 1) { - puts("Verilated::endOfThreadMTask(vlSymsp->__Vm_evalMsgQp);\n"); - } - if (v3Global.opt.threads()) puts("Verilated::endOfEval(vlSymsp->__Vm_evalMsgQp);\n"); - puts("}\n"); - splitSizeInc(10); - - // ::eval_end_step - if (v3Global.needTraceDumper() && !optSystemC()) { - puts("\nvoid " + topClassName() + "::eval_end_step() {\n"); - puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+eval_end_step " + topClassName() - + "::eval_end_step\\n\"); );\n"); - puts("#ifdef VM_TRACE\n"); - putsDecoration("// Tracing\n"); - // SystemC's eval loop deals with calling trace, not us - puts("if (VL_UNLIKELY(vlSymsp->__Vm_dumping)) _traceDump();\n"); - puts("#endif // VM_TRACE\n"); - puts("}\n"); - splitSizeInc(10); - } - - // ::final - puts("\nvoid " + topClassName() + "::final() {\n"); - puts(topClassName() + "__" + protect("_final") + "(this);\n"); - puts("}\n"); - splitSizeInc(10); -} - -void EmitCImp::emitThreadingState() { - ofp()->putsPrivate(false); // Accessed from loose function - AstExecGraph* execGraphp = v3Global.rootp()->execGraphp(); - UASSERT_OBJ(execGraphp, v3Global.rootp(), "Root should have an execGraphp"); - - puts("VlThreadPool* __Vm_threadPoolp;\n"); - puts("bool __Vm_even_cycle;\n"); - - if (v3Global.opt.profThreads()) { - // rdtsc() at current cycle start - puts("vluint64_t __Vm_profile_cycle_start = 0;\n"); - // Time we finished analysis - puts("vluint64_t __Vm_profile_time_finished = 0;\n"); - // Track our position in the cache warmup and actual profile window - puts("vluint32_t __Vm_profile_window_ct = 0;\n"); - } -} - void EmitCImp::emitIntTop(const AstNodeModule* modp) { // Always have this first; gcc has short circuiting if #ifdef is first in a file ofp()->putsGuard(); @@ -729,11 +458,6 @@ void EmitCImp::emitIntTop(const AstNodeModule* modp) { if (v3Global.opt.mtasks()) puts("#include \"verilated_threads.h\"\n"); if (v3Global.opt.savable()) puts("#include \"verilated_save.h\"\n"); if (v3Global.opt.coverage()) puts("#include \"verilated_cov.h\"\n"); - if (v3Global.dpi() && modp->isTop()) { - // do this before including our main .h file so that any references to - // types defined in svdpi.h are available - puts("#include \"svdpi.h\"\n"); - } } void EmitCImp::emitInt(AstNodeModule* modp) { @@ -759,8 +483,6 @@ void EmitCImp::emitInt(AstNodeModule* modp) { if (classp->extendsp()) puts(" : public " + prefixNameProtect(classp->extendsp()->classp())); puts(" {\n"); - } else if (optSystemC() && modp->isTop()) { - puts("SC_MODULE(" + prefixNameProtect(modp) + ") {\n"); } else { puts("VL_MODULE(" + prefixNameProtect(modp) + ") {\n"); } @@ -774,10 +496,6 @@ void EmitCImp::emitInt(AstNodeModule* modp) { if (!did) { did = true; putsDecoration("// CELLS\n"); - if (modp->isTop()) { - puts("// Public to allow access to /*verilator_public*/ items;\n"); - puts("// otherwise the application code can consider these internals.\n"); - } } puts(prefixNameProtect(cellp->modp()) + "* " + cellp->nameProtect() + ";\n"); } @@ -788,35 +506,23 @@ void EmitCImp::emitInt(AstNodeModule* modp) { string section; section = "\n// PORTS\n"; - if (modp->isTop()) { - section += ("// The application code writes and reads these signals to\n" - "// propagate new values into/out from the Verilated model.\n"); - } emitVarList(modp->stmtsp(), EVL_CLASS_IO, "", section /*ref*/); section = "\n// LOCAL SIGNALS\n"; - if (modp->isTop()) section += "// Internals; generally not touched by application code\n"; emitVarList(modp->stmtsp(), EVL_CLASS_SIG, "", section /*ref*/); section = "\n// LOCAL VARIABLES\n"; - if (modp->isTop()) section += "// Internals; generally not touched by application code\n"; emitVarList(modp->stmtsp(), EVL_CLASS_TEMP, "", section /*ref*/); puts("\n// INTERNAL VARIABLES\n"); - if (modp->isTop()) puts("// Internals; generally not touched by application code\n"); if (!VN_IS(modp, Class)) { // Avoid clang unused error (& don't want in every object) ofp()->putsPrivate(false); // public: so loose methods can pick it up puts(symClassName() + "* vlSymsp; // Symbol table\n"); } ofp()->putsPrivate(false); // public: - if (modp->isTop()) { - if (v3Global.opt.mtasks()) emitThreadingState(); - } emitCoverageDecl(modp); // may flip public/private section = "\n// PARAMETERS\n"; - if (modp->isTop()) - section += "// Parameters marked /*verilator public*/ for use by application code\n"; ofp()->putsPrivate(false); // public: emitVarList(modp->stmtsp(), EVL_CLASS_PAR, "", section /*ref*/); // Only those that are non-CONST @@ -833,98 +539,15 @@ void EmitCImp::emitInt(AstNodeModule* modp) { if (VN_IS(modp, Class)) { // CFuncs with isConstructor/isDestructor used instead - } else if (optSystemC() && modp->isTop()) { - ofp()->putsPrivate(false); // public: - puts("SC_CTOR(" + prefixNameProtect(modp) + ");\n"); - puts("virtual ~" + prefixNameProtect(modp) + "();\n"); - } else if (optSystemC()) { - ofp()->putsPrivate(false); // public: - puts(prefixNameProtect(modp) + "(const char* __VCname = \"\");\n"); - puts("~" + prefixNameProtect(modp) + "();\n"); } else { ofp()->putsPrivate(false); // public: - if (modp->isTop()) { - puts("/// Construct the model; called by application code\n"); - puts("/// If contextp is null, then the model will use the default global context\n"); - puts("/// If name is \"\", then makes a wrapper with a\n"); - puts("/// single model invisible with respect to DPI scope names.\n"); - puts(prefixNameProtect(modp) + "(VerilatedContext* contextp," - + " const char* name = \"TOP\");\n"); - puts(prefixNameProtect(modp) + "(const char* name = \"TOP\")\n"); - puts(" : " + prefixNameProtect(modp) + "(nullptr, name) {}\n"); - } else { - if (VN_IS(modp, Class)) { - // TODO move all constructor definition to e.g. V3CUse - puts(prefixNameProtect(modp) + "();\n"); - } else { - puts(prefixNameProtect(modp) + "(const char* name = \"TOP\");\n"); - } - } - if (modp->isTop()) { - puts("/// Destroy the model; called (often implicitly) by application code\n"); - } + puts(prefixNameProtect(modp) + "(const char* name);\n"); puts("~" + prefixNameProtect(modp) + "();\n"); } - if (v3Global.opt.trace() && modp->isTop()) { - puts("/// Trace signals in the model; called by application code\n"); - puts("void trace(" + v3Global.opt.traceClassBase() - + "C* tfp, int levels, int options = 0);\n"); - if (optSystemC()) { - puts("/// SC tracing; avoid overloaded virtual function lint warning\n"); - puts("virtual void trace(sc_trace_file* tfp) const override { " - "::sc_core::sc_module::trace(tfp); }\n"); - } - } - emitTextSection(AstType::atScInt); - if (modp->isTop()) { - puts("\n// API METHODS\n"); - puts("/// Return current simulation context for this model.\n"); - puts("/// Used to get to e.g. simulation time via contextp()->time()\n"); - puts("VerilatedContext* contextp() const;\n"); - - string callEvalEndStep - = (v3Global.needTraceDumper() && !optSystemC()) ? "eval_end_step(); " : ""; - if (optSystemC()) { - ofp()->putsPrivate(true); ///< eval() is invoked by our sensitive() calls. - } - if (!optSystemC()) { - puts("/// Evaluate the model. Application must call when inputs change.\n"); - } - puts("void eval() { eval_step(); " + callEvalEndStep + "}\n"); - if (!optSystemC()) { - puts("/// Evaluate when calling multiple units/models per time step.\n"); - } - puts("void eval_step();\n"); - if (!optSystemC()) { - puts("/// Evaluate at end of a timestep for tracing, when using eval_step().\n"); - puts("/// Application must call after all eval() and before time changes.\n"); - puts("void eval_end_step()"); - if (callEvalEndStep == "") { - puts(" {}\n"); - } else { - puts(";\n"); - } - } - ofp()->putsPrivate(false); // public: - if (!optSystemC()) { - puts("/// Simulation complete, run final blocks. Application " - "must call on completion.\n"); - } - puts("void final();\n"); - } - puts("\n// INTERNAL METHODS\n"); - if (modp->isTop()) { - ofp()->putsPrivate(false); // public: as accessed by loose functions - if (v3Global.needTraceDumper()) { - if (!optSystemC()) puts("void _traceDump();\n"); - puts("void _traceDumpOpen();\n"); - puts("void _traceDumpClose();\n"); - } - } if (!VN_IS(modp, Class)) { ofp()->putsPrivate(false); // public: @@ -946,17 +569,6 @@ void EmitCImp::emitInt(AstNodeModule* modp) { puts("\n//----------\n\n"); emitIntFuncDecls(modp, false); - - // Save/restore - if (v3Global.opt.savable() && modp->isTop()) { - puts("\n"); - puts("inline VerilatedSerialize& operator<<(VerilatedSerialize& os, " - + prefixNameProtect(modp) + "& rhs) {\n" // - + "Verilated::quiesce(); rhs." + protect("__Vserialize") + "(os); return os; }\n"); - puts("inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, " - + prefixNameProtect(modp) + "& rhs) {\n" // - + "Verilated::quiesce(); rhs." + protect("__Vdeserialize") + "(os); return os; }\n"); - } } //---------------------------------------------------------------------- @@ -989,13 +601,7 @@ void EmitCImp::emitImp(AstNodeModule* modp) { emitCoverageImp(modp); } - if (m_fast) { - emitTextSection(AstType::atScImp); - if (modp->isTop()) { - emitWrapFast(); - emitWrapEval(); - } - } + if (m_fast) { emitTextSection(AstType::atScImp); } // Blocks for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { @@ -1111,78 +717,6 @@ class EmitCTrace final : EmitCFunc { puts("\n"); } - void emitTraceSlow() { - puts("\n//======================\n"); - - if (v3Global.needTraceDumper() && !optSystemC()) { - puts("\nvoid " + topClassName() + "::_traceDump() {\n"); - // Caller checked for __Vm_dumperp non-nullptr - puts("const VerilatedLockGuard lock(vlSymsp->__Vm_dumperMutex);\n"); - puts("vlSymsp->__Vm_dumperp->dump(VL_TIME_Q());\n"); - puts("}\n"); - splitSizeInc(10); - } - - if (v3Global.needTraceDumper()) { - puts("\nvoid " + topClassName() + "::_traceDumpOpen() {\n"); - puts("const VerilatedLockGuard lock(vlSymsp->__Vm_dumperMutex);\n"); - puts("if (VL_UNLIKELY(!vlSymsp->__Vm_dumperp)) {\n"); - puts("vlSymsp->__Vm_dumperp = new " + v3Global.opt.traceClassLang() + "();\n"); - puts("trace(vlSymsp->__Vm_dumperp, 0, 0);\n"); - puts("std::string dumpfile = vlSymsp->_vm_contextp__->dumpfileCheck();\n"); - puts("vlSymsp->__Vm_dumperp->open(dumpfile.c_str());\n"); - puts("vlSymsp->__Vm_dumping = true;\n"); - puts("}\n"); - puts("}\n"); - splitSizeInc(10); - - puts("\nvoid " + topClassName() + "::_traceDumpClose() {\n"); - puts("const VerilatedLockGuard lock(vlSymsp->__Vm_dumperMutex);\n"); - puts("vlSymsp->__Vm_dumping = false;\n"); - puts("VL_DO_CLEAR(delete vlSymsp->__Vm_dumperp, vlSymsp->__Vm_dumperp = " - "nullptr);\n"); - puts("}\n"); - splitSizeInc(10); - } - - puts("\n"); - m_lazyDecls.emit("void " + topClassName() + "__", protect("traceInitTop"), - "(" + topClassName() + "* vlSelf, " + v3Global.opt.traceClassBase() - + "* tracep);"); - - puts("\nstatic void " + protect("traceInit") + "(void* voidSelf, " - + v3Global.opt.traceClassBase() + "* tracep, uint32_t code) {\n"); - putsDecoration("// Callback from tracep->open()\n"); - puts(topClassName() + "*const __restrict vlSelf = static_cast<" + topClassName() - + "*>(voidSelf);\n"); - puts("if (!vlSelf->vlSymsp->_vm_contextp__->calcUnusedSigs()) {\n"); - puts("VL_FATAL_MT(__FILE__, __LINE__, __FILE__,\n"); - puts(" \"Turning on wave traces requires Verilated::traceEverOn(true) call " - "before time 0.\");\n"); - puts("}\n"); - puts("vlSelf->vlSymsp->__Vm_baseCode = code;\n"); - puts("tracep->module(vlSelf->vlSymsp->name());\n"); - puts("tracep->scopeEscape(' ');\n"); - puts(topClassName() + "__" + protect("traceInitTop") + "(vlSelf, tracep);\n"); - puts("tracep->scopeEscape('.');\n"); // Restore so later traced files won't break - puts("}\n"); - splitSizeInc(10); - - puts("\n"); - m_lazyDecls.emit("void " + topClassName() + "__", protect("traceRegister"), - "(" + topClassName() + "* vlSelf, " + v3Global.opt.traceClassBase() - + "* tracep);"); - - puts("\nvoid " + topClassName() + "::trace("); - puts(v3Global.opt.traceClassBase() + "C* tfp, int, int) {\n"); - puts("tfp->spTrace()->addInitCb(&" + protect("traceInit") + ", this);\n"); - puts(topClassName() + "__" + protect("traceRegister") + "(this, tfp->spTrace());\n"); - puts("}\n"); - splitSizeInc(10); - - puts("\n//======================\n\n"); - } - bool emitTraceIsScBv(AstTraceInc* nodep) { const AstVarRef* varrefp = VN_CAST(nodep->declp()->valuep(), VarRef); if (!varrefp) return false; @@ -1528,8 +1062,6 @@ public: // Put out the file newOutCFile(0); - if (m_slow) emitTraceSlow(); - iterate(v3Global.rootp()); VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); diff --git a/src/V3EmitC.h b/src/V3EmitC.h index d5c053a9f..406a00429 100644 --- a/src/V3EmitC.h +++ b/src/V3EmitC.h @@ -30,6 +30,7 @@ public: static void emitc(); static void emitcConstPool(); static void emitcInlines(); + static void emitcModel(); static void emitcSyms(bool dpiHdrOnly = false); static void emitcTrace(); static void emitcFiles(); diff --git a/src/V3EmitCBase.cpp b/src/V3EmitCBase.cpp index 48cee377f..f955f99dc 100644 --- a/src/V3EmitCBase.cpp +++ b/src/V3EmitCBase.cpp @@ -86,7 +86,13 @@ void EmitCBaseVisitor::emitCFuncHeader(const AstCFunc* funcp, const AstNodeModul puts(funcp->rtnTypeVoid()); puts(" "); } - if (withScope && funcp->isProperMethod()) puts(prefixNameProtect(modp) + "::"); + if (withScope) { + if (funcp->dpiExportDispatcher()) { + puts(topClassName() + "::"); + } else if (funcp->isProperMethod()) { + puts(prefixNameProtect(modp) + "::"); + } + } puts(funcNameProtect(funcp, modp)); puts("(" + cFuncArgs(funcp) + ")"); if (funcp->isConst().trueKnown() && funcp->isProperMethod()) puts(" const"); @@ -108,8 +114,9 @@ void EmitCBaseVisitor::emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* if (!funcp->ifdef().empty()) puts("#endif // " + funcp->ifdef() + "\n"); } -void EmitCBaseVisitor::emitVarDecl(const AstVar* nodep, const string& prefixIfImp) { +void EmitCBaseVisitor::emitVarDecl(const AstVar* nodep, const string& prefixIfImp, bool asRef) { const AstBasicDType* const basicp = nodep->basicp(); + bool refNeedParens = VN_IS(nodep->dtypeSkipRefp(), UnpackArrayDType); const auto emitDeclArrayBrackets = [this](const AstVar* nodep) -> void { // This isn't very robust and may need cleanup for other data types @@ -137,7 +144,12 @@ void EmitCBaseVisitor::emitVarDecl(const AstVar* nodep, const string& prefixIfIm puts(nodep->scType()); puts("> "); } + if (asRef) { + if (refNeedParens) puts("("); + puts("&"); + } puts(nodep->nameProtect()); + if (asRef && refNeedParens) { puts(")"); } emitDeclArrayBrackets(nodep); puts(";\n"); } else if (nodep->isIO() && basicp && !basicp->isOpaque()) { @@ -159,9 +171,16 @@ void EmitCBaseVisitor::emitVarDecl(const AstVar* nodep, const string& prefixIfIm puts("16"); } else if (nodep->isWide()) { puts("W"); + refNeedParens = true; } - puts("(" + nodep->nameProtect()); + puts("("); + if (asRef) { + if (refNeedParens) puts("("); + puts("&"); + } + puts(nodep->nameProtect()); + if (asRef && refNeedParens) { puts(")"); } emitDeclArrayBrackets(nodep); // If it's a packed struct/array then nodep->width is the whole // thing, msb/lsb is just lowest dimension @@ -180,7 +199,7 @@ void EmitCBaseVisitor::emitVarDecl(const AstVar* nodep, const string& prefixIfIm && name.substr(name.size() - suffix.size()) == suffix; if (beStatic) puts("static VL_THREAD_LOCAL "); } - puts(nodep->vlArgType(true, false, false, prefixIfImp)); + puts(nodep->vlArgType(true, false, false, prefixIfImp, asRef)); puts(";\n"); } } diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h index 81af458fe..b9362991c 100644 --- a/src/V3EmitCBase.h +++ b/src/V3EmitCBase.h @@ -53,9 +53,10 @@ public: return VIdProtect::protectWordsIf(name, doIt); } static string ifNoProtect(const string& in) { return v3Global.opt.protectIds() ? "" : in; } - static string voidSelfAssign() { - return topClassName() + "* const __restrict vlSelf VL_ATTR_UNUSED = static_cast<" - + topClassName() + "*>(voidSelf);\n"; + static string voidSelfAssign(const AstNodeModule* modp) { + const string className = prefixNameProtect(modp); + return className + "* const __restrict vlSelf VL_ATTR_UNUSED = static_cast<" + className + + "*>(voidSelf);\n"; } static string symClassName() { return v3Global.opt.prefix() + "_" + protect("_Syms"); } static string symClassVar() { return symClassName() + "* __restrict vlSymsp"; } @@ -64,12 +65,7 @@ public: } static string funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp = nullptr); static string prefixNameProtect(const AstNode* nodep) { // C++ name with prefix - const AstNodeModule* modp = VN_CAST_CONST(nodep, NodeModule); - if (modp && modp->isTop()) { - return topClassName(); - } else { - return v3Global.opt.modPrefix() + "_" + protect(nodep->name()); - } + return v3Global.opt.modPrefix() + "_" + protect(nodep->name()); } static string topClassName() { // Return name of top wrapper module return v3Global.opt.prefix(); @@ -83,7 +79,7 @@ public: string cFuncArgs(const AstCFunc* nodep); void emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp, bool withScope); void emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp, bool cLinkage = false); - void emitVarDecl(const AstVar* nodep, const string& prefixIfImp); + void emitVarDecl(const AstVar* nodep, const string& prefixIfImp, bool asRef = false); void emitModCUse(AstNodeModule* modp, VUseType useType); // CONSTRUCTORS diff --git a/src/V3EmitCFunc.cpp b/src/V3EmitCFunc.cpp index f0c8e0ee5..5a5613981 100644 --- a/src/V3EmitCFunc.cpp +++ b/src/V3EmitCFunc.cpp @@ -701,31 +701,6 @@ void EmitCFunc::emitSortedVarList(const VarVec& anons, const VarVec& nonanons, } } -void EmitCFunc::emitIntFuncDecls(AstNodeModule* modp, bool inClassBody) { - std::vector funcsp; - - for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { - if (const AstCFunc* funcp = VN_CAST(nodep, CFunc)) { - if (funcp->dpiImportPrototype()) // DPI import prototypes are declared in __Dpi.h - continue; - if (funcp->isMethod() != inClassBody) // Only methods go inside class - continue; - if (funcp->isMethod() && funcp->isLoose()) // Loose methods are declared lazily - continue; - funcsp.push_back(funcp); - } - } - - stable_sort(funcsp.begin(), funcsp.end(), [](const AstNode* ap, const AstNode* bp) { // - return ap->name() < bp->name(); - }); - - for (const AstCFunc* funcp : funcsp) { - if (inClassBody) ofp()->putsPrivate(funcp->declPrivate()); - emitCFuncDecl(funcp, modp); - } -} - void EmitCFunc::emitCCallArgs(AstNodeCCall* nodep) { bool comma = false; if (nodep->funcp()->isLoose() && !nodep->funcp()->isStatic()) { diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 42e8f7daf..bee0293a4 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -188,7 +188,6 @@ public: } void emitOpName(AstNode* nodep, const string& format, AstNode* lhsp, AstNode* rhsp, AstNode* thsp); - void emitIntFuncDecls(AstNodeModule* modp, bool inClassBody); void emitCCallArgs(AstNodeCCall* nodep); void emitDereference(const string& pointer); void emitCvtPackStr(AstNode* nodep); @@ -514,7 +513,7 @@ public: case VDumpCtlType::VARS: // We ignore number of levels to dump in exprp() if (v3Global.opt.trace()) { - puts("vlSymsp->TOPp->_traceDumpOpen();\n"); + puts("vlSymsp->_traceDumpOpen();\n"); } else { puts("VL_PRINTF_MT(\"-Info: "); puts(protect(nodep->fileline()->filename())); diff --git a/src/V3EmitCModel.cpp b/src/V3EmitCModel.cpp new file mode 100644 index 000000000..cb1a0ba54 --- /dev/null +++ b/src/V3EmitCModel.cpp @@ -0,0 +1,633 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Emit C++ for model entry point class +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-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 +// +//************************************************************************* + +#include "config_build.h" +#include "verilatedos.h" + +#include "V3Global.h" +#include "V3EmitC.h" +#include "V3EmitCFunc.h" + +#include +#include + +class EmitCModel final : public EmitCFunc { + + // METHODS + VL_DEBUG_FUNC; + + void putSectionDelimiter(const string& name) { + puts("\n"); + puts("//============================================================\n"); + puts("// " + name + "\n"); + } + + void emitHeader(AstNodeModule* modp) { + UASSERT(!m_ofp, "Output file should not be open"); + + const string filename = v3Global.opt.makeDir() + "/" + topClassName() + ".h"; + newCFile(filename, /* slow: */ false, /* source: */ false); + m_ofp = v3Global.opt.systemC() ? new V3OutScFile(filename) : new V3OutCFile(filename); + + ofp()->putsHeader(); + puts("// DESCRIPTION: Verilator output: Primary model header\n"); + puts("//\n"); + puts("// This header should be included by all source files instantiating the design.\n"); + puts("// The class here is then constructed to instantiate the design.\n"); + puts("// See the Verilator manual for examples.\n"); + + ofp()->putsGuard(); + + // Include files + puts("\n"); + ofp()->putsIntTopInclude(); + if (v3Global.needHeavy()) { + puts("#include \"verilated_heavy.h\"\n"); + } else { + puts("#include \"verilated.h\"\n"); + } + if (v3Global.opt.mtasks()) puts("#include \"verilated_threads.h\"\n"); + if (v3Global.opt.savable()) puts("#include \"verilated_save.h\"\n"); + if (v3Global.opt.coverage()) puts("#include \"verilated_cov.h\"\n"); + if (v3Global.dpi()) puts("#include \"svdpi.h\"\n"); + + // Declare foreign instances up front to make C++ happy + puts("\n"); + puts("class " + symClassName() + ";\n"); + puts("class " + prefixNameProtect(modp) + ";\n"); // For rootp pointer only + if (v3Global.opt.trace()) puts("class " + v3Global.opt.traceClassLang() + ";\n"); + emitModCUse(modp, VUseType::INT_FWD_CLASS); // Note: This is needed for cell forwarding + + puts("\n"); + + puts("// This class is the main interface to the Verilated model\n"); + if (optSystemC()) { + puts("SC_MODULE(" + topClassName() + ") {\n"); + } else { + puts("class " + topClassName() + " VL_NOT_FINAL {\n"); + } + ofp()->resetPrivate(); + ofp()->putsPrivate(true); // private: + + puts("// Symbol table holding complete model state (owned by this class)\n"); + puts(symClassName() + "* const vlSymsp;\n"); + + puts("\n"); + ofp()->putsPrivate(false); // public: + // User accessible IO + puts("\n// PORTS\n" + "// The application code writes and reads these signals to\n" + "// propagate new values into/out from the Verilated model.\n"); + for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { + if (const AstVar* const varp = VN_CAST_CONST(nodep, Var)) { + if (varp->isPrimaryIO()) { // + emitVarDecl(varp, "", /* asRef: */ true); + } + } + } + + // Cells instantiated by the top level (for access to /* verilator public */) + puts("\n// CELLS\n" + "// Public to allow access to /* verilator public */ items.\n" + "// Otherwise the application code can consider these internals.\n"); + for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { + if (const AstCell* const cellp = VN_CAST_CONST(nodep, Cell)) { + puts(prefixNameProtect(cellp->modp()) + "* const " + cellp->nameProtect() + ";\n"); + } + } + + // root instance pointer (for access to internals, including public_flat items). + puts("\n// Root instance pointer to allow access to model internals,\n" + "// including inlined /* verilator public_flat_* */ items.\n"); + puts(prefixNameProtect(modp) + "* const rootp;\n"); + + puts("\n"); + ofp()->putsPrivate(false); // public: + puts("// CONSTRUCTORS\n"); + if (optSystemC()) { + puts("SC_CTOR(" + topClassName() + ");\n"); + puts("virtual ~" + topClassName() + "();\n"); + } else { + puts("/// Construct the model; called by application code\n"); + puts("/// If contextp is null, then the model will use the default global " + "context\n"); + puts("/// If name is \"\", then makes a wrapper with a\n"); + puts("/// single model invisible with respect to DPI scope names.\n"); + puts("explicit " + topClassName() + "(VerilatedContext* contextp," + + " const char* name = \"TOP\");\n"); + puts("explicit " + topClassName() + "(const char* name = \"TOP\");\n"); + puts("/// Destroy the model; called (often implicitly) by application code\n"); + puts("virtual ~" + topClassName() + "();\n"); + } + ofp()->putsPrivate(true); + puts("VL_UNCOPYABLE(" + topClassName() + "); ///< Copying not allowed\n"); + + puts("\n"); + ofp()->putsPrivate(false); // public: + puts("// API METHODS\n"); + string callEvalEndStep + = (v3Global.needTraceDumper() && !optSystemC()) ? "eval_end_step(); " : ""; + if (optSystemC()) { + ofp()->putsPrivate(true); ///< eval() is invoked by our sensitive() calls. + } + if (!optSystemC()) { + puts("/// Evaluate the model. Application must call when inputs change.\n"); + } + puts("void eval() { eval_step(); " + callEvalEndStep + "}\n"); + if (!optSystemC()) { + puts("/// Evaluate when calling multiple units/models per time step.\n"); + } + puts("void eval_step();\n"); + if (!optSystemC()) { + puts("/// Evaluate at end of a timestep for tracing, when using eval_step().\n"); + puts("/// Application must call after all eval() and before time changes.\n"); + puts("void eval_end_step()"); + if (callEvalEndStep == "") { + puts(" {}\n"); + } else { + puts(";\n"); + } + } + if (!optSystemC()) { + puts("/// Simulation complete, run final blocks. Application " + "must call on completion.\n"); + } + ofp()->putsPrivate(false); // public: + puts("void final();\n"); + + if (v3Global.opt.trace()) { + puts("/// Trace signals in the model; called by application code\n"); + puts("void trace(" + v3Global.opt.traceClassBase() + + "C* tfp, int levels, int options = 0);\n"); + if (optSystemC()) { + puts("/// SC tracing; avoid overloaded virtual function lint warning\n"); + puts("virtual void trace(sc_trace_file* tfp) const override { " + "::sc_core::sc_module::trace(tfp); }\n"); + } + } + + puts("/// Return current simulation context for this model.\n"); + puts("/// Used to get to e.g. simulation time via contextp()->time()\n"); + puts("VerilatedContext* contextp() const;\n"); + if (!optSystemC()) { + puts("/// Retrieve name of this model instance (as passed to constructor).\n"); + puts("const char* name() const;\n"); + } + + // Emit DPI export dispatcher declarations + { + std::vector funcps; + + for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { + if (const AstCFunc* funcp = VN_CAST(nodep, CFunc)) { + if (!funcp->dpiExportDispatcher()) continue; + funcps.push_back(funcp); + } + } + + stable_sort(funcps.begin(), funcps.end(), [](const AstNode* ap, const AstNode* bp) { + return ap->name() < bp->name(); + }); + + if (!funcps.empty()) { + puts("\n/// DPI Export functions\n"); + for (const AstCFunc* funcp : funcps) { emitCFuncDecl(funcp, modp); } + } + } + + if (v3Global.opt.savable()) { + puts("\n"); + puts("// Serialization functions\n"); + puts("friend VerilatedSerialize& operator<<(VerilatedSerialize& os, " // + + topClassName() + "& rhs);\n"); + puts("friend VerilatedDeserialize& operator>>(VerilatedDeserialize& os, " + + topClassName() + "& rhs);\n"); + } + + puts("} VL_ATTR_ALIGNED(VL_CACHE_LINE_BYTES);\n"); + + ofp()->putsEndGuard(); + + VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); + } + + void emitConstructorImplementation(AstNodeModule* modp) { + putSectionDelimiter("Constructors"); + + puts("\n"); + puts(topClassName() + "::" + topClassName()); + if (optSystemC()) { + puts("(sc_module_name /* unused */)\n"); + puts(" : vlSymsp{new " + symClassName() + "(nullptr, name(), this)}\n"); + } else { + puts(+"(VerilatedContext* _vcontextp__, const char* _vcname__)\n"); + puts(" : vlSymsp{new " + symClassName() + "(_vcontextp__, _vcname__, this)}\n"); + } + + // Set up IO references + for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { + if (const AstVar* const varp = VN_CAST_CONST(nodep, Var)) { + if (varp->isPrimaryIO()) { + const string protName = varp->nameProtect(); + puts(" , " + protName + "{vlSymsp->TOP." + protName + "}\n"); + } + } + } + + // Setup cell pointers + for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { + if (const AstCell* const cellp = VN_CAST_CONST(nodep, Cell)) { + const string protName = cellp->nameProtect(); + puts(" , " + protName + "{vlSymsp->TOP." + protName + "}\n"); + } + } + + // Setup rootp root instance pointer, + puts(" , rootp{&(vlSymsp->TOP)}\n"); + + puts("{\n"); + + if (optSystemC()) { + // Create sensitivity list for when to evaluate the model. + putsDecoration("// Sensitivities on all clocks and combinational inputs\n"); + puts("SC_METHOD(eval);\n"); + for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { + if (const AstVar* const varp = VN_CAST(nodep, Var)) { + if (varp->isNonOutput() && (varp->isScSensitive() || varp->isUsedClock())) { + int vects = 0; + // This isn't very robust and may need cleanup for other data types + for (AstUnpackArrayDType* arrayp + = VN_CAST(varp->dtypeSkipRefp(), UnpackArrayDType); + arrayp; + arrayp = VN_CAST(arrayp->subDTypep()->skipRefp(), UnpackArrayDType)) { + const int vecnum = vects++; + UASSERT_OBJ(arrayp->hi() >= arrayp->lo(), varp, + "Should have swapped msb & lsb earlier."); + const string ivar = string("__Vi") + cvtToStr(vecnum); + puts("for (int __Vi" + cvtToStr(vecnum) + "=" + + cvtToStr(arrayp->lo())); + puts("; " + ivar + "<=" + cvtToStr(arrayp->hi())); + puts("; ++" + ivar + ") {\n"); + } + puts("sensitive << " + varp->nameProtect()); + for (int v = 0; v < vects; ++v) puts("[__Vi" + cvtToStr(v) + "]"); + puts(";\n"); + for (int v = 0; v < vects; ++v) puts("}\n"); + } + } + } + puts("\n"); + } + + puts("}\n"); + + if (!optSystemC()) { + puts("\n"); + puts(topClassName() + "::" + topClassName() + "(const char* _vcname__)\n"); + puts(" : " + topClassName() + "(nullptr, _vcname__)\n{\n}\n"); + } + } + + void emitDestructorImplementation() { + putSectionDelimiter("Destructor"); + + puts("\n"); + puts(topClassName() + "::~" + topClassName() + "() {\n"); + puts("delete vlSymsp;\n"); + puts("}\n"); + } + + void emitSettleLoop(AstNodeModule* modp, bool initial) { + const string topModNameProtected = prefixNameProtect(modp); + + putsDecoration("// Evaluate till stable\n"); + puts("int __VclockLoop = 0;\n"); + puts("QData __Vchange = 1;\n"); + if (v3Global.opt.trace()) puts("vlSymsp->__Vm_activity = true;\n"); + puts("do {\n"); + puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+ "); + puts(initial ? "Initial" : "Clock"); + puts(" loop\\n\"););\n"); + if (initial) + puts(topModNameProtected + "__" + protect("_eval_settle") + "(&(vlSymsp->TOP));\n"); + puts(topModNameProtected + "__" + protect("_eval") + "(&(vlSymsp->TOP));\n"); + puts("if (VL_UNLIKELY(++__VclockLoop > " + cvtToStr(v3Global.opt.convergeLimit()) + + ")) {\n"); + puts("// About to fail, so enable debug to see what's not settling.\n"); + puts("// Note you must run make with OPT=-DVL_DEBUG for debug prints.\n"); + puts("int __Vsaved_debug = Verilated::debug();\n"); + puts("Verilated::debug(1);\n"); + puts("__Vchange = " + topModNameProtected + "__" + protect("_change_request") + + "(&(vlSymsp->TOP));\n"); + puts("Verilated::debug(__Vsaved_debug);\n"); + puts("VL_FATAL_MT("); + putsQuoted(protect(modp->fileline()->filename())); + puts(", "); + puts(cvtToStr(modp->fileline()->lineno())); + puts(", \"\",\n"); + puts("\"Verilated model didn't "); + if (initial) puts("DC "); + puts("converge\\n\"\n"); + puts("\"- See https://verilator.org/warn/DIDNOTCONVERGE\");\n"); + puts("} else {\n"); + puts("__Vchange = " + topModNameProtected + "__" + protect("_change_request") + + "(&(vlSymsp->TOP));\n"); + puts("}\n"); + puts("} while (VL_UNLIKELY(__Vchange));\n"); + } + + void emitStandardMethods(AstNodeModule* modp) { + UASSERT_OBJ(modp->isTop(), modp, "Attempting to emitWrapEval for non-top class"); + + const string topModNameProtected = prefixNameProtect(modp); + const string selfDecl = "(" + topModNameProtected + "* vlSelf)"; + + putSectionDelimiter("Evaluation loop"); + + // Forward declarations + puts("\n"); + puts("void " + topModNameProtected + "__" + protect("_eval_initial") + selfDecl + ";\n"); + puts("void " + topModNameProtected + "__" + protect("_eval_settle") + selfDecl + ";\n"); + puts("void " + topModNameProtected + "__" + protect("_eval") + selfDecl + ";\n"); + puts("QData " + topModNameProtected + "__" + protect("_change_request") + selfDecl + + ";\n"); + puts("#ifdef VL_DEBUG\n"); + puts("void " + topModNameProtected + "__" + protect("_eval_debug_assertions") + selfDecl + + ";\n"); + puts("#endif // VL_DEBUG\n"); + puts("void " + topModNameProtected + "__" + protect("_final") + selfDecl + ";\n"); + + // _eval_initial_loop + puts("\nstatic void " + protect("_eval_initial_loop") + "(" + symClassVar() + ")" + + " {\n"); + puts("vlSymsp->__Vm_didInit = true;\n"); + puts(topModNameProtected + "__" + protect("_eval_initial") + "(&(vlSymsp->TOP));\n"); + emitSettleLoop(modp, /* initial: */ true); + ensureNewLine(); + puts("}\n"); + + // ::eval_step + puts("\nvoid " + topClassName() + "::eval_step() {\n"); + puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+++++TOP Evaluate " + topClassName() + + "::eval_step\\n\"); );\n"); + puts("#ifdef VL_DEBUG\n"); + putsDecoration("// Debug assertions\n"); + puts(topModNameProtected + "__" + protect("_eval_debug_assertions") + + "(&(vlSymsp->TOP));\n"); + puts("#endif // VL_DEBUG\n"); + putsDecoration("// Initialize\n"); + puts("if (VL_UNLIKELY(!vlSymsp->__Vm_didInit)) " + protect("_eval_initial_loop") + + "(vlSymsp);\n"); + + if (v3Global.opt.threads() == 1) { + uint32_t mtaskId = 0; + putsDecoration("// MTask " + cvtToStr(mtaskId) + " start\n"); + puts("VL_DEBUG_IF(VL_DBG_MSGF(\"MTask" + cvtToStr(mtaskId) + " starting\\n\"););\n"); + puts("Verilated::mtaskId(" + cvtToStr(mtaskId) + ");\n"); + } + + if (v3Global.opt.mtasks() && v3Global.opt.profThreads()) { + puts("if (VL_UNLIKELY((vlSymsp->_vm_contextp__->profThreadsStart() != " + "vlSymsp->__Vm_profile_time_finished)\n"); + puts(" && (VL_TIME_Q() > vlSymsp->_vm_contextp__->profThreadsStart())\n"); + puts(" && (vlSymsp->_vm_contextp__->profThreadsWindow() >= 1))) {\n"); + // Within a profile (either starting, middle, or end) + puts("if (vlSymsp->__Vm_profile_window_ct == 0) {\n"); // Opening file? + // Start profile on this cycle. We'll capture a window worth, then + // only analyze the next window worth. The idea is that the first window + // capture will hit some cache-cold stuff (eg printf) but it'll be warm + // by the time we hit the second window, we hope. + puts("vlSymsp->__Vm_profile_cycle_start = VL_RDTSC_Q();\n"); + // "* 2" as first half is warmup, second half is collection + puts("vlSymsp->__Vm_profile_window_ct = vlSymsp->_vm_contextp__->profThreadsWindow() " + "* 2 " + "+ " + "1;\n"); + puts("}\n"); + puts("--(vlSymsp->__Vm_profile_window_ct);\n"); + puts("if (vlSymsp->__Vm_profile_window_ct == " + "vlSymsp->_vm_contextp__->profThreadsWindow()) {\n"); + // This barrier record in every threads' profile demarcates the + // cache-warm-up cycles before the barrier from the actual profile + // cycles afterward. + puts("vlSymsp->__Vm_threadPoolp->profileAppendAll("); + puts("VlProfileRec(VlProfileRec::Barrier()));\n"); + puts("vlSymsp->__Vm_profile_cycle_start = VL_RDTSC_Q();\n"); + puts("}\n"); + puts("else if (vlSymsp->__Vm_profile_window_ct == 0) {\n"); + // Ending file. + puts("vluint64_t elapsed = VL_RDTSC_Q() - vlSymsp->__Vm_profile_cycle_start;\n"); + puts("vlSymsp->__Vm_threadPoolp->profileDump(vlSymsp->_vm_contextp__->" + "profThreadsFilename().c_str(), elapsed);\n"); + // This turns off the test to enter the profiling code, but still + // allows the user to collect another profile by changing + // profThreadsStart + puts("vlSymsp->__Vm_profile_time_finished = " + "vlSymsp->_vm_contextp__->profThreadsStart();\n"); + puts("vlSymsp->__Vm_profile_cycle_start = 0;\n"); + puts("}\n"); + puts("}\n"); + } + + emitSettleLoop(modp, /* initial: */ false); + if (v3Global.opt.threads() == 1) { + puts("Verilated::endOfThreadMTask(vlSymsp->__Vm_evalMsgQp);\n"); + } + if (v3Global.opt.threads()) puts("Verilated::endOfEval(vlSymsp->__Vm_evalMsgQp);\n"); + puts("}\n"); + + // ::eval_end_step + if (v3Global.needTraceDumper() && !optSystemC()) { + puts("\nvoid " + topClassName() + "::eval_end_step() {\n"); + puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+eval_end_step " + topClassName() + + "::eval_end_step\\n\"); );\n"); + puts("#ifdef VM_TRACE\n"); + putsDecoration("// Tracing\n"); + // SystemC's eval loop deals with calling trace, not us + puts("if (VL_UNLIKELY(vlSymsp->__Vm_dumping)) vlSymsp->_traceDump();\n"); + puts("#endif // VM_TRACE\n"); + puts("}\n"); + } + + putSectionDelimiter("Invoke final blocks"); + // ::final + puts("\nvoid " + topClassName() + "::final() {\n"); + puts(topModNameProtected + "__" + protect("_final") + "(&(vlSymsp->TOP));\n"); + puts("}\n"); + + putSectionDelimiter("Utilities"); + // ::contextp + puts("\nVerilatedContext* " + topClassName() + "::contextp() const {\n"); + puts(/**/ "return vlSymsp->_vm_contextp__;\n"); + puts("}\n"); + + if (!optSystemC()) { + // ::name + puts("\nconst char* " + topClassName() + "::name() const {\n"); + puts(/**/ "return vlSymsp->name();\n"); + puts("}\n"); + } + } + + void emitTraceMethods(AstNodeModule* modp) { + const string topModNameProtected = prefixNameProtect(modp); + + putSectionDelimiter("Trace configuration"); + + // Forward declaration + puts("\nvoid " + topModNameProtected + "__" + protect("traceInitTop") + "(" + + topModNameProtected + "* vlSelf, " + v3Global.opt.traceClassBase() + + "* tracep);\n"); + + // Static helper function + puts("\nstatic void " + protect("traceInit") + "(void* voidSelf, " + + v3Global.opt.traceClassBase() + "* tracep, uint32_t code) {\n"); + putsDecoration("// Callback from tracep->open()\n"); + puts(voidSelfAssign(modp)); + puts(symClassAssign()); + puts("if (!vlSymsp->_vm_contextp__->calcUnusedSigs()) {\n"); + puts("VL_FATAL_MT(__FILE__, __LINE__, __FILE__,\n"); + puts("\"Turning on wave traces requires Verilated::traceEverOn(true) call before time " + "0.\");\n"); + puts("}\n"); + puts("vlSymsp->__Vm_baseCode = code;\n"); + puts("tracep->module(vlSymsp->name());\n"); + puts("tracep->scopeEscape(' ');\n"); + puts(topModNameProtected + "__" + protect("traceInitTop") + "(vlSelf, tracep);\n"); + puts("tracep->scopeEscape('.');\n"); // Restore so later traced files won't break + puts("}\n"); + + // Forward declaration + puts("\nvoid " + topModNameProtected + "__" + protect("traceRegister") + "(" + + topModNameProtected + "* vlSelf, " + v3Global.opt.traceClassBase() + + "* tracep);\n"); + + // ::trace + puts("\nvoid " + topClassName() + "::trace("); + puts(v3Global.opt.traceClassBase() + "C* tfp, int, int) {\n"); + puts("tfp->spTrace()->addInitCb(&" + protect("traceInit") + ", &(vlSymsp->TOP));\n"); + puts(topModNameProtected + "__" + protect("traceRegister") + + "(&(vlSymsp->TOP), tfp->spTrace());\n"); + puts("}\n"); + } + + void emitSerializationFunctions() { + putSectionDelimiter("Model serialization"); + + puts("\nVerilatedSerialize& operator<<(VerilatedSerialize& os, " + topClassName() + + "& rhs) {\n"); + puts("Verilated::quiesce();\n"); + puts("rhs.vlSymsp->" + protect("__Vserialize") + "(os);\n"); + puts("return os;\n"); + puts("}\n"); + + puts("\nVerilatedDeserialize& operator>>(VerilatedDeserialize& os, " + topClassName() + + "& rhs) {\n"); + puts("Verilated::quiesce();\n"); + puts("rhs.vlSymsp->" + protect("__Vdeserialize") + "(os);\n"); + puts("return os;\n"); + puts("}\n"); + } + + void emitImplementation(AstNodeModule* modp) { + UASSERT(!m_ofp, "Output file should not be open"); + + const string filename = v3Global.opt.makeDir() + "/" + topClassName() + ".cpp"; + newCFile(filename, /* slow: */ false, /* source: */ true); + m_ofp = v3Global.opt.systemC() ? new V3OutScFile(filename) : new V3OutCFile(filename); + + ofp()->putsHeader(); + puts("// DESCRIPTION: Verilator output: " + "Model implementation (design independent parts)\n"); + + puts("\n"); + puts("#include \"" + topClassName() + ".h\"\n"); + puts("#include \"" + symClassName() + ".h\"\n"); + if (v3Global.opt.trace()) { + puts("#include \"" + v3Global.opt.traceSourceLang() + ".h\"\n"); + } + if (v3Global.dpi()) { // + puts("#include \"verilated_dpi.h\"\n"); + } + + emitConstructorImplementation(modp); + emitDestructorImplementation(); + emitStandardMethods(modp); + if (v3Global.opt.trace()) { emitTraceMethods(modp); } + if (v3Global.opt.savable()) { emitSerializationFunctions(); } + + VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); + } + + void emitDpiExportDispatchers(AstNodeModule* modp) { + UASSERT(!m_ofp, "Output file should not be open"); + + // Emit DPI Export dispatchers + for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { + AstCFunc* const funcp = VN_CAST(nodep, CFunc); + if (!funcp || !funcp->dpiExportDispatcher()) continue; + + if (splitNeeded()) { + // Splitting file, so using parallel build. + v3Global.useParallelBuild(true); + // Close old file + VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); + } + + if (!m_ofp) { + const string filename = v3Global.opt.makeDir() + "/" + topClassName() + + "__Dpi_Export_" + cvtToStr(splitFilenumInc() - 1) + + ".cpp"; + newCFile(filename, /* slow: */ false, /* source: */ true); + m_ofp = v3Global.opt.systemC() ? new V3OutScFile(filename) + : new V3OutCFile(filename); + m_lazyDecls.reset(); + m_ofp->putsHeader(); + puts( + "// DESCRIPTION: Verilator output: Implementation of DPI export functions.\n"); + puts("//\n"); + puts("#include \"" + topClassName() + ".h\"\n"); + puts("#include \"" + symClassName() + ".h\"\n"); + puts("#include \"verilated_dpi.h\"\n"); + puts("\n"); + } + + iterate(funcp); + } + + if (m_ofp) { VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); } + } + + void main(AstNodeModule* modp) { + m_modp = modp; + emitHeader(modp); + emitImplementation(modp); + if (v3Global.dpi()) { emitDpiExportDispatchers(modp); } + } + + // VISITORS + +public: + explicit EmitCModel(AstNetlist* netlistp) { main(netlistp->topModulep()); } +}; + +//###################################################################### +// EmitC class functions + +void V3EmitC::emitcModel() { + UINFO(2, __FUNCTION__ << ": " << endl); + { EmitCModel emit(v3Global.rootp()); } +} diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 17307fa24..bcc22b94a 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -380,8 +380,7 @@ void EmitCSyms::emitSymHdr() { } ofp()->putsHeader(); - puts("// DESCR" - "IPTION: Verilator output: Symbol table internal header\n"); + puts("// DESCRIPTION: Verilator output: Symbol table internal header\n"); puts("//\n"); puts("// Internal details; most calling programs do not need this header,\n"); puts("// unless using verilator public meta comments.\n"); @@ -395,6 +394,12 @@ void EmitCSyms::emitSymHdr() { } else { puts("#include \"verilated.h\"\n"); } + if (v3Global.needTraceDumper()) { + puts("#include \"" + v3Global.opt.traceSourceLang() + ".h\"\n"); + } + + puts("\n// INCLUDE MODEL CLASS\n"); + puts("\n#include \"" + topClassName() + ".h\"\n"); puts("\n// INCLUDE MODULE CLASSES\n"); for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep; @@ -417,41 +422,52 @@ void EmitCSyms::emitSymHdr() { for (const auto& i : types) puts(i.first); } - puts("\n// SYMS CLASS\n"); - puts(string("class ") + symClassName() + " : public VerilatedSyms {\n"); + puts("\n// SYMS CLASS (contains all model state)\n"); + puts("class " + symClassName() + " final : public VerilatedSyms {\n"); ofp()->putsPrivate(false); // public: - puts("\n// LOCAL STATE\n"); - // Must be before subcells, as constructor order needed before _vlCoverInsert. - puts("const char* const __Vm_namep;\n"); + puts("// INTERNAL STATE\n"); + puts(topClassName() + "* const __Vm_modelp;\n"); if (v3Global.needTraceDumper()) { // __Vm_dumperp is local, otherwise we wouldn't know what design's eval() // should call a global dumpperp - puts("bool __Vm_dumping; // Dumping is active\n"); + puts("bool __Vm_dumping = false; // Dumping is active\n"); puts("VerilatedMutex __Vm_dumperMutex; // Protect __Vm_dumperp\n"); puts(v3Global.opt.traceClassLang() - + "* __Vm_dumperp VL_GUARDED_BY(__Vm_dumperMutex); /// Trace class for $dump*\n"); + + "* __Vm_dumperp VL_GUARDED_BY(__Vm_dumperMutex) = nullptr;" + " /// Trace class for $dump*\n"); } if (v3Global.opt.trace()) { - puts("bool __Vm_activity; ///< Used by trace routines to determine change occurred\n"); - puts("uint32_t __Vm_baseCode; " - "///< Used by trace routines when tracing multiple models\n"); + puts("bool __Vm_activity = false;" + " ///< Used by trace routines to determine change occurred\n"); + puts("uint32_t __Vm_baseCode = 0;" + " ///< Used by trace routines when tracing multiple models\n"); } - puts("bool __Vm_didInit;\n"); + puts("bool __Vm_didInit = false;\n"); - puts("\n// SUBCELL STATE\n"); + if (v3Global.opt.mtasks()) { + puts("VlThreadPool* const __Vm_threadPoolp;\n"); + puts("bool __Vm_even_cycle = false;\n"); + + if (v3Global.opt.profThreads()) { + // rdtsc() at current cycle start + puts("vluint64_t __Vm_profile_cycle_start = 0;\n"); + // Time we finished analysis + puts("vluint64_t __Vm_profile_time_finished = 0;\n"); + // Track our position in the cache warmup and actual profile window + puts("vluint32_t __Vm_profile_window_ct = 0;\n"); + } + } + + puts("\n// MODULE INSTANCE STATE\n"); for (const auto& i : m_scopes) { AstScope* scopep = i.first; AstNodeModule* modp = i.second; if (VN_IS(modp, Class)) continue; - if (modp->isTop()) { - ofp()->printf("%-30s ", (prefixNameProtect(modp) + "*").c_str()); - puts(protectIf(scopep->nameDotless() + "p", scopep->protect()) + ";\n"); - } else { - ofp()->printf("%-30s ", (prefixNameProtect(modp) + "").c_str()); - puts(protectIf(scopep->nameDotless(), scopep->protect()) + ";\n"); - } + const string name = prefixNameProtect(modp); + ofp()->printf("%-30s ", name.c_str()); + puts(protectIf(scopep->nameDotless(), scopep->protect()) + ";\n"); } if (m_coverBins) { @@ -474,28 +490,30 @@ void EmitCSyms::emitSymHdr() { puts("VerilatedHierarchy __Vhier;\n"); } - puts("\n// CREATORS\n"); - puts(symClassName() + "(VerilatedContext* contextp, " + topClassName() - + "* topp, const char* namep);\n"); + puts("\n// CONSTRUCTORS\n"); + puts(symClassName() + "(VerilatedContext* contextp, const char* namep, " + topClassName() + + "* modelp);\n"); puts(string("~") + symClassName() + "();\n"); for (const auto& i : m_usesVfinal) { puts("void " + symClassName() + "_" + cvtToStr(i.first) + "("); - if (i.second) { - puts("int __Vfinal"); - } else { - puts(topClassName() + "* topp"); - } + if (i.second) { puts("int __Vfinal"); } puts(");\n"); } puts("\n// METHODS\n"); - puts("inline const char* name() { return __Vm_namep; }\n"); + puts("const char* name() { return TOP.name(); }\n"); + + if (v3Global.needTraceDumper()) { + if (!optSystemC()) puts("void _traceDump();\n"); + puts("void _traceDumpOpen();\n"); + puts("void _traceDumpClose();\n"); + } + if (v3Global.opt.savable()) { puts("void " + protect("__Vserialize") + "(VerilatedSerialize& os);\n"); puts("void " + protect("__Vdeserialize") + "(VerilatedDeserialize& os);\n"); } - puts("\n"); puts("} VL_ATTR_ALIGNED(VL_CACHE_LINE_BYTES);\n"); ofp()->putsEndGuard(); @@ -533,20 +551,12 @@ void EmitCSyms::checkSplit(bool usesVfinal) { } m_ofpBase->puts(symClassName() + "_" + cvtToStr(m_funcNum) + "("); - if (usesVfinal) { - m_ofpBase->puts("__Vfinal"); - } else { - m_ofpBase->puts("topp"); - } + if (usesVfinal) { m_ofpBase->puts("__Vfinal"); } m_ofpBase->puts(");\n"); emitSymImpPreamble(); puts("void " + symClassName() + "::" + symClassName() + "_" + cvtToStr(m_funcNum) + "("); - if (usesVfinal) { - puts("int __Vfinal"); - } else { - puts(topClassName() + "* topp"); - } + if (usesVfinal) { puts("int __Vfinal"); } puts(") {\n"); } @@ -558,6 +568,7 @@ void EmitCSyms::emitSymImpPreamble() { // Includes puts("#include \"" + symClassName() + ".h\"\n"); + puts("#include \"" + topClassName() + ".h\"\n"); for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep; nodep = VN_CAST(nodep->nextp(), NodeModule)) { if (VN_IS(nodep, Class)) continue; // Class included earlier @@ -631,19 +642,14 @@ void EmitCSyms::emitSymImp() { // NOLINTNEXTLINE(performance-inefficient-string-concatenation) puts("void " + symClassName() + "::" + protect(funcname) + "(" + classname + "& os) {\n"); - puts("// LOCAL STATE\n"); - // __Vm_namep presumably already correct + puts("// Internal state\n"); if (v3Global.opt.trace()) puts("os" + op + "__Vm_activity;\n"); - puts("os" + op + "__Vm_didInit;\n"); - puts("// SUBCELL STATE\n"); - for (std::vector::iterator it = m_scopes.begin(); it != m_scopes.end(); - ++it) { - AstScope* scopep = it->first; - AstNodeModule* modp = it->second; - if (!modp->isTop()) { - puts(protectIf(scopep->nameDotless(), scopep->protect()) + "." - + protect(funcname) + "(os);\n"); - } + puts("os " + op + " __Vm_didInit;\n"); + puts("// Module instance state\n"); + for (const auto& pair : m_scopes) { + const AstScope* const scopep = pair.first; + puts(protectIf(scopep->nameDotless(), scopep->protect()) + "." + protect(funcname) + + "(os);\n"); } puts("}\n"); } @@ -651,61 +657,70 @@ void EmitCSyms::emitSymImp() { } puts("// FUNCTIONS\n"); + // Destructor puts(symClassName() + "::~" + symClassName() + "()\n"); puts("{\n"); emitScopeHier(true); - puts("}\n\n"); - puts(symClassName() + "::" + symClassName() + "(VerilatedContext* contextp, " + topClassName() - + "* topp, const char* namep)\n"); - puts(" // Setup locals\n"); - puts(" : VerilatedSyms{contextp}\n"); - puts(" , __Vm_namep(namep)\n"); // No leak, as gets destroyed when the top is destroyed if (v3Global.needTraceDumper()) { - puts(" , __Vm_dumping(false)\n"); - puts(" , __Vm_dumperp(nullptr)\n"); + puts("#ifdef VM_TRACE\n"); + puts("if (__Vm_dumping) _traceDumpClose();\n"); + puts("#endif // VM_TRACE\n"); } - if (v3Global.opt.trace()) { - puts(" , __Vm_activity(false)\n"); - puts(" , __Vm_baseCode(0)\n"); + if (v3Global.opt.mtasks()) { puts("delete __Vm_threadPoolp;\n"); } + puts("}\n\n"); + + // Constructor + puts(symClassName() + "::" + symClassName() + "(VerilatedContext* contextp, const char* namep," + + topClassName() + "* modelp)\n"); + puts(" : VerilatedSyms{contextp}\n"); + puts(" // Setup internal state of the Syms class\n"); + puts(" , __Vm_modelp(modelp)\n"); + + if (v3Global.opt.mtasks()) { + // TODO -- For now each model creates its own ThreadPool here, + // and deletes it in the destructor. If A and B are each top level + // modules, each creates a separate thread pool. This allows + // A.eval() and B.eval() to run concurrently without any + // interference -- so long as the physical machine has enough cores + // to support both pools and all testbench threads. + // + // In the future, we might want to let the client provide a + // threadpool to the constructor. This would allow two or more + // models to share a single threadpool. + // + // For example: suppose models A and B are each compiled to run on + // 4 threads. The client might create a single thread pool with 3 + // threads and pass it to both models. If the client can ensure that + // A.eval() and B.eval() do NOT run concurrently, there will be no + // contention for the threads. This mode is missing for now. (Is + // there demand for such a setup?) + // + // Note we create N-1 threads in the thread pool. The thread + // that calls eval() becomes the final Nth thread for the + // duration of the eval call. + puts(" , __Vm_threadPoolp(new VlThreadPool(_vm_contextp__, " + + cvtToStr(v3Global.opt.threads() - 1) + ", " + cvtToStr(v3Global.opt.profThreads()) + + "))\n"); } - puts(" , __Vm_didInit(false)\n"); - puts(" // Setup submodule names\n"); - char comma = ','; + + puts(" // Setup module instances\n"); for (const auto& i : m_scopes) { - AstScope* scopep = i.first; - AstNodeModule* modp = i.second; + const AstScope* const scopep = i.first; + const AstNodeModule* const modp = i.second; + puts(" , "); + puts(protect(scopep->nameDotless())); if (modp->isTop()) { + puts("(namep)\n"); } else { - puts(string(" ") + comma + " " + protect(scopep->nameDotless())); - puts("(Verilated::catName(topp->name(), "); // The "." is added by catName + puts("(Verilated::catName(namep, "); putsQuoted(protectWordsIf(scopep->prettyName(), scopep->protect())); puts("))\n"); - comma = ','; - ++m_numStmts; } + ++m_numStmts; } puts("{\n"); - puts("// Pointer to top level\n"); - puts("TOPp = topp;\n"); - puts("// Setup each module's pointers to their submodules\n"); - for (const auto& i : m_scopes) { - AstScope* scopep = i.first; - AstNodeModule* modp = i.second; - if (!modp->isTop()) { - checkSplit(false); - string arrow = scopep->name(); - string::size_type pos; - while ((pos = arrow.find('.')) != string::npos) arrow.replace(pos, 1, "->"); - if (arrow.substr(0, 5) == "TOP->") arrow.replace(0, 5, "TOPp->"); - ofp()->puts(protectWordsIf(arrow, scopep->protect())); - puts(" = &"); - puts(protectIf(scopep->nameDotless(), scopep->protect()) + ";\n"); - ++m_numStmts; - } - } - puts("// Configure time unit / time precision\n"); if (!v3Global.rootp()->timeunit().isNone()) { puts("_vm_contextp__->timeunit("); @@ -718,20 +733,38 @@ void EmitCSyms::emitSymImp() { puts(");\n"); } + puts("// Setup each module's pointers to their submodules\n"); + for (const auto& i : m_scopes) { + const AstScope* const scopep = i.first; + const AstNodeModule* const modp = i.second; + if (const AstScope* const aboveScopep = scopep->aboveScopep()) { + checkSplit(false); + const string protName = protectWordsIf(scopep->name(), scopep->protect()); + if (VN_IS(modp, ClassPackage)) { + // ClassPackage modules seem to be a bit out of place, so hard code... + puts("TOP"); + } else { + puts(protectIf(aboveScopep->nameDotless(), aboveScopep->protect())); + } + puts("."); + puts(protName.substr(protName.rfind(".") + 1)); + puts(" = &"); + puts(protectIf(scopep->nameDotless(), scopep->protect()) + ";\n"); + ++m_numStmts; + } + } + puts("// Setup each module's pointer back to symbol table (for public functions)\n"); - puts("TOPp->" + protect("__Vconfigure") + "(this, true);\n"); for (const auto& i : m_scopes) { AstScope* scopep = i.first; AstNodeModule* modp = i.second; - if (!modp->isTop()) { - checkSplit(false); - // first is used by AstCoverDecl's call to __vlCoverInsert - const bool first = !modp->user1(); - modp->user1(true); - puts(protectIf(scopep->nameDotless(), scopep->protect()) + "." - + protect("__Vconfigure") + "(this, " + (first ? "true" : "false") + ");\n"); - ++m_numStmts; - } + checkSplit(false); + // first is used by AstCoverDecl's call to __vlCoverInsert + const bool first = !modp->user1(); + modp->user1(true); + puts(protectIf(scopep->nameDotless(), scopep->protect()) + "." + protect("__Vconfigure") + + "(this, " + (first ? "true" : "false") + ");\n"); + ++m_numStmts; } if (!m_scopeNames.empty()) { // Setup scope names @@ -777,7 +810,6 @@ void EmitCSyms::emitSymImp() { // Someday. For now public isn't common. for (auto it = m_scopeVars.begin(); it != m_scopeVars.end(); ++it) { checkSplit(true); - AstNodeModule* modp = it->second.m_modp; AstScope* scopep = it->second.m_scopep; AstVar* varp = it->second.m_varp; // @@ -829,11 +861,7 @@ void EmitCSyms::emitSymImp() { putsQuoted(protect(it->second.m_varBasePretty)); std::string varName; - if (modp->isTop()) { - varName += (protectIf(scopep->nameDotless() + "p", scopep->protect()) + "->"); - } else { - varName += (protectIf(scopep->nameDotless(), scopep->protect()) + "."); - } + varName += (protectIf(scopep->nameDotless(), scopep->protect()) + "."); if (varp->isParam()) { varName += protect("var_" + varp->name()); @@ -872,6 +900,34 @@ void EmitCSyms::emitSymImp() { } m_ofpBase->puts("}\n"); + + if (v3Global.needTraceDumper()) { + if (!optSystemC()) { + puts("\nvoid " + symClassName() + "::_traceDump() {\n"); + // Caller checked for __Vm_dumperp non-nullptr + puts("const VerilatedLockGuard lock(__Vm_dumperMutex);\n"); + puts("__Vm_dumperp->dump(VL_TIME_Q());\n"); + puts("}\n"); + } + + puts("\nvoid " + symClassName() + "::_traceDumpOpen() {\n"); + puts("const VerilatedLockGuard lock(__Vm_dumperMutex);\n"); + puts("if (VL_UNLIKELY(!__Vm_dumperp)) {\n"); + puts("__Vm_dumperp = new " + v3Global.opt.traceClassLang() + "();\n"); + puts("__Vm_modelp->trace(__Vm_dumperp, 0, 0);\n"); + puts("std::string dumpfile = _vm_contextp__->dumpfileCheck();\n"); + puts("__Vm_dumperp->open(dumpfile.c_str());\n"); + puts("__Vm_dumping = true;\n"); + puts("}\n"); + puts("}\n"); + + puts("\nvoid " + symClassName() + "::_traceDumpClose() {\n"); + puts("const VerilatedLockGuard lock(__Vm_dumperMutex);\n"); + puts("__Vm_dumping = false;\n"); + puts("VL_DO_CLEAR(delete __Vm_dumperp, __Vm_dumperp = nullptr);\n"); + puts("}\n"); + } + closeSplit(); VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); } diff --git a/src/V3EmitXml.cpp b/src/V3EmitXml.cpp index e231a3d43..1e38e5552 100644 --- a/src/V3EmitXml.cpp +++ b/src/V3EmitXml.cpp @@ -324,10 +324,11 @@ private: && nodep->level() <= 2) { // ==2 because we don't add wrapper when in XML mode m_os << "\n"; m_os << "fileline()->xml() << " " - << nodep->fileline()->xmlDetailedLocation() << " name=\"" << nodep->name() << "\"" - << " submodname=\"" << nodep->name() << "\"" - << " hier=\"" << nodep->name() << "\""; - m_hier = nodep->name() + "."; + << nodep->fileline()->xmlDetailedLocation() // + << " name=\"" << nodep->prettyName() << "\"" + << " submodname=\"" << nodep->prettyName() << "\"" + << " hier=\"" << nodep->prettyName() << "\""; + m_hier = nodep->prettyName() + "."; m_hasChildren = false; iterateChildren(nodep); if (m_hasChildren) { diff --git a/src/V3File.cpp b/src/V3File.cpp index 89bf07940..fe9550838 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -965,7 +965,7 @@ protected: public: VIdProtectImp() { passthru("this"); - passthru("TOPp"); + passthru("TOP"); passthru("vlSelf"); passthru("vlSymsp"); } diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index d8b39c9eb..33a576ebc 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -592,13 +592,10 @@ public: // $root we walk up to Netlist else if (ident == "$root") { lookupSymp = rootEntp(); - // We've added TOP module, now everything else is one lower + // We've added the '$root' module, now everything else is one lower if (!m_forPrearray) { - VSymEnt* topSymp = lookupSymp->findIdFlat("TOP"); - if (!topSymp) { - topSymp->nodep()->v3fatalSrc("TOP not found under netlist for $root"); - } - lookupSymp = topSymp; + lookupSymp = lookupSymp->findIdFlat(ident); + UASSERT(lookupSymp, "Cannot find $root module under netlist"); } } // Move up and check cellname + modname diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp index add541016..52a0ac057 100644 --- a/src/V3LinkLevel.cpp +++ b/src/V3LinkLevel.cpp @@ -139,7 +139,9 @@ void V3LinkLevel::wrapTop(AstNetlist* rootp) { UINFO(1, "No module found to wrap\n"); return; } - AstNodeModule* newmodp = new AstModule(oldmodp->fileline(), string("TOP")); + + AstNodeModule* newmodp = new AstModule(oldmodp->fileline(), "$root"); + newmodp->name(AstNode::encodeName(newmodp->name())); // so origName is nice // Make the new module first in the list oldmodp->unlinkFrBackWithNext(); newmodp->addNext(oldmodp); diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp index 4f51ed0ec..f63124957 100644 --- a/src/V3Partition.cpp +++ b/src/V3Partition.cpp @@ -2617,9 +2617,10 @@ static void addMTaskToFunction(const ThreadSchedule& schedule, const uint32_t th recName = "__Vprfthr_" + cvtToStr(mtaskp->id()); addStrStmt("VlProfileRec* " + recName + " = nullptr;\n"); // Leave this if() here, as don't want to call VL_RDTSC_Q unless profiling - addStrStmt("if (VL_UNLIKELY(vlSelf->__Vm_profile_cycle_start)) {\n" + // - recName + " = vlSelf->__Vm_threadPoolp->profileAppend();\n" + // - recName + "->startRecord(VL_RDTSC_Q() - vlSelf->__Vm_profile_cycle_start," + // + addStrStmt("if (VL_UNLIKELY(vlSymsp->__Vm_profile_cycle_start)) {\n" + // + recName + " = vlSymsp->__Vm_threadPoolp->profileAppend();\n" + // + recName + "->startRecord(VL_RDTSC_Q() - vlSymsp->__Vm_profile_cycle_start," + + // " " + cvtToStr(mtaskp->id()) + "," + // " " + cvtToStr(mtaskp->cost()) + ");\n" + // "}\n"); @@ -2634,7 +2635,7 @@ static void addMTaskToFunction(const ThreadSchedule& schedule, const uint32_t th if (v3Global.opt.profThreads()) { // Leave this if() here, as don't want to call VL_RDTSC_Q unless profiling addStrStmt("if (VL_UNLIKELY(" + recName + ")) {\n" + // - recName + "->endRecord(VL_RDTSC_Q() - vlSelf->__Vm_profile_cycle_start);\n" + recName + "->endRecord(VL_RDTSC_Q() - vlSymsp->__Vm_profile_cycle_start);\n" + "}\n"); } @@ -2672,7 +2673,7 @@ static const std::vector createThreadFunctions(const ThreadSchedule& funcp->argTypes("void* voidSelf, bool even_cycle"); // Setup vlSelf an vlSyms - funcp->addStmtsp(new AstCStmt(fl, EmitCBaseVisitor::voidSelfAssign())); + funcp->addStmtsp(new AstCStmt(fl, EmitCBaseVisitor::voidSelfAssign(modp))); funcp->addStmtsp(new AstCStmt(fl, EmitCBaseVisitor::symClassAssign())); // Invoke each mtask scheduled to this thread from the thread function @@ -2710,26 +2711,26 @@ static void addThreadStartToExecGraph(AstExecGraph* const execGraphp, execGraphp->addStmtsp(new AstText(fl, text, /* tracking: */ true)); }; - addStrStmt("vlSelf->__Vm_even_cycle = !vlSelf->__Vm_even_cycle;\n"); + addStrStmt("vlSymsp->__Vm_even_cycle = !vlSymsp->__Vm_even_cycle;\n"); const uint32_t last = funcps.size() - 1; for (uint32_t i = 0; i <= last; ++i) { AstCFunc* const funcp = funcps.at(i); if (i != last) { // The first N-1 will run on the thread pool. - addTextStmt("vlSelf->__Vm_threadPoolp->workerp(" + cvtToStr(i) + ")->addTask("); + addTextStmt("vlSymsp->__Vm_threadPoolp->workerp(" + cvtToStr(i) + ")->addTask("); execGraphp->addStmtsp(new AstAddrOfCFunc(fl, funcp)); - addTextStmt(", vlSelf, vlSelf->__Vm_even_cycle);\n"); + addTextStmt(", vlSelf, vlSymsp->__Vm_even_cycle);\n"); } else { // The last will run on the main thread. AstCCall* const callp = new AstCCall(fl, funcp); - callp->argTypes("vlSelf, vlSelf->__Vm_even_cycle"); + callp->argTypes("vlSelf, vlSymsp->__Vm_even_cycle"); execGraphp->addStmtsp(callp); addStrStmt("Verilated::mtaskId(0);\n"); } } - addStrStmt("vlSelf->__Vm_mtaskstate_final.waitUntilUpstreamDone(vlSelf->__Vm_even_cycle);\n"); + addStrStmt("vlSelf->__Vm_mtaskstate_final.waitUntilUpstreamDone(vlSymsp->__Vm_even_cycle);\n"); } static void implementExecGraph(AstExecGraph* const execGraphp) { diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 8ee9b114f..9a742cafd 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -511,6 +511,7 @@ static void process() { V3EmitC::emitcInlines(); V3EmitC::emitcSyms(); V3EmitC::emitcConstPool(); + V3EmitC::emitcModel(); V3EmitC::emitcTrace(); } else if (v3Global.opt.dpiHdrOnly()) { V3EmitC::emitcSyms(true); diff --git a/test_regress/t/t_alw_noreorder.pl b/test_regress/t/t_alw_noreorder.pl index 392808699..b0543df38 100755 --- a/test_regress/t/t_alw_noreorder.pl +++ b/test_regress/t/t_alw_noreorder.pl @@ -19,8 +19,8 @@ file_grep($Self->{stats}, qr/Optimizations, Split always\s+(\d+)/i, 0); # Here we should see some dly vars since reorder is disabled. # (Whereas our twin test, t_alw_reorder, should see no dly vars # since it enables the reorder step.) -file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.cpp", qr/dly__t__DOT__v1/i); -file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.cpp", qr/dly__t__DOT__v2/i); +file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}___024root.cpp", qr/dly__t__DOT__v1/i); +file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}___024root.cpp", qr/dly__t__DOT__v2/i); execute( check_finished=>1, diff --git a/test_regress/t/t_c_this.pl b/test_regress/t/t_c_this.pl index 4260beacc..37616efd7 100755 --- a/test_regress/t/t_c_this.pl +++ b/test_regress/t/t_c_this.pl @@ -15,7 +15,7 @@ compile(); if ($Self->{vlt_all}) { # The word 'this' (but only the whole word 'this' should have been replaced # in the contents. - my $file = "$Self->{obj_dir}/$Self->{VM_PREFIX}.cpp"; + my $file = "$Self->{obj_dir}/$Self->{VM_PREFIX}___024root.cpp"; my $text = file_contents($file); error("$file has 'this->clk'") if ($text =~ m/\bthis->clk\b/); error("$file does not have 'xthis'") if ($text !~ m/\bxthis\b/); diff --git a/test_regress/t/t_debug_emitv.out b/test_regress/t/t_debug_emitv.out index f42904c37..d10784ec3 100644 --- a/test_regress/t/t_debug_emitv.out +++ b/test_regress/t/t_debug_emitv.out @@ -1,4 +1,4 @@ -module Vt_debug_emitv; +module Vt_debug_emitv___024root; input logic clk; input logic in; signed int [31:0] t.array[0:2]; diff --git a/test_regress/t/t_dist_portability.pl b/test_regress/t/t_dist_portability.pl index 78c4d6279..99fa2f164 100755 --- a/test_regress/t/t_dist_portability.pl +++ b/test_regress/t/t_dist_portability.pl @@ -80,7 +80,7 @@ sub cstr { my $grep = `$cmd`; my %names; foreach my $line (split /\n/, $grep) { - if ($line =~ /^([^:]+).*\(\)[a-z0-9_().->]*[.->]+(c_str|r?begin|r?end)\(\)/) { + if ($line =~ /^([^:]+)[^"]*\(\)[a-z0-9_().->]*[.->]+(c_str|r?begin|r?end)\(\)/) { next if $line =~ /lintok-begin-on-ref/; print "$line\n"; $names{$1} = 1; diff --git a/test_regress/t/t_emit_memb_limit.pl b/test_regress/t/t_emit_memb_limit.pl index 931ba7569..7920f341a 100755 --- a/test_regress/t/t_emit_memb_limit.pl +++ b/test_regress/t/t_emit_memb_limit.pl @@ -55,7 +55,7 @@ execute( check_finished => 1, ); -file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/struct \{/); +file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}___024root.h", qr/struct \{/); ok(1); 1; diff --git a/test_regress/t/t_flag_comp_limit_parens.pl b/test_regress/t/t_flag_comp_limit_parens.pl index e1ffcfc7b..11731a873 100755 --- a/test_regress/t/t_flag_comp_limit_parens.pl +++ b/test_regress/t/t_flag_comp_limit_parens.pl @@ -18,7 +18,7 @@ execute( check_finished => 1, ); -file_grep("$Self->{obj_dir}/Vt_flag_comp_limit_parens__Slow.cpp", qr/Vdeeptemp/x); +file_grep("$Self->{obj_dir}/Vt_flag_comp_limit_parens___024root__Slow.cpp", qr/Vdeeptemp/x); ok(1); 1; diff --git a/test_regress/t/t_flag_csplit_off.pl b/test_regress/t/t_flag_csplit_off.pl index 17c865a6a..d29b8f2ef 100755 --- a/test_regress/t/t_flag_csplit_off.pl +++ b/test_regress/t/t_flag_csplit_off.pl @@ -60,6 +60,7 @@ while (1) { sub check_no_splits { foreach my $file (glob("$Self->{obj_dir}/*.cpp")) { + $file =~ s/__024root//; if ($file =~ qr/__\d/) { error("Split file found: $file"); } diff --git a/test_regress/t/t_flag_xinitial_0.pl b/test_regress/t/t_flag_xinitial_0.pl index c14556cdc..167593271 100755 --- a/test_regress/t/t_flag_xinitial_0.pl +++ b/test_regress/t/t_flag_xinitial_0.pl @@ -18,7 +18,7 @@ execute( check_finished => 1, ); -file_grep_not("$Self->{obj_dir}/$Self->{VM_PREFIX}__Slow.cpp", qr/VL_RAND_RESET/); +file_grep_not("$Self->{obj_dir}/$Self->{VM_PREFIX}___024root__Slow.cpp", qr/VL_RAND_RESET/); ok(1); 1; diff --git a/test_regress/t/t_flag_xinitial_unique.pl b/test_regress/t/t_flag_xinitial_unique.pl index b94639b4e..572880d86 100755 --- a/test_regress/t/t_flag_xinitial_unique.pl +++ b/test_regress/t/t_flag_xinitial_unique.pl @@ -18,7 +18,7 @@ execute( check_finished => 1, ); -file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}__Slow.cpp", qr/VL_RAND_RESET/); +file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}___024root__Slow.cpp", qr/VL_RAND_RESET/); ok(1); 1; diff --git a/test_regress/t/t_foreach.pl b/test_regress/t/t_foreach.pl index f5e2135cc..06fc908f0 100755 --- a/test_regress/t/t_foreach.pl +++ b/test_regress/t/t_foreach.pl @@ -20,14 +20,14 @@ execute( # We expect all loops should be unrolled by verilator, # none of the loop variables should exist in the output: -file_grep_not("$Self->{obj_dir}/$Self->{VM_PREFIX}.cpp", qr/index_/); -file_grep_not("$Self->{obj_dir}/$Self->{VM_PREFIX}__Slow.cpp", qr/index_/); +file_grep_not("$Self->{obj_dir}/$Self->{VM_PREFIX}___024root.cpp", qr/index_/); +file_grep_not("$Self->{obj_dir}/$Self->{VM_PREFIX}___024root__Slow.cpp", qr/index_/); # Further, we expect that all logic within the loop should # have been evaluated inside the compiler. So there should be # no references to 'sum' in the .cpp. -file_grep_not("$Self->{obj_dir}/$Self->{VM_PREFIX}.cpp", qr/sum/); -file_grep_not("$Self->{obj_dir}/$Self->{VM_PREFIX}__Slow.cpp", qr/sum/); +file_grep_not("$Self->{obj_dir}/$Self->{VM_PREFIX}___024root.cpp", qr/sum/); +file_grep_not("$Self->{obj_dir}/$Self->{VM_PREFIX}___024root__Slow.cpp", qr/sum/); ok(1); 1; diff --git a/test_regress/t/t_optm_if_array.pl b/test_regress/t/t_optm_if_array.pl index 21408ee20..2b2ca158f 100755 --- a/test_regress/t/t_optm_if_array.pl +++ b/test_regress/t/t_optm_if_array.pl @@ -17,8 +17,8 @@ execute( check_finished => 1, ); -file_grep_not("$Self->{obj_dir}/$Self->{VM_PREFIX}.cpp", qr/rstn_r/); -file_grep_not("$Self->{obj_dir}/$Self->{VM_PREFIX}__Slow.cpp", qr/rstn_r/); +file_grep_not("$Self->{obj_dir}/$Self->{VM_PREFIX}___024root.cpp", qr/rstn_r/); +file_grep_not("$Self->{obj_dir}/$Self->{VM_PREFIX}___024root__Slow.cpp", qr/rstn_r/); ok(1); 1; diff --git a/test_regress/t/t_optm_redor.pl b/test_regress/t/t_optm_redor.pl index 21408ee20..2b2ca158f 100755 --- a/test_regress/t/t_optm_redor.pl +++ b/test_regress/t/t_optm_redor.pl @@ -17,8 +17,8 @@ execute( check_finished => 1, ); -file_grep_not("$Self->{obj_dir}/$Self->{VM_PREFIX}.cpp", qr/rstn_r/); -file_grep_not("$Self->{obj_dir}/$Self->{VM_PREFIX}__Slow.cpp", qr/rstn_r/); +file_grep_not("$Self->{obj_dir}/$Self->{VM_PREFIX}___024root.cpp", qr/rstn_r/); +file_grep_not("$Self->{obj_dir}/$Self->{VM_PREFIX}___024root__Slow.cpp", qr/rstn_r/); ok(1); 1; diff --git a/test_regress/t/t_protect_ids_key.out b/test_regress/t/t_protect_ids_key.out index 0eeb97a9f..7a7d53d4b 100644 --- a/test_regress/t/t_protect_ids_key.out +++ b/test_regress/t/t_protect_ids_key.out @@ -1,11 +1,12 @@ + - + diff --git a/test_regress/t/t_trace_two_cc.cpp b/test_regress/t/t_trace_two_cc.cpp index 4b445b8ed..02c639418 100644 --- a/test_regress/t/t_trace_two_cc.cpp +++ b/test_regress/t/t_trace_two_cc.cpp @@ -22,8 +22,9 @@ // Compile in place #include "Vt_trace_two_b.cpp" -#include "Vt_trace_two_b__Slow.cpp" #include "Vt_trace_two_b__Syms.cpp" +#include "Vt_trace_two_b___024root.cpp" +#include "Vt_trace_two_b___024root__Slow.cpp" #include "Vt_trace_two_b__Trace.cpp" #include "Vt_trace_two_b__Trace__Slow.cpp" diff --git a/test_regress/t/t_trace_two_sc.cpp b/test_regress/t/t_trace_two_sc.cpp index 6d0c0e125..7547853d5 100644 --- a/test_regress/t/t_trace_two_sc.cpp +++ b/test_regress/t/t_trace_two_sc.cpp @@ -18,7 +18,8 @@ // Compile in place #include "Vt_trace_two_b.cpp" -#include "Vt_trace_two_b__Slow.cpp" +#include "Vt_trace_two_b___024root.cpp" +#include "Vt_trace_two_b___024root__Slow.cpp" #include "Vt_trace_two_b__Syms.cpp" #include "Vt_trace_two_b__Trace.cpp" #include "Vt_trace_two_b__Trace__Slow.cpp" diff --git a/test_regress/t/t_tri_inz.cpp b/test_regress/t/t_tri_inz.cpp index c9393b5f3..fb0934859 100644 --- a/test_regress/t/t_tri_inz.cpp +++ b/test_regress/t/t_tri_inz.cpp @@ -4,6 +4,7 @@ // SPDX-License-Identifier: CC0-1.0 #include "Vt_tri_inz.h" +#include "Vt_tri_inz___024root.h" VM_PREFIX* tb = nullptr; bool pass = true; @@ -19,7 +20,7 @@ void checkone(const char* name, int got, int exp) { void check(int d, int en, int exp0, int exp1, int expx, int expz) { tb->d = d; - tb->d__en0 = en; + tb->rootp->d__en0 = en; tb->eval(); #ifdef TEST_VERBOSE printf("Drive d=%d en=%d got0=%d/1=%d/x=%d/z=%d exp0=%d/1=%d/x=%d/z=%d\n", d, en, tb->ext0, diff --git a/test_regress/t/t_unopt_converge_initial_run_bad.out b/test_regress/t/t_unopt_converge_initial_run_bad.out index 5445309d7..a410304f6 100644 --- a/test_regress/t/t_unopt_converge_initial_run_bad.out +++ b/test_regress/t/t_unopt_converge_initial_run_bad.out @@ -1,5 +1,5 @@ -V{t#,#}- Verilated::debug is on. Message prefix indicates {,}. --V{t#,#}+ Vt_unopt_converge_initial_run_bad___change_request +-V{t#,#}+ Vt_unopt_converge_initial_run_bad___024root___change_request -V{t#,#} CHANGE: t/t_unopt_converge_initial.v:19: x %Error: t/t_unopt_converge_initial.v:7: Verilated model didn't DC converge Aborting... diff --git a/test_regress/t/t_unopt_converge_print_bad.out b/test_regress/t/t_unopt_converge_print_bad.out index 0b271c309..800401d79 100644 --- a/test_regress/t/t_unopt_converge_print_bad.out +++ b/test_regress/t/t_unopt_converge_print_bad.out @@ -1,5 +1,5 @@ -V{t#,#}- Verilated::debug is on. Message prefix indicates {,}. --V{t#,#}+ Vt_unopt_converge_print_bad___change_request +-V{t#,#}+ Vt_unopt_converge_print_bad___024root___change_request -V{t#,#} CHANGE: t/t_unopt_converge.v:19: x %Error: t/t_unopt_converge.v:7: Verilated model didn't converge Aborting... diff --git a/test_regress/t/t_unopt_converge_run_bad.out b/test_regress/t/t_unopt_converge_run_bad.out index 362f65931..123a3e718 100644 --- a/test_regress/t/t_unopt_converge_run_bad.out +++ b/test_regress/t/t_unopt_converge_run_bad.out @@ -1,5 +1,5 @@ -V{t#,#}- Verilated::debug is on. Message prefix indicates {,}. --V{t#,#}+ Vt_unopt_converge_run_bad___change_request +-V{t#,#}+ Vt_unopt_converge_run_bad___024root___change_request -V{t#,#} CHANGE: t/t_unopt_converge.v:19: x %Error: t/t_unopt_converge.v:7: Verilated model didn't converge Aborting... diff --git a/test_regress/t/t_var_pins_cc.pl b/test_regress/t/t_var_pins_cc.pl index cdbb061e8..6c48aeee9 100755 --- a/test_regress/t/t_var_pins_cc.pl +++ b/test_regress/t/t_var_pins_cc.pl @@ -20,19 +20,19 @@ compile( ); { - file_grep("$Self->{obj_dir}/Vt_var_pins_cc.h", qr/VL_IN8 \(i1,0,0\);/x); - file_grep("$Self->{obj_dir}/Vt_var_pins_cc.h", qr/VL_IN8 \(i8,7,0\);/x); - file_grep("$Self->{obj_dir}/Vt_var_pins_cc.h", qr/VL_IN16 \(i16,15,0\);/x); - file_grep("$Self->{obj_dir}/Vt_var_pins_cc.h", qr/VL_IN \(i32,31,0\);/x); - file_grep("$Self->{obj_dir}/Vt_var_pins_cc.h", qr/VL_IN64 \(i64,63,0\);/x); - file_grep("$Self->{obj_dir}/Vt_var_pins_cc.h", qr/VL_INW \(i65,64,0,3\);/x); + file_grep("$Self->{obj_dir}/Vt_var_pins_cc.h", qr/VL_IN8 \(&i1,0,0\);/x); + file_grep("$Self->{obj_dir}/Vt_var_pins_cc.h", qr/VL_IN8 \(&i8,7,0\);/x); + file_grep("$Self->{obj_dir}/Vt_var_pins_cc.h", qr/VL_IN16 \(&i16,15,0\);/x); + file_grep("$Self->{obj_dir}/Vt_var_pins_cc.h", qr/VL_IN \(&i32,31,0\);/x); + file_grep("$Self->{obj_dir}/Vt_var_pins_cc.h", qr/VL_IN64 \(&i64,63,0\);/x); + file_grep("$Self->{obj_dir}/Vt_var_pins_cc.h", qr/VL_INW \(\(&i65\),64,0,3\);/x); - file_grep("$Self->{obj_dir}/Vt_var_pins_cc.h", qr/VL_OUT8 \(o1,0,0\);/x); - file_grep("$Self->{obj_dir}/Vt_var_pins_cc.h", qr/VL_OUT8 \(o8,7,0\);/x); - file_grep("$Self->{obj_dir}/Vt_var_pins_cc.h", qr/VL_OUT16\(o16,15,0\);/x); - file_grep("$Self->{obj_dir}/Vt_var_pins_cc.h", qr/VL_OUT \(o32,31,0\);/x); - file_grep("$Self->{obj_dir}/Vt_var_pins_cc.h", qr/VL_OUT64\(o64,63,0\);/x); - file_grep("$Self->{obj_dir}/Vt_var_pins_cc.h", qr/VL_OUTW \(o65,64,0,3\);/x); + file_grep("$Self->{obj_dir}/Vt_var_pins_cc.h", qr/VL_OUT8 \(&o1,0,0\);/x); + file_grep("$Self->{obj_dir}/Vt_var_pins_cc.h", qr/VL_OUT8 \(&o8,7,0\);/x); + file_grep("$Self->{obj_dir}/Vt_var_pins_cc.h", qr/VL_OUT16\(&o16,15,0\);/x); + file_grep("$Self->{obj_dir}/Vt_var_pins_cc.h", qr/VL_OUT \(&o32,31,0\);/x); + file_grep("$Self->{obj_dir}/Vt_var_pins_cc.h", qr/VL_OUT64\(&o64,63,0\);/x); + file_grep("$Self->{obj_dir}/Vt_var_pins_cc.h", qr/VL_OUTW \(\(&o65\),64,0,3\);/x); } ok(1); diff --git a/test_regress/t/t_var_pins_sc1.pl b/test_regress/t/t_var_pins_sc1.pl index 920eb8807..6e7485b34 100755 --- a/test_regress/t/t_var_pins_sc1.pl +++ b/test_regress/t/t_var_pins_sc1.pl @@ -18,27 +18,27 @@ compile( ); if ($Self->{vlt_all}) { - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ ibv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ ibv16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ ibv1_vlt;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ ibv16_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i8;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i32;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i64;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i65;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv1_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv16_vlt;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ obv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ obv16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ obv1_vlt;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ obv16_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o8;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o32;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o64;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o65;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv1_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv16_vlt;/x); } execute(); diff --git a/test_regress/t/t_var_pins_sc2.pl b/test_regress/t/t_var_pins_sc2.pl index c37403933..8edb72dbd 100755 --- a/test_regress/t/t_var_pins_sc2.pl +++ b/test_regress/t/t_var_pins_sc2.pl @@ -18,27 +18,27 @@ compile( ); { - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ i1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ ibv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ ibv16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ ibv1_vlt;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ ibv16_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i8;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i32;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i64;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i65;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv1_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv16_vlt;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ o1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ obv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ obv16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ obv1_vlt;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ obv16_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o8;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o32;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o64;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o65;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv1_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv16_vlt;/x); } execute(); diff --git a/test_regress/t/t_var_pins_sc32.pl b/test_regress/t/t_var_pins_sc32.pl index ed6db0cb3..6f202e8b5 100755 --- a/test_regress/t/t_var_pins_sc32.pl +++ b/test_regress/t/t_var_pins_sc32.pl @@ -18,27 +18,27 @@ compile( ); { - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ i1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ i8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ i16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ i32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ ibv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ ibv16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ ibv1_vlt;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ ibv16_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i8;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i32;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i64;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i65;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv1_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv16_vlt;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ o1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ o8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ o16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ o32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ obv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ obv16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ obv1_vlt;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ obv16_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o8;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o32;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o64;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o65;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv1_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv16_vlt;/x); } execute(); diff --git a/test_regress/t/t_var_pins_sc64.pl b/test_regress/t/t_var_pins_sc64.pl index cedf0208e..ec4a48b94 100755 --- a/test_regress/t/t_var_pins_sc64.pl +++ b/test_regress/t/t_var_pins_sc64.pl @@ -18,27 +18,27 @@ compile( ); if ($Self->{vlt_all}) { - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ i1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ i8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ i16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ i32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ i64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ ibv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ ibv16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ ibv1_vlt;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ ibv16_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i8;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i32;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i64;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i65;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv1_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv16_vlt;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ o1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ o8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ o16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ o32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ o64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ obv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ obv16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ obv1_vlt;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ obv16_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o8;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o32;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o64;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o65;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv1_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv16_vlt;/x); } execute(); diff --git a/test_regress/t/t_var_pins_sc_biguint.pl b/test_regress/t/t_var_pins_sc_biguint.pl index 42b06c465..bb64269ce 100755 --- a/test_regress/t/t_var_pins_sc_biguint.pl +++ b/test_regress/t/t_var_pins_sc_biguint.pl @@ -18,27 +18,27 @@ compile( ); if ($Self->{vlt_all}) { - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ i1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ i8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ i16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ i32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ i64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i128;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i513;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ ibv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ ibv16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i8;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i32;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i64;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i65;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i128;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i513;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ o1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ o8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ o16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ o32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ o64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o128;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o513;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ obv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ obv16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o8;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o32;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o64;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o65;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o128;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o513;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv16;/x); } execute(); diff --git a/test_regress/t/t_var_pins_sc_uint.pl b/test_regress/t/t_var_pins_sc_uint.pl index 28a2513b5..e7b965c3a 100755 --- a/test_regress/t/t_var_pins_sc_uint.pl +++ b/test_regress/t/t_var_pins_sc_uint.pl @@ -18,27 +18,27 @@ compile( ); { - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ i1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i128;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i513;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ ibv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ ibv16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i8;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i32;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i64;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i65;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i128;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i513;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ o1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o128;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o513;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ obv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ obv16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o8;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o32;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o64;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o65;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o128;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o513;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv16;/x); } execute(); diff --git a/test_regress/t/t_var_pins_sc_uint_biguint.pl b/test_regress/t/t_var_pins_sc_uint_biguint.pl index 363ec234c..64b7075a7 100755 --- a/test_regress/t/t_var_pins_sc_uint_biguint.pl +++ b/test_regress/t/t_var_pins_sc_uint_biguint.pl @@ -18,27 +18,27 @@ compile( ); { - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ i1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i128;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i513;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ ibv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ ibv16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i8;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i32;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i64;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i65;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i128;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i513;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ o1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o128;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o513;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ obv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ obv16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o8;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o32;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o64;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o65;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o128;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o513;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv16;/x); } execute(); diff --git a/test_regress/t/t_var_pins_scui.pl b/test_regress/t/t_var_pins_scui.pl index eac0b5e90..a28789078 100755 --- a/test_regress/t/t_var_pins_scui.pl +++ b/test_regress/t/t_var_pins_scui.pl @@ -18,23 +18,23 @@ compile( ); if ($Self->{vlt_all}) { - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ i1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ i8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ i16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ i32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ i64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ i65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ ibv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ ibv16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i8;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i32;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i64;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i65;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ o1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ o8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ o16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ o32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ o64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ o65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ obv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ obv16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o8;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o16;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o32;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o64;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o65;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv1;/x); + file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv16;/x); } execute(); diff --git a/test_regress/t/t_verilated_debug.out b/test_regress/t/t_verilated_debug.out index 0768fa5a6..5ac844a6b 100644 --- a/test_regress/t/t_verilated_debug.out +++ b/test_regress/t/t_verilated_debug.out @@ -1,30 +1,30 @@ -V{t#,#}- Verilated::debug is on. Message prefix indicates {,}. --V{t#,#}+ Vt_verilated_debug___ctor_var_reset +-V{t#,#}+ Vt_verilated_debug___024root___ctor_var_reset internalsDump: Version: Verilator ### Argv: obj_vlt/t_verilated_debug/Vt_verilated_debug scopesDump: -V{t#,#}+++++TOP Evaluate Vt_verilated_debug::eval_step --V{t#,#}+ Vt_verilated_debug___eval_debug_assertions --V{t#,#}+ Vt_verilated_debug___eval_initial --V{t#,#}+ Vt_verilated_debug___initial__TOP__1 +-V{t#,#}+ Vt_verilated_debug___024root___eval_debug_assertions +-V{t#,#}+ Vt_verilated_debug___024root___eval_initial +-V{t#,#}+ Vt_verilated_debug___024root___initial__TOP__1 Data: w96: 000000aa 000000bb 000000cc -V{t#,#}+ Initial loop --V{t#,#}+ Vt_verilated_debug___eval_settle --V{t#,#}+ Vt_verilated_debug___eval --V{t#,#}+ Vt_verilated_debug___change_request --V{t#,#}+ Vt_verilated_debug___change_request_1 +-V{t#,#}+ Vt_verilated_debug___024root___eval_settle +-V{t#,#}+ Vt_verilated_debug___024root___eval +-V{t#,#}+ Vt_verilated_debug___024root___change_request +-V{t#,#}+ Vt_verilated_debug___024root___change_request_1 -V{t#,#}+ Clock loop --V{t#,#}+ Vt_verilated_debug___eval --V{t#,#}+ Vt_verilated_debug___change_request --V{t#,#}+ Vt_verilated_debug___change_request_1 +-V{t#,#}+ Vt_verilated_debug___024root___eval +-V{t#,#}+ Vt_verilated_debug___024root___change_request +-V{t#,#}+ Vt_verilated_debug___024root___change_request_1 -V{t#,#}+++++TOP Evaluate Vt_verilated_debug::eval_step --V{t#,#}+ Vt_verilated_debug___eval_debug_assertions +-V{t#,#}+ Vt_verilated_debug___024root___eval_debug_assertions -V{t#,#}+ Clock loop --V{t#,#}+ Vt_verilated_debug___eval --V{t#,#}+ Vt_verilated_debug___sequent__TOP__2 +-V{t#,#}+ Vt_verilated_debug___024root___eval +-V{t#,#}+ Vt_verilated_debug___024root___sequent__TOP__2 *-* All Finished *-* --V{t#,#}+ Vt_verilated_debug___change_request --V{t#,#}+ Vt_verilated_debug___change_request_1 --V{t#,#}+ Vt_verilated_debug___final +-V{t#,#}+ Vt_verilated_debug___024root___change_request +-V{t#,#}+ Vt_verilated_debug___024root___change_request_1 +-V{t#,#}+ Vt_verilated_debug___024root___final diff --git a/test_regress/t/t_xml_flat.out b/test_regress/t/t_xml_flat.out index 853f82d5e..964c5b791 100644 --- a/test_regress/t/t_xml_flat.out +++ b/test_regress/t/t_xml_flat.out @@ -11,10 +11,10 @@ - + - + diff --git a/test_regress/t/t_xml_flat_no_inline_mod.out b/test_regress/t/t_xml_flat_no_inline_mod.out index 0ab79da52..e1d070bce 100644 --- a/test_regress/t/t_xml_flat_no_inline_mod.out +++ b/test_regress/t/t_xml_flat_no_inline_mod.out @@ -11,10 +11,10 @@ - + - + diff --git a/test_regress/t/t_xml_flat_pub_mod.out b/test_regress/t/t_xml_flat_pub_mod.out index 557437eb3..88b51b3ca 100644 --- a/test_regress/t/t_xml_flat_pub_mod.out +++ b/test_regress/t/t_xml_flat_pub_mod.out @@ -11,10 +11,10 @@ - + - + diff --git a/test_regress/t/t_xml_flat_vlvbound.out b/test_regress/t/t_xml_flat_vlvbound.out index 86271d4b1..28a1c9e97 100644 --- a/test_regress/t/t_xml_flat_vlvbound.out +++ b/test_regress/t/t_xml_flat_vlvbound.out @@ -11,10 +11,10 @@ - + - +