Merge branch 'master' into develop-v5
This commit is contained in:
commit
c9ac9a75a6
3
Changes
3
Changes
|
|
@ -24,6 +24,9 @@ Verilator 4.225 devel
|
||||||
|
|
||||||
**Minor:**
|
**Minor:**
|
||||||
|
|
||||||
|
* Fix incorrect bit op tree optimization (#3470). [algrobman]
|
||||||
|
* Fix empty string arguments to display (#3484). [Grulfen]
|
||||||
|
* Fix table misoptimizing away display (#3488). [Stefan Post]
|
||||||
|
|
||||||
|
|
||||||
Verilator 4.224 2022-06-19
|
Verilator 4.224 2022-06-19
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ Alex Chadwick
|
||||||
Aliaksei Chapyzhenka
|
Aliaksei Chapyzhenka
|
||||||
Ameya Vikram Singh
|
Ameya Vikram Singh
|
||||||
Andreas Kuster
|
Andreas Kuster
|
||||||
|
Arkadiusz Kozdra
|
||||||
Chris Randall
|
Chris Randall
|
||||||
Chuxuan Wang
|
Chuxuan Wang
|
||||||
Conor McCullough
|
Conor McCullough
|
||||||
|
|
|
||||||
|
|
@ -86,61 +86,17 @@ Connecting to C++
|
||||||
In C++ output mode (:vlopt:`--cc`), the Verilator generated model class is a
|
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
|
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
|
simulation, which instantiates the model class, and link with the Verilated
|
||||||
model. Here is a simple example:
|
model.
|
||||||
|
|
||||||
.. code-block:: C++
|
Refer to ``examples/make_tracing_c`` in the distribution for a detailed
|
||||||
|
commented example.
|
||||||
|
|
||||||
#include <verilated.h> // Defines common routines
|
Top level IO signals are read and written as members of the model. You
|
||||||
#include <iostream> // Need std::cout
|
call the model's :code:`eval()` method to evaluate the model. When the
|
||||||
#include "Vtop.h" // From Verilating "top.v"
|
simulation is complete call the model's :code:`final()` method to execute
|
||||||
|
any SystemVerilog final blocks, and complete any assertions. See
|
||||||
|
:ref:`Evaluation Loop`.
|
||||||
|
|
||||||
Vtop *top; // Instantiation of model
|
|
||||||
|
|
||||||
uint64_t main_time = 0; // Current simulation time
|
|
||||||
// This is a 64-bit integer to reduce wrap over issues and
|
|
||||||
// allow modulus. This is in units of the timeprecision
|
|
||||||
// used in Verilog (or from --timescale-override)
|
|
||||||
|
|
||||||
double sc_time_stamp() { // Called by $time in Verilog
|
|
||||||
return main_time; // converts to double, to match
|
|
||||||
// what SystemC does
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
|
||||||
Verilated::commandArgs(argc, argv); // Remember args
|
|
||||||
|
|
||||||
top = new Vtop; // Create model
|
|
||||||
// Do not instead make Vtop as a file-scope static
|
|
||||||
// variable, as the "C++ static initialization order fiasco"
|
|
||||||
// may cause a crash
|
|
||||||
|
|
||||||
top->reset_l = 0; // Set some inputs
|
|
||||||
|
|
||||||
while (!Verilated::gotFinish()) {
|
|
||||||
if (main_time > 10) {
|
|
||||||
top->reset_l = 1; // Deassert reset
|
|
||||||
}
|
|
||||||
if ((main_time % 10) == 1) {
|
|
||||||
top->clk = 1; // Toggle clock
|
|
||||||
}
|
|
||||||
if ((main_time % 10) == 6) {
|
|
||||||
top->clk = 0;
|
|
||||||
}
|
|
||||||
top->eval(); // Evaluate model
|
|
||||||
cout << top->out << endl; // Read a output
|
|
||||||
main_time++; // Time passes...
|
|
||||||
}
|
|
||||||
|
|
||||||
top->final(); // Done simulating
|
|
||||||
// // (Though this example doesn't get here)
|
|
||||||
delete top;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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
|
Connecting to SystemC
|
||||||
|
|
@ -449,14 +405,15 @@ accesses the above signal "readme" would be:
|
||||||
|
|
||||||
int main(int argc, char** argv, char** env) {
|
int main(int argc, char** argv, char** env) {
|
||||||
Verilated::commandArgs(argc, argv);
|
Verilated::commandArgs(argc, argv);
|
||||||
Vour* top = new Vour;
|
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||||
Verilated::internalsDump(); // See scopes to help debug
|
const std::unique_ptr<Vour> top{new Vour{contextp.get()}};
|
||||||
while (!Verilated::gotFinish()) {
|
|
||||||
|
contextp->internalsDump(); // See scopes to help debug
|
||||||
|
while (!contextp->gotFinish()) {
|
||||||
top->eval();
|
top->eval();
|
||||||
VerilatedVpi::callValueCbs(); // For signal callbacks
|
VerilatedVpi::callValueCbs(); // For signal callbacks
|
||||||
read_and_check();
|
read_and_check();
|
||||||
}
|
}
|
||||||
delete top;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ Simulation Runtime Arguments
|
||||||
|
|
||||||
The following are the arguments that may be passed to a Verilated
|
The following are the arguments that may be passed to a Verilated
|
||||||
executable, provided that executable calls
|
executable, provided that executable calls
|
||||||
:code:`Verilated::commandArgs()`.
|
:code:`VerilatedContext*->commandArgs(argc, argv)`.
|
||||||
|
|
||||||
All simulation runtime arguments begin with "+verilator", so that the
|
All simulation runtime arguments begin with "+verilator", so that the
|
||||||
user's executable may skip over all "+verilator" arguments when parsing its
|
user's executable may skip over all "+verilator" arguments when parsing its
|
||||||
|
|
@ -96,7 +96,7 @@ Summary:
|
||||||
.. option:: +verilator+noassert
|
.. option:: +verilator+noassert
|
||||||
|
|
||||||
Disable assert checking per runtime argument. This is the same as
|
Disable assert checking per runtime argument. This is the same as
|
||||||
calling :code:`Verilated::assertOn(false)` in the model.
|
calling :code:`VerilatedContext*->assertOn(false)` in the model.
|
||||||
|
|
||||||
.. option:: +verilator+V
|
.. option:: +verilator+V
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -478,7 +478,7 @@ $test$plusargs, $value$plusargs
|
||||||
|
|
||||||
.. code-block:: C++
|
.. code-block:: C++
|
||||||
|
|
||||||
Verilated::commandArgs(argc, argv);
|
{VerilatedContext*} ->commandArgs(argc, argv);
|
||||||
|
|
||||||
to register the command line before calling $test$plusargs or
|
to register the command line before calling $test$plusargs or
|
||||||
$value$plusargs.
|
$value$plusargs.
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,14 @@ int main(int argc, char** argv, char** env) {
|
||||||
// Prevent unused variable warnings
|
// Prevent unused variable warnings
|
||||||
if (false && argc && argv && env) {}
|
if (false && argc && argv && env) {}
|
||||||
|
|
||||||
|
// Construct a VerilatedContext to hold simulation time, etc.
|
||||||
|
VerilatedContext* contextp = new VerilatedContext;
|
||||||
|
|
||||||
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v"
|
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v"
|
||||||
Vtop* top = new Vtop;
|
Vtop* top = new Vtop{contextp};
|
||||||
|
|
||||||
// Simulate until $finish
|
// Simulate until $finish
|
||||||
while (!Verilated::gotFinish()) {
|
while (!contextp->gotFinish()) {
|
||||||
|
|
||||||
// Evaluate model
|
// Evaluate model
|
||||||
top->eval();
|
top->eval();
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,10 @@
|
||||||
#if defined(_WIN32) || defined(__MINGW32__)
|
#if defined(_WIN32) || defined(__MINGW32__)
|
||||||
# include <direct.h> // mkdir
|
# include <direct.h> // mkdir
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef VL_THREADED
|
||||||
|
# include "verilated_threads.h"
|
||||||
|
#endif
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
// Max characters in static char string for VL_VALUE_STRING
|
// Max characters in static char string for VL_VALUE_STRING
|
||||||
|
|
@ -1606,8 +1610,8 @@ IData VL_SYSTEM_IW(int lhswords, const WDataInP lhsp) VL_MT_SAFE {
|
||||||
return code >> 8; // Want exit status
|
return code >> 8; // Want exit status
|
||||||
}
|
}
|
||||||
|
|
||||||
IData VL_TESTPLUSARGS_I(const char* formatp) VL_MT_SAFE {
|
IData VL_TESTPLUSARGS_I(const std::string& format) VL_MT_SAFE {
|
||||||
const std::string& match = Verilated::threadContextp()->impp()->argPlusMatch(formatp);
|
const std::string& match = Verilated::threadContextp()->impp()->argPlusMatch(format.c_str());
|
||||||
return match.empty() ? 0 : 1;
|
return match.empty() ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2428,6 +2432,33 @@ const char* VerilatedContext::timeprecisionString() const VL_MT_SAFE {
|
||||||
return vl_time_str(timeprecision());
|
return vl_time_str(timeprecision());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VerilatedContext::threads(unsigned n) {
|
||||||
|
if (n == 0) VL_FATAL_MT(__FILE__, __LINE__, "", "%Error: Simulation threads must be >= 1");
|
||||||
|
|
||||||
|
if (m_threadPool) {
|
||||||
|
VL_FATAL_MT(
|
||||||
|
__FILE__, __LINE__, "",
|
||||||
|
"%Error: Cannot set simulation threads after the thread pool has been created.");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if VL_THREADED
|
||||||
|
if (m_threads == n) return; // To avoid unnecessary warnings
|
||||||
|
m_threads = n;
|
||||||
|
const unsigned hardwareThreadsAvailable = std::thread::hardware_concurrency();
|
||||||
|
if (m_threads > hardwareThreadsAvailable) {
|
||||||
|
VL_PRINTF_MT("%%Warning: System has %u hardware threads but simulation thread count set "
|
||||||
|
"to %u. This will likely cause significant slowdown.\n",
|
||||||
|
hardwareThreadsAvailable, m_threads);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (n > 1) {
|
||||||
|
VL_PRINTF_MT("%%Warning: Verilator run-time library built without VL_THREADS. Ignoring "
|
||||||
|
"call to 'VerilatedContext::threads' with argument %u.\n",
|
||||||
|
n);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void VerilatedContext::commandArgs(int argc, const char** argv) VL_MT_SAFE_EXCLUDES(m_argMutex) {
|
void VerilatedContext::commandArgs(int argc, const char** argv) VL_MT_SAFE_EXCLUDES(m_argMutex) {
|
||||||
const VerilatedLockGuard lock{m_argMutex};
|
const VerilatedLockGuard lock{m_argMutex};
|
||||||
m_args.m_argVec.clear(); // Empty first, then add
|
m_args.m_argVec.clear(); // Empty first, then add
|
||||||
|
|
@ -2458,6 +2489,33 @@ void VerilatedContext::internalsDump() const VL_MT_SAFE {
|
||||||
VerilatedImp::userDump();
|
VerilatedImp::userDump();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VerilatedContext::addModel(VerilatedModel* modelp) {
|
||||||
|
threadPoolp(); // Ensure thread pool is created, so m_threads cannot change any more
|
||||||
|
|
||||||
|
if (modelp->threads() > m_threads) {
|
||||||
|
std::ostringstream msg;
|
||||||
|
msg << "VerilatedContext has " << m_threads << " threads but model '"
|
||||||
|
<< modelp->modelName() << "' (instantiated as '" << modelp->hierName()
|
||||||
|
<< "') was Verilated with --threads " << modelp->threads() << ".\n";
|
||||||
|
const std::string str = msg.str();
|
||||||
|
VL_FATAL_MT(__FILE__, __LINE__, modelp->hierName(), str.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VerilatedVirtualBase* VerilatedContext::threadPoolp() {
|
||||||
|
if (m_threads == 1) return nullptr;
|
||||||
|
#if VL_THREADED
|
||||||
|
if (!m_threadPool) m_threadPool.reset(new VlThreadPool{this, m_threads - 1});
|
||||||
|
#endif
|
||||||
|
return m_threadPool.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
VerilatedVirtualBase*
|
||||||
|
VerilatedContext::enableExecutionProfiler(VerilatedVirtualBase* (*construct)(VerilatedContext&)) {
|
||||||
|
if (!m_executionProfiler) m_executionProfiler.reset(construct(*this));
|
||||||
|
return m_executionProfiler.get();
|
||||||
|
}
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
// VerilatedContextImp:: Methods - command line
|
// VerilatedContextImp:: Methods - command line
|
||||||
|
|
||||||
|
|
@ -2850,6 +2908,12 @@ void VerilatedImp::versionDump() VL_MT_SAFE {
|
||||||
VL_PRINTF_MT(" Version: %s %s\n", Verilated::productName(), Verilated::productVersion());
|
VL_PRINTF_MT(" Version: %s %s\n", Verilated::productName(), Verilated::productVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
// VerilatedModel:: Methods
|
||||||
|
|
||||||
|
VerilatedModel::VerilatedModel(VerilatedContext& context)
|
||||||
|
: m_context{context} {}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
// VerilatedModule:: Methods
|
// VerilatedModule:: Methods
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,7 @@
|
||||||
#endif
|
#endif
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
class VerilatedContext;
|
||||||
class VerilatedContextImp;
|
class VerilatedContextImp;
|
||||||
class VerilatedContextImpData;
|
class VerilatedContextImpData;
|
||||||
class VerilatedCovContext;
|
class VerilatedCovContext;
|
||||||
|
|
@ -252,6 +253,33 @@ public:
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
|
/// Base class of a Verilator generated (Verilated) model.
|
||||||
|
///
|
||||||
|
/// VerilatedModel is a base class of the user facing primary class generated
|
||||||
|
/// by Verilator.
|
||||||
|
|
||||||
|
class VerilatedModel VL_NOT_FINAL {
|
||||||
|
VL_UNCOPYABLE(VerilatedModel);
|
||||||
|
|
||||||
|
VerilatedContext& m_context; // The VerilatedContext this model is instantiated under
|
||||||
|
|
||||||
|
protected:
|
||||||
|
explicit VerilatedModel(VerilatedContext& context);
|
||||||
|
virtual ~VerilatedModel() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// Returns the VerilatedContext this model is instantiated under
|
||||||
|
/// Used to get to e.g. simulation time via contextp()->time()
|
||||||
|
inline VerilatedContext* contextp() const { return &m_context; }
|
||||||
|
/// Returns the hierarchical name of this module instance.
|
||||||
|
virtual const char* hierName() const = 0;
|
||||||
|
/// Returns the name of this model (the name of the generated model class).
|
||||||
|
virtual const char* modelName() const = 0;
|
||||||
|
/// Returns the thread level parallelism, this model was Verilated with. Always 1 or higher.
|
||||||
|
virtual unsigned threads() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
/// Base class for all Verilated module classes.
|
/// Base class for all Verilated module classes.
|
||||||
|
|
||||||
|
|
@ -266,10 +294,6 @@ public:
|
||||||
const char* name() const { return m_namep; } ///< Return name of module
|
const char* name() const { return m_namep; } ///< Return name of module
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Declare a module, ala SC_MODULE
|
|
||||||
#define VL_MODULE(modname) class modname VL_NOT_FINAL : public VerilatedModule
|
|
||||||
// Not class final in VL_MODULE, as users might be abstracting our models (--hierarchical)
|
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
// Functions overridable by user defines
|
// Functions overridable by user defines
|
||||||
// (Internals however must use VL_PRINTF_MT, which calls these.)
|
// (Internals however must use VL_PRINTF_MT, which calls these.)
|
||||||
|
|
@ -362,6 +386,16 @@ protected:
|
||||||
|
|
||||||
// Implementation details
|
// Implementation details
|
||||||
const std::unique_ptr<VerilatedContextImpData> m_impdatap;
|
const std::unique_ptr<VerilatedContextImpData> m_impdatap;
|
||||||
|
// Number of threads to use for simulation (size of m_threadPool + 1 for main thread)
|
||||||
|
#ifdef VL_THREADED
|
||||||
|
unsigned m_threads = std::thread::hardware_concurrency();
|
||||||
|
#else
|
||||||
|
const unsigned m_threads = 1;
|
||||||
|
#endif
|
||||||
|
// The thread pool shared by all models added to this context
|
||||||
|
std::unique_ptr<VerilatedVirtualBase> m_threadPool;
|
||||||
|
// The execution profiler shared by all models added to this context
|
||||||
|
std::unique_ptr<VerilatedVirtualBase> m_executionProfiler;
|
||||||
// Coverage access
|
// Coverage access
|
||||||
std::unique_ptr<VerilatedVirtualBase> m_coveragep; // Pointer for coveragep()
|
std::unique_ptr<VerilatedVirtualBase> m_coveragep; // Pointer for coveragep()
|
||||||
|
|
||||||
|
|
@ -495,6 +529,12 @@ public:
|
||||||
/// Get time precision as IEEE-standard text
|
/// Get time precision as IEEE-standard text
|
||||||
const char* timeprecisionString() const VL_MT_SAFE;
|
const char* timeprecisionString() const VL_MT_SAFE;
|
||||||
|
|
||||||
|
/// Get number of threads used for simulation (including the main thread)
|
||||||
|
unsigned threads() const { return m_threads; }
|
||||||
|
/// Set number of threads used for simulation (including the main thread)
|
||||||
|
/// Can only be called before the thread pool is created (before first model is added).
|
||||||
|
void threads(unsigned n);
|
||||||
|
|
||||||
/// Allow traces to at some point be enabled (disables some optimizations)
|
/// Allow traces to at some point be enabled (disables some optimizations)
|
||||||
void traceEverOn(bool flag) VL_MT_SAFE {
|
void traceEverOn(bool flag) VL_MT_SAFE {
|
||||||
if (flag) calcUnusedSigs(true);
|
if (flag) calcUnusedSigs(true);
|
||||||
|
|
@ -517,6 +557,12 @@ public: // But for internal use only
|
||||||
return reinterpret_cast<const VerilatedContextImp*>(this);
|
return reinterpret_cast<const VerilatedContextImp*>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addModel(VerilatedModel*);
|
||||||
|
|
||||||
|
VerilatedVirtualBase* threadPoolp();
|
||||||
|
VerilatedVirtualBase*
|
||||||
|
enableExecutionProfiler(VerilatedVirtualBase* (*construct)(VerilatedContext&));
|
||||||
|
|
||||||
// Internal: $dumpfile
|
// Internal: $dumpfile
|
||||||
void dumpfile(const std::string& flag) VL_MT_SAFE_EXCLUDES(m_timeDumpMutex);
|
void dumpfile(const std::string& flag) VL_MT_SAFE_EXCLUDES(m_timeDumpMutex);
|
||||||
std::string dumpfile() const VL_MT_SAFE_EXCLUDES(m_timeDumpMutex);
|
std::string dumpfile() const VL_MT_SAFE_EXCLUDES(m_timeDumpMutex);
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,7 @@ extern IData VL_SYSTEM_IW(int lhswords, WDataInP const lhsp);
|
||||||
extern IData VL_SYSTEM_IQ(QData lhs);
|
extern IData VL_SYSTEM_IQ(QData lhs);
|
||||||
inline IData VL_SYSTEM_II(IData lhs) VL_MT_SAFE { return VL_SYSTEM_IQ(lhs); }
|
inline IData VL_SYSTEM_II(IData lhs) VL_MT_SAFE { return VL_SYSTEM_IQ(lhs); }
|
||||||
|
|
||||||
extern IData VL_TESTPLUSARGS_I(const char* formatp);
|
extern IData VL_TESTPLUSARGS_I(const std::string& format);
|
||||||
extern const char* vl_mc_scan_plusargs(const char* prefixp); // PLIish
|
extern const char* vl_mc_scan_plusargs(const char* prefixp); // PLIish
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
|
|
|
||||||
|
|
@ -66,41 +66,66 @@ template <size_t N> static size_t roundUptoMultipleOf(size_t value) {
|
||||||
return (value + mask) & ~mask;
|
return (value + mask) & ~mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
VlExecutionProfiler::VlExecutionProfiler() {
|
VlExecutionProfiler::VlExecutionProfiler(VerilatedContext& context)
|
||||||
|
: m_context{context} {
|
||||||
// Setup profiling on main thread
|
// Setup profiling on main thread
|
||||||
setupThread(0);
|
setupThread(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VlExecutionProfiler::configure(const VerilatedContext& context) {
|
void VlExecutionProfiler::configure() {
|
||||||
|
|
||||||
if (VL_UNLIKELY(m_enabled)) {
|
if (VL_UNLIKELY(m_enabled)) {
|
||||||
--m_windowCount;
|
--m_windowCount;
|
||||||
if (VL_UNLIKELY(m_windowCount == context.profExecWindow())) {
|
if (VL_UNLIKELY(m_windowCount == m_context.profExecWindow())) {
|
||||||
VL_DEBUG_IF(VL_DBG_MSGF("+ profile start collection\n"););
|
VL_DEBUG_IF(VL_DBG_MSGF("+ profile start collection\n"););
|
||||||
clear(); // Clear the profile after the cache warm-up cycles.
|
clear(); // Clear the profile after the cache warm-up cycles.
|
||||||
m_tickBegin = VL_CPU_TICK();
|
m_tickBegin = VL_CPU_TICK();
|
||||||
} else if (VL_UNLIKELY(m_windowCount == 0)) {
|
} else if (VL_UNLIKELY(m_windowCount == 0)) {
|
||||||
const uint64_t tickEnd = VL_CPU_TICK();
|
const uint64_t tickEnd = VL_CPU_TICK();
|
||||||
VL_DEBUG_IF(VL_DBG_MSGF("+ profile end\n"););
|
VL_DEBUG_IF(VL_DBG_MSGF("+ profile end\n"););
|
||||||
const std::string& fileName = context.profExecFilename();
|
const std::string& fileName = m_context.profExecFilename();
|
||||||
dump(fileName.c_str(), tickEnd);
|
dump(fileName.c_str(), tickEnd);
|
||||||
m_enabled = false;
|
m_enabled = false;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint64_t startReq = context.profExecStart() + 1; // + 1, so we can start at time 0
|
const uint64_t startReq = m_context.profExecStart() + 1; // + 1, so we can start at time 0
|
||||||
|
|
||||||
if (VL_UNLIKELY(m_lastStartReq < startReq && VL_TIME_Q() >= context.profExecStart())) {
|
if (VL_UNLIKELY(m_lastStartReq < startReq && VL_TIME_Q() >= m_context.profExecStart())) {
|
||||||
VL_DEBUG_IF(VL_DBG_MSGF("+ profile start warmup\n"););
|
VL_DEBUG_IF(VL_DBG_MSGF("+ profile start warmup\n"););
|
||||||
VL_DEBUG_IF(assert(m_windowCount == 0););
|
VL_DEBUG_IF(assert(m_windowCount == 0););
|
||||||
m_enabled = true;
|
m_enabled = true;
|
||||||
m_windowCount = context.profExecWindow() * 2;
|
m_windowCount = m_context.profExecWindow() * 2;
|
||||||
m_lastStartReq = startReq;
|
m_lastStartReq = startReq;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VlExecutionProfiler::startWorkerSetup(VlExecutionProfiler* profilep, uint32_t threadId) {
|
VerilatedVirtualBase* VlExecutionProfiler::construct(VerilatedContext& context) {
|
||||||
profilep->setupThread(threadId);
|
VlExecutionProfiler* const selfp = new VlExecutionProfiler{context};
|
||||||
|
#if VL_THREADED
|
||||||
|
if (VlThreadPool* const threadPoolp = static_cast<VlThreadPool*>(context.threadPoolp())) {
|
||||||
|
for (int i = 0; i < threadPoolp->numThreads(); ++i) {
|
||||||
|
// Data to pass to worker thread initialization
|
||||||
|
struct Data {
|
||||||
|
VlExecutionProfiler* const selfp;
|
||||||
|
const uint32_t threadId;
|
||||||
|
} data{selfp, static_cast<uint32_t>(i + 1)};
|
||||||
|
|
||||||
|
// Initialize worker thread
|
||||||
|
threadPoolp->workerp(i)->addTask(
|
||||||
|
[](void* userp, bool) {
|
||||||
|
Data* const datap = static_cast<Data*>(userp);
|
||||||
|
datap->selfp->setupThread(datap->threadId);
|
||||||
|
},
|
||||||
|
&data);
|
||||||
|
|
||||||
|
// Wait until initializationis complete
|
||||||
|
threadPoolp->workerp(i)->wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return selfp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VlExecutionProfiler::setupThread(uint32_t threadId) {
|
void VlExecutionProfiler::setupThread(uint32_t threadId) {
|
||||||
|
|
@ -108,10 +133,13 @@ void VlExecutionProfiler::setupThread(uint32_t threadId) {
|
||||||
// while profiling.
|
// while profiling.
|
||||||
t_trace.reserve(RESERVED_TRACE_CAPACITY);
|
t_trace.reserve(RESERVED_TRACE_CAPACITY);
|
||||||
// Register thread-local buffer in list of all buffers
|
// Register thread-local buffer in list of all buffers
|
||||||
|
bool exists;
|
||||||
{
|
{
|
||||||
const VerilatedLockGuard lock{m_mutex};
|
const VerilatedLockGuard lock{m_mutex};
|
||||||
bool exists = !m_traceps.emplace(threadId, &t_trace).second;
|
exists = !m_traceps.emplace(threadId, &t_trace).second;
|
||||||
assert(!exists);
|
}
|
||||||
|
if (VL_UNLIKELY(exists)) {
|
||||||
|
VL_FATAL_MT(__FILE__, __LINE__, "", "multiple initialization of profiler on some thread");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,13 +33,14 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class VlExecutionProfiler;
|
class VlExecutionProfiler;
|
||||||
|
class VlThreadPool;
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// Macros to simplify generated code
|
// Macros to simplify generated code
|
||||||
|
|
||||||
#define VL_EXEC_TRACE_ADD_RECORD(vlSymsp) \
|
#define VL_EXEC_TRACE_ADD_RECORD(vlSymsp) \
|
||||||
if (VL_UNLIKELY((vlSymsp)->__Vm_executionProfiler.enabled())) \
|
if (VL_UNLIKELY((vlSymsp)->__Vm_executionProfilerp->enabled())) \
|
||||||
(vlSymsp)->__Vm_executionProfiler.addRecord()
|
(vlSymsp)->__Vm_executionProfilerp->addRecord()
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// Return high-precision counter for profiling, or 0x0 if not available
|
// Return high-precision counter for profiling, or 0x0 if not available
|
||||||
|
|
@ -131,7 +132,7 @@ static_assert(std::is_trivially_destructible<VlExecutionRecord>::value,
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// VlExecutionProfiler is for collecting profiling data about model execution
|
// VlExecutionProfiler is for collecting profiling data about model execution
|
||||||
|
|
||||||
class VlExecutionProfiler final {
|
class VlExecutionProfiler final : public VerilatedVirtualBase {
|
||||||
// CONSTANTS
|
// CONSTANTS
|
||||||
|
|
||||||
// In order to try to avoid dynamic memory allocations during the actual profiling phase,
|
// In order to try to avoid dynamic memory allocations during the actual profiling phase,
|
||||||
|
|
@ -149,6 +150,7 @@ class VlExecutionProfiler final {
|
||||||
using ExecutionTrace = std::vector<VlExecutionRecord>;
|
using ExecutionTrace = std::vector<VlExecutionRecord>;
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
|
VerilatedContext& m_context; // The context this profiler is under
|
||||||
static VL_THREAD_LOCAL ExecutionTrace t_trace; // thread-local trace buffers
|
static VL_THREAD_LOCAL ExecutionTrace t_trace; // thread-local trace buffers
|
||||||
mutable VerilatedMutex m_mutex;
|
mutable VerilatedMutex m_mutex;
|
||||||
// Map from thread id to &t_trace of given thread
|
// Map from thread id to &t_trace of given thread
|
||||||
|
|
@ -162,7 +164,8 @@ class VlExecutionProfiler final {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTOR
|
// CONSTRUCTOR
|
||||||
VlExecutionProfiler();
|
explicit VlExecutionProfiler(VerilatedContext& context);
|
||||||
|
virtual ~VlExecutionProfiler() = default;
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
|
|
||||||
|
|
@ -174,7 +177,7 @@ public:
|
||||||
return t_trace.back();
|
return t_trace.back();
|
||||||
}
|
}
|
||||||
// Configure profiler (called in beginning of 'eval')
|
// Configure profiler (called in beginning of 'eval')
|
||||||
void configure(const VerilatedContext&);
|
void configure();
|
||||||
// Setup profiling on a particular thread;
|
// Setup profiling on a particular thread;
|
||||||
void setupThread(uint32_t threadId);
|
void setupThread(uint32_t threadId);
|
||||||
// Clear all profiling data
|
// Clear all profiling data
|
||||||
|
|
@ -182,8 +185,8 @@ public:
|
||||||
// Write profiling data into file
|
// Write profiling data into file
|
||||||
void dump(const char* filenamep, uint64_t tickEnd) VL_MT_SAFE_EXCLUDES(m_mutex);
|
void dump(const char* filenamep, uint64_t tickEnd) VL_MT_SAFE_EXCLUDES(m_mutex);
|
||||||
|
|
||||||
// Called via VlStartWorkerCb in VlWorkerThread::startWorker
|
// Passed to VerilatedContext to create the VlExecutionProfiler profiler instance
|
||||||
static void startWorkerSetup(VlExecutionProfiler* profilep, uint32_t threadId);
|
static VerilatedVirtualBase* construct(VerilatedContext& context);
|
||||||
};
|
};
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
|
||||||
|
|
@ -47,11 +47,9 @@ VlMTaskVertex::VlMTaskVertex(uint32_t upstreamDepCount)
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// VlWorkerThread
|
// VlWorkerThread
|
||||||
|
|
||||||
VlWorkerThread::VlWorkerThread(uint32_t threadId, VerilatedContext* contextp,
|
VlWorkerThread::VlWorkerThread(VerilatedContext* contextp)
|
||||||
VlExecutionProfiler* profilerp, VlStartWorkerCb startCb)
|
|
||||||
: m_ready_size{0}
|
: m_ready_size{0}
|
||||||
, m_cthread{startWorker, this, threadId, profilerp, startCb}
|
, m_cthread{startWorker, this, contextp} {}
|
||||||
, m_contextp{contextp} {}
|
|
||||||
|
|
||||||
VlWorkerThread::~VlWorkerThread() {
|
VlWorkerThread::~VlWorkerThread() {
|
||||||
shutdown();
|
shutdown();
|
||||||
|
|
@ -59,47 +57,49 @@ VlWorkerThread::~VlWorkerThread() {
|
||||||
m_cthread.join();
|
m_cthread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VlWorkerThread::shutdownTask(void*, bool) {
|
static void shutdownTask(void*, bool) {
|
||||||
// Deliberately empty, we use the address of this function as a magic number
|
// Deliberately empty, we use the address of this function as a magic number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VlWorkerThread::shutdown() { addTask(shutdownTask, nullptr); }
|
||||||
|
|
||||||
|
void VlWorkerThread::wait() {
|
||||||
|
// Enqueue a task that sets this flag. Execution is in-order so this ensures completion.
|
||||||
|
std::atomic<bool> flag{false};
|
||||||
|
addTask([](void* flagp, bool) { static_cast<std::atomic<bool>*>(flagp)->store(true); }, &flag);
|
||||||
|
// Spin wait
|
||||||
|
for (unsigned i = 0; i < VL_LOCK_SPINS; ++i) {
|
||||||
|
if (flag.load()) return;
|
||||||
|
VL_CPU_RELAX();
|
||||||
|
}
|
||||||
|
// Yield wait
|
||||||
|
while (!flag.load()) std::this_thread::yield();
|
||||||
|
}
|
||||||
|
|
||||||
void VlWorkerThread::workerLoop() {
|
void VlWorkerThread::workerLoop() {
|
||||||
ExecRec work;
|
ExecRec work;
|
||||||
|
|
||||||
|
// Wait for the first task without spinning, in case the thread is never actually used.
|
||||||
|
dequeWork</* SpinWait: */ false>(&work);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
dequeWork(&work);
|
|
||||||
if (VL_UNLIKELY(work.m_fnp == shutdownTask)) break;
|
if (VL_UNLIKELY(work.m_fnp == shutdownTask)) break;
|
||||||
work.m_fnp(work.m_selfp, work.m_evenCycle);
|
work.m_fnp(work.m_selfp, work.m_evenCycle);
|
||||||
|
// Wait for next task with spinning.
|
||||||
|
dequeWork</* SpinWait: */ true>(&work);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VlWorkerThread::startWorker(VlWorkerThread* workerp, uint32_t threadId,
|
void VlWorkerThread::startWorker(VlWorkerThread* workerp, VerilatedContext* contextp) {
|
||||||
VlExecutionProfiler* profilerp, VlStartWorkerCb startCb) {
|
Verilated::threadContextp(contextp);
|
||||||
Verilated::threadContextp(workerp->m_contextp);
|
|
||||||
if (VL_UNLIKELY(startCb)) startCb(profilerp, threadId);
|
|
||||||
workerp->workerLoop();
|
workerp->workerLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// VlThreadPool
|
// VlThreadPool
|
||||||
|
|
||||||
VlThreadPool::VlThreadPool(VerilatedContext* contextp, int nThreads,
|
VlThreadPool::VlThreadPool(VerilatedContext* contextp, unsigned nThreads) {
|
||||||
VlExecutionProfiler* profilerp, VlStartWorkerCb startCb) {
|
for (unsigned i = 0; i < nThreads; ++i) m_workers.push_back(new VlWorkerThread{contextp});
|
||||||
// --threads N passes nThreads=N-1, as the "main" threads counts as 1
|
|
||||||
++nThreads;
|
|
||||||
const unsigned cpus = std::thread::hardware_concurrency();
|
|
||||||
if (cpus < nThreads) {
|
|
||||||
static int warnedOnce = 0;
|
|
||||||
if (!warnedOnce++) {
|
|
||||||
VL_PRINTF_MT("%%Warning: System has %u CPUs but model Verilated with"
|
|
||||||
" --threads %d; may run slow.\n",
|
|
||||||
cpus, nThreads);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Create worker threads
|
|
||||||
for (uint32_t threadId = 1; threadId < nThreads; ++threadId) {
|
|
||||||
m_workers.push_back(new VlWorkerThread{threadId, contextp, profilerp, startCb});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VlThreadPool::~VlThreadPool() {
|
VlThreadPool::~VlThreadPool() {
|
||||||
|
|
|
||||||
|
|
@ -60,9 +60,6 @@ using VlSelfP = void*;
|
||||||
|
|
||||||
using VlExecFnp = void (*)(VlSelfP, bool);
|
using VlExecFnp = void (*)(VlSelfP, bool);
|
||||||
|
|
||||||
// VlWorkerThread::startWorker callback, used to hook in VlExecutionProfiler
|
|
||||||
using VlStartWorkerCb = void (*)(VlExecutionProfiler*, uint32_t threadId);
|
|
||||||
|
|
||||||
// Track dependencies for a single MTask.
|
// Track dependencies for a single MTask.
|
||||||
class VlMTaskVertex final {
|
class VlMTaskVertex final {
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
|
|
@ -166,24 +163,23 @@ private:
|
||||||
std::atomic<size_t> m_ready_size;
|
std::atomic<size_t> m_ready_size;
|
||||||
|
|
||||||
std::thread m_cthread; // Underlying C++ thread record
|
std::thread m_cthread; // Underlying C++ thread record
|
||||||
VerilatedContext* const m_contextp; // Context for spawned thread
|
|
||||||
|
|
||||||
VL_UNCOPYABLE(VlWorkerThread);
|
VL_UNCOPYABLE(VlWorkerThread);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
explicit VlWorkerThread(uint32_t threadId, VerilatedContext* contextp,
|
explicit VlWorkerThread(VerilatedContext* contextp);
|
||||||
VlExecutionProfiler* profilerp, VlStartWorkerCb startCb);
|
|
||||||
~VlWorkerThread();
|
~VlWorkerThread();
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
|
template <bool SpinWait> //
|
||||||
inline void dequeWork(ExecRec* workp) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
inline void dequeWork(ExecRec* workp) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
// Spin for a while, waiting for new data
|
// Spin for a while, waiting for new data
|
||||||
for (int i = 0; i < VL_LOCK_SPINS; ++i) {
|
if VL_CONSTEXPR_CXX17 (SpinWait) {
|
||||||
if (VL_LIKELY(m_ready_size.load(std::memory_order_relaxed))) { //
|
for (unsigned i = 0; i < VL_LOCK_SPINS; ++i) {
|
||||||
break;
|
if (VL_LIKELY(m_ready_size.load(std::memory_order_relaxed))) break;
|
||||||
|
VL_CPU_RELAX();
|
||||||
}
|
}
|
||||||
VL_CPU_RELAX();
|
|
||||||
}
|
}
|
||||||
VerilatedLockGuard lock{m_mutex};
|
VerilatedLockGuard lock{m_mutex};
|
||||||
while (m_ready.empty()) {
|
while (m_ready.empty()) {
|
||||||
|
|
@ -197,7 +193,7 @@ public:
|
||||||
m_ready.erase(m_ready.begin());
|
m_ready.erase(m_ready.begin());
|
||||||
m_ready_size.fetch_sub(1, std::memory_order_relaxed);
|
m_ready_size.fetch_sub(1, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
inline void addTask(VlExecFnp fnp, VlSelfP selfp, bool evenCycle)
|
inline void addTask(VlExecFnp fnp, VlSelfP selfp, bool evenCycle = false)
|
||||||
VL_MT_SAFE_EXCLUDES(m_mutex) {
|
VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
bool notify;
|
bool notify;
|
||||||
{
|
{
|
||||||
|
|
@ -209,15 +205,14 @@ public:
|
||||||
if (notify) m_cv.notify_one();
|
if (notify) m_cv.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void shutdown() { addTask(shutdownTask, nullptr, false); }
|
void shutdown(); // Finish current tasks, then terminate thread
|
||||||
static void shutdownTask(void*, bool);
|
void wait(); // Blocks calling thread until all tasks complete in this thread
|
||||||
|
|
||||||
void workerLoop();
|
void workerLoop();
|
||||||
static void startWorker(VlWorkerThread* workerp, uint32_t threadId,
|
static void startWorker(VlWorkerThread* workerp, VerilatedContext* contextp);
|
||||||
VlExecutionProfiler* profilerp, VlStartWorkerCb startCb);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class VlThreadPool final {
|
class VlThreadPool final : public VerilatedVirtualBase {
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
std::vector<VlWorkerThread*> m_workers; // our workers
|
std::vector<VlWorkerThread*> m_workers; // our workers
|
||||||
|
|
||||||
|
|
@ -226,9 +221,8 @@ public:
|
||||||
// Construct a thread pool with 'nThreads' dedicated threads. The thread
|
// Construct a thread pool with 'nThreads' dedicated threads. The thread
|
||||||
// pool will create these threads and make them available to execute tasks
|
// pool will create these threads and make them available to execute tasks
|
||||||
// via this->workerp(index)->addTask(...)
|
// via this->workerp(index)->addTask(...)
|
||||||
VlThreadPool(VerilatedContext* contextp, int nThreads, VlExecutionProfiler* profilerp,
|
VlThreadPool(VerilatedContext* contextp, unsigned nThreads);
|
||||||
VlStartWorkerCb startCb);
|
virtual ~VlThreadPool();
|
||||||
~VlThreadPool();
|
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
inline int numThreads() const { return m_workers.size(); }
|
inline int numThreads() const { return m_workers.size(); }
|
||||||
|
|
|
||||||
|
|
@ -194,8 +194,6 @@ private:
|
||||||
static void parallelWorkerTask(void*, bool);
|
static void parallelWorkerTask(void*, bool);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using ParallelCallbackMap = std::unordered_map<VlThreadPool*, std::vector<CallbackRecord>>;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint32_t* m_sigs_oldvalp = nullptr; // Previous value store
|
uint32_t* m_sigs_oldvalp = nullptr; // Previous value store
|
||||||
EData* m_sigs_enabledp = nullptr; // Bit vector of enabled codes (nullptr = all on)
|
EData* m_sigs_enabledp = nullptr; // Bit vector of enabled codes (nullptr = all on)
|
||||||
|
|
@ -203,10 +201,10 @@ private:
|
||||||
uint64_t m_timeLastDump = 0; // Last time we did a dump
|
uint64_t m_timeLastDump = 0; // Last time we did a dump
|
||||||
std::vector<bool> m_sigs_enabledVec; // Staging for m_sigs_enabledp
|
std::vector<bool> m_sigs_enabledVec; // Staging for m_sigs_enabledp
|
||||||
std::vector<CallbackRecord> m_initCbs; // Routines to initialize tracing
|
std::vector<CallbackRecord> m_initCbs; // Routines to initialize tracing
|
||||||
ParallelCallbackMap m_fullCbs; // Routines to perform full dump
|
std::vector<CallbackRecord> m_fullCbs; // Routines to perform full dump
|
||||||
ParallelCallbackMap m_chgCbs; // Routines to perform incremental dump
|
std::vector<CallbackRecord> m_chgCbs; // Routines to perform incremental dump
|
||||||
std::vector<CallbackRecord> m_cleanupCbs; // Routines to call at the end of dump
|
std::vector<CallbackRecord> m_cleanupCbs; // Routines to call at the end of dump
|
||||||
std::vector<VlThreadPool*> m_threadPoolps; // All thread pools, in insertion order
|
VerilatedContext* m_contextp = nullptr; // The context used by the traced models
|
||||||
bool m_fullDump = true; // Whether a full dump is required on the next call to 'dump'
|
bool m_fullDump = true; // Whether a full dump is required on the next call to 'dump'
|
||||||
uint32_t m_nextCode = 0; // Next code number to assign
|
uint32_t m_nextCode = 0; // Next code number to assign
|
||||||
uint32_t m_numSignals = 0; // Number of distinct signals
|
uint32_t m_numSignals = 0; // Number of distinct signals
|
||||||
|
|
@ -217,16 +215,16 @@ private:
|
||||||
double m_timeRes = 1e-9; // Time resolution (ns/ms etc)
|
double m_timeRes = 1e-9; // Time resolution (ns/ms etc)
|
||||||
double m_timeUnit = 1e-0; // Time units (ns/ms etc)
|
double m_timeUnit = 1e-0; // Time units (ns/ms etc)
|
||||||
|
|
||||||
void addThreadPool(VlThreadPool* threadPoolp) VL_MT_SAFE_EXCLUDES(m_mutex);
|
void addContext(VerilatedContext*) VL_MT_SAFE_EXCLUDES(m_mutex);
|
||||||
|
|
||||||
void addCallbackRecord(std::vector<CallbackRecord>& cbVec, CallbackRecord& cbRec)
|
void addCallbackRecord(std::vector<CallbackRecord>& cbVec, CallbackRecord&& cbRec)
|
||||||
VL_MT_SAFE_EXCLUDES(m_mutex);
|
VL_MT_SAFE_EXCLUDES(m_mutex);
|
||||||
|
|
||||||
// Equivalent to 'this' but is of the sub-type 'T_Trace*'. Use 'self()->'
|
// Equivalent to 'this' but is of the sub-type 'T_Trace*'. Use 'self()->'
|
||||||
// to access duck-typed functions to avoid a virtual function call.
|
// to access duck-typed functions to avoid a virtual function call.
|
||||||
T_Trace* self() { return static_cast<T_Trace*>(this); }
|
T_Trace* self() { return static_cast<T_Trace*>(this); }
|
||||||
|
|
||||||
void runParallelCallbacks(const ParallelCallbackMap& cbMap);
|
void runCallbacks(const std::vector<CallbackRecord>& cbVec);
|
||||||
|
|
||||||
// Flush any remaining data for this file
|
// Flush any remaining data for this file
|
||||||
static void onFlush(void* selfp) VL_MT_UNSAFE_ONE;
|
static void onFlush(void* selfp) VL_MT_UNSAFE_ONE;
|
||||||
|
|
@ -341,10 +339,10 @@ public:
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
// Non-hot path internal interface to Verilator generated code
|
// Non-hot path internal interface to Verilator generated code
|
||||||
|
|
||||||
void addInitCb(initCb_t cb, void* userp) VL_MT_SAFE;
|
void addInitCb(initCb_t cb, void* userp, VerilatedContext*) VL_MT_SAFE;
|
||||||
void addFullCb(dumpCb_t cb, void* userp, VlThreadPool* = nullptr) VL_MT_SAFE;
|
void addFullCb(dumpCb_t cb, void* userp, VerilatedContext*) VL_MT_SAFE;
|
||||||
void addChgCb(dumpCb_t cb, void* userp, VlThreadPool* = nullptr) VL_MT_SAFE;
|
void addChgCb(dumpCb_t cb, void* userp, VerilatedContext*) VL_MT_SAFE;
|
||||||
void addCleanupCb(cleanupCb_t cb, void* userp) VL_MT_SAFE;
|
void addCleanupCb(cleanupCb_t cb, void* userp, VerilatedContext*) VL_MT_SAFE;
|
||||||
|
|
||||||
void scopeEscape(char flag) { m_scopeEscape = flag; }
|
void scopeEscape(char flag) { m_scopeEscape = flag; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -478,55 +478,52 @@ template <> VL_ATTR_NOINLINE void VerilatedTrace<VL_SUB_T, VL_BUF_T>::ParallelWo
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::runParallelCallbacks(const ParallelCallbackMap& cbMap) {
|
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::runCallbacks(const std::vector<CallbackRecord>& cbVec) {
|
||||||
for (VlThreadPool* threadPoolp : m_threadPoolps) {
|
|
||||||
#ifdef VL_TRACE_PARALLEL
|
#ifdef VL_TRACE_PARALLEL
|
||||||
// If tracing in parallel, dispatch to the thread pool (if exists)
|
// If tracing in parallel, dispatch to the thread pool
|
||||||
if (threadPoolp && threadPoolp->numThreads()) {
|
VlThreadPool* threadPoolp = static_cast<VlThreadPool*>(m_contextp->threadPoolp());
|
||||||
// List of work items for thread (std::list, as ParallelWorkerData is not movable)
|
// List of work items for thread (std::list, as ParallelWorkerData is not movable)
|
||||||
std::list<ParallelWorkerData> workerData;
|
std::list<ParallelWorkerData> workerData;
|
||||||
// We use the whole pool + the main thread
|
// We use the whole pool + the main thread
|
||||||
const unsigned threads = threadPoolp->numThreads() + 1;
|
const unsigned threads = threadPoolp->numThreads() + 1;
|
||||||
// Main thread executes all jobs with index % threads == 0
|
// Main thread executes all jobs with index % threads == 0
|
||||||
std::vector<ParallelWorkerData*> mainThreadWorkerData;
|
std::vector<ParallelWorkerData*> mainThreadWorkerData;
|
||||||
// The tracing callbacks to execute on this thread-pool
|
// Enuque all the jobs
|
||||||
const auto& cbVec = cbMap.at(threadPoolp);
|
for (unsigned i = 0; i < cbVec.size(); ++i) {
|
||||||
// Enuque all the jobs
|
const CallbackRecord& cbr = cbVec[i];
|
||||||
for (unsigned i = 0; i < cbVec.size(); ++i) {
|
// Always get the trace buffer on the main thread
|
||||||
const CallbackRecord& cbr = cbVec[i];
|
Buffer* const bufp = getTraceBuffer();
|
||||||
// Always get the trace buffer on the main thread
|
// Create new work item
|
||||||
Buffer* const bufp = getTraceBuffer();
|
workerData.emplace_back(cbr.m_dumpCb, cbr.m_userp, bufp);
|
||||||
// Create new work item
|
// Grab the new work item
|
||||||
workerData.emplace_back(cbr.m_dumpCb, cbr.m_userp, bufp);
|
ParallelWorkerData* const itemp = &workerData.back();
|
||||||
// Grab the new work item
|
// Enqueue task to thread pool, or main thread
|
||||||
ParallelWorkerData* const itemp = &workerData.back();
|
if (unsigned rem = i % threads) {
|
||||||
// Enqueue task to thread pool, or main thread
|
threadPoolp->workerp(rem - 1)->addTask(parallelWorkerTask, itemp);
|
||||||
if (unsigned rem = i % threads) {
|
} else {
|
||||||
threadPoolp->workerp(rem - 1)->addTask(parallelWorkerTask, itemp, false);
|
mainThreadWorkerData.push_back(itemp);
|
||||||
} else {
|
|
||||||
mainThreadWorkerData.push_back(itemp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Execute main thead jobs
|
|
||||||
for (ParallelWorkerData* const itemp : mainThreadWorkerData) {
|
|
||||||
parallelWorkerTask(itemp, false);
|
|
||||||
}
|
|
||||||
// Commit all trace buffers in order
|
|
||||||
for (ParallelWorkerData& item : workerData) {
|
|
||||||
// Wait until ready
|
|
||||||
item.wait();
|
|
||||||
// Commit the buffer
|
|
||||||
commitTraceBuffer(item.m_bufp);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// Execute main thead jobs
|
||||||
|
for (ParallelWorkerData* const itemp : mainThreadWorkerData) {
|
||||||
|
parallelWorkerTask(itemp, false);
|
||||||
|
}
|
||||||
|
// Commit all trace buffers in order
|
||||||
|
for (ParallelWorkerData& item : workerData) {
|
||||||
|
// Wait until ready
|
||||||
|
item.wait();
|
||||||
|
// Commit the buffer
|
||||||
|
commitTraceBuffer(item.m_bufp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Done
|
||||||
|
return;
|
||||||
#endif
|
#endif
|
||||||
// Fall back on sequential execution
|
// Fall back on sequential execution
|
||||||
for (const CallbackRecord& cbr : cbMap.at(threadPoolp)) {
|
for (const CallbackRecord& cbr : cbVec) {
|
||||||
Buffer* const traceBufferp = getTraceBuffer();
|
Buffer* const traceBufferp = getTraceBuffer();
|
||||||
cbr.m_dumpCb(cbr.m_userp, traceBufferp);
|
cbr.m_dumpCb(cbr.m_userp, traceBufferp);
|
||||||
commitTraceBuffer(traceBufferp);
|
commitTraceBuffer(traceBufferp);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -579,9 +576,9 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::dump(uint64_t timeui) VL_MT_SAFE_EXCLUD
|
||||||
// Run the callbacks
|
// Run the callbacks
|
||||||
if (VL_UNLIKELY(m_fullDump)) {
|
if (VL_UNLIKELY(m_fullDump)) {
|
||||||
m_fullDump = false; // No more need for next dump to be full
|
m_fullDump = false; // No more need for next dump to be full
|
||||||
runParallelCallbacks(m_fullCbs);
|
runCallbacks(m_fullCbs);
|
||||||
} else {
|
} else {
|
||||||
runParallelCallbacks(m_chgCbs);
|
runCallbacks(m_chgCbs);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t i = 0; i < m_cleanupCbs.size(); ++i) {
|
for (uint32_t i = 0; i < m_cleanupCbs.size(); ++i) {
|
||||||
|
|
@ -607,18 +604,20 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::dump(uint64_t timeui) VL_MT_SAFE_EXCLUD
|
||||||
// Non-hot path internal interface to Verilator generated code
|
// Non-hot path internal interface to Verilator generated code
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addThreadPool(VlThreadPool* threadPoolp)
|
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addContext(VerilatedContext* contextp)
|
||||||
VL_MT_SAFE_EXCLUDES(m_mutex) {
|
VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
const VerilatedLockGuard lock{m_mutex};
|
const VerilatedLockGuard lock{m_mutex};
|
||||||
for (VlThreadPool* const poolp : m_threadPoolps) {
|
if (m_contextp && contextp != m_contextp) {
|
||||||
if (poolp == threadPoolp) return;
|
VL_FATAL_MT(
|
||||||
|
__FILE__, __LINE__, "",
|
||||||
|
"A trace file instance can only handle models from the same simulation context");
|
||||||
}
|
}
|
||||||
m_threadPoolps.push_back(threadPoolp);
|
m_contextp = contextp;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addCallbackRecord(std::vector<CallbackRecord>& cbVec,
|
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addCallbackRecord(std::vector<CallbackRecord>& cbVec,
|
||||||
CallbackRecord& cbRec)
|
CallbackRecord&& cbRec)
|
||||||
VL_MT_SAFE_EXCLUDES(m_mutex) {
|
VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||||
const VerilatedLockGuard lock{m_mutex};
|
const VerilatedLockGuard lock{m_mutex};
|
||||||
if (VL_UNCOVERABLE(timeLastDump() != 0)) { // LCOV_EXCL_START
|
if (VL_UNCOVERABLE(timeLastDump() != 0)) { // LCOV_EXCL_START
|
||||||
|
|
@ -630,28 +629,28 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addCallbackRecord(std::vector<CallbackR
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addInitCb(initCb_t cb, void* userp) VL_MT_SAFE {
|
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addInitCb(initCb_t cb, void* userp,
|
||||||
CallbackRecord cbr{cb, userp};
|
VerilatedContext* contextp) VL_MT_SAFE {
|
||||||
addCallbackRecord(m_initCbs, cbr);
|
addContext(contextp);
|
||||||
|
addCallbackRecord(m_initCbs, CallbackRecord{cb, userp});
|
||||||
}
|
}
|
||||||
template <>
|
template <>
|
||||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addFullCb(dumpCb_t cb, void* userp,
|
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addFullCb(dumpCb_t cb, void* userp,
|
||||||
VlThreadPool* threadPoolp) VL_MT_SAFE {
|
VerilatedContext* contextp) VL_MT_SAFE {
|
||||||
CallbackRecord cbr{cb, userp};
|
addContext(contextp);
|
||||||
addThreadPool(threadPoolp);
|
addCallbackRecord(m_fullCbs, CallbackRecord{cb, userp});
|
||||||
addCallbackRecord(m_fullCbs[threadPoolp], cbr);
|
|
||||||
}
|
}
|
||||||
template <>
|
template <>
|
||||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addChgCb(dumpCb_t cb, void* userp,
|
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addChgCb(dumpCb_t cb, void* userp,
|
||||||
VlThreadPool* threadPoolp) VL_MT_SAFE {
|
VerilatedContext* contextp) VL_MT_SAFE {
|
||||||
CallbackRecord cbr{cb, userp};
|
addContext(contextp);
|
||||||
addThreadPool(threadPoolp);
|
addCallbackRecord(m_chgCbs, CallbackRecord{cb, userp});
|
||||||
addCallbackRecord(m_chgCbs[threadPoolp], cbr);
|
|
||||||
}
|
}
|
||||||
template <>
|
template <>
|
||||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addCleanupCb(cleanupCb_t cb, void* userp) VL_MT_SAFE {
|
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addCleanupCb(cleanupCb_t cb, void* userp,
|
||||||
CallbackRecord cbr{cb, userp};
|
VerilatedContext* contextp) VL_MT_SAFE {
|
||||||
addCallbackRecord(m_cleanupCbs, cbr);
|
addContext(contextp);
|
||||||
|
addCallbackRecord(m_cleanupCbs, CallbackRecord{cb, userp});
|
||||||
}
|
}
|
||||||
|
|
||||||
template <> void VerilatedTrace<VL_SUB_T, VL_BUF_T>::pushNamePrefix(const std::string& prefix) {
|
template <> void VerilatedTrace<VL_SUB_T, VL_BUF_T>::pushNamePrefix(const std::string& prefix) {
|
||||||
|
|
|
||||||
|
|
@ -234,6 +234,16 @@
|
||||||
# error "Verilator requires a C++11 or newer compiler"
|
# error "Verilator requires a C++11 or newer compiler"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
|
// C++-2017
|
||||||
|
|
||||||
|
#if __cplusplus >= 201703L
|
||||||
|
# define VL_CONSTEXPR_CXX17 constexpr
|
||||||
|
#else
|
||||||
|
# define VL_CONSTEXPR_CXX17
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
// Optimization
|
// Optimization
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1961,7 +1961,7 @@ private:
|
||||||
ASTNODE_PREFETCH(nodep->op2p());
|
ASTNODE_PREFETCH(nodep->op2p());
|
||||||
ASTNODE_PREFETCH(nodep->op3p());
|
ASTNODE_PREFETCH(nodep->op3p());
|
||||||
ASTNODE_PREFETCH(nodep->op4p());
|
ASTNODE_PREFETCH(nodep->op4p());
|
||||||
if /* TODO: 'constexpr' in C++17 */ (VisitNext) ASTNODE_PREFETCH(nodep->nextp());
|
if VL_CONSTEXPR_CXX17 (VisitNext) ASTNODE_PREFETCH(nodep->nextp());
|
||||||
|
|
||||||
// Apply function in pre-order
|
// Apply function in pre-order
|
||||||
if (privateTypeTest<typename std::remove_const<T_Arg>::type>(nodep)) {
|
if (privateTypeTest<typename std::remove_const<T_Arg>::type>(nodep)) {
|
||||||
|
|
@ -1977,7 +1977,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Traverse 'nextp()' chain if requested
|
// Traverse 'nextp()' chain if requested
|
||||||
if /* TODO: 'constexpr' in C++17 */ (VisitNext) {
|
if VL_CONSTEXPR_CXX17 (VisitNext) {
|
||||||
nodep = nodep->nextp();
|
nodep = nodep->nextp();
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
|
|
@ -2000,7 +2000,7 @@ private:
|
||||||
ASTNODE_PREFETCH(nodep->op2p());
|
ASTNODE_PREFETCH(nodep->op2p());
|
||||||
ASTNODE_PREFETCH(nodep->op3p());
|
ASTNODE_PREFETCH(nodep->op3p());
|
||||||
ASTNODE_PREFETCH(nodep->op4p());
|
ASTNODE_PREFETCH(nodep->op4p());
|
||||||
if /* TODO: 'constexpr' in C++17 */ (VisitNext) ASTNODE_PREFETCH(nodep->nextp());
|
if VL_CONSTEXPR_CXX17 (VisitNext) ASTNODE_PREFETCH(nodep->nextp());
|
||||||
|
|
||||||
// Apply function in pre-order
|
// Apply function in pre-order
|
||||||
if (privateTypeTest<typename std::remove_const<T_Arg>::type>(nodep)) {
|
if (privateTypeTest<typename std::remove_const<T_Arg>::type>(nodep)) {
|
||||||
|
|
@ -2024,7 +2024,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Traverse 'nextp()' chain if requested
|
// Traverse 'nextp()' chain if requested
|
||||||
if /* TODO: 'constexpr' in C++17 */ (VisitNext) {
|
if VL_CONSTEXPR_CXX17 (VisitNext) {
|
||||||
nodep = nodep->nextp();
|
nodep = nodep->nextp();
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -4568,26 +4568,21 @@ public:
|
||||||
class AstTestPlusArgs final : public AstNodeMath {
|
class AstTestPlusArgs final : public AstNodeMath {
|
||||||
// Parents: expr
|
// Parents: expr
|
||||||
// Child: variable to set. If nullptr then this is a $test$plusargs instead of $value$plusargs
|
// Child: variable to set. If nullptr then this is a $test$plusargs instead of $value$plusargs
|
||||||
private:
|
|
||||||
string m_text;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AstTestPlusArgs(FileLine* fl, const string& text)
|
AstTestPlusArgs(FileLine* fl, AstNode* searchp)
|
||||||
: ASTGEN_SUPER_TestPlusArgs(fl)
|
: ASTGEN_SUPER_TestPlusArgs(fl) {
|
||||||
, m_text{text} {}
|
setOp1p(searchp);
|
||||||
|
}
|
||||||
ASTNODE_NODE_FUNCS(TestPlusArgs)
|
ASTNODE_NODE_FUNCS(TestPlusArgs)
|
||||||
virtual string name() const override { return m_text; }
|
|
||||||
virtual string verilogKwd() const override { return "$test$plusargs"; }
|
virtual string verilogKwd() const override { return "$test$plusargs"; }
|
||||||
virtual string emitVerilog() override { return verilogKwd(); }
|
virtual string emitVerilog() override { return verilogKwd(); }
|
||||||
virtual string emitC() override { return "VL_VALUEPLUSARGS_%nq(%lw, %P, nullptr)"; }
|
virtual string emitC() override { return "VL_VALUEPLUSARGS_%nq(%lw, %P, nullptr)"; }
|
||||||
virtual bool isGateOptimizable() const override { return false; }
|
virtual bool isGateOptimizable() const override { return false; }
|
||||||
virtual bool isPredictOptimizable() const override { return false; }
|
virtual bool isPredictOptimizable() const override { return false; }
|
||||||
virtual bool cleanOut() const override { return true; }
|
virtual bool cleanOut() const override { return true; }
|
||||||
virtual bool same(const AstNode* samep) const override {
|
virtual bool same(const AstNode* samep) const override { return true; }
|
||||||
return text() == static_cast<const AstTestPlusArgs*>(samep)->text();
|
AstNode* searchp() const { return op1p(); } // op1 = Search expression
|
||||||
}
|
void searchp(AstNode* nodep) { setOp1p(nodep); }
|
||||||
string text() const { return m_text; } // * = Text to display
|
|
||||||
void text(const string& text) { m_text = text; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class AstGenFor final : public AstNodeFor {
|
class AstGenFor final : public AstNodeFor {
|
||||||
|
|
|
||||||
|
|
@ -35,17 +35,16 @@ private:
|
||||||
std::vector<T_Data*> m_allocated;
|
std::vector<T_Data*> m_allocated;
|
||||||
|
|
||||||
inline T_Data* getUserp(const T_Node* nodep) const {
|
inline T_Data* getUserp(const T_Node* nodep) const {
|
||||||
// This simplifies statically as T_UserN is constant. In C++17, use 'if constexpr'.
|
if VL_CONSTEXPR_CXX17 (T_UserN == 1) {
|
||||||
if (T_UserN == 1) {
|
|
||||||
const VNUser user = nodep->user1u();
|
const VNUser user = nodep->user1u();
|
||||||
return user.to<T_Data*>();
|
return user.to<T_Data*>();
|
||||||
} else if (T_UserN == 2) {
|
} else if VL_CONSTEXPR_CXX17 (T_UserN == 2) {
|
||||||
const VNUser user = nodep->user2u();
|
const VNUser user = nodep->user2u();
|
||||||
return user.to<T_Data*>();
|
return user.to<T_Data*>();
|
||||||
} else if (T_UserN == 3) {
|
} else if VL_CONSTEXPR_CXX17 (T_UserN == 3) {
|
||||||
const VNUser user = nodep->user3u();
|
const VNUser user = nodep->user3u();
|
||||||
return user.to<T_Data*>();
|
return user.to<T_Data*>();
|
||||||
} else if (T_UserN == 4) {
|
} else if VL_CONSTEXPR_CXX17 (T_UserN == 4) {
|
||||||
const VNUser user = nodep->user4u();
|
const VNUser user = nodep->user4u();
|
||||||
return user.to<T_Data*>();
|
return user.to<T_Data*>();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -55,14 +54,13 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void setUserp(T_Node* nodep, T_Data* userp) const {
|
inline void setUserp(T_Node* nodep, T_Data* userp) const {
|
||||||
// This simplifies statically as T_UserN is constant. In C++17, use 'if constexpr'.
|
if VL_CONSTEXPR_CXX17 (T_UserN == 1) {
|
||||||
if (T_UserN == 1) {
|
|
||||||
nodep->user1u(VNUser(userp));
|
nodep->user1u(VNUser(userp));
|
||||||
} else if (T_UserN == 2) {
|
} else if VL_CONSTEXPR_CXX17 (T_UserN == 2) {
|
||||||
nodep->user2u(VNUser(userp));
|
nodep->user2u(VNUser(userp));
|
||||||
} else if (T_UserN == 3) {
|
} else if VL_CONSTEXPR_CXX17 (T_UserN == 3) {
|
||||||
nodep->user3u(VNUser(userp));
|
nodep->user3u(VNUser(userp));
|
||||||
} else if (T_UserN == 4) {
|
} else if VL_CONSTEXPR_CXX17 (T_UserN == 4) {
|
||||||
nodep->user4u(VNUser(userp));
|
nodep->user4u(VNUser(userp));
|
||||||
} else {
|
} else {
|
||||||
nodep->user5u(VNUser(userp));
|
nodep->user5u(VNUser(userp));
|
||||||
|
|
@ -71,14 +69,13 @@ private:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
AstUserAllocatorBase() {
|
AstUserAllocatorBase() {
|
||||||
// This simplifies statically as T_UserN is constant. In C++17, use 'if constexpr'.
|
if VL_CONSTEXPR_CXX17 (T_UserN == 1) {
|
||||||
if (T_UserN == 1) {
|
|
||||||
VNUser1InUse::check();
|
VNUser1InUse::check();
|
||||||
} else if (T_UserN == 2) {
|
} else if VL_CONSTEXPR_CXX17 (T_UserN == 2) {
|
||||||
VNUser2InUse::check();
|
VNUser2InUse::check();
|
||||||
} else if (T_UserN == 3) {
|
} else if VL_CONSTEXPR_CXX17 (T_UserN == 3) {
|
||||||
VNUser3InUse::check();
|
VNUser3InUse::check();
|
||||||
} else if (T_UserN == 4) {
|
} else if VL_CONSTEXPR_CXX17 (T_UserN == 4) {
|
||||||
VNUser4InUse::check();
|
VNUser4InUse::check();
|
||||||
} else {
|
} else {
|
||||||
VNUser5InUse::check();
|
VNUser5InUse::check();
|
||||||
|
|
|
||||||
|
|
@ -80,30 +80,48 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
||||||
using ResultTerm = std::tuple<AstNode*, unsigned, bool>;
|
using ResultTerm = std::tuple<AstNode*, unsigned, bool>;
|
||||||
|
|
||||||
class LeafInfo final { // Leaf node (either AstConst or AstVarRef)
|
class LeafInfo final { // Leaf node (either AstConst or AstVarRef)
|
||||||
|
// MEMBERS
|
||||||
bool m_polarity = true;
|
bool m_polarity = true;
|
||||||
int m_lsb = 0;
|
int m_lsb = 0; // LSB of actually used bit of m_refp->varp()
|
||||||
|
int m_msb = 0; // MSB of actually used bit of m_refp->varp()
|
||||||
int m_wordIdx = -1; // -1 means AstWordSel is not used.
|
int m_wordIdx = -1; // -1 means AstWordSel is not used.
|
||||||
AstVarRef* m_refp = nullptr;
|
AstVarRef* m_refp = nullptr;
|
||||||
const AstConst* m_constp = nullptr;
|
const AstConst* m_constp = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
// CONSTRUCTORS
|
||||||
|
LeafInfo() = default;
|
||||||
|
LeafInfo(const LeafInfo& other) = default;
|
||||||
|
explicit LeafInfo(int lsb)
|
||||||
|
: m_lsb{lsb} {}
|
||||||
|
|
||||||
|
// METHODS
|
||||||
void setLeaf(AstVarRef* refp) {
|
void setLeaf(AstVarRef* refp) {
|
||||||
UASSERT(!m_refp && !m_constp, "Must be called just once");
|
UASSERT(!m_refp && !m_constp, "Must be called just once");
|
||||||
m_refp = refp;
|
m_refp = refp;
|
||||||
|
m_msb = refp->varp()->widthMin() - 1;
|
||||||
}
|
}
|
||||||
void setLeaf(const AstConst* constp) {
|
void setLeaf(const AstConst* constp) {
|
||||||
UASSERT(!m_refp && !m_constp, "Must be called just once");
|
UASSERT(!m_refp && !m_constp, "Must be called just once");
|
||||||
m_constp = constp;
|
m_constp = constp;
|
||||||
|
m_msb = constp->widthMin() - 1;
|
||||||
}
|
}
|
||||||
|
void updateBitRange(const AstCCast* castp) {
|
||||||
|
m_msb = std::min(m_msb, m_lsb + castp->width() - 1);
|
||||||
|
}
|
||||||
|
void updateBitRange(const AstShiftR* shiftp) {
|
||||||
|
m_lsb += VN_AS(shiftp->rhsp(), Const)->toUInt();
|
||||||
|
}
|
||||||
|
void wordIdx(int i) { m_wordIdx = i; }
|
||||||
|
void polarity(bool p) { m_polarity = p; }
|
||||||
|
|
||||||
AstVarRef* refp() const { return m_refp; }
|
AstVarRef* refp() const { return m_refp; }
|
||||||
const AstConst* constp() const { return m_constp; }
|
const AstConst* constp() const { return m_constp; }
|
||||||
int wordIdx() const { return m_wordIdx; }
|
int wordIdx() const { return m_wordIdx; }
|
||||||
bool polarity() const { return m_polarity; }
|
bool polarity() const { return m_polarity; }
|
||||||
int lsb() const { return m_lsb; }
|
int lsb() const { return m_lsb; }
|
||||||
|
|
||||||
void wordIdx(int i) { m_wordIdx = i; }
|
int msb() const { return std::min(m_msb, varWidth() - 1); }
|
||||||
void lsb(int l) { m_lsb = l; }
|
|
||||||
void polarity(bool p) { m_polarity = p; }
|
|
||||||
int varWidth() const {
|
int varWidth() const {
|
||||||
UASSERT(m_refp, "m_refp should be set");
|
UASSERT(m_refp, "m_refp should be set");
|
||||||
const int width = m_refp->varp()->widthMin();
|
const int width = m_refp->varp()->widthMin();
|
||||||
|
|
@ -382,7 +400,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
||||||
|
|
||||||
// Traverse down to see AstConst or AstVarRef
|
// Traverse down to see AstConst or AstVarRef
|
||||||
LeafInfo findLeaf(AstNode* nodep, bool expectConst) {
|
LeafInfo findLeaf(AstNode* nodep, bool expectConst) {
|
||||||
LeafInfo info;
|
LeafInfo info{m_lsb};
|
||||||
{
|
{
|
||||||
VL_RESTORER(m_leafp);
|
VL_RESTORER(m_leafp);
|
||||||
m_leafp = &info;
|
m_leafp = &info;
|
||||||
|
|
@ -402,7 +420,10 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
||||||
virtual void visit(AstNode* nodep) override {
|
virtual void visit(AstNode* nodep) override {
|
||||||
CONST_BITOP_SET_FAILED("Hit unexpected op", nodep);
|
CONST_BITOP_SET_FAILED("Hit unexpected op", nodep);
|
||||||
}
|
}
|
||||||
virtual void visit(AstCCast* nodep) override { iterateChildren(nodep); }
|
virtual void visit(AstCCast* nodep) override {
|
||||||
|
iterateChildren(nodep);
|
||||||
|
if (m_leafp) m_leafp->updateBitRange(nodep);
|
||||||
|
}
|
||||||
virtual void visit(AstShiftR* nodep) override {
|
virtual void visit(AstShiftR* nodep) override {
|
||||||
CONST_BITOP_RETURN_IF(!m_leafp, nodep);
|
CONST_BITOP_RETURN_IF(!m_leafp, nodep);
|
||||||
AstConst* const constp = VN_CAST(nodep->rhsp(), Const);
|
AstConst* const constp = VN_CAST(nodep->rhsp(), Const);
|
||||||
|
|
@ -410,12 +431,14 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
||||||
m_lsb += constp->toUInt();
|
m_lsb += constp->toUInt();
|
||||||
incrOps(nodep, __LINE__);
|
incrOps(nodep, __LINE__);
|
||||||
iterate(nodep->lhsp());
|
iterate(nodep->lhsp());
|
||||||
|
m_leafp->updateBitRange(nodep);
|
||||||
m_lsb -= constp->toUInt();
|
m_lsb -= constp->toUInt();
|
||||||
}
|
}
|
||||||
virtual void visit(AstNot* nodep) override {
|
virtual void visit(AstNot* nodep) override {
|
||||||
CONST_BITOP_RETURN_IF(nodep->widthMin() != 1, nodep);
|
CONST_BITOP_RETURN_IF(nodep->widthMin() != 1, nodep);
|
||||||
AstNode* lhsp = nodep->lhsp();
|
AstNode* lhsp = nodep->lhsp();
|
||||||
if (AstCCast* const castp = VN_CAST(lhsp, CCast)) lhsp = castp->lhsp();
|
AstCCast* const castp = VN_CAST(lhsp, CCast);
|
||||||
|
if (castp) lhsp = castp->lhsp();
|
||||||
CONST_BITOP_RETURN_IF(!VN_IS(lhsp, VarRef) && !VN_IS(lhsp, Xor) && !VN_IS(lhsp, RedXor)
|
CONST_BITOP_RETURN_IF(!VN_IS(lhsp, VarRef) && !VN_IS(lhsp, Xor) && !VN_IS(lhsp, RedXor)
|
||||||
&& !VN_IS(lhsp, ShiftR),
|
&& !VN_IS(lhsp, ShiftR),
|
||||||
lhsp);
|
lhsp);
|
||||||
|
|
@ -424,6 +447,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
// Don't restore m_polarity for Xor as it counts parity of the entire tree
|
// Don't restore m_polarity for Xor as it counts parity of the entire tree
|
||||||
if (!isXorTree()) m_polarity = !m_polarity;
|
if (!isXorTree()) m_polarity = !m_polarity;
|
||||||
|
if (m_leafp && castp) m_leafp->updateBitRange(castp);
|
||||||
}
|
}
|
||||||
virtual void visit(AstWordSel* nodep) override {
|
virtual void visit(AstWordSel* nodep) override {
|
||||||
CONST_BITOP_RETURN_IF(!m_leafp, nodep);
|
CONST_BITOP_RETURN_IF(!m_leafp, nodep);
|
||||||
|
|
@ -437,27 +461,27 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
||||||
CONST_BITOP_RETURN_IF(!m_leafp, nodep);
|
CONST_BITOP_RETURN_IF(!m_leafp, nodep);
|
||||||
m_leafp->setLeaf(nodep);
|
m_leafp->setLeaf(nodep);
|
||||||
m_leafp->polarity(m_polarity);
|
m_leafp->polarity(m_polarity);
|
||||||
m_leafp->lsb(m_lsb);
|
|
||||||
}
|
}
|
||||||
virtual void visit(AstConst* nodep) override {
|
virtual void visit(AstConst* nodep) override {
|
||||||
CONST_BITOP_RETURN_IF(!m_leafp, nodep);
|
CONST_BITOP_RETURN_IF(!m_leafp, nodep);
|
||||||
m_leafp->setLeaf(nodep);
|
m_leafp->setLeaf(nodep);
|
||||||
m_leafp->lsb(m_lsb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void visit(AstRedXor* nodep) override {
|
virtual void visit(AstRedXor* nodep) override {
|
||||||
Restorer restorer{*this};
|
Restorer restorer{*this};
|
||||||
CONST_BITOP_RETURN_IF(!VN_IS(m_rootp, Xor), nodep);
|
CONST_BITOP_RETURN_IF(!VN_IS(m_rootp, Xor), nodep);
|
||||||
AstNode* lhsp = nodep->lhsp();
|
AstNode* lhsp = nodep->lhsp();
|
||||||
if (const AstCCast* const castp = VN_CAST(lhsp, CCast)) lhsp = castp->lhsp();
|
const AstCCast* const castp = VN_CAST(lhsp, CCast);
|
||||||
|
if (castp) lhsp = castp->lhsp();
|
||||||
if (const AstAnd* const andp = VN_CAST(lhsp, And)) { // '^(mask & leaf)'
|
if (const AstAnd* const andp = VN_CAST(lhsp, And)) { // '^(mask & leaf)'
|
||||||
CONST_BITOP_RETURN_IF(!andp, lhsp);
|
CONST_BITOP_RETURN_IF(!andp, lhsp);
|
||||||
|
|
||||||
const LeafInfo& mask = findLeaf(andp->lhsp(), true);
|
const LeafInfo& mask = findLeaf(andp->lhsp(), true);
|
||||||
CONST_BITOP_RETURN_IF(!mask.constp() || mask.lsb() != 0, andp->lhsp());
|
CONST_BITOP_RETURN_IF(!mask.constp() || mask.lsb() != 0, andp->lhsp());
|
||||||
|
|
||||||
const LeafInfo& ref = findLeaf(andp->rhsp(), false);
|
LeafInfo ref = findLeaf(andp->rhsp(), false);
|
||||||
CONST_BITOP_RETURN_IF(!ref.refp(), andp->rhsp());
|
CONST_BITOP_RETURN_IF(!ref.refp(), andp->rhsp());
|
||||||
|
if (castp) ref.updateBitRange(castp);
|
||||||
|
|
||||||
restorer.disableRestore(); // Now all subtree succeeded
|
restorer.disableRestore(); // Now all subtree succeeded
|
||||||
|
|
||||||
|
|
@ -467,7 +491,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
||||||
incrOps(andp, __LINE__);
|
incrOps(andp, __LINE__);
|
||||||
|
|
||||||
// Mark all bits checked in this reduction
|
// Mark all bits checked in this reduction
|
||||||
const int maxBitIdx = std::min(ref.lsb() + maskNum.width(), ref.varWidth());
|
const int maxBitIdx = std::min(ref.lsb() + maskNum.width(), ref.msb() + 1);
|
||||||
for (int bitIdx = ref.lsb(); bitIdx < maxBitIdx; ++bitIdx) {
|
for (int bitIdx = ref.lsb(); bitIdx < maxBitIdx; ++bitIdx) {
|
||||||
const int maskIdx = bitIdx - ref.lsb();
|
const int maskIdx = bitIdx - ref.lsb();
|
||||||
if (maskNum.bitIs0(maskIdx)) continue;
|
if (maskNum.bitIs0(maskIdx)) continue;
|
||||||
|
|
@ -475,15 +499,16 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
||||||
m_bitPolarities.emplace_back(ref, true, bitIdx);
|
m_bitPolarities.emplace_back(ref, true, bitIdx);
|
||||||
}
|
}
|
||||||
} else { // '^leaf'
|
} else { // '^leaf'
|
||||||
const LeafInfo& ref = findLeaf(lhsp, false);
|
LeafInfo ref = findLeaf(lhsp, false);
|
||||||
CONST_BITOP_RETURN_IF(!ref.refp(), lhsp);
|
CONST_BITOP_RETURN_IF(!ref.refp(), lhsp);
|
||||||
|
if (castp) ref.updateBitRange(castp);
|
||||||
|
|
||||||
restorer.disableRestore(); // Now all checks passed
|
restorer.disableRestore(); // Now all checks passed
|
||||||
|
|
||||||
incrOps(nodep, __LINE__);
|
incrOps(nodep, __LINE__);
|
||||||
|
|
||||||
// Mark all bits checked by this comparison
|
// Mark all bits checked by this comparison
|
||||||
for (int bitIdx = ref.lsb(); bitIdx < ref.varWidth(); ++bitIdx) {
|
for (int bitIdx = ref.lsb(); bitIdx <= ref.msb(); ++bitIdx) {
|
||||||
m_bitPolarities.emplace_back(ref, true, bitIdx);
|
m_bitPolarities.emplace_back(ref, true, bitIdx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -503,7 +528,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
||||||
|
|
||||||
for (const bool right : {false, true}) {
|
for (const bool right : {false, true}) {
|
||||||
Restorer restorer{*this};
|
Restorer restorer{*this};
|
||||||
LeafInfo leafInfo;
|
LeafInfo leafInfo{m_lsb};
|
||||||
m_leafp = &leafInfo;
|
m_leafp = &leafInfo;
|
||||||
AstNode* opp = right ? nodep->rhsp() : nodep->lhsp();
|
AstNode* opp = right ? nodep->rhsp() : nodep->lhsp();
|
||||||
const bool origFailed = m_failed;
|
const bool origFailed = m_failed;
|
||||||
|
|
@ -522,7 +547,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
||||||
// The conditional on the lsb being in range is necessary for some degenerate
|
// The conditional on the lsb being in range is necessary for some degenerate
|
||||||
// case, e.g.: (IData)((QData)wide[0] >> 32), or <1-bit-var> >> 1, which is
|
// case, e.g.: (IData)((QData)wide[0] >> 32), or <1-bit-var> >> 1, which is
|
||||||
// just zero
|
// just zero
|
||||||
if (leafInfo.lsb() < leafInfo.varWidth()) {
|
if (leafInfo.lsb() <= leafInfo.msb()) {
|
||||||
m_bitPolarities.emplace_back(leafInfo, isXorTree() || leafInfo.polarity(),
|
m_bitPolarities.emplace_back(leafInfo, isXorTree() || leafInfo.polarity(),
|
||||||
leafInfo.lsb());
|
leafInfo.lsb());
|
||||||
} else if (isAndTree() && leafInfo.polarity()) {
|
} else if (isAndTree() && leafInfo.polarity()) {
|
||||||
|
|
@ -559,7 +584,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
||||||
incrOps(andp, __LINE__);
|
incrOps(andp, __LINE__);
|
||||||
|
|
||||||
// Mark all bits checked by this comparison
|
// Mark all bits checked by this comparison
|
||||||
const int maxBitIdx = std::min(ref.lsb() + maskNum.width(), ref.varWidth());
|
const int maxBitIdx = std::min(ref.lsb() + maskNum.width(), ref.msb() + 1);
|
||||||
for (int bitIdx = ref.lsb(); bitIdx < maxBitIdx; ++bitIdx) {
|
for (int bitIdx = ref.lsb(); bitIdx < maxBitIdx; ++bitIdx) {
|
||||||
const int maskIdx = bitIdx - ref.lsb();
|
const int maskIdx = bitIdx - ref.lsb();
|
||||||
if (maskNum.bitIs0(maskIdx)) continue;
|
if (maskNum.bitIs0(maskIdx)) continue;
|
||||||
|
|
@ -575,7 +600,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
||||||
incrOps(nodep, __LINE__);
|
incrOps(nodep, __LINE__);
|
||||||
|
|
||||||
// Mark all bits checked by this comparison
|
// Mark all bits checked by this comparison
|
||||||
const int maxBitIdx = std::min(ref.lsb() + compNum.width(), ref.varWidth());
|
const int maxBitIdx = std::min(ref.lsb() + compNum.width(), ref.msb() + 1);
|
||||||
for (int bitIdx = ref.lsb(); bitIdx < maxBitIdx; ++bitIdx) {
|
for (int bitIdx = ref.lsb(); bitIdx < maxBitIdx; ++bitIdx) {
|
||||||
const int maskIdx = bitIdx - ref.lsb();
|
const int maskIdx = bitIdx - ref.lsb();
|
||||||
const bool polarity = compNum.bitIs1(maskIdx) != maskFlip;
|
const bool polarity = compNum.bitIs1(maskIdx) != maskFlip;
|
||||||
|
|
|
||||||
|
|
@ -573,7 +573,7 @@ public:
|
||||||
}
|
}
|
||||||
virtual void visit(AstTestPlusArgs* nodep) override {
|
virtual void visit(AstTestPlusArgs* nodep) override {
|
||||||
puts("VL_TESTPLUSARGS_I(");
|
puts("VL_TESTPLUSARGS_I(");
|
||||||
putsQuoted(nodep->text());
|
emitCvtPackStr(nodep->searchp());
|
||||||
puts(")");
|
puts(")");
|
||||||
}
|
}
|
||||||
virtual void visit(AstFError* nodep) override {
|
virtual void visit(AstFError* nodep) override {
|
||||||
|
|
|
||||||
|
|
@ -251,15 +251,15 @@ class EmitCHeader final : public EmitCConstInit {
|
||||||
emitTextSection(modp, VNType::atScHdr);
|
emitTextSection(modp, VNType::atScHdr);
|
||||||
|
|
||||||
// Open class body {{{
|
// Open class body {{{
|
||||||
|
puts("\nclass ");
|
||||||
|
puts(prefixNameProtect(modp));
|
||||||
if (const AstClass* const classp = VN_CAST(modp, Class)) {
|
if (const AstClass* const classp = VN_CAST(modp, Class)) {
|
||||||
puts("class ");
|
|
||||||
puts(prefixNameProtect(modp));
|
|
||||||
if (classp->extendsp()) {
|
if (classp->extendsp()) {
|
||||||
puts(" : public ");
|
puts(" : public ");
|
||||||
puts(prefixNameProtect(classp->extendsp()->classp()));
|
puts(prefixNameProtect(classp->extendsp()->classp()));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
puts("VL_MODULE(" + prefixNameProtect(modp) + ")");
|
puts(" final : public VerilatedModule");
|
||||||
}
|
}
|
||||||
puts(" {\n");
|
puts(" {\n");
|
||||||
ofp()->resetPrivate();
|
ofp()->resetPrivate();
|
||||||
|
|
|
||||||
|
|
@ -173,7 +173,7 @@ class CMakeEmitter final {
|
||||||
+ ".cpp");
|
+ ".cpp");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (v3Global.opt.mtasks()) {
|
if (v3Global.opt.threads()) {
|
||||||
global.emplace_back("${VERILATOR_ROOT}/include/verilated_threads.cpp");
|
global.emplace_back("${VERILATOR_ROOT}/include/verilated_threads.cpp");
|
||||||
}
|
}
|
||||||
if (v3Global.opt.usesProfiler()) {
|
if (v3Global.opt.usesProfiler()) {
|
||||||
|
|
|
||||||
|
|
@ -89,11 +89,12 @@ class EmitCModel final : public EmitCFunc {
|
||||||
puts("\n");
|
puts("\n");
|
||||||
|
|
||||||
puts("// This class is the main interface to the Verilated model\n");
|
puts("// This class is the main interface to the Verilated model\n");
|
||||||
|
puts("class " + topClassName() + " VL_NOT_FINAL : ");
|
||||||
if (optSystemC()) {
|
if (optSystemC()) {
|
||||||
puts("SC_MODULE(" + topClassName() + ") {\n");
|
// SC_MODULE, but with multiple-inheritance of VerilatedModel
|
||||||
} else {
|
puts("public ::sc_core::sc_module, ");
|
||||||
puts("class " + topClassName() + " VL_NOT_FINAL {\n");
|
|
||||||
}
|
}
|
||||||
|
puts("public VerilatedModel {\n");
|
||||||
ofp()->resetPrivate();
|
ofp()->resetPrivate();
|
||||||
ofp()->putsPrivate(true); // private:
|
ofp()->putsPrivate(true); // private:
|
||||||
|
|
||||||
|
|
@ -194,9 +195,6 @@ class EmitCModel final : public EmitCFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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()) {
|
if (!optSystemC()) {
|
||||||
puts("/// Retrieve name of this model instance (as passed to constructor).\n");
|
puts("/// Retrieve name of this model instance (as passed to constructor).\n");
|
||||||
puts("const char* name() const;\n");
|
puts("const char* name() const;\n");
|
||||||
|
|
@ -221,6 +219,11 @@ class EmitCModel final : public EmitCFunc {
|
||||||
+ topClassName() + "& rhs);\n");
|
+ topClassName() + "& rhs);\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
puts("\n// Abstract methods from VerilatedModel\n");
|
||||||
|
puts("const char* hierName() const override final;\n");
|
||||||
|
puts("const char* modelName() const override final;\n");
|
||||||
|
puts("unsigned threads() const override final;\n");
|
||||||
|
|
||||||
puts("} VL_ATTR_ALIGNED(VL_CACHE_LINE_BYTES);\n");
|
puts("} VL_ATTR_ALIGNED(VL_CACHE_LINE_BYTES);\n");
|
||||||
|
|
||||||
ofp()->putsEndGuard();
|
ofp()->putsEndGuard();
|
||||||
|
|
@ -235,10 +238,12 @@ class EmitCModel final : public EmitCFunc {
|
||||||
puts(topClassName() + "::" + topClassName());
|
puts(topClassName() + "::" + topClassName());
|
||||||
if (optSystemC()) {
|
if (optSystemC()) {
|
||||||
puts("(sc_module_name /* unused */)\n");
|
puts("(sc_module_name /* unused */)\n");
|
||||||
puts(" : vlSymsp{new " + symClassName() + "(nullptr, name(), this)}\n");
|
puts(" : VerilatedModel{*Verilated::threadContextp()}\n");
|
||||||
|
puts(" , vlSymsp{new " + symClassName() + "(contextp(), name(), this)}\n");
|
||||||
} else {
|
} else {
|
||||||
puts(+"(VerilatedContext* _vcontextp__, const char* _vcname__)\n");
|
puts(+"(VerilatedContext* _vcontextp__, const char* _vcname__)\n");
|
||||||
puts(" : vlSymsp{new " + symClassName() + "(_vcontextp__, _vcname__, this)}\n");
|
puts(" : VerilatedModel{*_vcontextp__}\n");
|
||||||
|
puts(" , vlSymsp{new " + symClassName() + "(contextp(), _vcname__, this)}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up IO references
|
// Set up IO references
|
||||||
|
|
@ -263,6 +268,8 @@ class EmitCModel final : public EmitCFunc {
|
||||||
puts(" , rootp{&(vlSymsp->TOP)}\n");
|
puts(" , rootp{&(vlSymsp->TOP)}\n");
|
||||||
|
|
||||||
puts("{\n");
|
puts("{\n");
|
||||||
|
puts("// Register model with the context\n");
|
||||||
|
puts("contextp()->addModel(this);\n");
|
||||||
|
|
||||||
if (optSystemC()) {
|
if (optSystemC()) {
|
||||||
// Create sensitivity list for when to evaluate the model.
|
// Create sensitivity list for when to evaluate the model.
|
||||||
|
|
@ -301,7 +308,7 @@ class EmitCModel final : public EmitCFunc {
|
||||||
if (!optSystemC()) {
|
if (!optSystemC()) {
|
||||||
puts("\n");
|
puts("\n");
|
||||||
puts(topClassName() + "::" + topClassName() + "(const char* _vcname__)\n");
|
puts(topClassName() + "::" + topClassName() + "(const char* _vcname__)\n");
|
||||||
puts(" : " + topClassName() + "(nullptr, _vcname__)\n{\n}\n");
|
puts(" : " + topClassName() + "(Verilated::threadContextp(), _vcname__)\n{\n}\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -364,7 +371,7 @@ class EmitCModel final : public EmitCFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v3Global.opt.profExec()) {
|
if (v3Global.opt.profExec()) {
|
||||||
puts("vlSymsp->__Vm_executionProfiler.configure(*(vlSymsp->_vm_contextp__));\n");
|
puts("vlSymsp->__Vm_executionProfilerp->configure();\n");
|
||||||
puts("VL_EXEC_TRACE_ADD_RECORD(vlSymsp).evalBegin();\n");
|
puts("VL_EXEC_TRACE_ADD_RECORD(vlSymsp).evalBegin();\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -399,10 +406,6 @@ class EmitCModel final : public EmitCFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
putSectionDelimiter("Utilities");
|
putSectionDelimiter("Utilities");
|
||||||
// ::contextp
|
|
||||||
puts("\nVerilatedContext* " + topClassName() + "::contextp() const {\n");
|
|
||||||
puts(/**/ "return vlSymsp->_vm_contextp__;\n");
|
|
||||||
puts("}\n");
|
|
||||||
|
|
||||||
if (!optSystemC()) {
|
if (!optSystemC()) {
|
||||||
// ::name
|
// ::name
|
||||||
|
|
@ -419,6 +422,13 @@ class EmitCModel final : public EmitCFunc {
|
||||||
puts("\nVL_ATTR_COLD void " + topClassName() + "::final() {\n");
|
puts("\nVL_ATTR_COLD void " + topClassName() + "::final() {\n");
|
||||||
puts(/**/ topModNameProtected + "__" + protect("_eval_final") + "(&(vlSymsp->TOP));\n");
|
puts(/**/ topModNameProtected + "__" + protect("_eval_final") + "(&(vlSymsp->TOP));\n");
|
||||||
puts("}\n");
|
puts("}\n");
|
||||||
|
|
||||||
|
putSectionDelimiter("Implementations of abstract methods from VerilatedModel\n");
|
||||||
|
puts("const char* " + topClassName() + "::hierName() const { return vlSymsp->name(); }\n");
|
||||||
|
puts("const char* " + topClassName() + "::modelName() const { return \"" + topClassName()
|
||||||
|
+ "\"; }\n");
|
||||||
|
puts("unsigned " + topClassName() + "::threads() const { return "
|
||||||
|
+ cvtToStr(std::max(1, v3Global.opt.threads())) + "; }\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitTraceMethods(AstNodeModule* modp) {
|
void emitTraceMethods(AstNodeModule* modp) {
|
||||||
|
|
@ -471,7 +481,8 @@ class EmitCModel final : public EmitCFunc {
|
||||||
puts(/**/ "}");
|
puts(/**/ "}");
|
||||||
}
|
}
|
||||||
puts(/**/ "if (false && levels && options) {} // Prevent unused\n");
|
puts(/**/ "if (false && levels && options) {} // Prevent unused\n");
|
||||||
puts(/**/ "tfp->spTrace()->addInitCb(&" + protect("trace_init") + ", &(vlSymsp->TOP));\n");
|
puts(/**/ "tfp->spTrace()->addInitCb(&" + protect("trace_init")
|
||||||
|
+ ", &(vlSymsp->TOP), contextp());\n");
|
||||||
puts(/**/ topModNameProtected + "__" + protect("trace_register")
|
puts(/**/ topModNameProtected + "__" + protect("trace_register")
|
||||||
+ "(&(vlSymsp->TOP), tfp->spTrace());\n");
|
+ "(&(vlSymsp->TOP), tfp->spTrace());\n");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -446,17 +446,17 @@ void EmitCSyms::emitSymHdr() {
|
||||||
if (v3Global.hasEvents()) puts("std::vector<VlEvent*> __Vm_triggeredEvents;\n");
|
if (v3Global.hasEvents()) puts("std::vector<VlEvent*> __Vm_triggeredEvents;\n");
|
||||||
puts("bool __Vm_didInit = false;\n");
|
puts("bool __Vm_didInit = false;\n");
|
||||||
|
|
||||||
if (v3Global.opt.profExec()) {
|
|
||||||
puts("\n// EXECUTION PROFILING\n");
|
|
||||||
puts("VlExecutionProfiler __Vm_executionProfiler;\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (v3Global.opt.mtasks()) {
|
if (v3Global.opt.mtasks()) {
|
||||||
puts("\n// MULTI-THREADING\n");
|
puts("\n// MULTI-THREADING\n");
|
||||||
puts("VlThreadPool* const __Vm_threadPoolp;\n");
|
puts("VlThreadPool* const __Vm_threadPoolp;\n");
|
||||||
puts("bool __Vm_even_cycle = false;\n");
|
puts("bool __Vm_even_cycle = false;\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (v3Global.opt.profExec()) {
|
||||||
|
puts("\n// EXECUTION PROFILING\n");
|
||||||
|
puts("VlExecutionProfiler* const __Vm_executionProfilerp;\n");
|
||||||
|
}
|
||||||
|
|
||||||
puts("\n// MODULE INSTANCE STATE\n");
|
puts("\n// MODULE INSTANCE STATE\n");
|
||||||
for (const auto& i : m_scopes) {
|
for (const auto& i : m_scopes) {
|
||||||
const AstScope* const scopep = i.first;
|
const AstScope* const scopep = i.first;
|
||||||
|
|
@ -690,7 +690,6 @@ void EmitCSyms::emitSymImp() {
|
||||||
puts("_vm_pgoProfiler.write(\"" + topClassName()
|
puts("_vm_pgoProfiler.write(\"" + topClassName()
|
||||||
+ "\", _vm_contextp__->profVltFilename());\n");
|
+ "\", _vm_contextp__->profVltFilename());\n");
|
||||||
}
|
}
|
||||||
if (v3Global.opt.mtasks()) puts("delete __Vm_threadPoolp;\n");
|
|
||||||
puts("}\n\n");
|
puts("}\n\n");
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
|
|
@ -722,12 +721,13 @@ void EmitCSyms::emitSymImp() {
|
||||||
// Note we create N-1 threads in the thread pool. The thread
|
// Note we create N-1 threads in the thread pool. The thread
|
||||||
// that calls eval() becomes the final Nth thread for the
|
// that calls eval() becomes the final Nth thread for the
|
||||||
// duration of the eval call.
|
// duration of the eval call.
|
||||||
puts(" , __Vm_threadPoolp{new VlThreadPool{_vm_contextp__, "
|
puts(" , __Vm_threadPoolp{static_cast<VlThreadPool*>(contextp->threadPoolp())}\n");
|
||||||
+ cvtToStr(v3Global.opt.threads() - 1) + ", "
|
}
|
||||||
+ (v3Global.opt.profExec()
|
|
||||||
? "&__Vm_executionProfiler, &VlExecutionProfiler::startWorkerSetup"
|
if (v3Global.opt.profExec()) {
|
||||||
: "nullptr, nullptr")
|
puts(" , "
|
||||||
+ "}}\n");
|
"__Vm_executionProfilerp{static_cast<VlExecutionProfiler*>(contextp->"
|
||||||
|
"enableExecutionProfiler(&VlExecutionProfiler::construct))}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
puts(" // Setup module instances\n");
|
puts(" // Setup module instances\n");
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@ public:
|
||||||
putMakeClassEntry(of, v3Global.opt.traceSourceLang() + ".cpp");
|
putMakeClassEntry(of, v3Global.opt.traceSourceLang() + ".cpp");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (v3Global.opt.mtasks()) putMakeClassEntry(of, "verilated_threads.cpp");
|
if (v3Global.opt.threads()) putMakeClassEntry(of, "verilated_threads.cpp");
|
||||||
if (v3Global.opt.usesProfiler()) {
|
if (v3Global.opt.usesProfiler()) {
|
||||||
putMakeClassEntry(of, "verilated_profiler.cpp");
|
putMakeClassEntry(of, "verilated_profiler.cpp");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -225,11 +225,6 @@ private:
|
||||||
m_hash += nodep->text();
|
m_hash += nodep->text();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
virtual void visit(AstTestPlusArgs* nodep) override {
|
|
||||||
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { //
|
|
||||||
m_hash += nodep->text();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
virtual void visit(AstAddrOfCFunc* nodep) override {
|
virtual void visit(AstAddrOfCFunc* nodep) override {
|
||||||
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { //
|
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { //
|
||||||
iterateNull(nodep->funcp());
|
iterateNull(nodep->funcp());
|
||||||
|
|
|
||||||
|
|
@ -217,6 +217,13 @@ private:
|
||||||
iterateAndNextNull(nodep->msbp());
|
iterateAndNextNull(nodep->msbp());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstTestPlusArgs* nodep) override {
|
||||||
|
VL_RESTORER(m_setRefLvalue);
|
||||||
|
{
|
||||||
|
m_setRefLvalue = VAccess::NOCHANGE;
|
||||||
|
iterateAndNextNull(nodep->searchp());
|
||||||
|
}
|
||||||
|
}
|
||||||
virtual void visit(AstValuePlusArgs* nodep) override {
|
virtual void visit(AstValuePlusArgs* nodep) override {
|
||||||
VL_RESTORER(m_setRefLvalue);
|
VL_RESTORER(m_setRefLvalue);
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -319,43 +319,45 @@ private:
|
||||||
while (argp) {
|
while (argp) {
|
||||||
if (skipCount) {
|
if (skipCount) {
|
||||||
argp = argp->nextp();
|
argp = argp->nextp();
|
||||||
skipCount--;
|
--skipCount;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const AstConst* const constp = VN_CAST(argp, Const);
|
const AstConst* const constp = VN_CAST(argp, Const);
|
||||||
const bool isFromString = (constp) ? constp->num().isFromString() : false;
|
const bool isFromString = (constp) ? constp->num().isFromString() : false;
|
||||||
if (isFromString) {
|
if (isFromString) {
|
||||||
const int numchars = argp->dtypep()->width() / 8;
|
const int numchars = argp->dtypep()->width() / 8;
|
||||||
string str(numchars, ' ');
|
if (!constp->num().toString().empty()) {
|
||||||
// now scan for % operators
|
string str(numchars, ' ');
|
||||||
bool inpercent = false;
|
// now scan for % operators
|
||||||
for (int i = 0; i < numchars; i++) {
|
bool inpercent = false;
|
||||||
const int ii = numchars - i - 1;
|
for (int i = 0; i < numchars; i++) {
|
||||||
const char c = constp->num().dataByte(ii);
|
const int ii = numchars - i - 1;
|
||||||
str[i] = c;
|
const char c = constp->num().dataByte(ii);
|
||||||
if (!inpercent && c == '%') {
|
str[i] = c;
|
||||||
inpercent = true;
|
if (!inpercent && c == '%') {
|
||||||
} else if (inpercent) {
|
inpercent = true;
|
||||||
inpercent = false;
|
} else if (inpercent) {
|
||||||
switch (c) {
|
inpercent = false;
|
||||||
case '0': // FALLTHRU
|
switch (c) {
|
||||||
case '1': // FALLTHRU
|
case '0': // FALLTHRU
|
||||||
case '2': // FALLTHRU
|
case '1': // FALLTHRU
|
||||||
case '3': // FALLTHRU
|
case '2': // FALLTHRU
|
||||||
case '4': // FALLTHRU
|
case '3': // FALLTHRU
|
||||||
case '5': // FALLTHRU
|
case '4': // FALLTHRU
|
||||||
case '6': // FALLTHRU
|
case '5': // FALLTHRU
|
||||||
case '7': // FALLTHRU
|
case '6': // FALLTHRU
|
||||||
case '8': // FALLTHRU
|
case '7': // FALLTHRU
|
||||||
case '9': // FALLTHRU
|
case '8': // FALLTHRU
|
||||||
case '.': inpercent = true; break;
|
case '9': // FALLTHRU
|
||||||
case '%': break;
|
case '.': inpercent = true; break;
|
||||||
default:
|
case '%': break;
|
||||||
if (V3Number::displayedFmtLegal(c, isScan)) ++skipCount;
|
default:
|
||||||
|
if (V3Number::displayedFmtLegal(c, isScan)) ++skipCount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
newFormat.append(str);
|
||||||
}
|
}
|
||||||
newFormat.append(str);
|
|
||||||
AstNode* const nextp = argp->nextp();
|
AstNode* const nextp = argp->nextp();
|
||||||
argp->unlinkFrBack();
|
argp->unlinkFrBack();
|
||||||
VL_DO_DANGLING(pushDeletep(argp), argp);
|
VL_DO_DANGLING(pushDeletep(argp), argp);
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
//*************************************************************************
|
//*************************************************************************
|
||||||
//
|
//
|
||||||
// void example_usage() {
|
// void example_usage() {
|
||||||
// SimulateVisitor simvis (false, false);
|
// SimulateVisitor simvis{false, false};
|
||||||
// simvis.clear();
|
// simvis.clear();
|
||||||
// // Set all inputs to the constant
|
// // Set all inputs to the constant
|
||||||
// for (deque<AstVarScope*>::iterator it = m_inVarps.begin(); it!=m_inVarps.end(); ++it) {
|
// for (deque<AstVarScope*>::iterator it = m_inVarps.begin(); it!=m_inVarps.end(); ++it) {
|
||||||
|
|
@ -100,6 +100,7 @@ private:
|
||||||
bool m_anyAssignDly; ///< True if found a delayed assignment
|
bool m_anyAssignDly; ///< True if found a delayed assignment
|
||||||
bool m_anyAssignComb; ///< True if found a non-delayed assignment
|
bool m_anyAssignComb; ///< True if found a non-delayed assignment
|
||||||
bool m_inDlyAssign; ///< Under delayed assignment
|
bool m_inDlyAssign; ///< Under delayed assignment
|
||||||
|
bool m_isOutputter; // Creates output
|
||||||
int m_instrCount; ///< Number of nodes
|
int m_instrCount; ///< Number of nodes
|
||||||
int m_dataCount; ///< Bytes of data
|
int m_dataCount; ///< Bytes of data
|
||||||
AstJumpGo* m_jumpp; ///< Jump label we're branching from
|
AstJumpGo* m_jumpp; ///< Jump label we're branching from
|
||||||
|
|
@ -130,7 +131,7 @@ private:
|
||||||
const int width = itemp->width();
|
const int width = itemp->width();
|
||||||
const int lsb = itemp->lsb();
|
const int lsb = itemp->lsb();
|
||||||
const int msb = lsb + width - 1;
|
const int msb = lsb + width - 1;
|
||||||
V3Number fieldNum(nump, width);
|
V3Number fieldNum{nump, width};
|
||||||
fieldNum.opSel(*nump, msb, lsb);
|
fieldNum.opSel(*nump, msb, lsb);
|
||||||
out << itemp->name() << ": ";
|
out << itemp->name() << ": ";
|
||||||
if (AstNodeDType* const childTypep = itemp->subDTypep()) {
|
if (AstNodeDType* const childTypep = itemp->subDTypep()) {
|
||||||
|
|
@ -152,7 +153,7 @@ private:
|
||||||
const int width = childTypep->width();
|
const int width = childTypep->width();
|
||||||
const int lsb = width * element;
|
const int lsb = width * element;
|
||||||
const int msb = lsb + width - 1;
|
const int msb = lsb + width - 1;
|
||||||
V3Number fieldNum(nump, width);
|
V3Number fieldNum{nump, width};
|
||||||
fieldNum.opSel(*nump, msb, lsb);
|
fieldNum.opSel(*nump, msb, lsb);
|
||||||
const int arrayElem = arrayp->lo() + element;
|
const int arrayElem = arrayp->lo() + element;
|
||||||
out << arrayElem << " = " << prettyNumber(&fieldNum, childTypep);
|
out << arrayElem << " = " << prettyNumber(&fieldNum, childTypep);
|
||||||
|
|
@ -205,6 +206,7 @@ public:
|
||||||
AstNode* whyNotNodep() const { return m_whyNotNodep; }
|
AstNode* whyNotNodep() const { return m_whyNotNodep; }
|
||||||
|
|
||||||
bool isAssignDly() const { return m_anyAssignDly; }
|
bool isAssignDly() const { return m_anyAssignDly; }
|
||||||
|
bool isOutputter() const { return m_isOutputter; }
|
||||||
int instrCount() const { return m_instrCount; }
|
int instrCount() const { return m_instrCount; }
|
||||||
int dataCount() const { return m_dataCount; }
|
int dataCount() const { return m_dataCount; }
|
||||||
|
|
||||||
|
|
@ -236,7 +238,7 @@ private:
|
||||||
}
|
}
|
||||||
if (allocNewConst) {
|
if (allocNewConst) {
|
||||||
// Need to allocate new constant
|
// Need to allocate new constant
|
||||||
constp = new AstConst(nodep->fileline(), AstConst::DtypedValue(), nodep->dtypep(), 0);
|
constp = new AstConst{nodep->fileline(), AstConst::DtypedValue{}, nodep->dtypep(), 0};
|
||||||
// Mark as in use, add to free list for later reuse
|
// Mark as in use, add to free list for later reuse
|
||||||
constp->user2(1);
|
constp->user2(1);
|
||||||
freeList.push_back(constp);
|
freeList.push_back(constp);
|
||||||
|
|
@ -342,15 +344,16 @@ private:
|
||||||
nodep->user2p((void*)valuep);
|
nodep->user2p((void*)valuep);
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkNodeInfo(AstNode* nodep) {
|
void checkNodeInfo(AstNode* nodep, bool ignorePredict = false) {
|
||||||
if (m_checkOnly) {
|
if (m_checkOnly) {
|
||||||
m_instrCount += nodep->instrCount();
|
m_instrCount += nodep->instrCount();
|
||||||
m_dataCount += nodep->width();
|
m_dataCount += nodep->width();
|
||||||
}
|
}
|
||||||
if (!nodep->isPredictOptimizable()) {
|
if (!ignorePredict && !nodep->isPredictOptimizable()) {
|
||||||
// UINFO(9, " !predictopt " << nodep << endl);
|
// UINFO(9, " !predictopt " << nodep << endl);
|
||||||
clearOptimizable(nodep, "Isn't predictable");
|
clearOptimizable(nodep, "Isn't predictable");
|
||||||
}
|
}
|
||||||
|
if (nodep->isOutputter()) m_isOutputter = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void badNodeType(AstNode* nodep) {
|
void badNodeType(AstNode* nodep) {
|
||||||
|
|
@ -683,15 +686,15 @@ private:
|
||||||
initp = vscpnump;
|
initp = vscpnump;
|
||||||
} else { // Assignment to unassigned variable, all bits are X
|
} else { // Assignment to unassigned variable, all bits are X
|
||||||
// TODO generic initialization which builds X/arrays by recursion
|
// TODO generic initialization which builds X/arrays by recursion
|
||||||
AstConst* const outconstp = new AstConst(
|
AstConst* const outconstp = new AstConst{
|
||||||
nodep->fileline(), AstConst::WidthedValue(), basicp->widthMin(), 0);
|
nodep->fileline(), AstConst::WidthedValue{}, basicp->widthMin(), 0};
|
||||||
if (basicp->isZeroInit()) {
|
if (basicp->isZeroInit()) {
|
||||||
outconstp->num().setAllBits0();
|
outconstp->num().setAllBits0();
|
||||||
} else {
|
} else {
|
||||||
outconstp->num().setAllBitsX();
|
outconstp->num().setAllBitsX();
|
||||||
}
|
}
|
||||||
|
|
||||||
initp = new AstInitArray(nodep->fileline(), arrayp, outconstp);
|
initp = new AstInitArray{nodep->fileline(), arrayp, outconstp};
|
||||||
m_reclaimValuesp.push_back(initp);
|
m_reclaimValuesp.push_back(initp);
|
||||||
}
|
}
|
||||||
const uint32_t index = fetchConst(selp->bitp())->toUInt();
|
const uint32_t index = fetchConst(selp->bitp())->toUInt();
|
||||||
|
|
@ -706,7 +709,7 @@ private:
|
||||||
}
|
}
|
||||||
void handleAssignSel(AstNodeAssign* nodep, AstSel* selp) {
|
void handleAssignSel(AstNodeAssign* nodep, AstSel* selp) {
|
||||||
AstVarRef* varrefp = nullptr;
|
AstVarRef* varrefp = nullptr;
|
||||||
V3Number lsb(nodep);
|
V3Number lsb{nodep};
|
||||||
iterateAndNextNull(nodep->rhsp()); // Value to assign
|
iterateAndNextNull(nodep->rhsp()); // Value to assign
|
||||||
handleAssignSelRecurse(nodep, selp, varrefp /*ref*/, lsb /*ref*/, 0);
|
handleAssignSelRecurse(nodep, selp, varrefp /*ref*/, lsb /*ref*/, 0);
|
||||||
if (!m_checkOnly && optimizable()) {
|
if (!m_checkOnly && optimizable()) {
|
||||||
|
|
@ -719,8 +722,8 @@ private:
|
||||||
} else if (AstConst* const vscpnump = fetchConstNull(vscp)) {
|
} else if (AstConst* const vscpnump = fetchConstNull(vscp)) {
|
||||||
outconstp = vscpnump;
|
outconstp = vscpnump;
|
||||||
} else { // Assignment to unassigned variable, all bits are X or 0
|
} else { // Assignment to unassigned variable, all bits are X or 0
|
||||||
outconstp = new AstConst(nodep->fileline(), AstConst::WidthedValue(),
|
outconstp = new AstConst{nodep->fileline(), AstConst::WidthedValue{},
|
||||||
varrefp->varp()->widthMin(), 0);
|
varrefp->varp()->widthMin(), 0};
|
||||||
if (varrefp->varp()->basicp() && varrefp->varp()->basicp()->isZeroInit()) {
|
if (varrefp->varp()->basicp() && varrefp->varp()->basicp()->isZeroInit()) {
|
||||||
outconstp->num().setAllBits0();
|
outconstp->num().setAllBits0();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -742,7 +745,7 @@ private:
|
||||||
lsbRef = fetchConst(selp->lsbp())->num();
|
lsbRef = fetchConst(selp->lsbp())->num();
|
||||||
return; // And presumably still optimizable()
|
return; // And presumably still optimizable()
|
||||||
} else if (AstSel* const subselp = VN_CAST(selp->lhsp(), Sel)) {
|
} else if (AstSel* const subselp = VN_CAST(selp->lhsp(), Sel)) {
|
||||||
V3Number sublsb(nodep);
|
V3Number sublsb{nodep};
|
||||||
handleAssignSelRecurse(nodep, subselp, outVarrefpRef, sublsb /*ref*/, depth + 1);
|
handleAssignSelRecurse(nodep, subselp, outVarrefpRef, sublsb /*ref*/, depth + 1);
|
||||||
if (optimizable()) {
|
if (optimizable()) {
|
||||||
lsbRef = sublsb;
|
lsbRef = sublsb;
|
||||||
|
|
@ -756,6 +759,7 @@ private:
|
||||||
virtual void visit(AstNodeAssign* nodep) override {
|
virtual void visit(AstNodeAssign* nodep) override {
|
||||||
if (jumpingOver(nodep)) return;
|
if (jumpingOver(nodep)) return;
|
||||||
if (!optimizable()) return; // Accelerate
|
if (!optimizable()) return; // Accelerate
|
||||||
|
checkNodeInfo(nodep);
|
||||||
if (VN_IS(nodep, AssignForce)) {
|
if (VN_IS(nodep, AssignForce)) {
|
||||||
clearOptimizable(nodep, "Force");
|
clearOptimizable(nodep, "Force");
|
||||||
} else if (VN_IS(nodep, AssignDly)) {
|
} else if (VN_IS(nodep, AssignDly)) {
|
||||||
|
|
@ -829,7 +833,7 @@ private:
|
||||||
if (hit) break;
|
if (hit) break;
|
||||||
iterateAndNextNull(ep);
|
iterateAndNextNull(ep);
|
||||||
if (optimizable()) {
|
if (optimizable()) {
|
||||||
V3Number match(nodep, 1);
|
V3Number match{nodep, 1};
|
||||||
match.opEq(fetchConst(nodep->exprp())->num(), fetchConst(ep)->num());
|
match.opEq(fetchConst(nodep->exprp())->num(), fetchConst(ep)->num());
|
||||||
if (match.isNeqZero()) {
|
if (match.isNeqZero()) {
|
||||||
iterateAndNextNull(itemp->bodysp());
|
iterateAndNextNull(itemp->bodysp());
|
||||||
|
|
@ -970,6 +974,7 @@ private:
|
||||||
if (jumpingOver(nodep)) return;
|
if (jumpingOver(nodep)) return;
|
||||||
if (!optimizable()) return; // Accelerate
|
if (!optimizable()) return; // Accelerate
|
||||||
UINFO(5, " FUNCREF " << nodep << endl);
|
UINFO(5, " FUNCREF " << nodep << endl);
|
||||||
|
checkNodeInfo(nodep);
|
||||||
if (!m_params) {
|
if (!m_params) {
|
||||||
badNodeType(nodep);
|
badNodeType(nodep);
|
||||||
return;
|
return;
|
||||||
|
|
@ -1053,6 +1058,7 @@ private:
|
||||||
virtual void visit(AstSFormatF* nodep) override {
|
virtual void visit(AstSFormatF* nodep) override {
|
||||||
if (jumpingOver(nodep)) return;
|
if (jumpingOver(nodep)) return;
|
||||||
if (!optimizable()) return; // Accelerate
|
if (!optimizable()) return; // Accelerate
|
||||||
|
checkNodeInfo(nodep);
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
if (m_params) {
|
if (m_params) {
|
||||||
AstNode* nextArgp = nodep->exprsp();
|
AstNode* nextArgp = nodep->exprsp();
|
||||||
|
|
@ -1097,7 +1103,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
AstConst* const resultConstp
|
AstConst* const resultConstp
|
||||||
= new AstConst(nodep->fileline(), AstConst::String(), result);
|
= new AstConst{nodep->fileline(), AstConst::String{}, result};
|
||||||
setValue(nodep, resultConstp);
|
setValue(nodep, resultConstp);
|
||||||
m_reclaimValuesp.push_back(resultConstp);
|
m_reclaimValuesp.push_back(resultConstp);
|
||||||
}
|
}
|
||||||
|
|
@ -1106,6 +1112,9 @@ private:
|
||||||
virtual void visit(AstDisplay* nodep) override {
|
virtual void visit(AstDisplay* nodep) override {
|
||||||
if (jumpingOver(nodep)) return;
|
if (jumpingOver(nodep)) return;
|
||||||
if (!optimizable()) return; // Accelerate
|
if (!optimizable()) return; // Accelerate
|
||||||
|
// We ignore isPredictOptimizable as $display is often in constant
|
||||||
|
// functions and we want them to work if used with parameters
|
||||||
|
checkNodeInfo(nodep, /*display:*/ true);
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
if (m_params) {
|
if (m_params) {
|
||||||
AstConst* const textp = fetchConst(nodep->fmtp());
|
AstConst* const textp = fetchConst(nodep->fmtp());
|
||||||
|
|
@ -1155,6 +1164,7 @@ public:
|
||||||
m_anyAssignComb = false;
|
m_anyAssignComb = false;
|
||||||
m_anyAssignDly = false;
|
m_anyAssignDly = false;
|
||||||
m_inDlyAssign = false;
|
m_inDlyAssign = false;
|
||||||
|
m_isOutputter = false;
|
||||||
m_instrCount = 0;
|
m_instrCount = 0;
|
||||||
m_dataCount = 0;
|
m_dataCount = 0;
|
||||||
m_jumpp = nullptr;
|
m_jumpp = nullptr;
|
||||||
|
|
|
||||||
|
|
@ -92,8 +92,8 @@ public:
|
||||||
= elemDType->isString()
|
= elemDType->isString()
|
||||||
? elemDType
|
? elemDType
|
||||||
: v3Global.rootp()->findBitDType(width, width, VSigning::UNSIGNED);
|
: v3Global.rootp()->findBitDType(width, width, VSigning::UNSIGNED);
|
||||||
AstUnpackArrayDType* const tableDTypep
|
AstUnpackArrayDType* const tableDTypep = new AstUnpackArrayDType{
|
||||||
= new AstUnpackArrayDType(m_fl, subDTypep, new AstRange(m_fl, size, 0));
|
m_fl, subDTypep, new AstRange{m_fl, static_cast<int>(size), 0}};
|
||||||
v3Global.rootp()->typeTablep()->addTypesp(tableDTypep);
|
v3Global.rootp()->typeTablep()->addTypesp(tableDTypep);
|
||||||
// Create table initializer (with default value 0)
|
// Create table initializer (with default value 0)
|
||||||
AstConst* const defaultp = elemDType->isString()
|
AstConst* const defaultp = elemDType->isString()
|
||||||
|
|
@ -106,7 +106,7 @@ public:
|
||||||
UASSERT_OBJ(!m_varScopep, m_fl, "Table variable already created");
|
UASSERT_OBJ(!m_varScopep, m_fl, "Table variable already created");
|
||||||
// Default value is zero/empty string so don't add it
|
// Default value is zero/empty string so don't add it
|
||||||
if (value.isString() ? value.toString().empty() : value.isEqZero()) return;
|
if (value.isString() ? value.toString().empty() : value.isEqZero()) return;
|
||||||
m_initp->addIndexValuep(index, new AstConst(m_fl, value));
|
m_initp->addIndexValuep(index, new AstConst{m_fl, value});
|
||||||
}
|
}
|
||||||
|
|
||||||
AstVarScope* varScopep() {
|
AstVarScope* varScopep() {
|
||||||
|
|
@ -225,6 +225,9 @@ private:
|
||||||
if (!m_outWidthBytes || !m_inWidthBits) {
|
if (!m_outWidthBytes || !m_inWidthBits) {
|
||||||
chkvis.clearOptimizable(nodep, "Table has no outputs");
|
chkvis.clearOptimizable(nodep, "Table has no outputs");
|
||||||
}
|
}
|
||||||
|
if (chkvis.isOutputter()) {
|
||||||
|
chkvis.clearOptimizable(nodep, "Table creates display output");
|
||||||
|
}
|
||||||
UINFO(4, " Test: Opt=" << (chkvis.optimizable() ? "OK" : "NO") << ", Instrs="
|
UINFO(4, " Test: Opt=" << (chkvis.optimizable() ? "OK" : "NO") << ", Instrs="
|
||||||
<< chkvis.instrCount() << " Data=" << chkvis.dataCount()
|
<< chkvis.instrCount() << " Data=" << chkvis.dataCount()
|
||||||
<< " in width (bits)=" << m_inWidthBits << " out width (bytes)="
|
<< " in width (bits)=" << m_inWidthBits << " out width (bytes)="
|
||||||
|
|
@ -247,14 +250,14 @@ private:
|
||||||
|
|
||||||
// We will need a table index variable, create it here.
|
// We will need a table index variable, create it here.
|
||||||
AstVar* const indexVarp
|
AstVar* const indexVarp
|
||||||
= new AstVar(fl, VVarType::BLOCKTEMP, "__Vtableidx" + cvtToStr(m_modTables),
|
= new AstVar{fl, VVarType::BLOCKTEMP, "__Vtableidx" + cvtToStr(m_modTables),
|
||||||
VFlagBitPacked(), m_inWidthBits);
|
VFlagBitPacked{}, static_cast<int>(m_inWidthBits)};
|
||||||
m_modp->addStmtp(indexVarp);
|
m_modp->addStmtp(indexVarp);
|
||||||
AstVarScope* const indexVscp = new AstVarScope(indexVarp->fileline(), m_scopep, indexVarp);
|
AstVarScope* const indexVscp = new AstVarScope{indexVarp->fileline(), m_scopep, indexVarp};
|
||||||
m_scopep->addVarp(indexVscp);
|
m_scopep->addVarp(indexVscp);
|
||||||
|
|
||||||
// The 'output assigned' table builder
|
// The 'output assigned' table builder
|
||||||
TableBuilder outputAssignedTableBuilder(fl);
|
TableBuilder outputAssignedTableBuilder{fl};
|
||||||
outputAssignedTableBuilder.setTableSize(
|
outputAssignedTableBuilder.setTableSize(
|
||||||
nodep->findBitDType(m_outVarps.size(), m_outVarps.size(), VSigning::UNSIGNED),
|
nodep->findBitDType(m_outVarps.size(), m_outVarps.size(), VSigning::UNSIGNED),
|
||||||
VL_MASK_I(m_inWidthBits));
|
VL_MASK_I(m_inWidthBits));
|
||||||
|
|
@ -311,7 +314,7 @@ private:
|
||||||
<< simvis.whyNotMessage());
|
<< simvis.whyNotMessage());
|
||||||
|
|
||||||
// Build output value tables and the assigned flags table
|
// Build output value tables and the assigned flags table
|
||||||
V3Number outputAssignedMask(nodep, m_outVarps.size(), 0);
|
V3Number outputAssignedMask{nodep, static_cast<int>(m_outVarps.size()), 0};
|
||||||
for (TableOutputVar& tov : m_outVarps) {
|
for (TableOutputVar& tov : m_outVarps) {
|
||||||
if (V3Number* const outnump = simvis.fetchOutNumberNull(tov.varScopep())) {
|
if (V3Number* const outnump = simvis.fetchOutNumberNull(tov.varScopep())) {
|
||||||
UINFO(8, " Output " << tov.name() << " = " << *outnump << endl);
|
UINFO(8, " Output " << tov.name() << " = " << *outnump << endl);
|
||||||
|
|
@ -333,21 +336,21 @@ private:
|
||||||
// First var in inVars becomes the LSB of the concat
|
// First var in inVars becomes the LSB of the concat
|
||||||
AstNode* concatp = nullptr;
|
AstNode* concatp = nullptr;
|
||||||
for (AstVarScope* invscp : m_inVarps) {
|
for (AstVarScope* invscp : m_inVarps) {
|
||||||
AstVarRef* const refp = new AstVarRef(fl, invscp, VAccess::READ);
|
AstVarRef* const refp = new AstVarRef{fl, invscp, VAccess::READ};
|
||||||
if (concatp) {
|
if (concatp) {
|
||||||
concatp = new AstConcat(fl, refp, concatp);
|
concatp = new AstConcat{fl, refp, concatp};
|
||||||
} else {
|
} else {
|
||||||
concatp = refp;
|
concatp = refp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new AstAssign(fl, new AstVarRef(fl, indexVscp, VAccess::WRITE), concatp);
|
return new AstAssign{fl, new AstVarRef{fl, indexVscp, VAccess::WRITE}, concatp};
|
||||||
}
|
}
|
||||||
|
|
||||||
AstArraySel* select(FileLine* fl, AstVarScope* fromp, AstVarScope* indexp) {
|
AstArraySel* select(FileLine* fl, AstVarScope* fromp, AstVarScope* indexp) {
|
||||||
AstVarRef* const fromRefp = new AstVarRef(fl, fromp, VAccess::READ);
|
AstVarRef* const fromRefp = new AstVarRef{fl, fromp, VAccess::READ};
|
||||||
AstVarRef* const indexRefp = new AstVarRef(fl, indexp, VAccess::READ);
|
AstVarRef* const indexRefp = new AstVarRef{fl, indexp, VAccess::READ};
|
||||||
return new AstArraySel(fl, fromRefp, indexRefp);
|
return new AstArraySel{fl, fromRefp, indexRefp};
|
||||||
}
|
}
|
||||||
|
|
||||||
void createOutputAssigns(AstNode* nodep, AstNode* stmtsp, AstVarScope* indexVscp,
|
void createOutputAssigns(AstNode* nodep, AstNode* stmtsp, AstVarScope* indexVscp,
|
||||||
|
|
@ -362,12 +365,12 @@ private:
|
||||||
|
|
||||||
// If this output is unassigned on some code paths, wrap the assignment in an If
|
// If this output is unassigned on some code paths, wrap the assignment in an If
|
||||||
if (tov.mayBeUnassigned()) {
|
if (tov.mayBeUnassigned()) {
|
||||||
V3Number outputChgMask(nodep, m_outVarps.size(), 0);
|
V3Number outputChgMask{nodep, static_cast<int>(m_outVarps.size()), 0};
|
||||||
outputChgMask.setBit(tov.ord(), 1);
|
outputChgMask.setBit(tov.ord(), 1);
|
||||||
AstNode* const condp
|
AstNode* const condp
|
||||||
= new AstAnd(fl, select(fl, outputAssignedTableVscp, indexVscp),
|
= new AstAnd{fl, select(fl, outputAssignedTableVscp, indexVscp),
|
||||||
new AstConst(fl, outputChgMask));
|
new AstConst{fl, outputChgMask}};
|
||||||
outsetp = new AstIf(fl, condp, outsetp);
|
outsetp = new AstIf{fl, condp, outsetp};
|
||||||
}
|
}
|
||||||
|
|
||||||
stmtsp->addNext(outsetp);
|
stmtsp->addNext(outsetp);
|
||||||
|
|
|
||||||
|
|
@ -512,8 +512,10 @@ private:
|
||||||
m_regFuncp->addStmtsp(new AstText(flp, "tracep->addChgCb(", true));
|
m_regFuncp->addStmtsp(new AstText(flp, "tracep->addChgCb(", true));
|
||||||
}
|
}
|
||||||
m_regFuncp->addStmtsp(new AstAddrOfCFunc(flp, funcp));
|
m_regFuncp->addStmtsp(new AstAddrOfCFunc(flp, funcp));
|
||||||
const string threadPool{m_parallelism > 1 ? "vlSymsp->__Vm_threadPoolp" : "nullptr"};
|
m_regFuncp->addStmtsp(new AstText(flp, ", vlSelf", true));
|
||||||
m_regFuncp->addStmtsp(new AstText(flp, ", vlSelf, " + threadPool + ");\n", true));
|
m_regFuncp->addStmtsp(
|
||||||
|
new AstText(flp, ", vlSelf->vlSymsp->__Vm_modelp->contextp()", true));
|
||||||
|
m_regFuncp->addStmtsp(new AstText(flp, ");\n", true));
|
||||||
} else {
|
} else {
|
||||||
// Sub functions
|
// Sub functions
|
||||||
funcp->argTypes(v3Global.opt.traceClassBase() + "::Buffer* bufp");
|
funcp->argTypes(v3Global.opt.traceClassBase() + "::Buffer* bufp");
|
||||||
|
|
@ -700,7 +702,8 @@ private:
|
||||||
// Register it
|
// Register it
|
||||||
m_regFuncp->addStmtsp(new AstText(fl, "tracep->addCleanupCb(", true));
|
m_regFuncp->addStmtsp(new AstText(fl, "tracep->addCleanupCb(", true));
|
||||||
m_regFuncp->addStmtsp(new AstAddrOfCFunc(fl, cleanupFuncp));
|
m_regFuncp->addStmtsp(new AstAddrOfCFunc(fl, cleanupFuncp));
|
||||||
m_regFuncp->addStmtsp(new AstText(fl, ", vlSelf);\n", true));
|
m_regFuncp->addStmtsp(
|
||||||
|
new AstText(fl, ", vlSelf, vlSelf->vlSymsp->__Vm_modelp->contextp());\n", true));
|
||||||
|
|
||||||
// Clear global activity flag
|
// Clear global activity flag
|
||||||
cleanupFuncp->addStmtsp(
|
cleanupFuncp->addStmtsp(
|
||||||
|
|
|
||||||
|
|
@ -448,7 +448,6 @@ private:
|
||||||
// Widths: Constant, terminal
|
// Widths: Constant, terminal
|
||||||
virtual void visit(AstTime* nodep) override { nodep->dtypeSetUInt64(); }
|
virtual void visit(AstTime* nodep) override { nodep->dtypeSetUInt64(); }
|
||||||
virtual void visit(AstTimeD* nodep) override { nodep->dtypeSetDouble(); }
|
virtual void visit(AstTimeD* nodep) override { nodep->dtypeSetDouble(); }
|
||||||
virtual void visit(AstTestPlusArgs* nodep) override { nodep->dtypeSetSigned32(); }
|
|
||||||
virtual void visit(AstScopeName* nodep) override {
|
virtual void visit(AstScopeName* nodep) override {
|
||||||
nodep->dtypeSetUInt64(); // A pointer, but not that it matters
|
nodep->dtypeSetUInt64(); // A pointer, but not that it matters
|
||||||
}
|
}
|
||||||
|
|
@ -4352,6 +4351,12 @@ private:
|
||||||
userIterateAndNext(nodep->lsbp(), WidthVP(SELF, BOTH).p());
|
userIterateAndNext(nodep->lsbp(), WidthVP(SELF, BOTH).p());
|
||||||
userIterateAndNext(nodep->msbp(), WidthVP(SELF, BOTH).p());
|
userIterateAndNext(nodep->msbp(), WidthVP(SELF, BOTH).p());
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstTestPlusArgs* nodep) override {
|
||||||
|
if (m_vup->prelim()) {
|
||||||
|
userIterateAndNext(nodep->searchp(), WidthVP{SELF, BOTH}.p());
|
||||||
|
nodep->dtypeChgWidthSigned(32, 1, VSigning::SIGNED); // Spec says integer return
|
||||||
|
}
|
||||||
|
}
|
||||||
virtual void visit(AstValuePlusArgs* nodep) override {
|
virtual void visit(AstValuePlusArgs* nodep) override {
|
||||||
if (m_vup->prelim()) {
|
if (m_vup->prelim()) {
|
||||||
userIterateAndNext(nodep->searchp(), WidthVP(SELF, BOTH).p());
|
userIterateAndNext(nodep->searchp(), WidthVP(SELF, BOTH).p());
|
||||||
|
|
|
||||||
|
|
@ -3918,7 +3918,7 @@ system_f_call_or_t<nodep>: // IEEE: part of system_tf_call (can be task or
|
||||||
| yD_STABLE '(' expr ',' expr ')' { $$ = $3; BBUNSUP($1, "Unsupported: $stable and clock arguments"); }
|
| yD_STABLE '(' expr ',' expr ')' { $$ = $3; BBUNSUP($1, "Unsupported: $stable and clock arguments"); }
|
||||||
| yD_TAN '(' expr ')' { $$ = new AstTanD($1,$3); }
|
| yD_TAN '(' expr ')' { $$ = new AstTanD($1,$3); }
|
||||||
| yD_TANH '(' expr ')' { $$ = new AstTanhD($1,$3); }
|
| yD_TANH '(' expr ')' { $$ = new AstTanhD($1,$3); }
|
||||||
| yD_TESTPLUSARGS '(' str ')' { $$ = new AstTestPlusArgs($1,*$3); }
|
| yD_TESTPLUSARGS '(' expr ')' { $$ = new AstTestPlusArgs($1, $3); }
|
||||||
| yD_TIME parenE { $$ = new AstTime($1, VTimescale(VTimescale::NONE)); }
|
| yD_TIME parenE { $$ = new AstTime($1, VTimescale(VTimescale::NONE)); }
|
||||||
| yD_TYPENAME '(' exprOrDataType ')' { $$ = new AstAttrOf($1, VAttrType::TYPENAME, $3); }
|
| yD_TYPENAME '(' exprOrDataType ')' { $$ = new AstAttrOf($1, VAttrType::TYPENAME, $3); }
|
||||||
| yD_UNGETC '(' expr ',' expr ')' { $$ = new AstFUngetC($1, $5, $3); } // Arg swap to file first
|
| yD_UNGETC '(' expr ',' expr ')' { $$ = new AstFUngetC($1, $5, $3); } // Arg swap to file first
|
||||||
|
|
|
||||||
|
|
@ -578,6 +578,8 @@ sub new {
|
||||||
make_pli => 0, # need to compile pli
|
make_pli => 0, # need to compile pli
|
||||||
sc_time_resolution => "SC_PS", # Keep - PS is SystemC default
|
sc_time_resolution => "SC_PS", # Keep - PS is SystemC default
|
||||||
sim_time => 1100,
|
sim_time => 1100,
|
||||||
|
threads => -1, # --threads (negative means auto based on scenario)
|
||||||
|
context_threads => 0, # Number of threads to allocate in the context
|
||||||
benchmark => $opt_benchmark,
|
benchmark => $opt_benchmark,
|
||||||
verbose => $opt_verbose,
|
verbose => $opt_verbose,
|
||||||
run_env => '',
|
run_env => '',
|
||||||
|
|
@ -902,6 +904,7 @@ sub compile_vlt_flags {
|
||||||
@{$param{verilator_flags}},
|
@{$param{verilator_flags}},
|
||||||
@{$param{verilator_flags2}},
|
@{$param{verilator_flags2}},
|
||||||
@{$param{verilator_flags3}});
|
@{$param{verilator_flags3}});
|
||||||
|
die "%Error: specify threads via 'threads =>' argument, not as a command line option" unless ($checkflags !~ /(^|\s)-?-threads\s/ && $checkflags !~ /(^|\s)-?-no-threads($|\s)/);
|
||||||
$self->{sc} = 1 if ($checkflags =~ /-sc\b/);
|
$self->{sc} = 1 if ($checkflags =~ /-sc\b/);
|
||||||
$self->{trace} = ($opt_trace || $checkflags =~ /-trace\b/
|
$self->{trace} = ($opt_trace || $checkflags =~ /-trace\b/
|
||||||
|| $checkflags =~ /-trace-fst\b/);
|
|| $checkflags =~ /-trace-fst\b/);
|
||||||
|
|
@ -920,8 +923,7 @@ sub compile_vlt_flags {
|
||||||
unshift @verilator_flags, "--rr" if $opt_rr;
|
unshift @verilator_flags, "--rr" if $opt_rr;
|
||||||
unshift @verilator_flags, "--x-assign unique"; # More likely to be buggy
|
unshift @verilator_flags, "--x-assign unique"; # More likely to be buggy
|
||||||
unshift @verilator_flags, "--trace" if $opt_trace;
|
unshift @verilator_flags, "--trace" if $opt_trace;
|
||||||
my $threads = ::calc_threads($Vltmt_threads);
|
unshift @verilator_flags, "--threads $param{threads}" if $param{threads} >= 0;
|
||||||
unshift @verilator_flags, "--threads $threads" if $param{vltmt} && $checkflags !~ /-threads /;
|
|
||||||
unshift @verilator_flags, "--trace-threads 2" if $param{vltmt} && $checkflags =~ /-trace-fst /;
|
unshift @verilator_flags, "--trace-threads 2" if $param{vltmt} && $checkflags =~ /-trace-fst /;
|
||||||
unshift @verilator_flags, "--debug-partition" if $param{vltmt};
|
unshift @verilator_flags, "--debug-partition" if $param{vltmt};
|
||||||
unshift @verilator_flags, "-CFLAGS -ggdb -LDFLAGS -ggdb" if $opt_gdbsim;
|
unshift @verilator_flags, "-CFLAGS -ggdb -LDFLAGS -ggdb" if $opt_gdbsim;
|
||||||
|
|
@ -972,6 +974,13 @@ sub compile {
|
||||||
return 1 if $self->errors || $self->skips || $self->unsupporteds;
|
return 1 if $self->errors || $self->skips || $self->unsupporteds;
|
||||||
$self->oprint("Compile\n") if $self->{verbose};
|
$self->oprint("Compile\n") if $self->{verbose};
|
||||||
|
|
||||||
|
die "%Error: 'threads =>' argument must be <= 1 for vlt scenario" if $param{vlt} && $param{threads} > 1;
|
||||||
|
# Compute automatic parameter values
|
||||||
|
$param{threads} = ::calc_threads($Vltmt_threads) if $param{threads} < 0 && $param{vltmt};
|
||||||
|
$param{context_threads} = $param{threads} >= 1 ? $param{threads} : 1 if !$param{context_threads};
|
||||||
|
$self->{threads} = $param{threads};
|
||||||
|
$self->{context_threads} = $param{context_threads};
|
||||||
|
|
||||||
compile_vlt_cmd(%param);
|
compile_vlt_cmd(%param);
|
||||||
|
|
||||||
if (!$param{make_top_shell}) {
|
if (!$param{make_top_shell}) {
|
||||||
|
|
@ -1791,6 +1800,7 @@ sub _make_main {
|
||||||
}
|
}
|
||||||
|
|
||||||
print $fh " const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};\n";
|
print $fh " const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};\n";
|
||||||
|
print $fh " contextp->threads($self->{context_threads});\n";
|
||||||
print $fh " contextp->commandArgs(argc, argv);\n";
|
print $fh " contextp->commandArgs(argc, argv);\n";
|
||||||
print $fh " contextp->debug(" . ($self->{verilated_debug} ? 1 : 0) . ");\n";
|
print $fh " contextp->debug(" . ($self->{verilated_debug} ? 1 : 0) . ");\n";
|
||||||
print $fh " srand48(5);\n"; # Ensure determinism
|
print $fh " srand48(5);\n"; # Ensure determinism
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ execute(
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($Self->{vlt}) {
|
if ($Self->{vlt}) {
|
||||||
file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 11);
|
file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 14);
|
||||||
}
|
}
|
||||||
ok(1);
|
ok(1);
|
||||||
1;
|
1;
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ module t(/*AUTOARG*/
|
||||||
$write("[%0t] cyc==%0d crc=%x sum=%x\n", $time, cyc, crc, sum);
|
$write("[%0t] cyc==%0d crc=%x sum=%x\n", $time, cyc, crc, sum);
|
||||||
if (crc !== 64'hc77bb9b3784ea091) $stop;
|
if (crc !== 64'hc77bb9b3784ea091) $stop;
|
||||||
// What checksum will we end up with (above print should match)
|
// What checksum will we end up with (above print should match)
|
||||||
`define EXPECTED_SUM 64'hdccb9e7b8b638233
|
`define EXPECTED_SUM 64'hde21e019a3e12039
|
||||||
|
|
||||||
if (sum !== `EXPECTED_SUM) $stop;
|
if (sum !== `EXPECTED_SUM) $stop;
|
||||||
$write("*-* All Finished *-*\n");
|
$write("*-* All Finished *-*\n");
|
||||||
|
|
@ -86,10 +86,11 @@ module Test(/*AUTOARG*/
|
||||||
logic bug3182_out;
|
logic bug3182_out;
|
||||||
logic bug3197_out;
|
logic bug3197_out;
|
||||||
logic bug3445_out;
|
logic bug3445_out;
|
||||||
|
logic bug3470_out;
|
||||||
|
|
||||||
output logic o;
|
output logic o;
|
||||||
|
|
||||||
logic [7:0] tmp;
|
logic [8:0] tmp;
|
||||||
assign o = ^tmp;
|
assign o = ^tmp;
|
||||||
|
|
||||||
always_ff @(posedge clk) begin
|
always_ff @(posedge clk) begin
|
||||||
|
|
@ -113,11 +114,13 @@ module Test(/*AUTOARG*/
|
||||||
tmp[5] <= bug3182_out;
|
tmp[5] <= bug3182_out;
|
||||||
tmp[6] <= bug3197_out;
|
tmp[6] <= bug3197_out;
|
||||||
tmp[7] <= bug3445_out;
|
tmp[7] <= bug3445_out;
|
||||||
|
tmp[8] <= bug3470_out;
|
||||||
end
|
end
|
||||||
|
|
||||||
bug3182 i_bug3182(.in(d[4:0]), .out(bug3182_out));
|
bug3182 i_bug3182(.in(d[4:0]), .out(bug3182_out));
|
||||||
bug3197 i_bug3197(.clk(clk), .in(d), .out(bug3197_out));
|
bug3197 i_bug3197(.clk(clk), .in(d), .out(bug3197_out));
|
||||||
bug3445 i_bug3445(.clk(clk), .in(d), .out(bug3445_out));
|
bug3445 i_bug3445(.clk(clk), .in(d), .out(bug3445_out));
|
||||||
|
bug3470 i_bug3470(.clk(clk), .in(d), .out(bug3470_out));
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
|
@ -203,3 +206,32 @@ module bug3445(input wire clk, input wire [31:0] in, output wire out);
|
||||||
|
|
||||||
assign out = result0 ^ result1 ^ (result2 | result3);
|
assign out = result0 ^ result1 ^ (result2 | result3);
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
// Bug3470
|
||||||
|
// CCast had been ignored in bit op tree optimization
|
||||||
|
// Assume the following HDL input:
|
||||||
|
// (^d[38:32]) ^ (^d[31:0])
|
||||||
|
// where d is logic [38:0]
|
||||||
|
// ^d[31:0] becomes REDXOR(CCast(uint32_t, d)),
|
||||||
|
// but CCast was ignored and interpreted as ^d[38:0].
|
||||||
|
// Finally (^d[38:32]) ^ (^d31:0]) was wrongly transformed to
|
||||||
|
// (^d[38:32]) ^ (^d[38:0])
|
||||||
|
// -> (^d[38:32]) ^ ((^d[38:32]) ^ (^d[31:0]))
|
||||||
|
// -> ^d[31:0]
|
||||||
|
// Of course the correct result is ^d[38:0] = ^d
|
||||||
|
module bug3470(input wire clk, input wire [31:0] in, output wire out);
|
||||||
|
logic [38:0] d;
|
||||||
|
always_ff @(posedge clk)
|
||||||
|
d <= {d[6:0], in};
|
||||||
|
|
||||||
|
logic tmp, expected;
|
||||||
|
always_ff @(posedge clk) begin
|
||||||
|
tmp <= ^(d >> 32) ^ (^d[31:0]);
|
||||||
|
expected <= ^d;
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
if (tmp != expected) $stop;
|
||||||
|
|
||||||
|
assign out = tmp;
|
||||||
|
endmodule
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,8 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||||
scenarios(vltmt => 1); # Note issue shows up with --threads
|
scenarios(vltmt => 1); # Note issue shows up with --threads
|
||||||
|
|
||||||
compile(
|
compile(
|
||||||
verilator_flags2 => ['--compiler clang --threads 2 -Wno-UNOPTTHREADS'],
|
verilator_flags2 => ['--compiler clang -Wno-UNOPTTHREADS'],
|
||||||
|
threads => 2
|
||||||
);
|
);
|
||||||
|
|
||||||
ok(1);
|
ok(1);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
Merge:
|
Merge:
|
||||||
This should merge
|
This should merge
|
||||||
|
Merge:
|
||||||
|
This should also merge
|
||||||
f
|
f
|
||||||
1=1 a=top.t 1=1 1=1 b=top.t 1=1
|
1=1 a=top.t 1=1 1=1 b=top.t 1=1
|
||||||
pre
|
pre
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ execute(
|
||||||
);
|
);
|
||||||
|
|
||||||
file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}__stats.txt",
|
file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}__stats.txt",
|
||||||
qr/Node count, DISPLAY \s+ 41 \s+ 27 \s+ 27 \s+ 6/);
|
qr/Node count, DISPLAY \s+ 44 \s+ 27 \s+ 27 \s+ 6/);
|
||||||
|
|
||||||
ok(1);
|
ok(1);
|
||||||
1;
|
1;
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,10 @@ module t (/*AUTOARG*/);
|
||||||
$write("should ");
|
$write("should ");
|
||||||
$display("merge");
|
$display("merge");
|
||||||
|
|
||||||
|
$display("Merge:");
|
||||||
|
$write("This ", "", "should ", "", "also ");
|
||||||
|
$display("merge");
|
||||||
|
|
||||||
$display("f");
|
$display("f");
|
||||||
$write(" 1=%0d a=%m 1=%0d", one, one);
|
$write(" 1=%0d a=%m 1=%0d", one, one);
|
||||||
$display(" 1=%0d b=%m 1=%0d", one, one);
|
$display(" 1=%0d b=%m 1=%0d", one, one);
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,8 @@ scenarios(vltmt => 1);
|
||||||
top_filename("t/t_gen_alw.v");
|
top_filename("t/t_gen_alw.v");
|
||||||
|
|
||||||
compile(
|
compile(
|
||||||
v_flags2 => ["--debug --debugi 5 --threads 2"]
|
v_flags2 => ["--debug --debugi 5"],
|
||||||
|
threads => 2
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach my $dotname ("linkcells", "task_call", "gate_simp", "gate_opt",
|
foreach my $dotname ("linkcells", "task_call", "gate_simp", "gate_opt",
|
||||||
|
|
|
||||||
|
|
@ -26,11 +26,9 @@ using std::hex;
|
||||||
using std::setfill;
|
using std::setfill;
|
||||||
using std::setw;
|
using std::setw;
|
||||||
|
|
||||||
double sc_time_stamp() { return 0; }
|
|
||||||
|
|
||||||
// Convenience function to check we didn't finish unexpectedly
|
// Convenience function to check we didn't finish unexpectedly
|
||||||
static void checkFinish(const char* msg) {
|
static void checkFinish(VerilatedContext* contextp, const char* msg) {
|
||||||
if (Verilated::gotFinish()) {
|
if (contextp->gotFinish()) {
|
||||||
vl_fatal(__FILE__, __LINE__, "dut", msg);
|
vl_fatal(__FILE__, __LINE__, "dut", msg);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
@ -61,7 +59,9 @@ static void checkResult(bool p, const char* msg_fail) {
|
||||||
|
|
||||||
// Main function instantiates the model and steps through the test.
|
// Main function instantiates the model and steps through the test.
|
||||||
int main() {
|
int main() {
|
||||||
Vt_dpi_accessors* dut = new Vt_dpi_accessors("dut");
|
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||||
|
const std::unique_ptr<VM_PREFIX> dut{new VM_PREFIX{contextp.get(), "dut"}};
|
||||||
|
|
||||||
svScope scope = svGetScopeFromName("dut.t");
|
svScope scope = svGetScopeFromName("dut.t");
|
||||||
if (!scope) vl_fatal(__FILE__, __LINE__, "dut", "No svGetScopeFromName result");
|
if (!scope) vl_fatal(__FILE__, __LINE__, "dut", "No svGetScopeFromName result");
|
||||||
svSetScope(scope);
|
svSetScope(scope);
|
||||||
|
|
@ -112,7 +112,7 @@ int main() {
|
||||||
cout << "===============================\n";
|
cout << "===============================\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||||
dut->clk = 1 - dut->clk;
|
dut->clk = 1 - dut->clk;
|
||||||
a = (int)a_read();
|
a = (int)a_read();
|
||||||
logReg(dut->clk, "read a", a, " (before clk)");
|
logReg(dut->clk, "read a", a, " (before clk)");
|
||||||
|
|
@ -130,7 +130,7 @@ int main() {
|
||||||
"Test of scalar register reading failed.");
|
"Test of scalar register reading failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
checkFinish("t_dpi_accessors unexpected finish");
|
checkFinish(contextp.get(), "t_dpi_accessors unexpected finish");
|
||||||
|
|
||||||
// Check we can read a vector register.
|
// Check we can read a vector register.
|
||||||
#ifdef TEST_VERBOSE
|
#ifdef TEST_VERBOSE
|
||||||
|
|
@ -138,7 +138,7 @@ int main() {
|
||||||
cout << "===============================\n";
|
cout << "===============================\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||||
dut->clk = 1 - dut->clk;
|
dut->clk = 1 - dut->clk;
|
||||||
b = (int)b_read();
|
b = (int)b_read();
|
||||||
logRegHex(dut->clk, "read b", 8, b, " (before clk)");
|
logRegHex(dut->clk, "read b", 8, b, " (before clk)");
|
||||||
|
|
@ -153,7 +153,7 @@ int main() {
|
||||||
"Test of vector register reading failed.");
|
"Test of vector register reading failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
checkFinish("t_dpi_accessors unexpected finish");
|
checkFinish(contextp.get(), "t_dpi_accessors unexpected finish");
|
||||||
|
|
||||||
// Test we can read an array element
|
// Test we can read an array element
|
||||||
#ifdef TEST_VERBOSE
|
#ifdef TEST_VERBOSE
|
||||||
|
|
@ -162,7 +162,7 @@ int main() {
|
||||||
cout << "=============================\n";
|
cout << "=============================\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||||
dut->clk = 1 - dut->clk;
|
dut->clk = 1 - dut->clk;
|
||||||
mem32 = (int)mem32_read();
|
mem32 = (int)mem32_read();
|
||||||
logRegHex(dut->clk, "read mem32", 8, mem32, " (before clk)");
|
logRegHex(dut->clk, "read mem32", 8, mem32, " (before clk)");
|
||||||
|
|
@ -177,7 +177,7 @@ int main() {
|
||||||
checkResult(mem32 == 0x20, "Test of array element reading failed.");
|
checkResult(mem32 == 0x20, "Test of array element reading failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
checkFinish("t_dpi_accessors unexpected finish");
|
checkFinish(contextp.get(), "t_dpi_accessors unexpected finish");
|
||||||
|
|
||||||
// Check we can read a scalar wire
|
// Check we can read a scalar wire
|
||||||
#ifdef TEST_VERBOSE
|
#ifdef TEST_VERBOSE
|
||||||
|
|
@ -186,7 +186,7 @@ int main() {
|
||||||
cout << "===========================\n";
|
cout << "===========================\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||||
dut->clk = 1 - dut->clk;
|
dut->clk = 1 - dut->clk;
|
||||||
a = (int)a_read();
|
a = (int)a_read();
|
||||||
c = (int)c_read();
|
c = (int)c_read();
|
||||||
|
|
@ -206,7 +206,7 @@ int main() {
|
||||||
checkResult(c == (1 - a), "Test of scalar wire reading failed.");
|
checkResult(c == (1 - a), "Test of scalar wire reading failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
checkFinish("t_dpi_accessors unexpected finish");
|
checkFinish(contextp.get(), "t_dpi_accessors unexpected finish");
|
||||||
|
|
||||||
// Check we can read a vector wire
|
// Check we can read a vector wire
|
||||||
#ifdef TEST_VERBOSE
|
#ifdef TEST_VERBOSE
|
||||||
|
|
@ -215,7 +215,7 @@ int main() {
|
||||||
cout << "===========================\n";
|
cout << "===========================\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||||
dut->clk = 1 - dut->clk;
|
dut->clk = 1 - dut->clk;
|
||||||
b = (int)b_read();
|
b = (int)b_read();
|
||||||
d = (int)d_read();
|
d = (int)d_read();
|
||||||
|
|
@ -236,7 +236,7 @@ int main() {
|
||||||
checkResult(d == ((~b) & 0xff), "Test of vector wire reading failed.");
|
checkResult(d == ((~b) & 0xff), "Test of vector wire reading failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
checkFinish("t_dpi_accessors unexpected finish");
|
checkFinish(contextp.get(), "t_dpi_accessors unexpected finish");
|
||||||
|
|
||||||
// Check we can write a scalar register
|
// Check we can write a scalar register
|
||||||
#ifdef TEST_VERBOSE
|
#ifdef TEST_VERBOSE
|
||||||
|
|
@ -245,7 +245,7 @@ int main() {
|
||||||
cout << "===============================\n";
|
cout << "===============================\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||||
dut->clk = 1 - dut->clk;
|
dut->clk = 1 - dut->clk;
|
||||||
a = 1 - (int)a_read();
|
a = 1 - (int)a_read();
|
||||||
a_write(reinterpret_cast<const svBitVecVal*>(&a));
|
a_write(reinterpret_cast<const svBitVecVal*>(&a));
|
||||||
|
|
@ -265,7 +265,7 @@ int main() {
|
||||||
"Test of scalar register writing failed.");
|
"Test of scalar register writing failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
checkFinish("t_dpi_accessors unexpected finish");
|
checkFinish(contextp.get(), "t_dpi_accessors unexpected finish");
|
||||||
|
|
||||||
// Check we can write a vector register
|
// Check we can write a vector register
|
||||||
#ifdef TEST_VERBOSE
|
#ifdef TEST_VERBOSE
|
||||||
|
|
@ -274,7 +274,7 @@ int main() {
|
||||||
cout << "===============================\n";
|
cout << "===============================\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||||
dut->clk = 1 - dut->clk;
|
dut->clk = 1 - dut->clk;
|
||||||
b = (int)b_read() - 1;
|
b = (int)b_read() - 1;
|
||||||
b_write(reinterpret_cast<const svBitVecVal*>(&b));
|
b_write(reinterpret_cast<const svBitVecVal*>(&b));
|
||||||
|
|
@ -294,7 +294,7 @@ int main() {
|
||||||
"Test of vector register writing failed.");
|
"Test of vector register writing failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
checkFinish("t_dpi_accessors unexpected finish");
|
checkFinish(contextp.get(), "t_dpi_accessors unexpected finish");
|
||||||
|
|
||||||
// Test we can write an array element
|
// Test we can write an array element
|
||||||
#ifdef TEST_VERBOSE
|
#ifdef TEST_VERBOSE
|
||||||
|
|
@ -303,7 +303,7 @@ int main() {
|
||||||
cout << "=============================\n";
|
cout << "=============================\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||||
dut->clk = 1 - dut->clk;
|
dut->clk = 1 - dut->clk;
|
||||||
mem32 = (int)mem32_read() - 1;
|
mem32 = (int)mem32_read() - 1;
|
||||||
mem32_write(reinterpret_cast<const svBitVecVal*>(&mem32));
|
mem32_write(reinterpret_cast<const svBitVecVal*>(&mem32));
|
||||||
|
|
@ -323,7 +323,7 @@ int main() {
|
||||||
checkResult(mem32_after == mem32, "Test of array element writing failed.");
|
checkResult(mem32_after == mem32, "Test of array element writing failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
checkFinish("t_dpi_accessors unexpected finish");
|
checkFinish(contextp.get(), "t_dpi_accessors unexpected finish");
|
||||||
|
|
||||||
// Check we can read a vector register slice
|
// Check we can read a vector register slice
|
||||||
#ifdef TEST_VERBOSE
|
#ifdef TEST_VERBOSE
|
||||||
|
|
@ -332,7 +332,7 @@ int main() {
|
||||||
cout << "=====================================\n";
|
cout << "=====================================\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||||
dut->clk = 1 - dut->clk;
|
dut->clk = 1 - dut->clk;
|
||||||
b = (int)b_read();
|
b = (int)b_read();
|
||||||
int b_slice = (int)b_slice_read();
|
int b_slice = (int)b_slice_read();
|
||||||
|
|
@ -350,7 +350,7 @@ int main() {
|
||||||
checkResult(b_slice == (b & 0x0f), "Test of vector register slice reading failed.");
|
checkResult(b_slice == (b & 0x0f), "Test of vector register slice reading failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
checkFinish("t_dpi_accessors unexpected finish");
|
checkFinish(contextp.get(), "t_dpi_accessors unexpected finish");
|
||||||
|
|
||||||
// Test we can read an array element slice
|
// Test we can read an array element slice
|
||||||
#ifdef TEST_VERBOSE
|
#ifdef TEST_VERBOSE
|
||||||
|
|
@ -359,7 +359,7 @@ int main() {
|
||||||
cout << "===================================\n";
|
cout << "===================================\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||||
dut->clk = 1 - dut->clk;
|
dut->clk = 1 - dut->clk;
|
||||||
mem32 = (int)mem32_read();
|
mem32 = (int)mem32_read();
|
||||||
int mem32_slice = (int)mem32_slice_read();
|
int mem32_slice = (int)mem32_slice_read();
|
||||||
|
|
@ -379,7 +379,7 @@ int main() {
|
||||||
"Test of array element slice reading failed.");
|
"Test of array element slice reading failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
checkFinish("t_dpi_accessors unexpected finish");
|
checkFinish(contextp.get(), "t_dpi_accessors unexpected finish");
|
||||||
|
|
||||||
// Check we can read a vector wire slice
|
// Check we can read a vector wire slice
|
||||||
#ifdef TEST_VERBOSE
|
#ifdef TEST_VERBOSE
|
||||||
|
|
@ -388,7 +388,7 @@ int main() {
|
||||||
cout << "=================================\n";
|
cout << "=================================\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||||
dut->clk = 1 - dut->clk;
|
dut->clk = 1 - dut->clk;
|
||||||
b = (int)b_read();
|
b = (int)b_read();
|
||||||
d = (int)d_read();
|
d = (int)d_read();
|
||||||
|
|
@ -410,7 +410,7 @@ int main() {
|
||||||
checkResult(d_slice == ((d & 0x7e) >> 1), "Test of vector wire slice reading failed.");
|
checkResult(d_slice == ((d & 0x7e) >> 1), "Test of vector wire slice reading failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
checkFinish("t_dpi_accessors unexpected finish");
|
checkFinish(contextp.get(), "t_dpi_accessors unexpected finish");
|
||||||
|
|
||||||
// Check we can write a vector register slice
|
// Check we can write a vector register slice
|
||||||
#ifdef TEST_VERBOSE
|
#ifdef TEST_VERBOSE
|
||||||
|
|
@ -419,7 +419,7 @@ int main() {
|
||||||
cout << "=====================================\n";
|
cout << "=====================================\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||||
dut->clk = 1 - dut->clk;
|
dut->clk = 1 - dut->clk;
|
||||||
|
|
||||||
b = (int)b_read();
|
b = (int)b_read();
|
||||||
|
|
@ -449,7 +449,7 @@ int main() {
|
||||||
logRegHex(dut->clk, "read b [3:0]", 4, b_slice, " (after clk)");
|
logRegHex(dut->clk, "read b [3:0]", 4, b_slice, " (after clk)");
|
||||||
}
|
}
|
||||||
|
|
||||||
checkFinish("t_dpi_accessors unexpected finish");
|
checkFinish(contextp.get(), "t_dpi_accessors unexpected finish");
|
||||||
|
|
||||||
// Test we can write an array element slice
|
// Test we can write an array element slice
|
||||||
#ifdef TEST_VERBOSE
|
#ifdef TEST_VERBOSE
|
||||||
|
|
@ -458,7 +458,7 @@ int main() {
|
||||||
cout << "===================================\n";
|
cout << "===================================\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||||
dut->clk = 1 - dut->clk;
|
dut->clk = 1 - dut->clk;
|
||||||
|
|
||||||
mem32 = (int)mem32_read();
|
mem32 = (int)mem32_read();
|
||||||
|
|
@ -494,7 +494,7 @@ int main() {
|
||||||
"Test of array element slice writing failed.");
|
"Test of array element slice writing failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
checkFinish("t_dpi_accessors unexpected finish");
|
checkFinish(contextp.get(), "t_dpi_accessors unexpected finish");
|
||||||
|
|
||||||
// Check we can read complex registers
|
// Check we can read complex registers
|
||||||
#ifdef TEST_VERBOSE
|
#ifdef TEST_VERBOSE
|
||||||
|
|
@ -503,7 +503,7 @@ int main() {
|
||||||
cout << "================================\n";
|
cout << "================================\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||||
dut->clk = 1 - dut->clk;
|
dut->clk = 1 - dut->clk;
|
||||||
|
|
||||||
b = (int)b_read();
|
b = (int)b_read();
|
||||||
|
|
@ -540,9 +540,9 @@ int main() {
|
||||||
cout << endl;
|
cout << endl;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
checkFinish("t_dpi_accessors unexpected finish");
|
checkFinish(contextp.get(), "t_dpi_accessors unexpected finish");
|
||||||
|
|
||||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||||
dut->clk = 1 - dut->clk;
|
dut->clk = 1 - dut->clk;
|
||||||
|
|
||||||
e = 0x05 | (i << 4);
|
e = 0x05 | (i << 4);
|
||||||
|
|
@ -574,7 +574,7 @@ int main() {
|
||||||
"Test of complex register reading l2 failed.");
|
"Test of complex register reading l2 failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
checkFinish("t_dpi_accessors unexpected finish");
|
checkFinish(contextp.get(), "t_dpi_accessors unexpected finish");
|
||||||
|
|
||||||
// Test we can write a complex register
|
// Test we can write a complex register
|
||||||
#ifdef TEST_VERBOSE
|
#ifdef TEST_VERBOSE
|
||||||
|
|
@ -583,7 +583,7 @@ int main() {
|
||||||
cout << "================================\n";
|
cout << "================================\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||||
dut->clk = 1 - dut->clk;
|
dut->clk = 1 - dut->clk;
|
||||||
|
|
||||||
b = (int)b_read();
|
b = (int)b_read();
|
||||||
|
|
@ -632,9 +632,9 @@ int main() {
|
||||||
cout << endl;
|
cout << endl;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
checkFinish("t_dpi_accessors unexpected finish");
|
checkFinish(contextp.get(), "t_dpi_accessors unexpected finish");
|
||||||
|
|
||||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||||
dut->clk = 1 - dut->clk;
|
dut->clk = 1 - dut->clk;
|
||||||
|
|
||||||
e = (int)e_read();
|
e = (int)e_read();
|
||||||
|
|
@ -671,11 +671,10 @@ int main() {
|
||||||
logRegHex(dut->clk, "read l2", 8, l2, " (before clk)");
|
logRegHex(dut->clk, "read l2", 8, l2, " (before clk)");
|
||||||
}
|
}
|
||||||
|
|
||||||
checkFinish("t_dpi_accessors unexpected finish");
|
checkFinish(contextp.get(), "t_dpi_accessors unexpected finish");
|
||||||
|
|
||||||
// Tidy up
|
// Tidy up
|
||||||
dut->final();
|
dut->final();
|
||||||
VL_DO_DANGLING(delete dut, dut);
|
|
||||||
cout << "*-* All Finished *-*\n";
|
cout << "*-* All Finished *-*\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -110,39 +110,39 @@ void mon_eval() {
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
||||||
unsigned int main_time = 0;
|
|
||||||
|
|
||||||
double sc_time_stamp() { return main_time; }
|
|
||||||
int main(int argc, char** argv, char** env) {
|
int main(int argc, char** argv, char** env) {
|
||||||
uint64_t sim_time = 1100;
|
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||||
Verilated::commandArgs(argc, argv);
|
|
||||||
Verilated::debug(0);
|
|
||||||
|
|
||||||
VM_PREFIX* topp = new VM_PREFIX(""); // Note null name - we're flattening it out
|
uint64_t sim_time = 1100;
|
||||||
|
contextp->commandArgs(argc, argv);
|
||||||
|
contextp->debug(0);
|
||||||
|
|
||||||
|
const std::unique_ptr<VM_PREFIX> topp{new VM_PREFIX{contextp.get(),
|
||||||
|
// Note null name - we're flattening it out
|
||||||
|
""}};
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
#ifdef VERILATOR
|
#ifdef VERILATOR
|
||||||
# ifdef TEST_VERBOSE
|
# ifdef TEST_VERBOSE
|
||||||
Verilated::scopesDump();
|
contextp->scopesDump();
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
topp->eval();
|
topp->eval();
|
||||||
topp->clk = 0;
|
topp->clk = 0;
|
||||||
main_time += 10;
|
contextp->timeInc(10);
|
||||||
|
|
||||||
while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) {
|
while (contextp->time() < sim_time && !contextp->gotFinish()) {
|
||||||
main_time += 1;
|
contextp->timeInc(1);
|
||||||
topp->eval();
|
topp->eval();
|
||||||
topp->clk = !topp->clk;
|
topp->clk = !topp->clk;
|
||||||
// mon_do();
|
// mon_do();
|
||||||
}
|
}
|
||||||
if (!Verilated::gotFinish()) {
|
if (!contextp->gotFinish()) {
|
||||||
vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
||||||
}
|
}
|
||||||
topp->final();
|
topp->final();
|
||||||
|
|
||||||
VL_DO_DANGLING(delete topp, topp);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@ mkdir $child_dir;
|
||||||
(VM_PREFIX => "$Self->{VM_PREFIX}_child",
|
(VM_PREFIX => "$Self->{VM_PREFIX}_child",
|
||||||
top_filename => "$Self->{name}_child.v",
|
top_filename => "$Self->{name}_child.v",
|
||||||
verilator_flags => ["-cc", "-Mdir", "${child_dir}", "--debug-check"],
|
verilator_flags => ["-cc", "-Mdir", "${child_dir}", "--debug-check"],
|
||||||
|
# Can't use multi threading (like hier blocks), but needs to be thread safe
|
||||||
|
threads => $Self->{vltmt} ? 1 : 0,
|
||||||
);
|
);
|
||||||
|
|
||||||
run(logfile => "${child_dir}/vlt_compile.log",
|
run(logfile => "${child_dir}/vlt_compile.log",
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,9 @@ scenarios(vlt_all => 1);
|
||||||
top_filename("t/t_gen_alw.v");
|
top_filename("t/t_gen_alw.v");
|
||||||
|
|
||||||
compile(
|
compile(
|
||||||
|
v_flags2 => ["--prof-exec"],
|
||||||
# Checks below care about thread count, so use 2 (minimum reasonable)
|
# Checks below care about thread count, so use 2 (minimum reasonable)
|
||||||
v_flags2 => ["--prof-exec", ($Self->{vltmt} ? "--threads 2" : "")]
|
threads => $Self->{vltmt} ? 2 : 0
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
//
|
||||||
|
// DESCRIPTION: Verilator: Verilog Multiple Model Test Module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2022 by Geza Lore.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include "verilated.h"
|
||||||
|
#include "Vt_gantt_two.h"
|
||||||
|
|
||||||
|
int main(int argc, char** argv, char** env) {
|
||||||
|
srand48(5);
|
||||||
|
|
||||||
|
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||||
|
#ifdef VL_THREADED
|
||||||
|
contextp->threads(2);
|
||||||
|
#endif
|
||||||
|
contextp->commandArgs(argc, argv);
|
||||||
|
contextp->debug(0);
|
||||||
|
|
||||||
|
std::unique_ptr<Vt_gantt_two> topap{new Vt_gantt_two{contextp.get(), "topa"}};
|
||||||
|
std::unique_ptr<Vt_gantt_two> topbp{new Vt_gantt_two{contextp.get(), "topb"}};
|
||||||
|
|
||||||
|
topap->clk = false;
|
||||||
|
topap->eval();
|
||||||
|
topbp->clk = false;
|
||||||
|
topbp->eval();
|
||||||
|
|
||||||
|
contextp->timeInc(10);
|
||||||
|
while ((contextp->time() < 1100) && !contextp->gotFinish()) {
|
||||||
|
topap->clk = !topap->clk;
|
||||||
|
topap->eval();
|
||||||
|
topbp->clk = !topbp->clk;
|
||||||
|
topbp->eval();
|
||||||
|
contextp->timeInc(5);
|
||||||
|
}
|
||||||
|
if (!contextp->gotFinish()) {
|
||||||
|
vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2003 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
|
||||||
|
|
||||||
|
# Test for bin/verilator_gantt,
|
||||||
|
|
||||||
|
scenarios(vlt_all => 1);
|
||||||
|
|
||||||
|
# It doesn't really matter what test
|
||||||
|
# we use, so long as it runs several cycles,
|
||||||
|
# enough for the profiling to happen:
|
||||||
|
top_filename("t/t_gen_alw.v");
|
||||||
|
|
||||||
|
compile(
|
||||||
|
make_top_shell => 0,
|
||||||
|
make_main => 0,
|
||||||
|
v_flags2 => ["--prof-exec --exe $Self->{t_dir}/$Self->{name}.cpp"],
|
||||||
|
# Checks below care about thread count, so use 2 (minimum reasonable)
|
||||||
|
threads => $Self->{vltmt} ? 2 : 0,
|
||||||
|
make_flags => 'CPPFLAGS_ADD=-DVL_NO_LEGACY',
|
||||||
|
);
|
||||||
|
|
||||||
|
execute(
|
||||||
|
all_run_flags => ["+verilator+prof+exec+start+4",
|
||||||
|
" +verilator+prof+exec+window+4",
|
||||||
|
" +verilator+prof+exec+file+$Self->{obj_dir}/profile_exec.dat",
|
||||||
|
" +verilator+prof+vlt+file+$Self->{obj_dir}/profile.vlt",
|
||||||
|
],
|
||||||
|
check_finished => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
# For now, verilator_gantt still reads from STDIN
|
||||||
|
# (probably it should take a file, gantt.dat like verilator_profcfunc)
|
||||||
|
# The profiling data still goes direct to the runtime's STDOUT
|
||||||
|
# (maybe that should go to a separate file - gantt.dat?)
|
||||||
|
run(cmd => ["$ENV{VERILATOR_ROOT}/bin/verilator_gantt",
|
||||||
|
"$Self->{obj_dir}/profile_exec.dat",
|
||||||
|
"--vcd $Self->{obj_dir}/profile_exec.vcd",
|
||||||
|
"| tee $Self->{obj_dir}/gantt.log"],
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($Self->{vltmt}) {
|
||||||
|
file_grep("$Self->{obj_dir}/gantt.log", qr/Total threads += 2/i);
|
||||||
|
file_grep("$Self->{obj_dir}/gantt.log", qr/Total mtasks += 7/i);
|
||||||
|
} else {
|
||||||
|
file_grep("$Self->{obj_dir}/gantt.log", qr/Total threads += 1/i);
|
||||||
|
file_grep("$Self->{obj_dir}/gantt.log", qr/Total mtasks += 0/i);
|
||||||
|
}
|
||||||
|
file_grep("$Self->{obj_dir}/gantt.log", qr/Total evals += 4/i);
|
||||||
|
|
||||||
|
# Diff to itself, just to check parsing
|
||||||
|
vcd_identical("$Self->{obj_dir}/profile_exec.vcd", "$Self->{obj_dir}/profile_exec.vcd");
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
@ -18,11 +18,12 @@ scenarios(vlt_all => 1);
|
||||||
|
|
||||||
compile(
|
compile(
|
||||||
v_flags2 => ['t/t_hier_block.cpp'],
|
v_flags2 => ['t/t_hier_block.cpp'],
|
||||||
verilator_flags2 => ['--stats', ($Self->{vltmt} ? ' --threads 6' : ''),
|
verilator_flags2 => ['--stats',
|
||||||
'--hierarchical',
|
'--hierarchical',
|
||||||
'--Wno-TIMESCALEMOD',
|
'--Wno-TIMESCALEMOD',
|
||||||
'--CFLAGS', '"-pipe -DCPP_MACRO=cplusplus"'
|
'--CFLAGS', '"-pipe -DCPP_MACRO=cplusplus"'
|
||||||
],
|
],
|
||||||
|
threads => $Self->{vltmt} ? 6 : 0
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,17 @@
|
||||||
#include "Vt_hier_block.h"
|
#include "Vt_hier_block.h"
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
std::unique_ptr<Vt_hier_block> top{new Vt_hier_block("top")};
|
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||||
Verilated::commandArgs(argc, argv);
|
#if VL_THREADED
|
||||||
for (int i = 0; i < 100 && !Verilated::gotFinish(); ++i) {
|
contextp->threads(6);
|
||||||
|
#endif
|
||||||
|
contextp->commandArgs(argc, argv);
|
||||||
|
std::unique_ptr<Vt_hier_block> top{new Vt_hier_block{contextp.get(), "top"}};
|
||||||
|
for (int i = 0; i < 100 && !contextp->gotFinish(); ++i) {
|
||||||
top->eval();
|
top->eval();
|
||||||
top->clk ^= 1;
|
top->clk ^= 1;
|
||||||
}
|
}
|
||||||
if (!Verilated::gotFinish()) {
|
if (!contextp->gotFinish()) {
|
||||||
vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
||||||
}
|
}
|
||||||
top->final();
|
top->final();
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,8 @@ compile(
|
||||||
v_flags2 => ['t/t_hier_block.cpp'],
|
v_flags2 => ['t/t_hier_block.cpp'],
|
||||||
verilator_flags2 => ['--stats',
|
verilator_flags2 => ['--stats',
|
||||||
'+define+USE_VLT', 't/t_hier_block_vlt.vlt',
|
'+define+USE_VLT', 't/t_hier_block_vlt.vlt',
|
||||||
'--CFLAGS', '"-pipe -DCPP_MACRO=cplusplus"',
|
'--CFLAGS', '"-pipe -DCPP_MACRO=cplusplus"'],
|
||||||
($Self->{vltmt} ? ' --threads 6' : '')],
|
threads => $Self->{vltmt} ? 6 : 0
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,9 @@ compile(
|
||||||
verilator_flags2 => ['--sc',
|
verilator_flags2 => ['--sc',
|
||||||
'--stats',
|
'--stats',
|
||||||
'--hierarchical',
|
'--hierarchical',
|
||||||
($Self->{vltmt} ? ' --threads 6' : ''),
|
|
||||||
'--CFLAGS', '"-pipe -DCPP_MACRO=cplusplus"'
|
'--CFLAGS', '"-pipe -DCPP_MACRO=cplusplus"'
|
||||||
],
|
],
|
||||||
|
threads => $Self->{vltmt} ? 6 : 0
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,11 @@ compile(
|
||||||
verilator_flags2 => ['--sc',
|
verilator_flags2 => ['--sc',
|
||||||
'--stats',
|
'--stats',
|
||||||
'--hierarchical',
|
'--hierarchical',
|
||||||
($Self->{vltmt} ? ' --threads 6' : ''),
|
|
||||||
'--CFLAGS', '"-pipe -DCPP_MACRO=cplusplus"',
|
'--CFLAGS', '"-pipe -DCPP_MACRO=cplusplus"',
|
||||||
"--CFLAGS", '"-O0 -ggdb"',
|
"--CFLAGS", '"-O0 -ggdb"',
|
||||||
"--trace-fst"
|
"--trace-fst"
|
||||||
],
|
],
|
||||||
|
threads => $Self->{vltmt} ? 6 : 0
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,11 @@ compile(
|
||||||
verilator_flags2 => ['--sc',
|
verilator_flags2 => ['--sc',
|
||||||
'--stats',
|
'--stats',
|
||||||
'--hierarchical',
|
'--hierarchical',
|
||||||
($Self->{vltmt} ? ' --threads 6' : ''),
|
|
||||||
'--CFLAGS', '"-pipe -DCPP_MACRO=cplusplus"',
|
'--CFLAGS', '"-pipe -DCPP_MACRO=cplusplus"',
|
||||||
"--CFLAGS", '"-O0 -ggdb"',
|
"--CFLAGS", '"-O0 -ggdb"',
|
||||||
"--trace"
|
"--trace"
|
||||||
],
|
],
|
||||||
|
threads => $Self->{vltmt} ? 6 : 0
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,12 @@ top_filename("t/t_hier_block.v");
|
||||||
|
|
||||||
compile(
|
compile(
|
||||||
v_flags2 => ['t/t_hier_block.cpp'],
|
v_flags2 => ['t/t_hier_block.cpp'],
|
||||||
verilator_flags2 => [($Self->{vltmt} ? ' --threads 6' : ''),
|
verilator_flags2 => ['--hierarchical',
|
||||||
'--hierarchical',
|
|
||||||
'--Wno-TIMESCALEMOD',
|
'--Wno-TIMESCALEMOD',
|
||||||
'--trace-fst',
|
'--trace-fst',
|
||||||
'--no-trace-underscore', # To avoid handle mismatches
|
'--no-trace-underscore', # To avoid handle mismatches
|
||||||
],
|
],
|
||||||
|
threads => $Self->{vltmt} ? 6 : 0
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,12 @@ top_filename("t/t_hier_block.v");
|
||||||
|
|
||||||
compile(
|
compile(
|
||||||
v_flags2 => ['t/t_hier_block.cpp'],
|
v_flags2 => ['t/t_hier_block.cpp'],
|
||||||
verilator_flags2 => [($Self->{vltmt} ? ' --threads 6' : ''),
|
verilator_flags2 => ['--hierarchical',
|
||||||
'--hierarchical',
|
|
||||||
'--Wno-TIMESCALEMOD',
|
'--Wno-TIMESCALEMOD',
|
||||||
'--trace',
|
'--trace',
|
||||||
'--no-trace-underscore', # To avoid handle mismatches
|
'--no-trace-underscore', # To avoid handle mismatches
|
||||||
],
|
],
|
||||||
|
threads => $Self->{vltmt} ? 6 : 0
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,8 @@ compile(
|
||||||
'--hierarchical',
|
'--hierarchical',
|
||||||
'+define+SHOW_TIMESCALE',
|
'+define+SHOW_TIMESCALE',
|
||||||
'+define+USE_VLT', 't/t_hier_block_vlt.vlt',
|
'+define+USE_VLT', 't/t_hier_block_vlt.vlt',
|
||||||
'--CFLAGS', '"-pipe -DCPP_MACRO=cplusplus"',
|
'--CFLAGS', '"-pipe -DCPP_MACRO=cplusplus"'],
|
||||||
($Self->{vltmt} ? ' --threads 6' : '')],
|
threads => $Self->{vltmt} ? 6 : 0
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,9 @@ top_filename("t/t_inst_tree.v");
|
||||||
|
|
||||||
my $default_vltmt_threads = $Self->get_default_vltmt_threads();
|
my $default_vltmt_threads = $Self->get_default_vltmt_threads();
|
||||||
compile(
|
compile(
|
||||||
verilator_flags2 => ['--stats', "$Self->{t_dir}/$Self->{name}.vlt",
|
verilator_flags2 => ['--stats', "$Self->{t_dir}/$Self->{name}.vlt"],
|
||||||
# Force 3 threads even if we have fewer cores
|
# Force 3 threads even if we have fewer cores
|
||||||
$Self->{vltmt} ? "--threads $default_vltmt_threads" : ""]
|
threads => $Self->{vltmt} ? $default_vltmt_threads : 0
|
||||||
);
|
);
|
||||||
|
|
||||||
sub checkRelativeRefs {
|
sub checkRelativeRefs {
|
||||||
|
|
|
||||||
|
|
@ -48,11 +48,12 @@ void make_and_destroy() {
|
||||||
#ifdef VL_NO_LEGACY
|
#ifdef VL_NO_LEGACY
|
||||||
VerilatedContext* contextp = new VerilatedContext;
|
VerilatedContext* contextp = new VerilatedContext;
|
||||||
VM_PREFIX* topp = new VM_PREFIX{contextp};
|
VM_PREFIX* topp = new VM_PREFIX{contextp};
|
||||||
|
contextp->debug(0);
|
||||||
#else
|
#else
|
||||||
VM_PREFIX* topp = new VM_PREFIX;
|
VM_PREFIX* topp = new VM_PREFIX;
|
||||||
|
Verilated::debug(0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Verilated::debug(0);
|
|
||||||
topp->eval();
|
topp->eval();
|
||||||
topp->clk = true;
|
topp->clk = true;
|
||||||
while (!
|
while (!
|
||||||
|
|
|
||||||
|
|
@ -56,10 +56,11 @@ while (1) {
|
||||||
|
|
||||||
compile(
|
compile(
|
||||||
verilator_flags2 => ["$secret_dir/secret.sv",
|
verilator_flags2 => ["$secret_dir/secret.sv",
|
||||||
($Self->{vltmt} ? ' --threads 1' : ''),
|
|
||||||
"-LDFLAGS",
|
"-LDFLAGS",
|
||||||
"'-Wl,-rpath,$abs_secret_dir -L$abs_secret_dir -l$secret_prefix'"],
|
"'-Wl,-rpath,$abs_secret_dir -L$abs_secret_dir -l$secret_prefix'"],
|
||||||
xsim_flags2 => ["$secret_dir/secret.sv"],
|
xsim_flags2 => ["$secret_dir/secret.sv"],
|
||||||
|
threads => $Self->{vltmt} ? 1 : 0,
|
||||||
|
context_threads => $Self->{vltmt} ? 6 : 1
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
Clocked
|
||||||
|
Clocked
|
||||||
|
Clocked
|
||||||
|
Clocked
|
||||||
|
Clocked
|
||||||
|
Clocked
|
||||||
|
Clocked
|
||||||
|
Clocked
|
||||||
|
Clocked
|
||||||
|
Clocked
|
||||||
|
Clocked
|
||||||
|
*-* All Finished *-*
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2003 by Wilson Snyder. This program is free software; you
|
||||||
|
# can redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
scenarios(simulator => 1);
|
||||||
|
|
||||||
|
compile(
|
||||||
|
verilator_flags2 => ["--stats"],
|
||||||
|
);
|
||||||
|
|
||||||
|
execute(
|
||||||
|
check_finished => 1,
|
||||||
|
expect_filename => $Self->{golden_filename},
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2022 by Wilson Snyder.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/
|
||||||
|
// Outputs
|
||||||
|
test,
|
||||||
|
// Inputs
|
||||||
|
clk
|
||||||
|
);
|
||||||
|
input clk;
|
||||||
|
|
||||||
|
output reg [5:0] test;
|
||||||
|
parameter STATE1 = 6'b000001;
|
||||||
|
parameter STATE2 = 6'b000010;
|
||||||
|
parameter STATE3 = 6'b000100;
|
||||||
|
parameter STATE4 = 6'b001000;
|
||||||
|
parameter STATE5 = 6'b010000;
|
||||||
|
parameter STATE6 = 6'b100000;
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
$display("Clocked");
|
||||||
|
case (test)
|
||||||
|
STATE1: test <= STATE2;
|
||||||
|
STATE2: test <= STATE3;
|
||||||
|
STATE3: test <= STATE4;
|
||||||
|
STATE4: test <= STATE5;
|
||||||
|
STATE5: test <= STATE6;
|
||||||
|
default: test <= STATE1;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
int cyc;
|
||||||
|
always @(posedge clk) begin
|
||||||
|
cyc <= cyc + 1;
|
||||||
|
if (cyc == 10) begin
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||||
scenarios(vltmt => 1);
|
scenarios(vltmt => 1);
|
||||||
|
|
||||||
compile(
|
compile(
|
||||||
v_flags2 => ["--threads 2"],
|
threads => 2,
|
||||||
fails => 1,
|
fails => 1,
|
||||||
expect_filename => $Self->{golden_filename},
|
expect_filename => $Self->{golden_filename},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,8 @@ scenarios(vltmt => 1);
|
||||||
top_filename("t/t_gen_alw.v");
|
top_filename("t/t_gen_alw.v");
|
||||||
|
|
||||||
compile(
|
compile(
|
||||||
v_flags2 => ["--prof-pgo --threads 2"]
|
v_flags2 => ["--prof-pgo"],
|
||||||
|
threads => 2
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
|
|
@ -30,8 +31,8 @@ file_grep("$Self->{obj_dir}/profile.vlt", qr/profile_data/i);
|
||||||
compile(
|
compile(
|
||||||
# Intentinally no --prof-pgo here to make sure profile data can be read in
|
# Intentinally no --prof-pgo here to make sure profile data can be read in
|
||||||
# without it (that is: --prof-pgo has no effect on profile_data hash names)
|
# without it (that is: --prof-pgo has no effect on profile_data hash names)
|
||||||
v_flags2 => ["--threads 2",
|
v_flags2 => [" $Self->{obj_dir}/profile.vlt"],
|
||||||
" $Self->{obj_dir}/profile.vlt"],
|
threads => 2
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ scenarios(simulator => 1);
|
||||||
# %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads.
|
# %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads.
|
||||||
# So use 6 threads here though it's not optimal in performace wise, but ok.
|
# So use 6 threads here though it's not optimal in performace wise, but ok.
|
||||||
compile(
|
compile(
|
||||||
verilator_flags2 => ['--stats' . ($Self->{vltmt} ? ' --threads 6' : ''),
|
verilator_flags2 => ['--stats', "$Self->{t_dir}/t_split_var_0.vlt"],
|
||||||
"$Self->{t_dir}/t_split_var_0.vlt"],
|
threads => $Self->{vltmt} ? 6 : 0
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,8 @@ top_filename("t/t_split_var_0.v");
|
||||||
# %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads.
|
# %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads.
|
||||||
# So use 6 threads here though it's not optimal in performace wise, but ok.
|
# So use 6 threads here though it's not optimal in performace wise, but ok.
|
||||||
compile(
|
compile(
|
||||||
verilator_flags2 => ['--cc --trace --stats' . ($Self->{vltmt} ? ' --threads 6' : ''),
|
verilator_flags2 => ['--cc --trace --stats +define+TEST_ATTRIBUTES'],
|
||||||
'+define+TEST_ATTRIBUTES'],
|
threads => $Self->{vltmt} ? 6 : 0
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,12 @@ module t;
|
||||||
//if ($test$plusargs("")!==1) $stop; // Simulators differ in this answer
|
//if ($test$plusargs("")!==1) $stop; // Simulators differ in this answer
|
||||||
if ($test$plusargs("NOTTHERE")!==0) $stop;
|
if ($test$plusargs("NOTTHERE")!==0) $stop;
|
||||||
|
|
||||||
|
sv_in = "PLUS";
|
||||||
|
`ifdef VERILATOR
|
||||||
|
if ($c1(0)) sv_in = "NEVER"; // Prevent constant propagation
|
||||||
|
`endif
|
||||||
|
if ($test$plusargs(sv_in)!==1) $stop;
|
||||||
|
|
||||||
p_i = 10;
|
p_i = 10;
|
||||||
if ($value$plusargs("NOTTHERE%d", p_i) !== 0) $stop;
|
if ($value$plusargs("NOTTHERE%d", p_i) !== 0) $stop;
|
||||||
if ($value$plusargs("NOTTHERE%0d", p_i) !== 0) $stop;
|
if ($value$plusargs("NOTTHERE%0d", p_i) !== 0) $stop;
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,8 @@ scenarios(simulator => 1);
|
||||||
top_filename("t/t_threads_counter.v");
|
top_filename("t/t_threads_counter.v");
|
||||||
|
|
||||||
compile(
|
compile(
|
||||||
verilator_flags2 => ['--cc --no-threads'],
|
verilator_flags2 => ['--cc'],
|
||||||
|
threads => 0,
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,8 @@ scenarios(vltmt => 1);
|
||||||
top_filename("t/t_threads_counter.v");
|
top_filename("t/t_threads_counter.v");
|
||||||
|
|
||||||
compile(
|
compile(
|
||||||
verilator_flags2 => ['--cc --threads 1'],
|
verilator_flags2 => ['--cc'],
|
||||||
|
threads => 1
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,8 @@ scenarios(vltmt => 1);
|
||||||
top_filename("t/t_threads_counter.v");
|
top_filename("t/t_threads_counter.v");
|
||||||
|
|
||||||
compile(
|
compile(
|
||||||
verilator_flags2 => ['--cc --threads 2'],
|
verilator_flags2 => ['--cc'],
|
||||||
|
threads => 2
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,8 @@ scenarios(vltmt => 1);
|
||||||
top_filename("t/t_threads_counter.v");
|
top_filename("t/t_threads_counter.v");
|
||||||
|
|
||||||
compile(
|
compile(
|
||||||
verilator_flags2 => ['--cc --threads 4'],
|
verilator_flags2 => ['--cc'],
|
||||||
|
threads => 4
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
|
|
|
||||||
|
|
@ -10,19 +10,16 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||||
|
|
||||||
scenarios(vltmt => 1);
|
scenarios(vltmt => 1);
|
||||||
|
|
||||||
if ($Self->cfg_with_m32) {
|
|
||||||
skip("Does not work with -m32 (resource unavailable)");
|
|
||||||
}
|
|
||||||
|
|
||||||
compile(
|
compile(
|
||||||
verilator_flags2 => ['--cc --threads 1024'],
|
verilator_flags2 => ['--cc'],
|
||||||
|
threads => 4,
|
||||||
|
context_threads => 2
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
check_finished => 1,
|
fails => 1
|
||||||
);
|
);
|
||||||
|
|
||||||
file_grep($Self->{run_log_filename}, qr/System has .* CPUs but.*--threads 1024/);
|
file_grep($Self->{run_log_filename}, qr/%Error: .*\/verilated\.cpp:\d+: VerilatedContext has 2 threads but model 'Vt_threads_crazy' \(instantiated as 'top'\) was Verilated with --threads 4\./);
|
||||||
|
|
||||||
ok(1);
|
ok(1);
|
||||||
1;
|
1;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you
|
||||||
|
# can redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
scenarios(vlt_all => 1);
|
||||||
|
|
||||||
|
if ($Self->cfg_with_m32) {
|
||||||
|
skip("Does not work with -m32 (resource unavailable)");
|
||||||
|
}
|
||||||
|
|
||||||
|
top_filename("t/t_threads_crazy.v");
|
||||||
|
|
||||||
|
compile(
|
||||||
|
verilator_flags2 => ['--cc'],
|
||||||
|
threads => $Self->{vltmt} ? 2 : 0,
|
||||||
|
context_threads => 1024
|
||||||
|
);
|
||||||
|
|
||||||
|
execute(
|
||||||
|
check_finished => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($Self->{vltmt}) {
|
||||||
|
file_grep($Self->{run_log_filename}, qr/System has \d+ hardware threads but simulation thread count set to 1024\. This will likely cause significant slowdown\./);
|
||||||
|
} else {
|
||||||
|
file_grep($Self->{run_log_filename}, qr/Verilator run-time library built without VL_THREADS\. Ignoring call to 'VerilatedContext::threads' with argument 1024\./);
|
||||||
|
}
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
@ -13,7 +13,8 @@ scenarios(vltmt => 1);
|
||||||
top_filename("t/t_threads_counter.v");
|
top_filename("t/t_threads_counter.v");
|
||||||
|
|
||||||
compile(
|
compile(
|
||||||
verilator_flags2 => ['--cc --threads 2 --debug-nondeterminism --no-skip-identical'],
|
verilator_flags2 => ['--cc --debug-nondeterminism --no-skip-identical'],
|
||||||
|
threads => 2
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ scenarios(simulator => 1);
|
||||||
# %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads.
|
# %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads.
|
||||||
# Strangely, asking for more threads makes it go away.
|
# Strangely, asking for more threads makes it go away.
|
||||||
compile(
|
compile(
|
||||||
verilator_flags2 => ['--cc --trace --trace-params -Wno-LITENDIAN',
|
verilator_flags2 => ['--cc --trace --trace-params -Wno-LITENDIAN'],
|
||||||
($Self->{vltmt} ? '--threads 6' : '')],
|
threads => $Self->{vltmt} ? 6 : 0
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ top_filename("t/t_trace_litendian.v");
|
||||||
# %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads.
|
# %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads.
|
||||||
# Strangely, asking for more threads makes it go away.
|
# Strangely, asking for more threads makes it go away.
|
||||||
compile(
|
compile(
|
||||||
verilator_flags2 => ['--cc --trace-fst --trace-params -Wno-LITENDIAN',
|
verilator_flags2 => ['--cc --trace-fst --trace-params -Wno-LITENDIAN'],
|
||||||
($Self->{vltmt} ? '--threads 6' : '')],
|
threads => $Self->{vltmt} ? 6 : 0
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,8 @@ else {
|
||||||
# %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads.
|
# %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads.
|
||||||
# Strangely, asking for more threads makes it go away.
|
# Strangely, asking for more threads makes it go away.
|
||||||
compile(
|
compile(
|
||||||
verilator_flags2 => ['--sc --trace-fst --trace-params -Wno-LITENDIAN',
|
verilator_flags2 => ['--sc --trace-fst --trace-params -Wno-LITENDIAN'],
|
||||||
($Self->{vltmt} ? '--threads 6' : '')],
|
threads => $Self->{vltmt} ? 6 : 0
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
|
|
|
||||||
|
|
@ -25,21 +25,21 @@
|
||||||
|
|
||||||
VM_PREFIX* ap;
|
VM_PREFIX* ap;
|
||||||
Vt_trace_two_b* bp;
|
Vt_trace_two_b* bp;
|
||||||
uint64_t main_time = 0;
|
|
||||||
double sc_time_stamp() { return main_time; }
|
|
||||||
|
|
||||||
int main(int argc, char** argv, char** env) {
|
int main(int argc, char** argv, char** env) {
|
||||||
|
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||||
|
|
||||||
uint64_t sim_time = 1100;
|
uint64_t sim_time = 1100;
|
||||||
Verilated::commandArgs(argc, argv);
|
contextp->commandArgs(argc, argv);
|
||||||
Verilated::debug(0);
|
contextp->debug(0);
|
||||||
Verilated::traceEverOn(true);
|
contextp->traceEverOn(true);
|
||||||
srand48(5);
|
srand48(5);
|
||||||
ap = new VM_PREFIX("topa");
|
ap = new VM_PREFIX{contextp.get(), "topa"};
|
||||||
bp = new Vt_trace_two_b("topb");
|
bp = new Vt_trace_two_b{contextp.get(), "topb"};
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
#ifdef TEST_HDR_TRACE
|
#ifdef TEST_HDR_TRACE
|
||||||
Verilated::traceEverOn(true);
|
contextp->traceEverOn(true);
|
||||||
# ifdef TEST_FST
|
# ifdef TEST_FST
|
||||||
VerilatedFstC* tfp = new VerilatedFstC;
|
VerilatedFstC* tfp = new VerilatedFstC;
|
||||||
ap->trace(tfp, 99);
|
ap->trace(tfp, 99);
|
||||||
|
|
@ -59,14 +59,14 @@ int main(int argc, char** argv, char** env) {
|
||||||
bp->eval_step();
|
bp->eval_step();
|
||||||
ap->eval_end_step();
|
ap->eval_end_step();
|
||||||
bp->eval_end_step();
|
bp->eval_end_step();
|
||||||
if (tfp) tfp->dump(main_time);
|
if (tfp) tfp->dump(contextp->time());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
{
|
{
|
||||||
ap->clk = false;
|
ap->clk = false;
|
||||||
main_time += 10;
|
contextp->timeInc(10);
|
||||||
}
|
}
|
||||||
while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) {
|
while (contextp->time() < sim_time && !contextp->gotFinish()) {
|
||||||
ap->clk = !ap->clk;
|
ap->clk = !ap->clk;
|
||||||
bp->clk = ap->clk;
|
bp->clk = ap->clk;
|
||||||
ap->eval_step();
|
ap->eval_step();
|
||||||
|
|
@ -74,11 +74,11 @@ int main(int argc, char** argv, char** env) {
|
||||||
ap->eval_end_step();
|
ap->eval_end_step();
|
||||||
bp->eval_end_step();
|
bp->eval_end_step();
|
||||||
#ifdef TEST_HDR_TRACE
|
#ifdef TEST_HDR_TRACE
|
||||||
if (tfp) tfp->dump(main_time);
|
if (tfp) tfp->dump(contextp->time());
|
||||||
#endif
|
#endif
|
||||||
main_time += 5;
|
contextp->timeInc(5);
|
||||||
}
|
}
|
||||||
if (!Verilated::gotFinish()) {
|
if (!contextp->gotFinish()) {
|
||||||
vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
||||||
}
|
}
|
||||||
ap->final();
|
ap->final();
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,6 @@
|
||||||
|
|
||||||
VM_PREFIX* tb = nullptr;
|
VM_PREFIX* tb = nullptr;
|
||||||
|
|
||||||
double sc_time_stamp() { return 0; }
|
|
||||||
|
|
||||||
bool check() {
|
bool check() {
|
||||||
bool pass;
|
bool pass;
|
||||||
int c = (tb->A >> tb->SEL) & 0x1;
|
int c = (tb->A >> tb->SEL) & 0x1;
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,6 @@
|
||||||
|
|
||||||
VM_PREFIX* tb = nullptr;
|
VM_PREFIX* tb = nullptr;
|
||||||
|
|
||||||
double sc_time_stamp() { return 0; }
|
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
Verilated::debug(0);
|
Verilated::debug(0);
|
||||||
tb = new VM_PREFIX("tb");
|
tb = new VM_PREFIX("tb");
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||||
# Version 2.0.
|
# Version 2.0.
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
scenarios(vlt => 1);
|
scenarios(vltmt => 1);
|
||||||
|
|
||||||
my $root = "..";
|
my $root = "..";
|
||||||
|
|
||||||
|
|
@ -17,10 +17,10 @@ compile(
|
||||||
verilator_flags2 => ["--cc",
|
verilator_flags2 => ["--cc",
|
||||||
"--coverage-toggle --coverage-line --coverage-user",
|
"--coverage-toggle --coverage-line --coverage-user",
|
||||||
"--trace --vpi ",
|
"--trace --vpi ",
|
||||||
"--threads 2",
|
|
||||||
"--trace-threads 1",
|
"--trace-threads 1",
|
||||||
"--prof-exec", "--prof-pgo",
|
"--prof-exec", "--prof-pgo",
|
||||||
"$root/include/verilated_save.cpp"],
|
"$root/include/verilated_save.cpp"],
|
||||||
|
threads => 2
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,8 @@ my $root = "..";
|
||||||
|
|
||||||
compile(
|
compile(
|
||||||
# Can't use --coverage and --savable together, so cheat and compile inline
|
# Can't use --coverage and --savable together, so cheat and compile inline
|
||||||
verilator_flags2 => ["--cc --coverage-toggle --coverage-line --coverage-user --trace --threads 1 --vpi $root/include/verilated_save.cpp"],
|
verilator_flags2 => ["--cc --coverage-toggle --coverage-line --coverage-user --trace --vpi $root/include/verilated_save.cpp"],
|
||||||
|
threads => 1
|
||||||
);
|
);
|
||||||
|
|
||||||
execute(
|
execute(
|
||||||
|
|
|
||||||
|
|
@ -143,11 +143,15 @@ static void register_filler_cb() {
|
||||||
double sc_time_stamp() { return main_time; }
|
double sc_time_stamp() { return main_time; }
|
||||||
|
|
||||||
int main(int argc, char** argv, char** env) {
|
int main(int argc, char** argv, char** env) {
|
||||||
uint64_t sim_time = 100;
|
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||||
Verilated::commandArgs(argc, argv);
|
|
||||||
Verilated::debug(0);
|
|
||||||
|
|
||||||
VM_PREFIX* topp = new VM_PREFIX(""); // Note null name - we're flattening it out
|
uint64_t sim_time = 100;
|
||||||
|
contextp->commandArgs(argc, argv);
|
||||||
|
contextp->debug(0);
|
||||||
|
|
||||||
|
const std::unique_ptr<VM_PREFIX> topp{new VM_PREFIX{contextp.get(),
|
||||||
|
// Note null name - we're flattening it out
|
||||||
|
""}};
|
||||||
|
|
||||||
reregister_value_cb();
|
reregister_value_cb();
|
||||||
TEST_CHECK_NZ(vh_value_cb);
|
TEST_CHECK_NZ(vh_value_cb);
|
||||||
|
|
@ -158,7 +162,7 @@ int main(int argc, char** argv, char** env) {
|
||||||
topp->eval();
|
topp->eval();
|
||||||
topp->clk = 0;
|
topp->clk = 0;
|
||||||
|
|
||||||
while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) {
|
while (main_time < sim_time && !contextp->gotFinish()) {
|
||||||
main_time += 1;
|
main_time += 1;
|
||||||
if (verbose) VL_PRINTF("Sim Time %d got_error %d\n", main_time, errors);
|
if (verbose) VL_PRINTF("Sim Time %d got_error %d\n", main_time, errors);
|
||||||
topp->clk = !topp->clk;
|
topp->clk = !topp->clk;
|
||||||
|
|
@ -168,11 +172,10 @@ int main(int argc, char** argv, char** env) {
|
||||||
if (errors) vl_stop(__FILE__, __LINE__, "TOP-cpp");
|
if (errors) vl_stop(__FILE__, __LINE__, "TOP-cpp");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Verilated::gotFinish()) {
|
if (!contextp->gotFinish()) {
|
||||||
vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
||||||
}
|
}
|
||||||
topp->final();
|
topp->final();
|
||||||
|
|
||||||
VL_DO_DANGLING(delete topp, topp);
|
|
||||||
return errors ? 10 : 0;
|
return errors ? 10 : 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,6 @@ bool callbacks_expected_called[CB_COUNT] = {false};
|
||||||
std::vector<int>::const_iterator cb_iter;
|
std::vector<int>::const_iterator cb_iter;
|
||||||
std::vector<CallbackState>::const_iterator state_iter;
|
std::vector<CallbackState>::const_iterator state_iter;
|
||||||
|
|
||||||
unsigned int main_time = 0;
|
|
||||||
bool got_error = false;
|
bool got_error = false;
|
||||||
|
|
||||||
#ifdef TEST_VERBOSE
|
#ifdef TEST_VERBOSE
|
||||||
|
|
@ -245,27 +244,29 @@ static int register_test_callback() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
double sc_time_stamp() { return main_time; }
|
|
||||||
|
|
||||||
int main(int argc, char** argv, char** env) {
|
int main(int argc, char** argv, char** env) {
|
||||||
|
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||||
|
|
||||||
uint64_t sim_time = 100;
|
uint64_t sim_time = 100;
|
||||||
bool cbs_called;
|
bool cbs_called;
|
||||||
Verilated::commandArgs(argc, argv);
|
contextp->commandArgs(argc, argv);
|
||||||
|
|
||||||
VM_PREFIX* topp = new VM_PREFIX(""); // Note null name - we're flattening it out
|
const std::unique_ptr<VM_PREFIX> topp{new VM_PREFIX{contextp.get(),
|
||||||
|
// Note null name - we're flattening it out
|
||||||
|
""}};
|
||||||
|
|
||||||
if (verbose) VL_PRINTF("-- { Sim Time %d } --\n", main_time);
|
if (verbose) VL_PRINTF("-- { Sim Time %" PRId64 " } --\n", contextp->time());
|
||||||
|
|
||||||
register_test_callback();
|
register_test_callback();
|
||||||
|
|
||||||
topp->eval();
|
topp->eval();
|
||||||
topp->clk = 0;
|
topp->clk = 0;
|
||||||
main_time += 1;
|
contextp->timeInc(1);
|
||||||
|
|
||||||
while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) {
|
while (contextp->time() < sim_time && !contextp->gotFinish()) {
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
VL_PRINTF("-- { Sim Time %d , Callback %s (%d) , Testcase State %d } --\n", main_time,
|
VL_PRINTF("-- { Sim Time %" PRId64 " , Callback %s (%d) , Testcase State %d } --\n",
|
||||||
cb_reason_to_string(*cb_iter), *cb_iter, *state_iter);
|
contextp->time(), cb_reason_to_string(*cb_iter), *cb_iter, *state_iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
topp->eval();
|
topp->eval();
|
||||||
|
|
@ -285,14 +286,17 @@ int main(int argc, char** argv, char** env) {
|
||||||
|
|
||||||
VerilatedVpi::callTimedCbs();
|
VerilatedVpi::callTimedCbs();
|
||||||
|
|
||||||
main_time = VerilatedVpi::cbNextDeadline();
|
int64_t next_time = VerilatedVpi::cbNextDeadline();
|
||||||
if (main_time == -1 && !Verilated::gotFinish()) {
|
contextp->time(next_time);
|
||||||
if (verbose) VL_PRINTF("-- { Sim Time %d , No more testcases } --\n", main_time);
|
if (next_time == -1 && !contextp->gotFinish()) {
|
||||||
|
if (verbose)
|
||||||
|
VL_PRINTF("-- { Sim Time %" PRId64 " , No more testcases } --\n",
|
||||||
|
contextp->time());
|
||||||
if (got_error) {
|
if (got_error) {
|
||||||
vl_stop(__FILE__, __LINE__, "TOP-cpp");
|
vl_stop(__FILE__, __LINE__, "TOP-cpp");
|
||||||
} else {
|
} else {
|
||||||
VL_PRINTF("*-* All Finished *-*\n");
|
VL_PRINTF("*-* All Finished *-*\n");
|
||||||
Verilated::gotFinish(true);
|
contextp->gotFinish(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -302,11 +306,10 @@ int main(int argc, char** argv, char** env) {
|
||||||
topp->clk = !topp->clk;
|
topp->clk = !topp->clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Verilated::gotFinish()) {
|
if (!contextp->gotFinish()) {
|
||||||
vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
||||||
}
|
}
|
||||||
topp->final();
|
topp->final();
|
||||||
|
|
||||||
VL_DO_DANGLING(delete topp, topp);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,6 @@
|
||||||
#define TEST_MSG \
|
#define TEST_MSG \
|
||||||
if (0) printf
|
if (0) printf
|
||||||
|
|
||||||
unsigned int main_time = 0;
|
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
||||||
#define CHECK_RESULT_VH(got, exp) \
|
#define CHECK_RESULT_VH(got, exp) \
|
||||||
|
|
@ -240,22 +238,25 @@ void vpi_compat_bootstrap(void) {
|
||||||
void (*vlog_startup_routines[])() = {vpi_compat_bootstrap, 0};
|
void (*vlog_startup_routines[])() = {vpi_compat_bootstrap, 0};
|
||||||
|
|
||||||
#else
|
#else
|
||||||
double sc_time_stamp() { return main_time; }
|
|
||||||
int main(int argc, char** argv, char** env) {
|
int main(int argc, char** argv, char** env) {
|
||||||
uint64_t sim_time = 1100;
|
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||||
Verilated::commandArgs(argc, argv);
|
|
||||||
Verilated::debug(0);
|
|
||||||
|
|
||||||
Vt_vpi_get* topp = new Vt_vpi_get(""); // Note null name - we're flattening it out
|
uint64_t sim_time = 1100;
|
||||||
|
contextp->commandArgs(argc, argv);
|
||||||
|
contextp->debug(0);
|
||||||
|
|
||||||
|
const std::unique_ptr<VM_PREFIX> topp{new VM_PREFIX{contextp.get(),
|
||||||
|
// Note null name - we're flattening it out
|
||||||
|
""}};
|
||||||
|
|
||||||
#ifdef VERILATOR
|
#ifdef VERILATOR
|
||||||
#ifdef TEST_VERBOSE
|
#ifdef TEST_VERBOSE
|
||||||
Verilated::scopesDump();
|
contextp->scopesDump();
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if VM_TRACE
|
#if VM_TRACE
|
||||||
Verilated::traceEverOn(true);
|
contextp->traceEverOn(true);
|
||||||
VL_PRINTF("Enabling waves...\n");
|
VL_PRINTF("Enabling waves...\n");
|
||||||
VerilatedVcdC* tfp = new VerilatedVcdC;
|
VerilatedVcdC* tfp = new VerilatedVcdC;
|
||||||
topp->trace(tfp, 99);
|
topp->trace(tfp, 99);
|
||||||
|
|
@ -264,19 +265,19 @@ int main(int argc, char** argv, char** env) {
|
||||||
|
|
||||||
topp->eval();
|
topp->eval();
|
||||||
topp->clk = 0;
|
topp->clk = 0;
|
||||||
main_time += 10;
|
contextp->timeInc(10);
|
||||||
|
|
||||||
while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) {
|
while (contextp->time() < sim_time && !contextp->gotFinish()) {
|
||||||
main_time += 1;
|
contextp->timeInc(1);
|
||||||
topp->eval();
|
topp->eval();
|
||||||
VerilatedVpi::callValueCbs();
|
VerilatedVpi::callValueCbs();
|
||||||
topp->clk = !topp->clk;
|
topp->clk = !topp->clk;
|
||||||
// mon_do();
|
// mon_do();
|
||||||
#if VM_TRACE
|
#if VM_TRACE
|
||||||
if (tfp) tfp->dump(main_time);
|
if (tfp) tfp->dump(contextp->time());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (!Verilated::gotFinish()) {
|
if (!contextp->gotFinish()) {
|
||||||
vl_fatal(FILENM, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
vl_fatal(FILENM, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
||||||
}
|
}
|
||||||
topp->final();
|
topp->final();
|
||||||
|
|
@ -285,7 +286,6 @@ int main(int argc, char** argv, char** env) {
|
||||||
if (tfp) tfp->close();
|
if (tfp) tfp->close();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VL_DO_DANGLING(delete topp, topp);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,6 @@
|
||||||
#define DEBUG \
|
#define DEBUG \
|
||||||
if (0) printf
|
if (0) printf
|
||||||
|
|
||||||
unsigned int main_time = 0;
|
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
@ -250,24 +249,27 @@ void (*vlog_startup_routines[])() = {vpi_compat_bootstrap, 0};
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
double sc_time_stamp() { return main_time; }
|
|
||||||
int main(int argc, char** argv, char** env) {
|
int main(int argc, char** argv, char** env) {
|
||||||
uint64_t sim_time = 1100;
|
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||||
Verilated::commandArgs(argc, argv);
|
|
||||||
Verilated::debug(0);
|
|
||||||
// we're going to be checking for these errors do don't crash out
|
|
||||||
Verilated::fatalOnVpiError(0);
|
|
||||||
|
|
||||||
VM_PREFIX* topp = new VM_PREFIX(""); // Note null name - we're flattening it out
|
uint64_t sim_time = 1100;
|
||||||
|
contextp->commandArgs(argc, argv);
|
||||||
|
contextp->debug(0);
|
||||||
|
// we're going to be checking for these errors do don't crash out
|
||||||
|
contextp->fatalOnVpiError(0);
|
||||||
|
|
||||||
|
const std::unique_ptr<VM_PREFIX> topp{new VM_PREFIX{contextp.get(),
|
||||||
|
// Note null name - we're flattening it out
|
||||||
|
""}};
|
||||||
|
|
||||||
#ifdef VERILATOR
|
#ifdef VERILATOR
|
||||||
#ifdef TEST_VERBOSE
|
#ifdef TEST_VERBOSE
|
||||||
Verilated::scopesDump();
|
contextp->scopesDump();
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if VM_TRACE
|
#if VM_TRACE
|
||||||
Verilated::traceEverOn(true);
|
contextp->traceEverOn(true);
|
||||||
VL_PRINTF("Enabling waves...\n");
|
VL_PRINTF("Enabling waves...\n");
|
||||||
VerilatedVcdC* tfp = new VerilatedVcdC;
|
VerilatedVcdC* tfp = new VerilatedVcdC;
|
||||||
topp->trace(tfp, 99);
|
topp->trace(tfp, 99);
|
||||||
|
|
@ -276,19 +278,19 @@ int main(int argc, char** argv, char** env) {
|
||||||
|
|
||||||
topp->eval();
|
topp->eval();
|
||||||
topp->clk = 0;
|
topp->clk = 0;
|
||||||
main_time += 10;
|
contextp->timeInc(10);
|
||||||
|
|
||||||
while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) {
|
while (contextp->time() < sim_time && !contextp->gotFinish()) {
|
||||||
main_time += 1;
|
contextp->timeInc(1);
|
||||||
topp->eval();
|
topp->eval();
|
||||||
VerilatedVpi::callValueCbs();
|
VerilatedVpi::callValueCbs();
|
||||||
topp->clk = !topp->clk;
|
topp->clk = !topp->clk;
|
||||||
// mon_do();
|
// mon_do();
|
||||||
#if VM_TRACE
|
#if VM_TRACE
|
||||||
if (tfp) tfp->dump(main_time);
|
if (tfp) tfp->dump(contextp->time());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (!Verilated::gotFinish()) {
|
if (!contextp->gotFinish()) {
|
||||||
vl_fatal(FILENM, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
vl_fatal(FILENM, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
||||||
}
|
}
|
||||||
topp->final();
|
topp->final();
|
||||||
|
|
@ -297,7 +299,6 @@ int main(int argc, char** argv, char** env) {
|
||||||
if (tfp) tfp->close();
|
if (tfp) tfp->close();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VL_DO_DANGLING(delete topp, topp);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,6 @@
|
||||||
#define DEBUG \
|
#define DEBUG \
|
||||||
if (0) printf
|
if (0) printf
|
||||||
|
|
||||||
unsigned int main_time = 0;
|
|
||||||
|
|
||||||
#define CHECK_RESULT_NZ(got) \
|
#define CHECK_RESULT_NZ(got) \
|
||||||
if (!(got)) { \
|
if (!(got)) { \
|
||||||
printf("%%Error: %s:%d: GOT = NULL EXP = !NULL\n", FILENM, __LINE__); \
|
printf("%%Error: %s:%d: GOT = NULL EXP = !NULL\n", FILENM, __LINE__); \
|
||||||
|
|
@ -172,27 +170,36 @@ void (*vlog_startup_routines[])() = {vpi_compat_bootstrap, 0};
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
double sc_time_stamp() { return main_time; }
|
|
||||||
int main(int argc, char** argv, char** env) {
|
int main(int argc, char** argv, char** env) {
|
||||||
uint64_t sim_time = 1100;
|
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||||
Verilated::commandArgs(argc, argv);
|
|
||||||
Verilated::debug(0);
|
uint64_t sim_time = 1100;
|
||||||
// we're going to be checking for these errors do don't crash out
|
contextp->commandArgs(argc, argv);
|
||||||
Verilated::fatalOnVpiError(0);
|
contextp->debug(0);
|
||||||
|
// we're going to be checking for these errors do don't crash out
|
||||||
|
contextp->fatalOnVpiError(0);
|
||||||
|
|
||||||
|
{
|
||||||
|
// Construct and destroy
|
||||||
|
const std::unique_ptr<VM_PREFIX> topp{
|
||||||
|
new VM_PREFIX{contextp.get(),
|
||||||
|
// Note null name - we're flattening it out
|
||||||
|
""}};
|
||||||
|
}
|
||||||
|
|
||||||
VM_PREFIX* topp = new VM_PREFIX(""); // Note null name - we're flattening it out
|
|
||||||
// Test second construction
|
// Test second construction
|
||||||
delete topp;
|
const std::unique_ptr<VM_PREFIX> topp{new VM_PREFIX{contextp.get(),
|
||||||
topp = new VM_PREFIX("");
|
// Note null name - we're flattening it out
|
||||||
|
""}};
|
||||||
|
|
||||||
#ifdef VERILATOR
|
#ifdef VERILATOR
|
||||||
#ifdef TEST_VERBOSE
|
#ifdef TEST_VERBOSE
|
||||||
Verilated::scopesDump();
|
contextp->scopesDump();
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if VM_TRACE
|
#if VM_TRACE
|
||||||
Verilated::traceEverOn(true);
|
contextp->traceEverOn(true);
|
||||||
VL_PRINTF("Enabling waves...\n");
|
VL_PRINTF("Enabling waves...\n");
|
||||||
VerilatedVcdC* tfp = new VerilatedVcdC;
|
VerilatedVcdC* tfp = new VerilatedVcdC;
|
||||||
topp->trace(tfp, 99);
|
topp->trace(tfp, 99);
|
||||||
|
|
@ -201,19 +208,19 @@ int main(int argc, char** argv, char** env) {
|
||||||
|
|
||||||
topp->eval();
|
topp->eval();
|
||||||
topp->clk = 0;
|
topp->clk = 0;
|
||||||
main_time += 10;
|
contextp->timeInc(10);
|
||||||
|
|
||||||
while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) {
|
while (contextp->time() < sim_time && !contextp->gotFinish()) {
|
||||||
main_time += 1;
|
contextp->timeInc(1);
|
||||||
topp->eval();
|
topp->eval();
|
||||||
VerilatedVpi::callValueCbs();
|
VerilatedVpi::callValueCbs();
|
||||||
topp->clk = !topp->clk;
|
topp->clk = !topp->clk;
|
||||||
// mon_do();
|
// mon_do();
|
||||||
#if VM_TRACE
|
#if VM_TRACE
|
||||||
if (tfp) tfp->dump(main_time);
|
if (tfp) tfp->dump(contextp->time());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (!Verilated::gotFinish()) {
|
if (!contextp->gotFinish()) {
|
||||||
vl_fatal(FILENM, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
vl_fatal(FILENM, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
||||||
}
|
}
|
||||||
topp->final();
|
topp->final();
|
||||||
|
|
@ -222,7 +229,6 @@ int main(int argc, char** argv, char** env) {
|
||||||
if (tfp) tfp->close();
|
if (tfp) tfp->close();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VL_DO_DANGLING(delete topp, topp);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,6 @@
|
||||||
#define DEBUG \
|
#define DEBUG \
|
||||||
if (0) printf
|
if (0) printf
|
||||||
|
|
||||||
unsigned int main_time = 0;
|
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
||||||
#define CHECK_RESULT_VH(got, exp) \
|
#define CHECK_RESULT_VH(got, exp) \
|
||||||
|
|
@ -240,24 +238,27 @@ void (*vlog_startup_routines[])() = {vpi_compat_bootstrap, 0};
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
double sc_time_stamp() { return main_time; }
|
|
||||||
int main(int argc, char** argv, char** env) {
|
int main(int argc, char** argv, char** env) {
|
||||||
uint64_t sim_time = 1100;
|
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||||
Verilated::commandArgs(argc, argv);
|
|
||||||
Verilated::debug(0);
|
|
||||||
// we're going to be checking for these errors do don't crash out
|
|
||||||
Verilated::fatalOnVpiError(0);
|
|
||||||
|
|
||||||
VM_PREFIX* topp = new VM_PREFIX(""); // Note null name - we're flattening it out
|
uint64_t sim_time = 1100;
|
||||||
|
contextp->commandArgs(argc, argv);
|
||||||
|
contextp->debug(0);
|
||||||
|
// we're going to be checking for these errors do don't crash out
|
||||||
|
contextp->fatalOnVpiError(0);
|
||||||
|
|
||||||
|
const std::unique_ptr<VM_PREFIX> topp{new VM_PREFIX{contextp.get(),
|
||||||
|
// Note null name - we're flattening it out
|
||||||
|
""}};
|
||||||
|
|
||||||
#ifdef VERILATOR
|
#ifdef VERILATOR
|
||||||
#ifdef TEST_VERBOSE
|
#ifdef TEST_VERBOSE
|
||||||
Verilated::scopesDump();
|
contextp->scopesDump();
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if VM_TRACE
|
#if VM_TRACE
|
||||||
Verilated::traceEverOn(true);
|
contextp->traceEverOn(true);
|
||||||
VL_PRINTF("Enabling waves...\n");
|
VL_PRINTF("Enabling waves...\n");
|
||||||
VerilatedVcdC* tfp = new VerilatedVcdC;
|
VerilatedVcdC* tfp = new VerilatedVcdC;
|
||||||
topp->trace(tfp, 99);
|
topp->trace(tfp, 99);
|
||||||
|
|
@ -266,19 +267,19 @@ int main(int argc, char** argv, char** env) {
|
||||||
|
|
||||||
topp->eval();
|
topp->eval();
|
||||||
topp->clk = 0;
|
topp->clk = 0;
|
||||||
main_time += 10;
|
contextp->timeInc(10);
|
||||||
|
|
||||||
while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) {
|
while (contextp->time() < sim_time && !contextp->gotFinish()) {
|
||||||
main_time += 1;
|
contextp->timeInc(1);
|
||||||
topp->eval();
|
topp->eval();
|
||||||
VerilatedVpi::callValueCbs();
|
VerilatedVpi::callValueCbs();
|
||||||
topp->clk = !topp->clk;
|
topp->clk = !topp->clk;
|
||||||
// mon_do();
|
// mon_do();
|
||||||
#if VM_TRACE
|
#if VM_TRACE
|
||||||
if (tfp) tfp->dump(main_time);
|
if (tfp) tfp->dump(contextp->time());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (!Verilated::gotFinish()) {
|
if (!contextp->gotFinish()) {
|
||||||
vl_fatal(FILENM, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
vl_fatal(FILENM, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
||||||
}
|
}
|
||||||
topp->final();
|
topp->final();
|
||||||
|
|
@ -287,7 +288,6 @@ int main(int argc, char** argv, char** env) {
|
||||||
if (tfp) tfp->close();
|
if (tfp) tfp->close();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VL_DO_DANGLING(delete topp, topp);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,27 +22,27 @@
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
unsigned int main_time = 0;
|
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
||||||
double sc_time_stamp() { return main_time; }
|
|
||||||
|
|
||||||
int main(int argc, char** argv, char** env) {
|
int main(int argc, char** argv, char** env) {
|
||||||
uint64_t sim_time = 1100;
|
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||||
Verilated::commandArgs(argc, argv);
|
|
||||||
Verilated::debug(0);
|
|
||||||
|
|
||||||
VM_PREFIX* topp = new VM_PREFIX(""); // Note null name - we're flattening it out
|
uint64_t sim_time = 1100;
|
||||||
|
contextp->commandArgs(argc, argv);
|
||||||
|
contextp->debug(0);
|
||||||
|
|
||||||
|
const std::unique_ptr<VM_PREFIX> topp{new VM_PREFIX{contextp.get(),
|
||||||
|
// Note null name - we're flattening it out
|
||||||
|
""}};
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
#ifdef TEST_VERBOSE
|
#ifdef TEST_VERBOSE
|
||||||
Verilated::scopesDump();
|
contextp->scopesDump();
|
||||||
#endif
|
#endif
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
#if VM_TRACE
|
#if VM_TRACE
|
||||||
Verilated::traceEverOn(true);
|
contextp->traceEverOn(true);
|
||||||
VL_PRINTF("Enabling waves...\n");
|
VL_PRINTF("Enabling waves...\n");
|
||||||
VerilatedVcdC* tfp = new VerilatedVcdC;
|
VerilatedVcdC* tfp = new VerilatedVcdC;
|
||||||
topp->trace(tfp, 99);
|
topp->trace(tfp, 99);
|
||||||
|
|
@ -54,24 +54,24 @@ int main(int argc, char** argv, char** env) {
|
||||||
topp->eval();
|
topp->eval();
|
||||||
topp->clk = 0;
|
topp->clk = 0;
|
||||||
|
|
||||||
while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) {
|
while (vl_time_stamp64() < sim_time && !contextp->gotFinish()) {
|
||||||
main_time += 1;
|
contextp->timeInc(1);
|
||||||
topp->eval();
|
topp->eval();
|
||||||
VerilatedVpi::callValueCbs();
|
VerilatedVpi::callValueCbs();
|
||||||
VerilatedVpi::callTimedCbs();
|
VerilatedVpi::callTimedCbs();
|
||||||
if (main_time > 20) { // Else haven't registered callbacks
|
if (contextp->time() > 20) { // Else haven't registered callbacks
|
||||||
TEST_CHECK_EQ(VerilatedVpi::cbNextDeadline(), main_time + 1);
|
TEST_CHECK_EQ(VerilatedVpi::cbNextDeadline(), contextp->time() + 1);
|
||||||
}
|
}
|
||||||
if ((main_time % 5) == 0) topp->clk = !topp->clk;
|
if ((contextp->time() % 5) == 0) topp->clk = !topp->clk;
|
||||||
// mon_do();
|
// mon_do();
|
||||||
#if VM_TRACE
|
#if VM_TRACE
|
||||||
if (tfp) tfp->dump(main_time);
|
if (tfp) tfp->dump(contextp->time());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
VerilatedVpi::callCbs(cbEndOfSimulation);
|
VerilatedVpi::callCbs(cbEndOfSimulation);
|
||||||
|
|
||||||
if (!Verilated::gotFinish()) {
|
if (!contextp->gotFinish()) {
|
||||||
vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
||||||
}
|
}
|
||||||
topp->final();
|
topp->final();
|
||||||
|
|
@ -80,6 +80,5 @@ int main(int argc, char** argv, char** env) {
|
||||||
if (tfp) tfp->close();
|
if (tfp) tfp->close();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VL_DO_DANGLING(delete topp, topp);
|
|
||||||
return errors ? 10 : 0;
|
return errors ? 10 : 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@
|
||||||
#define DEBUG \
|
#define DEBUG \
|
||||||
if (0) printf
|
if (0) printf
|
||||||
|
|
||||||
unsigned int main_time = 0;
|
|
||||||
unsigned int callback_count = 0;
|
unsigned int callback_count = 0;
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
@ -184,24 +183,27 @@ extern "C" int mon_check() {
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
||||||
double sc_time_stamp() { return main_time; }
|
|
||||||
int main(int argc, char** argv, char** env) {
|
int main(int argc, char** argv, char** env) {
|
||||||
uint64_t sim_time = 1100;
|
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||||
Verilated::commandArgs(argc, argv);
|
|
||||||
Verilated::debug(0);
|
|
||||||
// we're going to be checking for these errors do don't crash out
|
|
||||||
Verilated::fatalOnVpiError(0);
|
|
||||||
|
|
||||||
VM_PREFIX* topp = new VM_PREFIX(""); // Note null name - we're flattening it out
|
uint64_t sim_time = 1100;
|
||||||
|
contextp->commandArgs(argc, argv);
|
||||||
|
contextp->debug(0);
|
||||||
|
// we're going to be checking for these errors do don't crash out
|
||||||
|
contextp->fatalOnVpiError(0);
|
||||||
|
|
||||||
|
const std::unique_ptr<VM_PREFIX> topp{new VM_PREFIX{contextp.get(),
|
||||||
|
// Note null name - we're flattening it out
|
||||||
|
""}};
|
||||||
|
|
||||||
#ifdef VERILATOR
|
#ifdef VERILATOR
|
||||||
#ifdef TEST_VERBOSE
|
#ifdef TEST_VERBOSE
|
||||||
Verilated::scopesDump();
|
contextp->scopesDump();
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if VM_TRACE
|
#if VM_TRACE
|
||||||
Verilated::traceEverOn(true);
|
contextp->traceEverOn(true);
|
||||||
VL_PRINTF("Enabling waves...\n");
|
VL_PRINTF("Enabling waves...\n");
|
||||||
VerilatedVcdC* tfp = new VerilatedVcdC;
|
VerilatedVcdC* tfp = new VerilatedVcdC;
|
||||||
topp->trace(tfp, 99);
|
topp->trace(tfp, 99);
|
||||||
|
|
@ -210,20 +212,20 @@ int main(int argc, char** argv, char** env) {
|
||||||
|
|
||||||
topp->eval();
|
topp->eval();
|
||||||
topp->clk = 0;
|
topp->clk = 0;
|
||||||
main_time += 10;
|
contextp->timeInc(10);
|
||||||
|
|
||||||
while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) {
|
while (contextp->time() < sim_time && !contextp->gotFinish()) {
|
||||||
main_time += 1;
|
contextp->timeInc(1);
|
||||||
topp->eval();
|
topp->eval();
|
||||||
// VerilatedVpi::callValueCbs(); // Make sure can link without verilated_vpi.h included
|
// VerilatedVpi::callValueCbs(); // Make sure can link without verilated_vpi.h included
|
||||||
topp->clk = !topp->clk;
|
topp->clk = !topp->clk;
|
||||||
// mon_do();
|
// mon_do();
|
||||||
#if VM_TRACE
|
#if VM_TRACE
|
||||||
if (tfp) tfp->dump(main_time);
|
if (tfp) tfp->dump(contextp->time());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (!callback_count) vl_fatal(FILENM, __LINE__, "main", "%Error: never got callbacks");
|
if (!callback_count) vl_fatal(FILENM, __LINE__, "main", "%Error: never got callbacks");
|
||||||
if (!Verilated::gotFinish()) {
|
if (!contextp->gotFinish()) {
|
||||||
vl_fatal(FILENM, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
vl_fatal(FILENM, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
||||||
}
|
}
|
||||||
topp->final();
|
topp->final();
|
||||||
|
|
@ -232,6 +234,5 @@ int main(int argc, char** argv, char** env) {
|
||||||
if (tfp) tfp->close();
|
if (tfp) tfp->close();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VL_DO_DANGLING(delete topp, topp);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -693,20 +693,24 @@ void (*vlog_startup_routines[])() = {vpi_compat_bootstrap, 0};
|
||||||
|
|
||||||
double sc_time_stamp() { return main_time; }
|
double sc_time_stamp() { return main_time; }
|
||||||
int main(int argc, char** argv, char** env) {
|
int main(int argc, char** argv, char** env) {
|
||||||
uint64_t sim_time = 1100;
|
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||||
Verilated::commandArgs(argc, argv);
|
|
||||||
Verilated::debug(0);
|
|
||||||
|
|
||||||
VM_PREFIX* topp = new VM_PREFIX(""); // Note null name - we're flattening it out
|
uint64_t sim_time = 1100;
|
||||||
|
contextp->commandArgs(argc, argv);
|
||||||
|
contextp->debug(0);
|
||||||
|
|
||||||
|
const std::unique_ptr<VM_PREFIX> topp{new VM_PREFIX{contextp.get(),
|
||||||
|
// Note null name - we're flattening it out
|
||||||
|
""}};
|
||||||
|
|
||||||
#ifdef VERILATOR
|
#ifdef VERILATOR
|
||||||
#ifdef TEST_VERBOSE
|
#ifdef TEST_VERBOSE
|
||||||
Verilated::scopesDump();
|
contextp->scopesDump();
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if VM_TRACE
|
#if VM_TRACE
|
||||||
Verilated::traceEverOn(true);
|
contextp->traceEverOn(true);
|
||||||
VL_PRINTF("Enabling waves...\n");
|
VL_PRINTF("Enabling waves...\n");
|
||||||
VerilatedVcdC* tfp = new VerilatedVcdC;
|
VerilatedVcdC* tfp = new VerilatedVcdC;
|
||||||
topp->trace(tfp, 99);
|
topp->trace(tfp, 99);
|
||||||
|
|
@ -717,7 +721,7 @@ int main(int argc, char** argv, char** env) {
|
||||||
topp->clk = 0;
|
topp->clk = 0;
|
||||||
main_time += 10;
|
main_time += 10;
|
||||||
|
|
||||||
while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) {
|
while (vl_time_stamp64() < sim_time && !contextp->gotFinish()) {
|
||||||
main_time += 1;
|
main_time += 1;
|
||||||
topp->eval();
|
topp->eval();
|
||||||
VerilatedVpi::callValueCbs();
|
VerilatedVpi::callValueCbs();
|
||||||
|
|
@ -731,7 +735,7 @@ int main(int argc, char** argv, char** env) {
|
||||||
CHECK_RESULT(callback_count_half, 250);
|
CHECK_RESULT(callback_count_half, 250);
|
||||||
CHECK_RESULT(callback_count_quad, 2);
|
CHECK_RESULT(callback_count_quad, 2);
|
||||||
CHECK_RESULT(callback_count_strs, callback_count_strs_max);
|
CHECK_RESULT(callback_count_strs, callback_count_strs_max);
|
||||||
if (!Verilated::gotFinish()) {
|
if (!contextp->gotFinish()) {
|
||||||
vl_fatal(FILENM, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
vl_fatal(FILENM, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
||||||
}
|
}
|
||||||
topp->final();
|
topp->final();
|
||||||
|
|
@ -740,7 +744,6 @@ int main(int argc, char** argv, char** env) {
|
||||||
if (tfp) tfp->close();
|
if (tfp) tfp->close();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VL_DO_DANGLING(delete topp, topp);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,6 @@
|
||||||
#include "TestVpi.h"
|
#include "TestVpi.h"
|
||||||
|
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
unsigned int main_time = 0;
|
|
||||||
unsigned int callback_count_zero_time = 0;
|
unsigned int callback_count_zero_time = 0;
|
||||||
unsigned int callback_count_start_of_sim = 0;
|
unsigned int callback_count_start_of_sim = 0;
|
||||||
|
|
||||||
|
|
@ -105,25 +104,27 @@ void (*vlog_startup_routines[])() = {vpi_compat_bootstrap, 0};
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
double sc_time_stamp() { return main_time; }
|
|
||||||
|
|
||||||
int main(int argc, char** argv, char** env) {
|
int main(int argc, char** argv, char** env) {
|
||||||
uint64_t sim_time = 1100;
|
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||||
Verilated::commandArgs(argc, argv);
|
|
||||||
Verilated::debug(0);
|
|
||||||
|
|
||||||
VM_PREFIX* topp = new VM_PREFIX(""); // Note null name - we're flattening it out
|
uint64_t sim_time = 1100;
|
||||||
|
contextp->commandArgs(argc, argv);
|
||||||
|
contextp->debug(0);
|
||||||
|
|
||||||
|
const std::unique_ptr<VM_PREFIX> topp{new VM_PREFIX{contextp.get(),
|
||||||
|
// Note null name - we're flattening it out
|
||||||
|
""}};
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
#ifdef VERILATOR
|
#ifdef VERILATOR
|
||||||
# ifdef TEST_VERBOSE
|
# ifdef TEST_VERBOSE
|
||||||
Verilated::scopesDump();
|
contextp->scopesDump();
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
#if VM_TRACE
|
#if VM_TRACE
|
||||||
Verilated::traceEverOn(true);
|
contextp->traceEverOn(true);
|
||||||
VL_PRINTF("Enabling waves...\n");
|
VL_PRINTF("Enabling waves...\n");
|
||||||
VerilatedVcdC* tfp = new VerilatedVcdC;
|
VerilatedVcdC* tfp = new VerilatedVcdC;
|
||||||
topp->trace(tfp, 99);
|
topp->trace(tfp, 99);
|
||||||
|
|
@ -146,23 +147,23 @@ int main(int argc, char** argv, char** env) {
|
||||||
|
|
||||||
topp->eval();
|
topp->eval();
|
||||||
topp->clk = 0;
|
topp->clk = 0;
|
||||||
main_time += 1;
|
contextp->timeInc(1);
|
||||||
|
|
||||||
while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) {
|
while (contextp->time() < sim_time && !contextp->gotFinish()) {
|
||||||
main_time += 1;
|
contextp->timeInc(1);
|
||||||
topp->eval();
|
topp->eval();
|
||||||
VerilatedVpi::callValueCbs();
|
VerilatedVpi::callValueCbs();
|
||||||
VerilatedVpi::callTimedCbs();
|
VerilatedVpi::callTimedCbs();
|
||||||
topp->clk = !topp->clk;
|
topp->clk = !topp->clk;
|
||||||
// mon_do();
|
// mon_do();
|
||||||
#if VM_TRACE
|
#if VM_TRACE
|
||||||
if (tfp) tfp->dump(main_time);
|
if (tfp) tfp->dump(contextp->time());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
VerilatedVpi::callCbs(cbEndOfSimulation);
|
VerilatedVpi::callCbs(cbEndOfSimulation);
|
||||||
|
|
||||||
if (!Verilated::gotFinish()) {
|
if (!contextp->gotFinish()) {
|
||||||
vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
||||||
}
|
}
|
||||||
topp->final();
|
topp->final();
|
||||||
|
|
@ -171,7 +172,6 @@ int main(int argc, char** argv, char** env) {
|
||||||
if (tfp) tfp->close();
|
if (tfp) tfp->close();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VL_DO_DANGLING(delete topp, topp);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,8 @@ int main(int argc, char** argv, char** env) {
|
||||||
std::unique_ptr<VerilatedContext> context1p{new VerilatedContext};
|
std::unique_ptr<VerilatedContext> context1p{new VerilatedContext};
|
||||||
|
|
||||||
// configuration
|
// configuration
|
||||||
|
context0p->threads(1);
|
||||||
|
context1p->threads(1);
|
||||||
context0p->fatalOnError(false);
|
context0p->fatalOnError(false);
|
||||||
context1p->fatalOnError(false);
|
context1p->fatalOnError(false);
|
||||||
context0p->traceEverOn(true);
|
context0p->traceEverOn(true);
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,9 @@ compile(
|
||||||
make_top_shell => 0,
|
make_top_shell => 0,
|
||||||
make_main => 0,
|
make_main => 0,
|
||||||
# link threads library, add custom .cpp code, add tracing & coverage support
|
# link threads library, add custom .cpp code, add tracing & coverage support
|
||||||
verilator_flags2 => ["-threads 1 --exe $Self->{t_dir}/$Self->{name}.cpp",
|
verilator_flags2 => ["--exe $Self->{t_dir}/$Self->{name}.cpp",
|
||||||
"--trace --coverage -cc"],
|
"--trace --coverage -cc"],
|
||||||
|
threads => 1,
|
||||||
make_flags => 'CPPFLAGS_ADD=-DVL_NO_LEGACY',
|
make_flags => 'CPPFLAGS_ADD=-DVL_NO_LEGACY',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,9 @@ compile(
|
||||||
make_top_shell => 0,
|
make_top_shell => 0,
|
||||||
make_main => 0,
|
make_main => 0,
|
||||||
# link threads library, add custom .cpp code, add tracing & coverage support
|
# link threads library, add custom .cpp code, add tracing & coverage support
|
||||||
verilator_flags2 => ["-threads 1 --exe $Self->{t_dir}/t_wrapper_context.cpp",
|
verilator_flags2 => ["--exe $Self->{t_dir}/t_wrapper_context.cpp",
|
||||||
"--trace-fst --coverage -cc"],
|
"--trace-fst --coverage -cc"],
|
||||||
|
threads => 1,
|
||||||
make_flags => 'CPPFLAGS_ADD=-DVL_NO_LEGACY',
|
make_flags => 'CPPFLAGS_ADD=-DVL_NO_LEGACY',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,9 @@ compile(
|
||||||
make_top_shell => 0,
|
make_top_shell => 0,
|
||||||
make_main => 0,
|
make_main => 0,
|
||||||
# link threads library, add custom .cpp code, add tracing & coverage support
|
# link threads library, add custom .cpp code, add tracing & coverage support
|
||||||
verilator_flags2 => ["-threads 1 --exe $Self->{t_dir}/t_wrapper_context.cpp",
|
verilator_flags2 => ["--exe $Self->{t_dir}/t_wrapper_context.cpp",
|
||||||
"--trace --coverage -cc"],
|
"--trace --coverage -cc"],
|
||||||
|
threads => 1,
|
||||||
make_flags => 'CPPFLAGS_ADD=-DVL_NO_LEGACY',
|
make_flags => 'CPPFLAGS_ADD=-DVL_NO_LEGACY',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue