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:**
|
||||
|
||||
* 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
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ Alex Chadwick
|
|||
Aliaksei Chapyzhenka
|
||||
Ameya Vikram Singh
|
||||
Andreas Kuster
|
||||
Arkadiusz Kozdra
|
||||
Chris Randall
|
||||
Chuxuan Wang
|
||||
Conor McCullough
|
||||
|
|
|
|||
|
|
@ -86,61 +86,17 @@ Connecting to C++
|
|||
In C++ output mode (:vlopt:`--cc`), the Verilator generated model class is a
|
||||
simple C++ class. The user must write a C++ wrapper and main loop for the
|
||||
simulation, which instantiates the model class, and link with the Verilated
|
||||
model. Here is a simple example:
|
||||
model.
|
||||
|
||||
.. code-block:: C++
|
||||
Refer to ``examples/make_tracing_c`` in the distribution for a detailed
|
||||
commented example.
|
||||
|
||||
#include <verilated.h> // Defines common routines
|
||||
#include <iostream> // Need std::cout
|
||||
#include "Vtop.h" // From Verilating "top.v"
|
||||
Top level IO signals are read and written as members of the model. You
|
||||
call the model's :code:`eval()` method to evaluate the model. When the
|
||||
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
|
||||
|
|
@ -449,14 +405,15 @@ accesses the above signal "readme" would be:
|
|||
|
||||
int main(int argc, char** argv, char** env) {
|
||||
Verilated::commandArgs(argc, argv);
|
||||
Vour* top = new Vour;
|
||||
Verilated::internalsDump(); // See scopes to help debug
|
||||
while (!Verilated::gotFinish()) {
|
||||
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||
const std::unique_ptr<Vour> top{new Vour{contextp.get()}};
|
||||
|
||||
contextp->internalsDump(); // See scopes to help debug
|
||||
while (!contextp->gotFinish()) {
|
||||
top->eval();
|
||||
VerilatedVpi::callValueCbs(); // For signal callbacks
|
||||
read_and_check();
|
||||
}
|
||||
delete top;
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ Simulation Runtime Arguments
|
|||
|
||||
The following are the arguments that may be passed to a Verilated
|
||||
executable, provided that executable calls
|
||||
:code:`Verilated::commandArgs()`.
|
||||
:code:`VerilatedContext*->commandArgs(argc, argv)`.
|
||||
|
||||
All simulation runtime arguments begin with "+verilator", so that the
|
||||
user's executable may skip over all "+verilator" arguments when parsing its
|
||||
|
|
@ -96,7 +96,7 @@ Summary:
|
|||
.. option:: +verilator+noassert
|
||||
|
||||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -478,7 +478,7 @@ $test$plusargs, $value$plusargs
|
|||
|
||||
.. code-block:: C++
|
||||
|
||||
Verilated::commandArgs(argc, argv);
|
||||
{VerilatedContext*} ->commandArgs(argc, argv);
|
||||
|
||||
to register the command line before calling $test$plusargs or
|
||||
$value$plusargs.
|
||||
|
|
|
|||
|
|
@ -21,11 +21,14 @@ int main(int argc, char** argv, char** env) {
|
|||
// Prevent unused variable warnings
|
||||
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"
|
||||
Vtop* top = new Vtop;
|
||||
Vtop* top = new Vtop{contextp};
|
||||
|
||||
// Simulate until $finish
|
||||
while (!Verilated::gotFinish()) {
|
||||
while (!contextp->gotFinish()) {
|
||||
|
||||
// Evaluate model
|
||||
top->eval();
|
||||
|
|
|
|||
|
|
@ -66,6 +66,10 @@
|
|||
#if defined(_WIN32) || defined(__MINGW32__)
|
||||
# include <direct.h> // mkdir
|
||||
#endif
|
||||
|
||||
#ifdef VL_THREADED
|
||||
# include "verilated_threads.h"
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
IData VL_TESTPLUSARGS_I(const char* formatp) VL_MT_SAFE {
|
||||
const std::string& match = Verilated::threadContextp()->impp()->argPlusMatch(formatp);
|
||||
IData VL_TESTPLUSARGS_I(const std::string& format) VL_MT_SAFE {
|
||||
const std::string& match = Verilated::threadContextp()->impp()->argPlusMatch(format.c_str());
|
||||
return match.empty() ? 0 : 1;
|
||||
}
|
||||
|
||||
|
|
@ -2428,6 +2432,33 @@ const char* VerilatedContext::timeprecisionString() const VL_MT_SAFE {
|
|||
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) {
|
||||
const VerilatedLockGuard lock{m_argMutex};
|
||||
m_args.m_argVec.clear(); // Empty first, then add
|
||||
|
|
@ -2458,6 +2489,33 @@ void VerilatedContext::internalsDump() const VL_MT_SAFE {
|
|||
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
|
||||
|
||||
|
|
@ -2850,6 +2908,12 @@ void VerilatedImp::versionDump() VL_MT_SAFE {
|
|||
VL_PRINTF_MT(" Version: %s %s\n", Verilated::productName(), Verilated::productVersion());
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// VerilatedModel:: Methods
|
||||
|
||||
VerilatedModel::VerilatedModel(VerilatedContext& context)
|
||||
: m_context{context} {}
|
||||
|
||||
//===========================================================================
|
||||
// VerilatedModule:: Methods
|
||||
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@
|
|||
#endif
|
||||
// clang-format on
|
||||
|
||||
class VerilatedContext;
|
||||
class VerilatedContextImp;
|
||||
class VerilatedContextImpData;
|
||||
class VerilatedCovContext;
|
||||
|
|
@ -252,6 +253,33 @@ public:
|
|||
#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.
|
||||
|
||||
|
|
@ -266,10 +294,6 @@ public:
|
|||
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
|
||||
// (Internals however must use VL_PRINTF_MT, which calls these.)
|
||||
|
|
@ -362,6 +386,16 @@ protected:
|
|||
|
||||
// Implementation details
|
||||
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
|
||||
std::unique_ptr<VerilatedVirtualBase> m_coveragep; // Pointer for coveragep()
|
||||
|
||||
|
|
@ -495,6 +529,12 @@ public:
|
|||
/// Get time precision as IEEE-standard text
|
||||
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)
|
||||
void traceEverOn(bool flag) VL_MT_SAFE {
|
||||
if (flag) calcUnusedSigs(true);
|
||||
|
|
@ -517,6 +557,12 @@ public: // But for internal use only
|
|||
return reinterpret_cast<const VerilatedContextImp*>(this);
|
||||
}
|
||||
|
||||
void addModel(VerilatedModel*);
|
||||
|
||||
VerilatedVirtualBase* threadPoolp();
|
||||
VerilatedVirtualBase*
|
||||
enableExecutionProfiler(VerilatedVirtualBase* (*construct)(VerilatedContext&));
|
||||
|
||||
// Internal: $dumpfile
|
||||
void dumpfile(const std::string& flag) 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);
|
||||
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
|
||||
|
||||
//=========================================================================
|
||||
|
|
|
|||
|
|
@ -66,41 +66,66 @@ template <size_t N> static size_t roundUptoMultipleOf(size_t value) {
|
|||
return (value + mask) & ~mask;
|
||||
}
|
||||
|
||||
VlExecutionProfiler::VlExecutionProfiler() {
|
||||
VlExecutionProfiler::VlExecutionProfiler(VerilatedContext& context)
|
||||
: m_context{context} {
|
||||
// Setup profiling on main thread
|
||||
setupThread(0);
|
||||
}
|
||||
|
||||
void VlExecutionProfiler::configure(const VerilatedContext& context) {
|
||||
void VlExecutionProfiler::configure() {
|
||||
|
||||
if (VL_UNLIKELY(m_enabled)) {
|
||||
--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"););
|
||||
clear(); // Clear the profile after the cache warm-up cycles.
|
||||
m_tickBegin = VL_CPU_TICK();
|
||||
} else if (VL_UNLIKELY(m_windowCount == 0)) {
|
||||
const uint64_t tickEnd = VL_CPU_TICK();
|
||||
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);
|
||||
m_enabled = false;
|
||||
}
|
||||
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(assert(m_windowCount == 0););
|
||||
m_enabled = true;
|
||||
m_windowCount = context.profExecWindow() * 2;
|
||||
m_windowCount = m_context.profExecWindow() * 2;
|
||||
m_lastStartReq = startReq;
|
||||
}
|
||||
}
|
||||
|
||||
void VlExecutionProfiler::startWorkerSetup(VlExecutionProfiler* profilep, uint32_t threadId) {
|
||||
profilep->setupThread(threadId);
|
||||
VerilatedVirtualBase* VlExecutionProfiler::construct(VerilatedContext& context) {
|
||||
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) {
|
||||
|
|
@ -108,10 +133,13 @@ void VlExecutionProfiler::setupThread(uint32_t threadId) {
|
|||
// while profiling.
|
||||
t_trace.reserve(RESERVED_TRACE_CAPACITY);
|
||||
// Register thread-local buffer in list of all buffers
|
||||
bool exists;
|
||||
{
|
||||
const VerilatedLockGuard lock{m_mutex};
|
||||
bool exists = !m_traceps.emplace(threadId, &t_trace).second;
|
||||
assert(!exists);
|
||||
exists = !m_traceps.emplace(threadId, &t_trace).second;
|
||||
}
|
||||
if (VL_UNLIKELY(exists)) {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "", "multiple initialization of profiler on some thread");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,13 +33,14 @@
|
|||
#include <vector>
|
||||
|
||||
class VlExecutionProfiler;
|
||||
class VlThreadPool;
|
||||
|
||||
//=============================================================================
|
||||
// Macros to simplify generated code
|
||||
|
||||
#define VL_EXEC_TRACE_ADD_RECORD(vlSymsp) \
|
||||
if (VL_UNLIKELY((vlSymsp)->__Vm_executionProfiler.enabled())) \
|
||||
(vlSymsp)->__Vm_executionProfiler.addRecord()
|
||||
if (VL_UNLIKELY((vlSymsp)->__Vm_executionProfilerp->enabled())) \
|
||||
(vlSymsp)->__Vm_executionProfilerp->addRecord()
|
||||
|
||||
//=============================================================================
|
||||
// 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
|
||||
|
||||
class VlExecutionProfiler final {
|
||||
class VlExecutionProfiler final : public VerilatedVirtualBase {
|
||||
// CONSTANTS
|
||||
|
||||
// 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>;
|
||||
|
||||
// STATE
|
||||
VerilatedContext& m_context; // The context this profiler is under
|
||||
static VL_THREAD_LOCAL ExecutionTrace t_trace; // thread-local trace buffers
|
||||
mutable VerilatedMutex m_mutex;
|
||||
// Map from thread id to &t_trace of given thread
|
||||
|
|
@ -162,7 +164,8 @@ class VlExecutionProfiler final {
|
|||
|
||||
public:
|
||||
// CONSTRUCTOR
|
||||
VlExecutionProfiler();
|
||||
explicit VlExecutionProfiler(VerilatedContext& context);
|
||||
virtual ~VlExecutionProfiler() = default;
|
||||
|
||||
// METHODS
|
||||
|
||||
|
|
@ -174,7 +177,7 @@ public:
|
|||
return t_trace.back();
|
||||
}
|
||||
// Configure profiler (called in beginning of 'eval')
|
||||
void configure(const VerilatedContext&);
|
||||
void configure();
|
||||
// Setup profiling on a particular thread;
|
||||
void setupThread(uint32_t threadId);
|
||||
// Clear all profiling data
|
||||
|
|
@ -182,8 +185,8 @@ public:
|
|||
// Write profiling data into file
|
||||
void dump(const char* filenamep, uint64_t tickEnd) VL_MT_SAFE_EXCLUDES(m_mutex);
|
||||
|
||||
// Called via VlStartWorkerCb in VlWorkerThread::startWorker
|
||||
static void startWorkerSetup(VlExecutionProfiler* profilep, uint32_t threadId);
|
||||
// Passed to VerilatedContext to create the VlExecutionProfiler profiler instance
|
||||
static VerilatedVirtualBase* construct(VerilatedContext& context);
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
|
|
|
|||
|
|
@ -47,11 +47,9 @@ VlMTaskVertex::VlMTaskVertex(uint32_t upstreamDepCount)
|
|||
//=============================================================================
|
||||
// VlWorkerThread
|
||||
|
||||
VlWorkerThread::VlWorkerThread(uint32_t threadId, VerilatedContext* contextp,
|
||||
VlExecutionProfiler* profilerp, VlStartWorkerCb startCb)
|
||||
VlWorkerThread::VlWorkerThread(VerilatedContext* contextp)
|
||||
: m_ready_size{0}
|
||||
, m_cthread{startWorker, this, threadId, profilerp, startCb}
|
||||
, m_contextp{contextp} {}
|
||||
, m_cthread{startWorker, this, contextp} {}
|
||||
|
||||
VlWorkerThread::~VlWorkerThread() {
|
||||
shutdown();
|
||||
|
|
@ -59,47 +57,49 @@ VlWorkerThread::~VlWorkerThread() {
|
|||
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
|
||||
}
|
||||
|
||||
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() {
|
||||
ExecRec work;
|
||||
|
||||
// Wait for the first task without spinning, in case the thread is never actually used.
|
||||
dequeWork</* SpinWait: */ false>(&work);
|
||||
|
||||
while (true) {
|
||||
dequeWork(&work);
|
||||
if (VL_UNLIKELY(work.m_fnp == shutdownTask)) break;
|
||||
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,
|
||||
VlExecutionProfiler* profilerp, VlStartWorkerCb startCb) {
|
||||
Verilated::threadContextp(workerp->m_contextp);
|
||||
if (VL_UNLIKELY(startCb)) startCb(profilerp, threadId);
|
||||
void VlWorkerThread::startWorker(VlWorkerThread* workerp, VerilatedContext* contextp) {
|
||||
Verilated::threadContextp(contextp);
|
||||
workerp->workerLoop();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// VlThreadPool
|
||||
|
||||
VlThreadPool::VlThreadPool(VerilatedContext* contextp, int nThreads,
|
||||
VlExecutionProfiler* profilerp, VlStartWorkerCb startCb) {
|
||||
// --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(VerilatedContext* contextp, unsigned nThreads) {
|
||||
for (unsigned i = 0; i < nThreads; ++i) m_workers.push_back(new VlWorkerThread{contextp});
|
||||
}
|
||||
|
||||
VlThreadPool::~VlThreadPool() {
|
||||
|
|
|
|||
|
|
@ -60,9 +60,6 @@ using VlSelfP = void*;
|
|||
|
||||
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.
|
||||
class VlMTaskVertex final {
|
||||
// MEMBERS
|
||||
|
|
@ -166,24 +163,23 @@ private:
|
|||
std::atomic<size_t> m_ready_size;
|
||||
|
||||
std::thread m_cthread; // Underlying C++ thread record
|
||||
VerilatedContext* const m_contextp; // Context for spawned thread
|
||||
|
||||
VL_UNCOPYABLE(VlWorkerThread);
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit VlWorkerThread(uint32_t threadId, VerilatedContext* contextp,
|
||||
VlExecutionProfiler* profilerp, VlStartWorkerCb startCb);
|
||||
explicit VlWorkerThread(VerilatedContext* contextp);
|
||||
~VlWorkerThread();
|
||||
|
||||
// METHODS
|
||||
template <bool SpinWait> //
|
||||
inline void dequeWork(ExecRec* workp) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||
// Spin for a while, waiting for new data
|
||||
for (int i = 0; i < VL_LOCK_SPINS; ++i) {
|
||||
if (VL_LIKELY(m_ready_size.load(std::memory_order_relaxed))) { //
|
||||
break;
|
||||
if VL_CONSTEXPR_CXX17 (SpinWait) {
|
||||
for (unsigned i = 0; i < VL_LOCK_SPINS; ++i) {
|
||||
if (VL_LIKELY(m_ready_size.load(std::memory_order_relaxed))) break;
|
||||
VL_CPU_RELAX();
|
||||
}
|
||||
VL_CPU_RELAX();
|
||||
}
|
||||
VerilatedLockGuard lock{m_mutex};
|
||||
while (m_ready.empty()) {
|
||||
|
|
@ -197,7 +193,7 @@ public:
|
|||
m_ready.erase(m_ready.begin());
|
||||
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) {
|
||||
bool notify;
|
||||
{
|
||||
|
|
@ -209,15 +205,14 @@ public:
|
|||
if (notify) m_cv.notify_one();
|
||||
}
|
||||
|
||||
inline void shutdown() { addTask(shutdownTask, nullptr, false); }
|
||||
static void shutdownTask(void*, bool);
|
||||
void shutdown(); // Finish current tasks, then terminate thread
|
||||
void wait(); // Blocks calling thread until all tasks complete in this thread
|
||||
|
||||
void workerLoop();
|
||||
static void startWorker(VlWorkerThread* workerp, uint32_t threadId,
|
||||
VlExecutionProfiler* profilerp, VlStartWorkerCb startCb);
|
||||
static void startWorker(VlWorkerThread* workerp, VerilatedContext* contextp);
|
||||
};
|
||||
|
||||
class VlThreadPool final {
|
||||
class VlThreadPool final : public VerilatedVirtualBase {
|
||||
// MEMBERS
|
||||
std::vector<VlWorkerThread*> m_workers; // our workers
|
||||
|
||||
|
|
@ -226,9 +221,8 @@ public:
|
|||
// Construct a thread pool with 'nThreads' dedicated threads. The thread
|
||||
// pool will create these threads and make them available to execute tasks
|
||||
// via this->workerp(index)->addTask(...)
|
||||
VlThreadPool(VerilatedContext* contextp, int nThreads, VlExecutionProfiler* profilerp,
|
||||
VlStartWorkerCb startCb);
|
||||
~VlThreadPool();
|
||||
VlThreadPool(VerilatedContext* contextp, unsigned nThreads);
|
||||
virtual ~VlThreadPool();
|
||||
|
||||
// METHODS
|
||||
inline int numThreads() const { return m_workers.size(); }
|
||||
|
|
|
|||
|
|
@ -194,8 +194,6 @@ private:
|
|||
static void parallelWorkerTask(void*, bool);
|
||||
#endif
|
||||
|
||||
using ParallelCallbackMap = std::unordered_map<VlThreadPool*, std::vector<CallbackRecord>>;
|
||||
|
||||
protected:
|
||||
uint32_t* m_sigs_oldvalp = nullptr; // Previous value store
|
||||
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
|
||||
std::vector<bool> m_sigs_enabledVec; // Staging for m_sigs_enabledp
|
||||
std::vector<CallbackRecord> m_initCbs; // Routines to initialize tracing
|
||||
ParallelCallbackMap m_fullCbs; // Routines to perform full dump
|
||||
ParallelCallbackMap m_chgCbs; // Routines to perform incremental dump
|
||||
std::vector<CallbackRecord> m_fullCbs; // Routines to perform full 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<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'
|
||||
uint32_t m_nextCode = 0; // Next code number to assign
|
||||
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_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);
|
||||
|
||||
// Equivalent to 'this' but is of the sub-type 'T_Trace*'. Use 'self()->'
|
||||
// to access duck-typed functions to avoid a virtual function call.
|
||||
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
|
||||
static void onFlush(void* selfp) VL_MT_UNSAFE_ONE;
|
||||
|
|
@ -341,10 +339,10 @@ public:
|
|||
//=========================================================================
|
||||
// Non-hot path internal interface to Verilator generated code
|
||||
|
||||
void addInitCb(initCb_t cb, void* userp) VL_MT_SAFE;
|
||||
void addFullCb(dumpCb_t cb, void* userp, VlThreadPool* = nullptr) VL_MT_SAFE;
|
||||
void addChgCb(dumpCb_t cb, void* userp, VlThreadPool* = nullptr) VL_MT_SAFE;
|
||||
void addCleanupCb(cleanupCb_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, VerilatedContext*) VL_MT_SAFE;
|
||||
void addChgCb(dumpCb_t cb, void* userp, VerilatedContext*) VL_MT_SAFE;
|
||||
void addCleanupCb(cleanupCb_t cb, void* userp, VerilatedContext*) VL_MT_SAFE;
|
||||
|
||||
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
|
||||
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::runParallelCallbacks(const ParallelCallbackMap& cbMap) {
|
||||
for (VlThreadPool* threadPoolp : m_threadPoolps) {
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::runCallbacks(const std::vector<CallbackRecord>& cbVec) {
|
||||
#ifdef VL_TRACE_PARALLEL
|
||||
// If tracing in parallel, dispatch to the thread pool (if exists)
|
||||
if (threadPoolp && threadPoolp->numThreads()) {
|
||||
// List of work items for thread (std::list, as ParallelWorkerData is not movable)
|
||||
std::list<ParallelWorkerData> workerData;
|
||||
// We use the whole pool + the main thread
|
||||
const unsigned threads = threadPoolp->numThreads() + 1;
|
||||
// Main thread executes all jobs with index % threads == 0
|
||||
std::vector<ParallelWorkerData*> mainThreadWorkerData;
|
||||
// The tracing callbacks to execute on this thread-pool
|
||||
const auto& cbVec = cbMap.at(threadPoolp);
|
||||
// Enuque all the jobs
|
||||
for (unsigned i = 0; i < cbVec.size(); ++i) {
|
||||
const CallbackRecord& cbr = cbVec[i];
|
||||
// Always get the trace buffer on the main thread
|
||||
Buffer* const bufp = getTraceBuffer();
|
||||
// Create new work item
|
||||
workerData.emplace_back(cbr.m_dumpCb, cbr.m_userp, bufp);
|
||||
// Grab the new work item
|
||||
ParallelWorkerData* const itemp = &workerData.back();
|
||||
// Enqueue task to thread pool, or main thread
|
||||
if (unsigned rem = i % threads) {
|
||||
threadPoolp->workerp(rem - 1)->addTask(parallelWorkerTask, itemp, false);
|
||||
} 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;
|
||||
// If tracing in parallel, dispatch to the thread pool
|
||||
VlThreadPool* threadPoolp = static_cast<VlThreadPool*>(m_contextp->threadPoolp());
|
||||
// List of work items for thread (std::list, as ParallelWorkerData is not movable)
|
||||
std::list<ParallelWorkerData> workerData;
|
||||
// We use the whole pool + the main thread
|
||||
const unsigned threads = threadPoolp->numThreads() + 1;
|
||||
// Main thread executes all jobs with index % threads == 0
|
||||
std::vector<ParallelWorkerData*> mainThreadWorkerData;
|
||||
// Enuque all the jobs
|
||||
for (unsigned i = 0; i < cbVec.size(); ++i) {
|
||||
const CallbackRecord& cbr = cbVec[i];
|
||||
// Always get the trace buffer on the main thread
|
||||
Buffer* const bufp = getTraceBuffer();
|
||||
// Create new work item
|
||||
workerData.emplace_back(cbr.m_dumpCb, cbr.m_userp, bufp);
|
||||
// Grab the new work item
|
||||
ParallelWorkerData* const itemp = &workerData.back();
|
||||
// Enqueue task to thread pool, or main thread
|
||||
if (unsigned rem = i % threads) {
|
||||
threadPoolp->workerp(rem - 1)->addTask(parallelWorkerTask, 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);
|
||||
}
|
||||
|
||||
// Done
|
||||
return;
|
||||
#endif
|
||||
// Fall back on sequential execution
|
||||
for (const CallbackRecord& cbr : cbMap.at(threadPoolp)) {
|
||||
Buffer* const traceBufferp = getTraceBuffer();
|
||||
cbr.m_dumpCb(cbr.m_userp, traceBufferp);
|
||||
commitTraceBuffer(traceBufferp);
|
||||
}
|
||||
// Fall back on sequential execution
|
||||
for (const CallbackRecord& cbr : cbVec) {
|
||||
Buffer* const traceBufferp = getTraceBuffer();
|
||||
cbr.m_dumpCb(cbr.m_userp, 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
|
||||
if (VL_UNLIKELY(m_fullDump)) {
|
||||
m_fullDump = false; // No more need for next dump to be full
|
||||
runParallelCallbacks(m_fullCbs);
|
||||
runCallbacks(m_fullCbs);
|
||||
} else {
|
||||
runParallelCallbacks(m_chgCbs);
|
||||
runCallbacks(m_chgCbs);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
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) {
|
||||
const VerilatedLockGuard lock{m_mutex};
|
||||
for (VlThreadPool* const poolp : m_threadPoolps) {
|
||||
if (poolp == threadPoolp) return;
|
||||
if (m_contextp && contextp != m_contextp) {
|
||||
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 <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addCallbackRecord(std::vector<CallbackRecord>& cbVec,
|
||||
CallbackRecord& cbRec)
|
||||
CallbackRecord&& cbRec)
|
||||
VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||
const VerilatedLockGuard lock{m_mutex};
|
||||
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 <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addInitCb(initCb_t cb, void* userp) VL_MT_SAFE {
|
||||
CallbackRecord cbr{cb, userp};
|
||||
addCallbackRecord(m_initCbs, cbr);
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addInitCb(initCb_t cb, void* userp,
|
||||
VerilatedContext* contextp) VL_MT_SAFE {
|
||||
addContext(contextp);
|
||||
addCallbackRecord(m_initCbs, CallbackRecord{cb, userp});
|
||||
}
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addFullCb(dumpCb_t cb, void* userp,
|
||||
VlThreadPool* threadPoolp) VL_MT_SAFE {
|
||||
CallbackRecord cbr{cb, userp};
|
||||
addThreadPool(threadPoolp);
|
||||
addCallbackRecord(m_fullCbs[threadPoolp], cbr);
|
||||
VerilatedContext* contextp) VL_MT_SAFE {
|
||||
addContext(contextp);
|
||||
addCallbackRecord(m_fullCbs, CallbackRecord{cb, userp});
|
||||
}
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addChgCb(dumpCb_t cb, void* userp,
|
||||
VlThreadPool* threadPoolp) VL_MT_SAFE {
|
||||
CallbackRecord cbr{cb, userp};
|
||||
addThreadPool(threadPoolp);
|
||||
addCallbackRecord(m_chgCbs[threadPoolp], cbr);
|
||||
VerilatedContext* contextp) VL_MT_SAFE {
|
||||
addContext(contextp);
|
||||
addCallbackRecord(m_chgCbs, CallbackRecord{cb, userp});
|
||||
}
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addCleanupCb(cleanupCb_t cb, void* userp) VL_MT_SAFE {
|
||||
CallbackRecord cbr{cb, userp};
|
||||
addCallbackRecord(m_cleanupCbs, cbr);
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addCleanupCb(cleanupCb_t cb, void* userp,
|
||||
VerilatedContext* contextp) VL_MT_SAFE {
|
||||
addContext(contextp);
|
||||
addCallbackRecord(m_cleanupCbs, CallbackRecord{cb, userp});
|
||||
}
|
||||
|
||||
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"
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
// C++-2017
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
# define VL_CONSTEXPR_CXX17 constexpr
|
||||
#else
|
||||
# define VL_CONSTEXPR_CXX17
|
||||
#endif
|
||||
|
||||
|
||||
//=========================================================================
|
||||
// Optimization
|
||||
|
||||
|
|
|
|||
|
|
@ -1961,7 +1961,7 @@ private:
|
|||
ASTNODE_PREFETCH(nodep->op2p());
|
||||
ASTNODE_PREFETCH(nodep->op3p());
|
||||
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
|
||||
if (privateTypeTest<typename std::remove_const<T_Arg>::type>(nodep)) {
|
||||
|
|
@ -1977,7 +1977,7 @@ private:
|
|||
}
|
||||
|
||||
// Traverse 'nextp()' chain if requested
|
||||
if /* TODO: 'constexpr' in C++17 */ (VisitNext) {
|
||||
if VL_CONSTEXPR_CXX17 (VisitNext) {
|
||||
nodep = nodep->nextp();
|
||||
} else {
|
||||
break;
|
||||
|
|
@ -2000,7 +2000,7 @@ private:
|
|||
ASTNODE_PREFETCH(nodep->op2p());
|
||||
ASTNODE_PREFETCH(nodep->op3p());
|
||||
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
|
||||
if (privateTypeTest<typename std::remove_const<T_Arg>::type>(nodep)) {
|
||||
|
|
@ -2024,7 +2024,7 @@ private:
|
|||
}
|
||||
|
||||
// Traverse 'nextp()' chain if requested
|
||||
if /* TODO: 'constexpr' in C++17 */ (VisitNext) {
|
||||
if VL_CONSTEXPR_CXX17 (VisitNext) {
|
||||
nodep = nodep->nextp();
|
||||
} else {
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -4568,26 +4568,21 @@ public:
|
|||
class AstTestPlusArgs final : public AstNodeMath {
|
||||
// Parents: expr
|
||||
// Child: variable to set. If nullptr then this is a $test$plusargs instead of $value$plusargs
|
||||
private:
|
||||
string m_text;
|
||||
|
||||
public:
|
||||
AstTestPlusArgs(FileLine* fl, const string& text)
|
||||
: ASTGEN_SUPER_TestPlusArgs(fl)
|
||||
, m_text{text} {}
|
||||
AstTestPlusArgs(FileLine* fl, AstNode* searchp)
|
||||
: ASTGEN_SUPER_TestPlusArgs(fl) {
|
||||
setOp1p(searchp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(TestPlusArgs)
|
||||
virtual string name() const override { return m_text; }
|
||||
virtual string verilogKwd() const override { return "$test$plusargs"; }
|
||||
virtual string emitVerilog() override { return verilogKwd(); }
|
||||
virtual string emitC() override { return "VL_VALUEPLUSARGS_%nq(%lw, %P, nullptr)"; }
|
||||
virtual bool isGateOptimizable() const override { return false; }
|
||||
virtual bool isPredictOptimizable() const override { return false; }
|
||||
virtual bool cleanOut() const override { return true; }
|
||||
virtual bool same(const AstNode* samep) const override {
|
||||
return text() == static_cast<const AstTestPlusArgs*>(samep)->text();
|
||||
}
|
||||
string text() const { return m_text; } // * = Text to display
|
||||
void text(const string& text) { m_text = text; }
|
||||
virtual bool same(const AstNode* samep) const override { return true; }
|
||||
AstNode* searchp() const { return op1p(); } // op1 = Search expression
|
||||
void searchp(AstNode* nodep) { setOp1p(nodep); }
|
||||
};
|
||||
|
||||
class AstGenFor final : public AstNodeFor {
|
||||
|
|
|
|||
|
|
@ -35,17 +35,16 @@ private:
|
|||
std::vector<T_Data*> m_allocated;
|
||||
|
||||
inline T_Data* getUserp(const T_Node* nodep) const {
|
||||
// This simplifies statically as T_UserN is constant. In C++17, use 'if constexpr'.
|
||||
if (T_UserN == 1) {
|
||||
if VL_CONSTEXPR_CXX17 (T_UserN == 1) {
|
||||
const VNUser user = nodep->user1u();
|
||||
return user.to<T_Data*>();
|
||||
} else if (T_UserN == 2) {
|
||||
} else if VL_CONSTEXPR_CXX17 (T_UserN == 2) {
|
||||
const VNUser user = nodep->user2u();
|
||||
return user.to<T_Data*>();
|
||||
} else if (T_UserN == 3) {
|
||||
} else if VL_CONSTEXPR_CXX17 (T_UserN == 3) {
|
||||
const VNUser user = nodep->user3u();
|
||||
return user.to<T_Data*>();
|
||||
} else if (T_UserN == 4) {
|
||||
} else if VL_CONSTEXPR_CXX17 (T_UserN == 4) {
|
||||
const VNUser user = nodep->user4u();
|
||||
return user.to<T_Data*>();
|
||||
} else {
|
||||
|
|
@ -55,14 +54,13 @@ private:
|
|||
}
|
||||
|
||||
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 (T_UserN == 1) {
|
||||
if VL_CONSTEXPR_CXX17 (T_UserN == 1) {
|
||||
nodep->user1u(VNUser(userp));
|
||||
} else if (T_UserN == 2) {
|
||||
} else if VL_CONSTEXPR_CXX17 (T_UserN == 2) {
|
||||
nodep->user2u(VNUser(userp));
|
||||
} else if (T_UserN == 3) {
|
||||
} else if VL_CONSTEXPR_CXX17 (T_UserN == 3) {
|
||||
nodep->user3u(VNUser(userp));
|
||||
} else if (T_UserN == 4) {
|
||||
} else if VL_CONSTEXPR_CXX17 (T_UserN == 4) {
|
||||
nodep->user4u(VNUser(userp));
|
||||
} else {
|
||||
nodep->user5u(VNUser(userp));
|
||||
|
|
@ -71,14 +69,13 @@ private:
|
|||
|
||||
protected:
|
||||
AstUserAllocatorBase() {
|
||||
// This simplifies statically as T_UserN is constant. In C++17, use 'if constexpr'.
|
||||
if (T_UserN == 1) {
|
||||
if VL_CONSTEXPR_CXX17 (T_UserN == 1) {
|
||||
VNUser1InUse::check();
|
||||
} else if (T_UserN == 2) {
|
||||
} else if VL_CONSTEXPR_CXX17 (T_UserN == 2) {
|
||||
VNUser2InUse::check();
|
||||
} else if (T_UserN == 3) {
|
||||
} else if VL_CONSTEXPR_CXX17 (T_UserN == 3) {
|
||||
VNUser3InUse::check();
|
||||
} else if (T_UserN == 4) {
|
||||
} else if VL_CONSTEXPR_CXX17 (T_UserN == 4) {
|
||||
VNUser4InUse::check();
|
||||
} else {
|
||||
VNUser5InUse::check();
|
||||
|
|
|
|||
|
|
@ -80,30 +80,48 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
|||
using ResultTerm = std::tuple<AstNode*, unsigned, bool>;
|
||||
|
||||
class LeafInfo final { // Leaf node (either AstConst or AstVarRef)
|
||||
// MEMBERS
|
||||
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.
|
||||
AstVarRef* m_refp = nullptr;
|
||||
const AstConst* m_constp = nullptr;
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
LeafInfo() = default;
|
||||
LeafInfo(const LeafInfo& other) = default;
|
||||
explicit LeafInfo(int lsb)
|
||||
: m_lsb{lsb} {}
|
||||
|
||||
// METHODS
|
||||
void setLeaf(AstVarRef* refp) {
|
||||
UASSERT(!m_refp && !m_constp, "Must be called just once");
|
||||
m_refp = refp;
|
||||
m_msb = refp->varp()->widthMin() - 1;
|
||||
}
|
||||
void setLeaf(const AstConst* constp) {
|
||||
UASSERT(!m_refp && !m_constp, "Must be called just once");
|
||||
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; }
|
||||
const AstConst* constp() const { return m_constp; }
|
||||
int wordIdx() const { return m_wordIdx; }
|
||||
bool polarity() const { return m_polarity; }
|
||||
int lsb() const { return m_lsb; }
|
||||
|
||||
void wordIdx(int i) { m_wordIdx = i; }
|
||||
void lsb(int l) { m_lsb = l; }
|
||||
void polarity(bool p) { m_polarity = p; }
|
||||
int msb() const { return std::min(m_msb, varWidth() - 1); }
|
||||
int varWidth() const {
|
||||
UASSERT(m_refp, "m_refp should be set");
|
||||
const int width = m_refp->varp()->widthMin();
|
||||
|
|
@ -382,7 +400,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
|||
|
||||
// Traverse down to see AstConst or AstVarRef
|
||||
LeafInfo findLeaf(AstNode* nodep, bool expectConst) {
|
||||
LeafInfo info;
|
||||
LeafInfo info{m_lsb};
|
||||
{
|
||||
VL_RESTORER(m_leafp);
|
||||
m_leafp = &info;
|
||||
|
|
@ -402,7 +420,10 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
|||
virtual void visit(AstNode* nodep) override {
|
||||
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 {
|
||||
CONST_BITOP_RETURN_IF(!m_leafp, nodep);
|
||||
AstConst* const constp = VN_CAST(nodep->rhsp(), Const);
|
||||
|
|
@ -410,12 +431,14 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
|||
m_lsb += constp->toUInt();
|
||||
incrOps(nodep, __LINE__);
|
||||
iterate(nodep->lhsp());
|
||||
m_leafp->updateBitRange(nodep);
|
||||
m_lsb -= constp->toUInt();
|
||||
}
|
||||
virtual void visit(AstNot* nodep) override {
|
||||
CONST_BITOP_RETURN_IF(nodep->widthMin() != 1, nodep);
|
||||
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)
|
||||
&& !VN_IS(lhsp, ShiftR),
|
||||
lhsp);
|
||||
|
|
@ -424,6 +447,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
|||
iterateChildren(nodep);
|
||||
// Don't restore m_polarity for Xor as it counts parity of the entire tree
|
||||
if (!isXorTree()) m_polarity = !m_polarity;
|
||||
if (m_leafp && castp) m_leafp->updateBitRange(castp);
|
||||
}
|
||||
virtual void visit(AstWordSel* nodep) override {
|
||||
CONST_BITOP_RETURN_IF(!m_leafp, nodep);
|
||||
|
|
@ -437,27 +461,27 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
|||
CONST_BITOP_RETURN_IF(!m_leafp, nodep);
|
||||
m_leafp->setLeaf(nodep);
|
||||
m_leafp->polarity(m_polarity);
|
||||
m_leafp->lsb(m_lsb);
|
||||
}
|
||||
virtual void visit(AstConst* nodep) override {
|
||||
CONST_BITOP_RETURN_IF(!m_leafp, nodep);
|
||||
m_leafp->setLeaf(nodep);
|
||||
m_leafp->lsb(m_lsb);
|
||||
}
|
||||
|
||||
virtual void visit(AstRedXor* nodep) override {
|
||||
Restorer restorer{*this};
|
||||
CONST_BITOP_RETURN_IF(!VN_IS(m_rootp, Xor), nodep);
|
||||
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)'
|
||||
CONST_BITOP_RETURN_IF(!andp, lhsp);
|
||||
|
||||
const LeafInfo& mask = findLeaf(andp->lhsp(), true);
|
||||
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());
|
||||
if (castp) ref.updateBitRange(castp);
|
||||
|
||||
restorer.disableRestore(); // Now all subtree succeeded
|
||||
|
||||
|
|
@ -467,7 +491,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
|||
incrOps(andp, __LINE__);
|
||||
|
||||
// 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) {
|
||||
const int maskIdx = bitIdx - ref.lsb();
|
||||
if (maskNum.bitIs0(maskIdx)) continue;
|
||||
|
|
@ -475,15 +499,16 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
|||
m_bitPolarities.emplace_back(ref, true, bitIdx);
|
||||
}
|
||||
} else { // '^leaf'
|
||||
const LeafInfo& ref = findLeaf(lhsp, false);
|
||||
LeafInfo ref = findLeaf(lhsp, false);
|
||||
CONST_BITOP_RETURN_IF(!ref.refp(), lhsp);
|
||||
if (castp) ref.updateBitRange(castp);
|
||||
|
||||
restorer.disableRestore(); // Now all checks passed
|
||||
|
||||
incrOps(nodep, __LINE__);
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -503,7 +528,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
|||
|
||||
for (const bool right : {false, true}) {
|
||||
Restorer restorer{*this};
|
||||
LeafInfo leafInfo;
|
||||
LeafInfo leafInfo{m_lsb};
|
||||
m_leafp = &leafInfo;
|
||||
AstNode* opp = right ? nodep->rhsp() : nodep->lhsp();
|
||||
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
|
||||
// case, e.g.: (IData)((QData)wide[0] >> 32), or <1-bit-var> >> 1, which is
|
||||
// just zero
|
||||
if (leafInfo.lsb() < leafInfo.varWidth()) {
|
||||
if (leafInfo.lsb() <= leafInfo.msb()) {
|
||||
m_bitPolarities.emplace_back(leafInfo, isXorTree() || leafInfo.polarity(),
|
||||
leafInfo.lsb());
|
||||
} else if (isAndTree() && leafInfo.polarity()) {
|
||||
|
|
@ -559,7 +584,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
|||
incrOps(andp, __LINE__);
|
||||
|
||||
// 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) {
|
||||
const int maskIdx = bitIdx - ref.lsb();
|
||||
if (maskNum.bitIs0(maskIdx)) continue;
|
||||
|
|
@ -575,7 +600,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
|
|||
incrOps(nodep, __LINE__);
|
||||
|
||||
// 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) {
|
||||
const int maskIdx = bitIdx - ref.lsb();
|
||||
const bool polarity = compNum.bitIs1(maskIdx) != maskFlip;
|
||||
|
|
|
|||
|
|
@ -573,7 +573,7 @@ public:
|
|||
}
|
||||
virtual void visit(AstTestPlusArgs* nodep) override {
|
||||
puts("VL_TESTPLUSARGS_I(");
|
||||
putsQuoted(nodep->text());
|
||||
emitCvtPackStr(nodep->searchp());
|
||||
puts(")");
|
||||
}
|
||||
virtual void visit(AstFError* nodep) override {
|
||||
|
|
|
|||
|
|
@ -251,15 +251,15 @@ class EmitCHeader final : public EmitCConstInit {
|
|||
emitTextSection(modp, VNType::atScHdr);
|
||||
|
||||
// Open class body {{{
|
||||
puts("\nclass ");
|
||||
puts(prefixNameProtect(modp));
|
||||
if (const AstClass* const classp = VN_CAST(modp, Class)) {
|
||||
puts("class ");
|
||||
puts(prefixNameProtect(modp));
|
||||
if (classp->extendsp()) {
|
||||
puts(" : public ");
|
||||
puts(prefixNameProtect(classp->extendsp()->classp()));
|
||||
}
|
||||
} else {
|
||||
puts("VL_MODULE(" + prefixNameProtect(modp) + ")");
|
||||
puts(" final : public VerilatedModule");
|
||||
}
|
||||
puts(" {\n");
|
||||
ofp()->resetPrivate();
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ class CMakeEmitter final {
|
|||
+ ".cpp");
|
||||
}
|
||||
}
|
||||
if (v3Global.opt.mtasks()) {
|
||||
if (v3Global.opt.threads()) {
|
||||
global.emplace_back("${VERILATOR_ROOT}/include/verilated_threads.cpp");
|
||||
}
|
||||
if (v3Global.opt.usesProfiler()) {
|
||||
|
|
|
|||
|
|
@ -89,11 +89,12 @@ class EmitCModel final : public EmitCFunc {
|
|||
puts("\n");
|
||||
|
||||
puts("// This class is the main interface to the Verilated model\n");
|
||||
puts("class " + topClassName() + " VL_NOT_FINAL : ");
|
||||
if (optSystemC()) {
|
||||
puts("SC_MODULE(" + topClassName() + ") {\n");
|
||||
} else {
|
||||
puts("class " + topClassName() + " VL_NOT_FINAL {\n");
|
||||
// SC_MODULE, but with multiple-inheritance of VerilatedModel
|
||||
puts("public ::sc_core::sc_module, ");
|
||||
}
|
||||
puts("public VerilatedModel {\n");
|
||||
ofp()->resetPrivate();
|
||||
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()) {
|
||||
puts("/// Retrieve name of this model instance (as passed to constructor).\n");
|
||||
puts("const char* name() const;\n");
|
||||
|
|
@ -221,6 +219,11 @@ class EmitCModel final : public EmitCFunc {
|
|||
+ 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");
|
||||
|
||||
ofp()->putsEndGuard();
|
||||
|
|
@ -235,10 +238,12 @@ class EmitCModel final : public EmitCFunc {
|
|||
puts(topClassName() + "::" + topClassName());
|
||||
if (optSystemC()) {
|
||||
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 {
|
||||
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
|
||||
|
|
@ -263,6 +268,8 @@ class EmitCModel final : public EmitCFunc {
|
|||
puts(" , rootp{&(vlSymsp->TOP)}\n");
|
||||
|
||||
puts("{\n");
|
||||
puts("// Register model with the context\n");
|
||||
puts("contextp()->addModel(this);\n");
|
||||
|
||||
if (optSystemC()) {
|
||||
// Create sensitivity list for when to evaluate the model.
|
||||
|
|
@ -301,7 +308,7 @@ class EmitCModel final : public EmitCFunc {
|
|||
if (!optSystemC()) {
|
||||
puts("\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()) {
|
||||
puts("vlSymsp->__Vm_executionProfiler.configure(*(vlSymsp->_vm_contextp__));\n");
|
||||
puts("vlSymsp->__Vm_executionProfilerp->configure();\n");
|
||||
puts("VL_EXEC_TRACE_ADD_RECORD(vlSymsp).evalBegin();\n");
|
||||
}
|
||||
|
||||
|
|
@ -399,10 +406,6 @@ class EmitCModel final : public EmitCFunc {
|
|||
}
|
||||
|
||||
putSectionDelimiter("Utilities");
|
||||
// ::contextp
|
||||
puts("\nVerilatedContext* " + topClassName() + "::contextp() const {\n");
|
||||
puts(/**/ "return vlSymsp->_vm_contextp__;\n");
|
||||
puts("}\n");
|
||||
|
||||
if (!optSystemC()) {
|
||||
// ::name
|
||||
|
|
@ -419,6 +422,13 @@ class EmitCModel final : public EmitCFunc {
|
|||
puts("\nVL_ATTR_COLD void " + topClassName() + "::final() {\n");
|
||||
puts(/**/ topModNameProtected + "__" + protect("_eval_final") + "(&(vlSymsp->TOP));\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) {
|
||||
|
|
@ -471,7 +481,8 @@ class EmitCModel final : public EmitCFunc {
|
|||
puts(/**/ "}");
|
||||
}
|
||||
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")
|
||||
+ "(&(vlSymsp->TOP), tfp->spTrace());\n");
|
||||
|
||||
|
|
|
|||
|
|
@ -446,17 +446,17 @@ void EmitCSyms::emitSymHdr() {
|
|||
if (v3Global.hasEvents()) puts("std::vector<VlEvent*> __Vm_triggeredEvents;\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()) {
|
||||
puts("\n// MULTI-THREADING\n");
|
||||
puts("VlThreadPool* const __Vm_threadPoolp;\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");
|
||||
for (const auto& i : m_scopes) {
|
||||
const AstScope* const scopep = i.first;
|
||||
|
|
@ -690,7 +690,6 @@ void EmitCSyms::emitSymImp() {
|
|||
puts("_vm_pgoProfiler.write(\"" + topClassName()
|
||||
+ "\", _vm_contextp__->profVltFilename());\n");
|
||||
}
|
||||
if (v3Global.opt.mtasks()) puts("delete __Vm_threadPoolp;\n");
|
||||
puts("}\n\n");
|
||||
|
||||
// Constructor
|
||||
|
|
@ -722,12 +721,13 @@ void EmitCSyms::emitSymImp() {
|
|||
// Note we create N-1 threads in the thread pool. The thread
|
||||
// that calls eval() becomes the final Nth thread for the
|
||||
// duration of the eval call.
|
||||
puts(" , __Vm_threadPoolp{new VlThreadPool{_vm_contextp__, "
|
||||
+ cvtToStr(v3Global.opt.threads() - 1) + ", "
|
||||
+ (v3Global.opt.profExec()
|
||||
? "&__Vm_executionProfiler, &VlExecutionProfiler::startWorkerSetup"
|
||||
: "nullptr, nullptr")
|
||||
+ "}}\n");
|
||||
puts(" , __Vm_threadPoolp{static_cast<VlThreadPool*>(contextp->threadPoolp())}\n");
|
||||
}
|
||||
|
||||
if (v3Global.opt.profExec()) {
|
||||
puts(" , "
|
||||
"__Vm_executionProfilerp{static_cast<VlExecutionProfiler*>(contextp->"
|
||||
"enableExecutionProfiler(&VlExecutionProfiler::construct))}\n");
|
||||
}
|
||||
|
||||
puts(" // Setup module instances\n");
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ public:
|
|||
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()) {
|
||||
putMakeClassEntry(of, "verilated_profiler.cpp");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -225,11 +225,6 @@ private:
|
|||
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 {
|
||||
m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { //
|
||||
iterateNull(nodep->funcp());
|
||||
|
|
|
|||
|
|
@ -217,6 +217,13 @@ private:
|
|||
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 {
|
||||
VL_RESTORER(m_setRefLvalue);
|
||||
{
|
||||
|
|
|
|||
|
|
@ -319,43 +319,45 @@ private:
|
|||
while (argp) {
|
||||
if (skipCount) {
|
||||
argp = argp->nextp();
|
||||
skipCount--;
|
||||
--skipCount;
|
||||
continue;
|
||||
}
|
||||
const AstConst* const constp = VN_CAST(argp, Const);
|
||||
const bool isFromString = (constp) ? constp->num().isFromString() : false;
|
||||
if (isFromString) {
|
||||
const int numchars = argp->dtypep()->width() / 8;
|
||||
string str(numchars, ' ');
|
||||
// now scan for % operators
|
||||
bool inpercent = false;
|
||||
for (int i = 0; i < numchars; i++) {
|
||||
const int ii = numchars - i - 1;
|
||||
const char c = constp->num().dataByte(ii);
|
||||
str[i] = c;
|
||||
if (!inpercent && c == '%') {
|
||||
inpercent = true;
|
||||
} else if (inpercent) {
|
||||
inpercent = false;
|
||||
switch (c) {
|
||||
case '0': // FALLTHRU
|
||||
case '1': // FALLTHRU
|
||||
case '2': // FALLTHRU
|
||||
case '3': // FALLTHRU
|
||||
case '4': // FALLTHRU
|
||||
case '5': // FALLTHRU
|
||||
case '6': // FALLTHRU
|
||||
case '7': // FALLTHRU
|
||||
case '8': // FALLTHRU
|
||||
case '9': // FALLTHRU
|
||||
case '.': inpercent = true; break;
|
||||
case '%': break;
|
||||
default:
|
||||
if (V3Number::displayedFmtLegal(c, isScan)) ++skipCount;
|
||||
if (!constp->num().toString().empty()) {
|
||||
string str(numchars, ' ');
|
||||
// now scan for % operators
|
||||
bool inpercent = false;
|
||||
for (int i = 0; i < numchars; i++) {
|
||||
const int ii = numchars - i - 1;
|
||||
const char c = constp->num().dataByte(ii);
|
||||
str[i] = c;
|
||||
if (!inpercent && c == '%') {
|
||||
inpercent = true;
|
||||
} else if (inpercent) {
|
||||
inpercent = false;
|
||||
switch (c) {
|
||||
case '0': // FALLTHRU
|
||||
case '1': // FALLTHRU
|
||||
case '2': // FALLTHRU
|
||||
case '3': // FALLTHRU
|
||||
case '4': // FALLTHRU
|
||||
case '5': // FALLTHRU
|
||||
case '6': // FALLTHRU
|
||||
case '7': // FALLTHRU
|
||||
case '8': // FALLTHRU
|
||||
case '9': // FALLTHRU
|
||||
case '.': inpercent = true; break;
|
||||
case '%': break;
|
||||
default:
|
||||
if (V3Number::displayedFmtLegal(c, isScan)) ++skipCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
newFormat.append(str);
|
||||
}
|
||||
newFormat.append(str);
|
||||
AstNode* const nextp = argp->nextp();
|
||||
argp->unlinkFrBack();
|
||||
VL_DO_DANGLING(pushDeletep(argp), argp);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
//*************************************************************************
|
||||
//
|
||||
// void example_usage() {
|
||||
// SimulateVisitor simvis (false, false);
|
||||
// SimulateVisitor simvis{false, false};
|
||||
// simvis.clear();
|
||||
// // Set all inputs to the constant
|
||||
// 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_anyAssignComb; ///< True if found a non-delayed assignment
|
||||
bool m_inDlyAssign; ///< Under delayed assignment
|
||||
bool m_isOutputter; // Creates output
|
||||
int m_instrCount; ///< Number of nodes
|
||||
int m_dataCount; ///< Bytes of data
|
||||
AstJumpGo* m_jumpp; ///< Jump label we're branching from
|
||||
|
|
@ -130,7 +131,7 @@ private:
|
|||
const int width = itemp->width();
|
||||
const int lsb = itemp->lsb();
|
||||
const int msb = lsb + width - 1;
|
||||
V3Number fieldNum(nump, width);
|
||||
V3Number fieldNum{nump, width};
|
||||
fieldNum.opSel(*nump, msb, lsb);
|
||||
out << itemp->name() << ": ";
|
||||
if (AstNodeDType* const childTypep = itemp->subDTypep()) {
|
||||
|
|
@ -152,7 +153,7 @@ private:
|
|||
const int width = childTypep->width();
|
||||
const int lsb = width * element;
|
||||
const int msb = lsb + width - 1;
|
||||
V3Number fieldNum(nump, width);
|
||||
V3Number fieldNum{nump, width};
|
||||
fieldNum.opSel(*nump, msb, lsb);
|
||||
const int arrayElem = arrayp->lo() + element;
|
||||
out << arrayElem << " = " << prettyNumber(&fieldNum, childTypep);
|
||||
|
|
@ -205,6 +206,7 @@ public:
|
|||
AstNode* whyNotNodep() const { return m_whyNotNodep; }
|
||||
|
||||
bool isAssignDly() const { return m_anyAssignDly; }
|
||||
bool isOutputter() const { return m_isOutputter; }
|
||||
int instrCount() const { return m_instrCount; }
|
||||
int dataCount() const { return m_dataCount; }
|
||||
|
||||
|
|
@ -236,7 +238,7 @@ private:
|
|||
}
|
||||
if (allocNewConst) {
|
||||
// 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
|
||||
constp->user2(1);
|
||||
freeList.push_back(constp);
|
||||
|
|
@ -342,15 +344,16 @@ private:
|
|||
nodep->user2p((void*)valuep);
|
||||
}
|
||||
|
||||
void checkNodeInfo(AstNode* nodep) {
|
||||
void checkNodeInfo(AstNode* nodep, bool ignorePredict = false) {
|
||||
if (m_checkOnly) {
|
||||
m_instrCount += nodep->instrCount();
|
||||
m_dataCount += nodep->width();
|
||||
}
|
||||
if (!nodep->isPredictOptimizable()) {
|
||||
if (!ignorePredict && !nodep->isPredictOptimizable()) {
|
||||
// UINFO(9, " !predictopt " << nodep << endl);
|
||||
clearOptimizable(nodep, "Isn't predictable");
|
||||
}
|
||||
if (nodep->isOutputter()) m_isOutputter = true;
|
||||
}
|
||||
|
||||
void badNodeType(AstNode* nodep) {
|
||||
|
|
@ -683,15 +686,15 @@ private:
|
|||
initp = vscpnump;
|
||||
} else { // Assignment to unassigned variable, all bits are X
|
||||
// TODO generic initialization which builds X/arrays by recursion
|
||||
AstConst* const outconstp = new AstConst(
|
||||
nodep->fileline(), AstConst::WidthedValue(), basicp->widthMin(), 0);
|
||||
AstConst* const outconstp = new AstConst{
|
||||
nodep->fileline(), AstConst::WidthedValue{}, basicp->widthMin(), 0};
|
||||
if (basicp->isZeroInit()) {
|
||||
outconstp->num().setAllBits0();
|
||||
} else {
|
||||
outconstp->num().setAllBitsX();
|
||||
}
|
||||
|
||||
initp = new AstInitArray(nodep->fileline(), arrayp, outconstp);
|
||||
initp = new AstInitArray{nodep->fileline(), arrayp, outconstp};
|
||||
m_reclaimValuesp.push_back(initp);
|
||||
}
|
||||
const uint32_t index = fetchConst(selp->bitp())->toUInt();
|
||||
|
|
@ -706,7 +709,7 @@ private:
|
|||
}
|
||||
void handleAssignSel(AstNodeAssign* nodep, AstSel* selp) {
|
||||
AstVarRef* varrefp = nullptr;
|
||||
V3Number lsb(nodep);
|
||||
V3Number lsb{nodep};
|
||||
iterateAndNextNull(nodep->rhsp()); // Value to assign
|
||||
handleAssignSelRecurse(nodep, selp, varrefp /*ref*/, lsb /*ref*/, 0);
|
||||
if (!m_checkOnly && optimizable()) {
|
||||
|
|
@ -719,8 +722,8 @@ private:
|
|||
} else if (AstConst* const vscpnump = fetchConstNull(vscp)) {
|
||||
outconstp = vscpnump;
|
||||
} else { // Assignment to unassigned variable, all bits are X or 0
|
||||
outconstp = new AstConst(nodep->fileline(), AstConst::WidthedValue(),
|
||||
varrefp->varp()->widthMin(), 0);
|
||||
outconstp = new AstConst{nodep->fileline(), AstConst::WidthedValue{},
|
||||
varrefp->varp()->widthMin(), 0};
|
||||
if (varrefp->varp()->basicp() && varrefp->varp()->basicp()->isZeroInit()) {
|
||||
outconstp->num().setAllBits0();
|
||||
} else {
|
||||
|
|
@ -742,7 +745,7 @@ private:
|
|||
lsbRef = fetchConst(selp->lsbp())->num();
|
||||
return; // And presumably still optimizable()
|
||||
} else if (AstSel* const subselp = VN_CAST(selp->lhsp(), Sel)) {
|
||||
V3Number sublsb(nodep);
|
||||
V3Number sublsb{nodep};
|
||||
handleAssignSelRecurse(nodep, subselp, outVarrefpRef, sublsb /*ref*/, depth + 1);
|
||||
if (optimizable()) {
|
||||
lsbRef = sublsb;
|
||||
|
|
@ -756,6 +759,7 @@ private:
|
|||
virtual void visit(AstNodeAssign* nodep) override {
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (!optimizable()) return; // Accelerate
|
||||
checkNodeInfo(nodep);
|
||||
if (VN_IS(nodep, AssignForce)) {
|
||||
clearOptimizable(nodep, "Force");
|
||||
} else if (VN_IS(nodep, AssignDly)) {
|
||||
|
|
@ -829,7 +833,7 @@ private:
|
|||
if (hit) break;
|
||||
iterateAndNextNull(ep);
|
||||
if (optimizable()) {
|
||||
V3Number match(nodep, 1);
|
||||
V3Number match{nodep, 1};
|
||||
match.opEq(fetchConst(nodep->exprp())->num(), fetchConst(ep)->num());
|
||||
if (match.isNeqZero()) {
|
||||
iterateAndNextNull(itemp->bodysp());
|
||||
|
|
@ -970,6 +974,7 @@ private:
|
|||
if (jumpingOver(nodep)) return;
|
||||
if (!optimizable()) return; // Accelerate
|
||||
UINFO(5, " FUNCREF " << nodep << endl);
|
||||
checkNodeInfo(nodep);
|
||||
if (!m_params) {
|
||||
badNodeType(nodep);
|
||||
return;
|
||||
|
|
@ -1053,6 +1058,7 @@ private:
|
|||
virtual void visit(AstSFormatF* nodep) override {
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (!optimizable()) return; // Accelerate
|
||||
checkNodeInfo(nodep);
|
||||
iterateChildren(nodep);
|
||||
if (m_params) {
|
||||
AstNode* nextArgp = nodep->exprsp();
|
||||
|
|
@ -1097,7 +1103,7 @@ private:
|
|||
}
|
||||
|
||||
AstConst* const resultConstp
|
||||
= new AstConst(nodep->fileline(), AstConst::String(), result);
|
||||
= new AstConst{nodep->fileline(), AstConst::String{}, result};
|
||||
setValue(nodep, resultConstp);
|
||||
m_reclaimValuesp.push_back(resultConstp);
|
||||
}
|
||||
|
|
@ -1106,6 +1112,9 @@ private:
|
|||
virtual void visit(AstDisplay* nodep) override {
|
||||
if (jumpingOver(nodep)) return;
|
||||
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);
|
||||
if (m_params) {
|
||||
AstConst* const textp = fetchConst(nodep->fmtp());
|
||||
|
|
@ -1155,6 +1164,7 @@ public:
|
|||
m_anyAssignComb = false;
|
||||
m_anyAssignDly = false;
|
||||
m_inDlyAssign = false;
|
||||
m_isOutputter = false;
|
||||
m_instrCount = 0;
|
||||
m_dataCount = 0;
|
||||
m_jumpp = nullptr;
|
||||
|
|
|
|||
|
|
@ -92,8 +92,8 @@ public:
|
|||
= elemDType->isString()
|
||||
? elemDType
|
||||
: v3Global.rootp()->findBitDType(width, width, VSigning::UNSIGNED);
|
||||
AstUnpackArrayDType* const tableDTypep
|
||||
= new AstUnpackArrayDType(m_fl, subDTypep, new AstRange(m_fl, size, 0));
|
||||
AstUnpackArrayDType* const tableDTypep = new AstUnpackArrayDType{
|
||||
m_fl, subDTypep, new AstRange{m_fl, static_cast<int>(size), 0}};
|
||||
v3Global.rootp()->typeTablep()->addTypesp(tableDTypep);
|
||||
// Create table initializer (with default value 0)
|
||||
AstConst* const defaultp = elemDType->isString()
|
||||
|
|
@ -106,7 +106,7 @@ public:
|
|||
UASSERT_OBJ(!m_varScopep, m_fl, "Table variable already created");
|
||||
// Default value is zero/empty string so don't add it
|
||||
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() {
|
||||
|
|
@ -225,6 +225,9 @@ private:
|
|||
if (!m_outWidthBytes || !m_inWidthBits) {
|
||||
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="
|
||||
<< chkvis.instrCount() << " Data=" << chkvis.dataCount()
|
||||
<< " in width (bits)=" << m_inWidthBits << " out width (bytes)="
|
||||
|
|
@ -247,14 +250,14 @@ private:
|
|||
|
||||
// We will need a table index variable, create it here.
|
||||
AstVar* const indexVarp
|
||||
= new AstVar(fl, VVarType::BLOCKTEMP, "__Vtableidx" + cvtToStr(m_modTables),
|
||||
VFlagBitPacked(), m_inWidthBits);
|
||||
= new AstVar{fl, VVarType::BLOCKTEMP, "__Vtableidx" + cvtToStr(m_modTables),
|
||||
VFlagBitPacked{}, static_cast<int>(m_inWidthBits)};
|
||||
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);
|
||||
|
||||
// The 'output assigned' table builder
|
||||
TableBuilder outputAssignedTableBuilder(fl);
|
||||
TableBuilder outputAssignedTableBuilder{fl};
|
||||
outputAssignedTableBuilder.setTableSize(
|
||||
nodep->findBitDType(m_outVarps.size(), m_outVarps.size(), VSigning::UNSIGNED),
|
||||
VL_MASK_I(m_inWidthBits));
|
||||
|
|
@ -311,7 +314,7 @@ private:
|
|||
<< simvis.whyNotMessage());
|
||||
|
||||
// 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) {
|
||||
if (V3Number* const outnump = simvis.fetchOutNumberNull(tov.varScopep())) {
|
||||
UINFO(8, " Output " << tov.name() << " = " << *outnump << endl);
|
||||
|
|
@ -333,21 +336,21 @@ private:
|
|||
// First var in inVars becomes the LSB of the concat
|
||||
AstNode* concatp = nullptr;
|
||||
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) {
|
||||
concatp = new AstConcat(fl, refp, concatp);
|
||||
concatp = new AstConcat{fl, refp, concatp};
|
||||
} else {
|
||||
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) {
|
||||
AstVarRef* const fromRefp = new AstVarRef(fl, fromp, VAccess::READ);
|
||||
AstVarRef* const indexRefp = new AstVarRef(fl, indexp, VAccess::READ);
|
||||
return new AstArraySel(fl, fromRefp, indexRefp);
|
||||
AstVarRef* const fromRefp = new AstVarRef{fl, fromp, VAccess::READ};
|
||||
AstVarRef* const indexRefp = new AstVarRef{fl, indexp, VAccess::READ};
|
||||
return new AstArraySel{fl, fromRefp, indexRefp};
|
||||
}
|
||||
|
||||
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 (tov.mayBeUnassigned()) {
|
||||
V3Number outputChgMask(nodep, m_outVarps.size(), 0);
|
||||
V3Number outputChgMask{nodep, static_cast<int>(m_outVarps.size()), 0};
|
||||
outputChgMask.setBit(tov.ord(), 1);
|
||||
AstNode* const condp
|
||||
= new AstAnd(fl, select(fl, outputAssignedTableVscp, indexVscp),
|
||||
new AstConst(fl, outputChgMask));
|
||||
outsetp = new AstIf(fl, condp, outsetp);
|
||||
= new AstAnd{fl, select(fl, outputAssignedTableVscp, indexVscp),
|
||||
new AstConst{fl, outputChgMask}};
|
||||
outsetp = new AstIf{fl, condp, outsetp};
|
||||
}
|
||||
|
||||
stmtsp->addNext(outsetp);
|
||||
|
|
|
|||
|
|
@ -512,8 +512,10 @@ private:
|
|||
m_regFuncp->addStmtsp(new AstText(flp, "tracep->addChgCb(", true));
|
||||
}
|
||||
m_regFuncp->addStmtsp(new AstAddrOfCFunc(flp, funcp));
|
||||
const string threadPool{m_parallelism > 1 ? "vlSymsp->__Vm_threadPoolp" : "nullptr"};
|
||||
m_regFuncp->addStmtsp(new AstText(flp, ", vlSelf, " + threadPool + ");\n", true));
|
||||
m_regFuncp->addStmtsp(new AstText(flp, ", vlSelf", true));
|
||||
m_regFuncp->addStmtsp(
|
||||
new AstText(flp, ", vlSelf->vlSymsp->__Vm_modelp->contextp()", true));
|
||||
m_regFuncp->addStmtsp(new AstText(flp, ");\n", true));
|
||||
} else {
|
||||
// Sub functions
|
||||
funcp->argTypes(v3Global.opt.traceClassBase() + "::Buffer* bufp");
|
||||
|
|
@ -700,7 +702,8 @@ private:
|
|||
// Register it
|
||||
m_regFuncp->addStmtsp(new AstText(fl, "tracep->addCleanupCb(", true));
|
||||
m_regFuncp->addStmtsp(new AstAddrOfCFunc(fl, cleanupFuncp));
|
||||
m_regFuncp->addStmtsp(new AstText(fl, ", vlSelf);\n", true));
|
||||
m_regFuncp->addStmtsp(
|
||||
new AstText(fl, ", vlSelf, vlSelf->vlSymsp->__Vm_modelp->contextp());\n", true));
|
||||
|
||||
// Clear global activity flag
|
||||
cleanupFuncp->addStmtsp(
|
||||
|
|
|
|||
|
|
@ -448,7 +448,6 @@ private:
|
|||
// Widths: Constant, terminal
|
||||
virtual void visit(AstTime* nodep) override { nodep->dtypeSetUInt64(); }
|
||||
virtual void visit(AstTimeD* nodep) override { nodep->dtypeSetDouble(); }
|
||||
virtual void visit(AstTestPlusArgs* nodep) override { nodep->dtypeSetSigned32(); }
|
||||
virtual void visit(AstScopeName* nodep) override {
|
||||
nodep->dtypeSetUInt64(); // A pointer, but not that it matters
|
||||
}
|
||||
|
|
@ -4352,6 +4351,12 @@ private:
|
|||
userIterateAndNext(nodep->lsbp(), 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 {
|
||||
if (m_vup->prelim()) {
|
||||
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_TAN '(' expr ')' { $$ = new AstTanD($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_TYPENAME '(' exprOrDataType ')' { $$ = new AstAttrOf($1, VAttrType::TYPENAME, $3); }
|
||||
| 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
|
||||
sc_time_resolution => "SC_PS", # Keep - PS is SystemC default
|
||||
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,
|
||||
verbose => $opt_verbose,
|
||||
run_env => '',
|
||||
|
|
@ -902,6 +904,7 @@ sub compile_vlt_flags {
|
|||
@{$param{verilator_flags}},
|
||||
@{$param{verilator_flags2}},
|
||||
@{$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->{trace} = ($opt_trace || $checkflags =~ /-trace\b/
|
||||
|| $checkflags =~ /-trace-fst\b/);
|
||||
|
|
@ -920,8 +923,7 @@ sub compile_vlt_flags {
|
|||
unshift @verilator_flags, "--rr" if $opt_rr;
|
||||
unshift @verilator_flags, "--x-assign unique"; # More likely to be buggy
|
||||
unshift @verilator_flags, "--trace" if $opt_trace;
|
||||
my $threads = ::calc_threads($Vltmt_threads);
|
||||
unshift @verilator_flags, "--threads $threads" if $param{vltmt} && $checkflags !~ /-threads /;
|
||||
unshift @verilator_flags, "--threads $param{threads}" if $param{threads} >= 0;
|
||||
unshift @verilator_flags, "--trace-threads 2" if $param{vltmt} && $checkflags =~ /-trace-fst /;
|
||||
unshift @verilator_flags, "--debug-partition" if $param{vltmt};
|
||||
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;
|
||||
$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);
|
||||
|
||||
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 " contextp->threads($self->{context_threads});\n";
|
||||
print $fh " contextp->commandArgs(argc, argv);\n";
|
||||
print $fh " contextp->debug(" . ($self->{verilated_debug} ? 1 : 0) . ");\n";
|
||||
print $fh " srand48(5);\n"; # Ensure determinism
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ execute(
|
|||
);
|
||||
|
||||
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);
|
||||
1;
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ module t(/*AUTOARG*/
|
|||
$write("[%0t] cyc==%0d crc=%x sum=%x\n", $time, cyc, crc, sum);
|
||||
if (crc !== 64'hc77bb9b3784ea091) $stop;
|
||||
// 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;
|
||||
$write("*-* All Finished *-*\n");
|
||||
|
|
@ -86,10 +86,11 @@ module Test(/*AUTOARG*/
|
|||
logic bug3182_out;
|
||||
logic bug3197_out;
|
||||
logic bug3445_out;
|
||||
logic bug3470_out;
|
||||
|
||||
output logic o;
|
||||
|
||||
logic [7:0] tmp;
|
||||
logic [8:0] tmp;
|
||||
assign o = ^tmp;
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
|
|
@ -113,11 +114,13 @@ module Test(/*AUTOARG*/
|
|||
tmp[5] <= bug3182_out;
|
||||
tmp[6] <= bug3197_out;
|
||||
tmp[7] <= bug3445_out;
|
||||
tmp[8] <= bug3470_out;
|
||||
end
|
||||
|
||||
bug3182 i_bug3182(.in(d[4:0]), .out(bug3182_out));
|
||||
bug3197 i_bug3197(.clk(clk), .in(d), .out(bug3197_out));
|
||||
bug3445 i_bug3445(.clk(clk), .in(d), .out(bug3445_out));
|
||||
bug3470 i_bug3470(.clk(clk), .in(d), .out(bug3470_out));
|
||||
|
||||
endmodule
|
||||
|
||||
|
|
@ -203,3 +206,32 @@ module bug3445(input wire clk, input wire [31:0] in, output wire out);
|
|||
|
||||
assign out = result0 ^ result1 ^ (result2 | result3);
|
||||
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
|
||||
|
||||
compile(
|
||||
verilator_flags2 => ['--compiler clang --threads 2 -Wno-UNOPTTHREADS'],
|
||||
verilator_flags2 => ['--compiler clang -Wno-UNOPTTHREADS'],
|
||||
threads => 2
|
||||
);
|
||||
|
||||
ok(1);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
Merge:
|
||||
This should merge
|
||||
Merge:
|
||||
This should also merge
|
||||
f
|
||||
1=1 a=top.t 1=1 1=1 b=top.t 1=1
|
||||
pre
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ execute(
|
|||
);
|
||||
|
||||
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);
|
||||
1;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@ module t (/*AUTOARG*/);
|
|||
$write("should ");
|
||||
$display("merge");
|
||||
|
||||
$display("Merge:");
|
||||
$write("This ", "", "should ", "", "also ");
|
||||
$display("merge");
|
||||
|
||||
$display("f");
|
||||
$write(" 1=%0d a=%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");
|
||||
|
||||
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",
|
||||
|
|
|
|||
|
|
@ -26,11 +26,9 @@ using std::hex;
|
|||
using std::setfill;
|
||||
using std::setw;
|
||||
|
||||
double sc_time_stamp() { return 0; }
|
||||
|
||||
// Convenience function to check we didn't finish unexpectedly
|
||||
static void checkFinish(const char* msg) {
|
||||
if (Verilated::gotFinish()) {
|
||||
static void checkFinish(VerilatedContext* contextp, const char* msg) {
|
||||
if (contextp->gotFinish()) {
|
||||
vl_fatal(__FILE__, __LINE__, "dut", msg);
|
||||
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.
|
||||
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");
|
||||
if (!scope) vl_fatal(__FILE__, __LINE__, "dut", "No svGetScopeFromName result");
|
||||
svSetScope(scope);
|
||||
|
|
@ -112,7 +112,7 @@ int main() {
|
|||
cout << "===============================\n";
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
||||
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
a = (int)a_read();
|
||||
logReg(dut->clk, "read a", a, " (before clk)");
|
||||
|
|
@ -130,7 +130,7 @@ int main() {
|
|||
"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.
|
||||
#ifdef TEST_VERBOSE
|
||||
|
|
@ -138,7 +138,7 @@ int main() {
|
|||
cout << "===============================\n";
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
||||
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
b = (int)b_read();
|
||||
logRegHex(dut->clk, "read b", 8, b, " (before clk)");
|
||||
|
|
@ -153,7 +153,7 @@ int main() {
|
|||
"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
|
||||
#ifdef TEST_VERBOSE
|
||||
|
|
@ -162,7 +162,7 @@ int main() {
|
|||
cout << "=============================\n";
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
||||
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
mem32 = (int)mem32_read();
|
||||
logRegHex(dut->clk, "read mem32", 8, mem32, " (before clk)");
|
||||
|
|
@ -177,7 +177,7 @@ int main() {
|
|||
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
|
||||
#ifdef TEST_VERBOSE
|
||||
|
|
@ -186,7 +186,7 @@ int main() {
|
|||
cout << "===========================\n";
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
||||
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
a = (int)a_read();
|
||||
c = (int)c_read();
|
||||
|
|
@ -206,7 +206,7 @@ int main() {
|
|||
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
|
||||
#ifdef TEST_VERBOSE
|
||||
|
|
@ -215,7 +215,7 @@ int main() {
|
|||
cout << "===========================\n";
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
||||
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
b = (int)b_read();
|
||||
d = (int)d_read();
|
||||
|
|
@ -236,7 +236,7 @@ int main() {
|
|||
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
|
||||
#ifdef TEST_VERBOSE
|
||||
|
|
@ -245,7 +245,7 @@ int main() {
|
|||
cout << "===============================\n";
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
||||
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
a = 1 - (int)a_read();
|
||||
a_write(reinterpret_cast<const svBitVecVal*>(&a));
|
||||
|
|
@ -265,7 +265,7 @@ int main() {
|
|||
"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
|
||||
#ifdef TEST_VERBOSE
|
||||
|
|
@ -274,7 +274,7 @@ int main() {
|
|||
cout << "===============================\n";
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
||||
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
b = (int)b_read() - 1;
|
||||
b_write(reinterpret_cast<const svBitVecVal*>(&b));
|
||||
|
|
@ -294,7 +294,7 @@ int main() {
|
|||
"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
|
||||
#ifdef TEST_VERBOSE
|
||||
|
|
@ -303,7 +303,7 @@ int main() {
|
|||
cout << "=============================\n";
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
||||
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
mem32 = (int)mem32_read() - 1;
|
||||
mem32_write(reinterpret_cast<const svBitVecVal*>(&mem32));
|
||||
|
|
@ -323,7 +323,7 @@ int main() {
|
|||
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
|
||||
#ifdef TEST_VERBOSE
|
||||
|
|
@ -332,7 +332,7 @@ int main() {
|
|||
cout << "=====================================\n";
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
||||
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
b = (int)b_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.");
|
||||
}
|
||||
|
||||
checkFinish("t_dpi_accessors unexpected finish");
|
||||
checkFinish(contextp.get(), "t_dpi_accessors unexpected finish");
|
||||
|
||||
// Test we can read an array element slice
|
||||
#ifdef TEST_VERBOSE
|
||||
|
|
@ -359,7 +359,7 @@ int main() {
|
|||
cout << "===================================\n";
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
||||
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
mem32 = (int)mem32_read();
|
||||
int mem32_slice = (int)mem32_slice_read();
|
||||
|
|
@ -379,7 +379,7 @@ int main() {
|
|||
"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
|
||||
#ifdef TEST_VERBOSE
|
||||
|
|
@ -388,7 +388,7 @@ int main() {
|
|||
cout << "=================================\n";
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
||||
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
b = (int)b_read();
|
||||
d = (int)d_read();
|
||||
|
|
@ -410,7 +410,7 @@ int main() {
|
|||
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
|
||||
#ifdef TEST_VERBOSE
|
||||
|
|
@ -419,7 +419,7 @@ int main() {
|
|||
cout << "=====================================\n";
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
||||
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
|
||||
b = (int)b_read();
|
||||
|
|
@ -449,7 +449,7 @@ int main() {
|
|||
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
|
||||
#ifdef TEST_VERBOSE
|
||||
|
|
@ -458,7 +458,7 @@ int main() {
|
|||
cout << "===================================\n";
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
||||
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
|
||||
mem32 = (int)mem32_read();
|
||||
|
|
@ -494,7 +494,7 @@ int main() {
|
|||
"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
|
||||
#ifdef TEST_VERBOSE
|
||||
|
|
@ -503,7 +503,7 @@ int main() {
|
|||
cout << "================================\n";
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
||||
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
|
||||
b = (int)b_read();
|
||||
|
|
@ -540,9 +540,9 @@ int main() {
|
|||
cout << endl;
|
||||
#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;
|
||||
|
||||
e = 0x05 | (i << 4);
|
||||
|
|
@ -574,7 +574,7 @@ int main() {
|
|||
"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
|
||||
#ifdef TEST_VERBOSE
|
||||
|
|
@ -583,7 +583,7 @@ int main() {
|
|||
cout << "================================\n";
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) {
|
||||
for (int i = 0; !contextp->gotFinish() && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
|
||||
b = (int)b_read();
|
||||
|
|
@ -632,9 +632,9 @@ int main() {
|
|||
cout << endl;
|
||||
#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;
|
||||
|
||||
e = (int)e_read();
|
||||
|
|
@ -671,11 +671,10 @@ int main() {
|
|||
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
|
||||
dut->final();
|
||||
VL_DO_DANGLING(delete dut, dut);
|
||||
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) {
|
||||
uint64_t sim_time = 1100;
|
||||
Verilated::commandArgs(argc, argv);
|
||||
Verilated::debug(0);
|
||||
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||
|
||||
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
|
||||
#ifdef VERILATOR
|
||||
# ifdef TEST_VERBOSE
|
||||
Verilated::scopesDump();
|
||||
contextp->scopesDump();
|
||||
# endif
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
topp->eval();
|
||||
topp->clk = 0;
|
||||
main_time += 10;
|
||||
contextp->timeInc(10);
|
||||
|
||||
while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) {
|
||||
main_time += 1;
|
||||
while (contextp->time() < sim_time && !contextp->gotFinish()) {
|
||||
contextp->timeInc(1);
|
||||
topp->eval();
|
||||
topp->clk = !topp->clk;
|
||||
// mon_do();
|
||||
}
|
||||
if (!Verilated::gotFinish()) {
|
||||
if (!contextp->gotFinish()) {
|
||||
vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
||||
}
|
||||
topp->final();
|
||||
|
||||
VL_DO_DANGLING(delete topp, topp);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ mkdir $child_dir;
|
|||
(VM_PREFIX => "$Self->{VM_PREFIX}_child",
|
||||
top_filename => "$Self->{name}_child.v",
|
||||
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",
|
||||
|
|
|
|||
|
|
@ -18,8 +18,9 @@ scenarios(vlt_all => 1);
|
|||
top_filename("t/t_gen_alw.v");
|
||||
|
||||
compile(
|
||||
v_flags2 => ["--prof-exec"],
|
||||
# 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(
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
v_flags2 => ['t/t_hier_block.cpp'],
|
||||
verilator_flags2 => ['--stats', ($Self->{vltmt} ? ' --threads 6' : ''),
|
||||
verilator_flags2 => ['--stats',
|
||||
'--hierarchical',
|
||||
'--Wno-TIMESCALEMOD',
|
||||
'--CFLAGS', '"-pipe -DCPP_MACRO=cplusplus"'
|
||||
],
|
||||
threads => $Self->{vltmt} ? 6 : 0
|
||||
);
|
||||
|
||||
execute(
|
||||
|
|
|
|||
|
|
@ -13,13 +13,17 @@
|
|||
#include "Vt_hier_block.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
std::unique_ptr<Vt_hier_block> top{new Vt_hier_block("top")};
|
||||
Verilated::commandArgs(argc, argv);
|
||||
for (int i = 0; i < 100 && !Verilated::gotFinish(); ++i) {
|
||||
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||
#if VL_THREADED
|
||||
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->clk ^= 1;
|
||||
}
|
||||
if (!Verilated::gotFinish()) {
|
||||
if (!contextp->gotFinish()) {
|
||||
vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
||||
}
|
||||
top->final();
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ compile(
|
|||
v_flags2 => ['t/t_hier_block.cpp'],
|
||||
verilator_flags2 => ['--stats',
|
||||
'+define+USE_VLT', 't/t_hier_block_vlt.vlt',
|
||||
'--CFLAGS', '"-pipe -DCPP_MACRO=cplusplus"',
|
||||
($Self->{vltmt} ? ' --threads 6' : '')],
|
||||
'--CFLAGS', '"-pipe -DCPP_MACRO=cplusplus"'],
|
||||
threads => $Self->{vltmt} ? 6 : 0
|
||||
);
|
||||
|
||||
execute(
|
||||
|
|
|
|||
|
|
@ -22,9 +22,9 @@ compile(
|
|||
verilator_flags2 => ['--sc',
|
||||
'--stats',
|
||||
'--hierarchical',
|
||||
($Self->{vltmt} ? ' --threads 6' : ''),
|
||||
'--CFLAGS', '"-pipe -DCPP_MACRO=cplusplus"'
|
||||
],
|
||||
threads => $Self->{vltmt} ? 6 : 0
|
||||
);
|
||||
|
||||
execute(
|
||||
|
|
|
|||
|
|
@ -22,11 +22,11 @@ compile(
|
|||
verilator_flags2 => ['--sc',
|
||||
'--stats',
|
||||
'--hierarchical',
|
||||
($Self->{vltmt} ? ' --threads 6' : ''),
|
||||
'--CFLAGS', '"-pipe -DCPP_MACRO=cplusplus"',
|
||||
"--CFLAGS", '"-O0 -ggdb"',
|
||||
"--trace-fst"
|
||||
],
|
||||
threads => $Self->{vltmt} ? 6 : 0
|
||||
);
|
||||
|
||||
execute(
|
||||
|
|
|
|||
|
|
@ -22,11 +22,11 @@ compile(
|
|||
verilator_flags2 => ['--sc',
|
||||
'--stats',
|
||||
'--hierarchical',
|
||||
($Self->{vltmt} ? ' --threads 6' : ''),
|
||||
'--CFLAGS', '"-pipe -DCPP_MACRO=cplusplus"',
|
||||
"--CFLAGS", '"-O0 -ggdb"',
|
||||
"--trace"
|
||||
],
|
||||
threads => $Self->{vltmt} ? 6 : 0
|
||||
);
|
||||
|
||||
execute(
|
||||
|
|
|
|||
|
|
@ -17,12 +17,12 @@ top_filename("t/t_hier_block.v");
|
|||
|
||||
compile(
|
||||
v_flags2 => ['t/t_hier_block.cpp'],
|
||||
verilator_flags2 => [($Self->{vltmt} ? ' --threads 6' : ''),
|
||||
'--hierarchical',
|
||||
verilator_flags2 => ['--hierarchical',
|
||||
'--Wno-TIMESCALEMOD',
|
||||
'--trace-fst',
|
||||
'--no-trace-underscore', # To avoid handle mismatches
|
||||
],
|
||||
threads => $Self->{vltmt} ? 6 : 0
|
||||
);
|
||||
|
||||
execute(
|
||||
|
|
|
|||
|
|
@ -17,12 +17,12 @@ top_filename("t/t_hier_block.v");
|
|||
|
||||
compile(
|
||||
v_flags2 => ['t/t_hier_block.cpp'],
|
||||
verilator_flags2 => [($Self->{vltmt} ? ' --threads 6' : ''),
|
||||
'--hierarchical',
|
||||
verilator_flags2 => ['--hierarchical',
|
||||
'--Wno-TIMESCALEMOD',
|
||||
'--trace',
|
||||
'--no-trace-underscore', # To avoid handle mismatches
|
||||
],
|
||||
threads => $Self->{vltmt} ? 6 : 0
|
||||
);
|
||||
|
||||
execute(
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ compile(
|
|||
'--hierarchical',
|
||||
'+define+SHOW_TIMESCALE',
|
||||
'+define+USE_VLT', 't/t_hier_block_vlt.vlt',
|
||||
'--CFLAGS', '"-pipe -DCPP_MACRO=cplusplus"',
|
||||
($Self->{vltmt} ? ' --threads 6' : '')],
|
||||
'--CFLAGS', '"-pipe -DCPP_MACRO=cplusplus"'],
|
||||
threads => $Self->{vltmt} ? 6 : 0
|
||||
);
|
||||
|
||||
execute(
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@ top_filename("t/t_inst_tree.v");
|
|||
|
||||
my $default_vltmt_threads = $Self->get_default_vltmt_threads();
|
||||
compile(
|
||||
verilator_flags2 => ['--stats', "$Self->{t_dir}/$Self->{name}.vlt",
|
||||
# Force 3 threads even if we have fewer cores
|
||||
$Self->{vltmt} ? "--threads $default_vltmt_threads" : ""]
|
||||
verilator_flags2 => ['--stats', "$Self->{t_dir}/$Self->{name}.vlt"],
|
||||
# Force 3 threads even if we have fewer cores
|
||||
threads => $Self->{vltmt} ? $default_vltmt_threads : 0
|
||||
);
|
||||
|
||||
sub checkRelativeRefs {
|
||||
|
|
|
|||
|
|
@ -48,11 +48,12 @@ void make_and_destroy() {
|
|||
#ifdef VL_NO_LEGACY
|
||||
VerilatedContext* contextp = new VerilatedContext;
|
||||
VM_PREFIX* topp = new VM_PREFIX{contextp};
|
||||
contextp->debug(0);
|
||||
#else
|
||||
VM_PREFIX* topp = new VM_PREFIX;
|
||||
Verilated::debug(0);
|
||||
#endif
|
||||
|
||||
Verilated::debug(0);
|
||||
topp->eval();
|
||||
topp->clk = true;
|
||||
while (!
|
||||
|
|
|
|||
|
|
@ -56,10 +56,11 @@ while (1) {
|
|||
|
||||
compile(
|
||||
verilator_flags2 => ["$secret_dir/secret.sv",
|
||||
($Self->{vltmt} ? ' --threads 1' : ''),
|
||||
"-LDFLAGS",
|
||||
"'-Wl,-rpath,$abs_secret_dir -L$abs_secret_dir -l$secret_prefix'"],
|
||||
xsim_flags2 => ["$secret_dir/secret.sv"],
|
||||
threads => $Self->{vltmt} ? 1 : 0,
|
||||
context_threads => $Self->{vltmt} ? 6 : 1
|
||||
);
|
||||
|
||||
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);
|
||||
|
||||
compile(
|
||||
v_flags2 => ["--threads 2"],
|
||||
threads => 2,
|
||||
fails => 1,
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ scenarios(vltmt => 1);
|
|||
top_filename("t/t_gen_alw.v");
|
||||
|
||||
compile(
|
||||
v_flags2 => ["--prof-pgo --threads 2"]
|
||||
v_flags2 => ["--prof-pgo"],
|
||||
threads => 2
|
||||
);
|
||||
|
||||
execute(
|
||||
|
|
@ -30,8 +31,8 @@ file_grep("$Self->{obj_dir}/profile.vlt", qr/profile_data/i);
|
|||
compile(
|
||||
# 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)
|
||||
v_flags2 => ["--threads 2",
|
||||
" $Self->{obj_dir}/profile.vlt"],
|
||||
v_flags2 => [" $Self->{obj_dir}/profile.vlt"],
|
||||
threads => 2
|
||||
);
|
||||
|
||||
execute(
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ scenarios(simulator => 1);
|
|||
# %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.
|
||||
compile(
|
||||
verilator_flags2 => ['--stats' . ($Self->{vltmt} ? ' --threads 6' : ''),
|
||||
"$Self->{t_dir}/t_split_var_0.vlt"],
|
||||
verilator_flags2 => ['--stats', "$Self->{t_dir}/t_split_var_0.vlt"],
|
||||
threads => $Self->{vltmt} ? 6 : 0
|
||||
);
|
||||
|
||||
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.
|
||||
# So use 6 threads here though it's not optimal in performace wise, but ok.
|
||||
compile(
|
||||
verilator_flags2 => ['--cc --trace --stats' . ($Self->{vltmt} ? ' --threads 6' : ''),
|
||||
'+define+TEST_ATTRIBUTES'],
|
||||
verilator_flags2 => ['--cc --trace --stats +define+TEST_ATTRIBUTES'],
|
||||
threads => $Self->{vltmt} ? 6 : 0
|
||||
);
|
||||
|
||||
execute(
|
||||
|
|
|
|||
|
|
@ -22,6 +22,12 @@ module t;
|
|||
//if ($test$plusargs("")!==1) $stop; // Simulators differ in this answer
|
||||
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;
|
||||
if ($value$plusargs("NOTTHERE%d", 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");
|
||||
|
||||
compile(
|
||||
verilator_flags2 => ['--cc --no-threads'],
|
||||
verilator_flags2 => ['--cc'],
|
||||
threads => 0,
|
||||
);
|
||||
|
||||
execute(
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ scenarios(vltmt => 1);
|
|||
top_filename("t/t_threads_counter.v");
|
||||
|
||||
compile(
|
||||
verilator_flags2 => ['--cc --threads 1'],
|
||||
verilator_flags2 => ['--cc'],
|
||||
threads => 1
|
||||
);
|
||||
|
||||
execute(
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ scenarios(vltmt => 1);
|
|||
top_filename("t/t_threads_counter.v");
|
||||
|
||||
compile(
|
||||
verilator_flags2 => ['--cc --threads 2'],
|
||||
verilator_flags2 => ['--cc'],
|
||||
threads => 2
|
||||
);
|
||||
|
||||
execute(
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ scenarios(vltmt => 1);
|
|||
top_filename("t/t_threads_counter.v");
|
||||
|
||||
compile(
|
||||
verilator_flags2 => ['--cc --threads 4'],
|
||||
verilator_flags2 => ['--cc'],
|
||||
threads => 4
|
||||
);
|
||||
|
||||
execute(
|
||||
|
|
|
|||
|
|
@ -10,19 +10,16 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
|||
|
||||
scenarios(vltmt => 1);
|
||||
|
||||
if ($Self->cfg_with_m32) {
|
||||
skip("Does not work with -m32 (resource unavailable)");
|
||||
}
|
||||
|
||||
compile(
|
||||
verilator_flags2 => ['--cc --threads 1024'],
|
||||
verilator_flags2 => ['--cc'],
|
||||
threads => 4,
|
||||
context_threads => 2
|
||||
);
|
||||
|
||||
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);
|
||||
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");
|
||||
|
||||
compile(
|
||||
verilator_flags2 => ['--cc --threads 2 --debug-nondeterminism --no-skip-identical'],
|
||||
verilator_flags2 => ['--cc --debug-nondeterminism --no-skip-identical'],
|
||||
threads => 2
|
||||
);
|
||||
|
||||
execute(
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ scenarios(simulator => 1);
|
|||
# %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads.
|
||||
# Strangely, asking for more threads makes it go away.
|
||||
compile(
|
||||
verilator_flags2 => ['--cc --trace --trace-params -Wno-LITENDIAN',
|
||||
($Self->{vltmt} ? '--threads 6' : '')],
|
||||
verilator_flags2 => ['--cc --trace --trace-params -Wno-LITENDIAN'],
|
||||
threads => $Self->{vltmt} ? 6 : 0
|
||||
);
|
||||
|
||||
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.
|
||||
# Strangely, asking for more threads makes it go away.
|
||||
compile(
|
||||
verilator_flags2 => ['--cc --trace-fst --trace-params -Wno-LITENDIAN',
|
||||
($Self->{vltmt} ? '--threads 6' : '')],
|
||||
verilator_flags2 => ['--cc --trace-fst --trace-params -Wno-LITENDIAN'],
|
||||
threads => $Self->{vltmt} ? 6 : 0
|
||||
);
|
||||
|
||||
execute(
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ else {
|
|||
# %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads.
|
||||
# Strangely, asking for more threads makes it go away.
|
||||
compile(
|
||||
verilator_flags2 => ['--sc --trace-fst --trace-params -Wno-LITENDIAN',
|
||||
($Self->{vltmt} ? '--threads 6' : '')],
|
||||
verilator_flags2 => ['--sc --trace-fst --trace-params -Wno-LITENDIAN'],
|
||||
threads => $Self->{vltmt} ? 6 : 0
|
||||
);
|
||||
|
||||
execute(
|
||||
|
|
|
|||
|
|
@ -25,21 +25,21 @@
|
|||
|
||||
VM_PREFIX* ap;
|
||||
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) {
|
||||
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||
|
||||
uint64_t sim_time = 1100;
|
||||
Verilated::commandArgs(argc, argv);
|
||||
Verilated::debug(0);
|
||||
Verilated::traceEverOn(true);
|
||||
contextp->commandArgs(argc, argv);
|
||||
contextp->debug(0);
|
||||
contextp->traceEverOn(true);
|
||||
srand48(5);
|
||||
ap = new VM_PREFIX("topa");
|
||||
bp = new Vt_trace_two_b("topb");
|
||||
ap = new VM_PREFIX{contextp.get(), "topa"};
|
||||
bp = new Vt_trace_two_b{contextp.get(), "topb"};
|
||||
|
||||
// clang-format off
|
||||
#ifdef TEST_HDR_TRACE
|
||||
Verilated::traceEverOn(true);
|
||||
contextp->traceEverOn(true);
|
||||
# ifdef TEST_FST
|
||||
VerilatedFstC* tfp = new VerilatedFstC;
|
||||
ap->trace(tfp, 99);
|
||||
|
|
@ -59,14 +59,14 @@ int main(int argc, char** argv, char** env) {
|
|||
bp->eval_step();
|
||||
ap->eval_end_step();
|
||||
bp->eval_end_step();
|
||||
if (tfp) tfp->dump(main_time);
|
||||
if (tfp) tfp->dump(contextp->time());
|
||||
#endif
|
||||
|
||||
{
|
||||
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;
|
||||
bp->clk = ap->clk;
|
||||
ap->eval_step();
|
||||
|
|
@ -74,11 +74,11 @@ int main(int argc, char** argv, char** env) {
|
|||
ap->eval_end_step();
|
||||
bp->eval_end_step();
|
||||
#ifdef TEST_HDR_TRACE
|
||||
if (tfp) tfp->dump(main_time);
|
||||
if (tfp) tfp->dump(contextp->time());
|
||||
#endif
|
||||
main_time += 5;
|
||||
contextp->timeInc(5);
|
||||
}
|
||||
if (!Verilated::gotFinish()) {
|
||||
if (!contextp->gotFinish()) {
|
||||
vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
||||
}
|
||||
ap->final();
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@
|
|||
|
||||
VM_PREFIX* tb = nullptr;
|
||||
|
||||
double sc_time_stamp() { return 0; }
|
||||
|
||||
bool check() {
|
||||
bool pass;
|
||||
int c = (tb->A >> tb->SEL) & 0x1;
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@
|
|||
|
||||
VM_PREFIX* tb = nullptr;
|
||||
|
||||
double sc_time_stamp() { return 0; }
|
||||
|
||||
int main() {
|
||||
Verilated::debug(0);
|
||||
tb = new VM_PREFIX("tb");
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
|||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
scenarios(vlt => 1);
|
||||
scenarios(vltmt => 1);
|
||||
|
||||
my $root = "..";
|
||||
|
||||
|
|
@ -17,10 +17,10 @@ compile(
|
|||
verilator_flags2 => ["--cc",
|
||||
"--coverage-toggle --coverage-line --coverage-user",
|
||||
"--trace --vpi ",
|
||||
"--threads 2",
|
||||
"--trace-threads 1",
|
||||
"--prof-exec", "--prof-pgo",
|
||||
"$root/include/verilated_save.cpp"],
|
||||
threads => 2
|
||||
);
|
||||
|
||||
execute(
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@ my $root = "..";
|
|||
|
||||
compile(
|
||||
# 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(
|
||||
|
|
|
|||
|
|
@ -143,11 +143,15 @@ static void register_filler_cb() {
|
|||
double sc_time_stamp() { return main_time; }
|
||||
|
||||
int main(int argc, char** argv, char** env) {
|
||||
uint64_t sim_time = 100;
|
||||
Verilated::commandArgs(argc, argv);
|
||||
Verilated::debug(0);
|
||||
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||
|
||||
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();
|
||||
TEST_CHECK_NZ(vh_value_cb);
|
||||
|
|
@ -158,7 +162,7 @@ int main(int argc, char** argv, char** env) {
|
|||
topp->eval();
|
||||
topp->clk = 0;
|
||||
|
||||
while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) {
|
||||
while (main_time < sim_time && !contextp->gotFinish()) {
|
||||
main_time += 1;
|
||||
if (verbose) VL_PRINTF("Sim Time %d got_error %d\n", main_time, errors);
|
||||
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 (!Verilated::gotFinish()) {
|
||||
if (!contextp->gotFinish()) {
|
||||
vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
||||
}
|
||||
topp->final();
|
||||
|
||||
VL_DO_DANGLING(delete topp, topp);
|
||||
return errors ? 10 : 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ bool callbacks_expected_called[CB_COUNT] = {false};
|
|||
std::vector<int>::const_iterator cb_iter;
|
||||
std::vector<CallbackState>::const_iterator state_iter;
|
||||
|
||||
unsigned int main_time = 0;
|
||||
bool got_error = false;
|
||||
|
||||
#ifdef TEST_VERBOSE
|
||||
|
|
@ -245,27 +244,29 @@ static int register_test_callback() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
double sc_time_stamp() { return main_time; }
|
||||
|
||||
int main(int argc, char** argv, char** env) {
|
||||
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||
|
||||
uint64_t sim_time = 100;
|
||||
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();
|
||||
|
||||
topp->eval();
|
||||
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) {
|
||||
VL_PRINTF("-- { Sim Time %d , Callback %s (%d) , Testcase State %d } --\n", main_time,
|
||||
cb_reason_to_string(*cb_iter), *cb_iter, *state_iter);
|
||||
VL_PRINTF("-- { Sim Time %" PRId64 " , Callback %s (%d) , Testcase State %d } --\n",
|
||||
contextp->time(), cb_reason_to_string(*cb_iter), *cb_iter, *state_iter);
|
||||
}
|
||||
|
||||
topp->eval();
|
||||
|
|
@ -285,14 +286,17 @@ int main(int argc, char** argv, char** env) {
|
|||
|
||||
VerilatedVpi::callTimedCbs();
|
||||
|
||||
main_time = VerilatedVpi::cbNextDeadline();
|
||||
if (main_time == -1 && !Verilated::gotFinish()) {
|
||||
if (verbose) VL_PRINTF("-- { Sim Time %d , No more testcases } --\n", main_time);
|
||||
int64_t next_time = VerilatedVpi::cbNextDeadline();
|
||||
contextp->time(next_time);
|
||||
if (next_time == -1 && !contextp->gotFinish()) {
|
||||
if (verbose)
|
||||
VL_PRINTF("-- { Sim Time %" PRId64 " , No more testcases } --\n",
|
||||
contextp->time());
|
||||
if (got_error) {
|
||||
vl_stop(__FILE__, __LINE__, "TOP-cpp");
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
if (!Verilated::gotFinish()) {
|
||||
if (!contextp->gotFinish()) {
|
||||
vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
||||
}
|
||||
topp->final();
|
||||
|
||||
VL_DO_DANGLING(delete topp, topp);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,8 +40,6 @@
|
|||
#define TEST_MSG \
|
||||
if (0) printf
|
||||
|
||||
unsigned int main_time = 0;
|
||||
|
||||
//======================================================================
|
||||
|
||||
#define CHECK_RESULT_VH(got, exp) \
|
||||
|
|
@ -240,22 +238,25 @@ void vpi_compat_bootstrap(void) {
|
|||
void (*vlog_startup_routines[])() = {vpi_compat_bootstrap, 0};
|
||||
|
||||
#else
|
||||
double sc_time_stamp() { return main_time; }
|
||||
int main(int argc, char** argv, char** env) {
|
||||
uint64_t sim_time = 1100;
|
||||
Verilated::commandArgs(argc, argv);
|
||||
Verilated::debug(0);
|
||||
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||
|
||||
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 TEST_VERBOSE
|
||||
Verilated::scopesDump();
|
||||
contextp->scopesDump();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if VM_TRACE
|
||||
Verilated::traceEverOn(true);
|
||||
contextp->traceEverOn(true);
|
||||
VL_PRINTF("Enabling waves...\n");
|
||||
VerilatedVcdC* tfp = new VerilatedVcdC;
|
||||
topp->trace(tfp, 99);
|
||||
|
|
@ -264,19 +265,19 @@ int main(int argc, char** argv, char** env) {
|
|||
|
||||
topp->eval();
|
||||
topp->clk = 0;
|
||||
main_time += 10;
|
||||
contextp->timeInc(10);
|
||||
|
||||
while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) {
|
||||
main_time += 1;
|
||||
while (contextp->time() < sim_time && !contextp->gotFinish()) {
|
||||
contextp->timeInc(1);
|
||||
topp->eval();
|
||||
VerilatedVpi::callValueCbs();
|
||||
topp->clk = !topp->clk;
|
||||
// mon_do();
|
||||
#if VM_TRACE
|
||||
if (tfp) tfp->dump(main_time);
|
||||
if (tfp) tfp->dump(contextp->time());
|
||||
#endif
|
||||
}
|
||||
if (!Verilated::gotFinish()) {
|
||||
if (!contextp->gotFinish()) {
|
||||
vl_fatal(FILENM, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
||||
}
|
||||
topp->final();
|
||||
|
|
@ -285,7 +286,6 @@ int main(int argc, char** argv, char** env) {
|
|||
if (tfp) tfp->close();
|
||||
#endif
|
||||
|
||||
VL_DO_DANGLING(delete topp, topp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@
|
|||
#define DEBUG \
|
||||
if (0) printf
|
||||
|
||||
unsigned int main_time = 0;
|
||||
int errors = 0;
|
||||
|
||||
//======================================================================
|
||||
|
|
@ -250,24 +249,27 @@ void (*vlog_startup_routines[])() = {vpi_compat_bootstrap, 0};
|
|||
|
||||
#else
|
||||
|
||||
double sc_time_stamp() { return main_time; }
|
||||
int main(int argc, char** argv, char** env) {
|
||||
uint64_t sim_time = 1100;
|
||||
Verilated::commandArgs(argc, argv);
|
||||
Verilated::debug(0);
|
||||
// we're going to be checking for these errors do don't crash out
|
||||
Verilated::fatalOnVpiError(0);
|
||||
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||
|
||||
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 TEST_VERBOSE
|
||||
Verilated::scopesDump();
|
||||
contextp->scopesDump();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if VM_TRACE
|
||||
Verilated::traceEverOn(true);
|
||||
contextp->traceEverOn(true);
|
||||
VL_PRINTF("Enabling waves...\n");
|
||||
VerilatedVcdC* tfp = new VerilatedVcdC;
|
||||
topp->trace(tfp, 99);
|
||||
|
|
@ -276,19 +278,19 @@ int main(int argc, char** argv, char** env) {
|
|||
|
||||
topp->eval();
|
||||
topp->clk = 0;
|
||||
main_time += 10;
|
||||
contextp->timeInc(10);
|
||||
|
||||
while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) {
|
||||
main_time += 1;
|
||||
while (contextp->time() < sim_time && !contextp->gotFinish()) {
|
||||
contextp->timeInc(1);
|
||||
topp->eval();
|
||||
VerilatedVpi::callValueCbs();
|
||||
topp->clk = !topp->clk;
|
||||
// mon_do();
|
||||
#if VM_TRACE
|
||||
if (tfp) tfp->dump(main_time);
|
||||
if (tfp) tfp->dump(contextp->time());
|
||||
#endif
|
||||
}
|
||||
if (!Verilated::gotFinish()) {
|
||||
if (!contextp->gotFinish()) {
|
||||
vl_fatal(FILENM, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
||||
}
|
||||
topp->final();
|
||||
|
|
@ -297,7 +299,6 @@ int main(int argc, char** argv, char** env) {
|
|||
if (tfp) tfp->close();
|
||||
#endif
|
||||
|
||||
VL_DO_DANGLING(delete topp, topp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,8 +40,6 @@
|
|||
#define DEBUG \
|
||||
if (0) printf
|
||||
|
||||
unsigned int main_time = 0;
|
||||
|
||||
#define CHECK_RESULT_NZ(got) \
|
||||
if (!(got)) { \
|
||||
printf("%%Error: %s:%d: GOT = NULL EXP = !NULL\n", FILENM, __LINE__); \
|
||||
|
|
@ -172,27 +170,36 @@ void (*vlog_startup_routines[])() = {vpi_compat_bootstrap, 0};
|
|||
|
||||
#else
|
||||
|
||||
double sc_time_stamp() { return main_time; }
|
||||
int main(int argc, char** argv, char** env) {
|
||||
uint64_t sim_time = 1100;
|
||||
Verilated::commandArgs(argc, argv);
|
||||
Verilated::debug(0);
|
||||
// we're going to be checking for these errors do don't crash out
|
||||
Verilated::fatalOnVpiError(0);
|
||||
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||
|
||||
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);
|
||||
|
||||
{
|
||||
// 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
|
||||
delete topp;
|
||||
topp = new VM_PREFIX("");
|
||||
const std::unique_ptr<VM_PREFIX> topp{new VM_PREFIX{contextp.get(),
|
||||
// Note null name - we're flattening it out
|
||||
""}};
|
||||
|
||||
#ifdef VERILATOR
|
||||
#ifdef TEST_VERBOSE
|
||||
Verilated::scopesDump();
|
||||
contextp->scopesDump();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if VM_TRACE
|
||||
Verilated::traceEverOn(true);
|
||||
contextp->traceEverOn(true);
|
||||
VL_PRINTF("Enabling waves...\n");
|
||||
VerilatedVcdC* tfp = new VerilatedVcdC;
|
||||
topp->trace(tfp, 99);
|
||||
|
|
@ -201,19 +208,19 @@ int main(int argc, char** argv, char** env) {
|
|||
|
||||
topp->eval();
|
||||
topp->clk = 0;
|
||||
main_time += 10;
|
||||
contextp->timeInc(10);
|
||||
|
||||
while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) {
|
||||
main_time += 1;
|
||||
while (contextp->time() < sim_time && !contextp->gotFinish()) {
|
||||
contextp->timeInc(1);
|
||||
topp->eval();
|
||||
VerilatedVpi::callValueCbs();
|
||||
topp->clk = !topp->clk;
|
||||
// mon_do();
|
||||
#if VM_TRACE
|
||||
if (tfp) tfp->dump(main_time);
|
||||
if (tfp) tfp->dump(contextp->time());
|
||||
#endif
|
||||
}
|
||||
if (!Verilated::gotFinish()) {
|
||||
if (!contextp->gotFinish()) {
|
||||
vl_fatal(FILENM, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
||||
}
|
||||
topp->final();
|
||||
|
|
@ -222,7 +229,6 @@ int main(int argc, char** argv, char** env) {
|
|||
if (tfp) tfp->close();
|
||||
#endif
|
||||
|
||||
VL_DO_DANGLING(delete topp, topp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,8 +40,6 @@
|
|||
#define DEBUG \
|
||||
if (0) printf
|
||||
|
||||
unsigned int main_time = 0;
|
||||
|
||||
//======================================================================
|
||||
|
||||
#define CHECK_RESULT_VH(got, exp) \
|
||||
|
|
@ -240,24 +238,27 @@ void (*vlog_startup_routines[])() = {vpi_compat_bootstrap, 0};
|
|||
|
||||
#else
|
||||
|
||||
double sc_time_stamp() { return main_time; }
|
||||
int main(int argc, char** argv, char** env) {
|
||||
uint64_t sim_time = 1100;
|
||||
Verilated::commandArgs(argc, argv);
|
||||
Verilated::debug(0);
|
||||
// we're going to be checking for these errors do don't crash out
|
||||
Verilated::fatalOnVpiError(0);
|
||||
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||
|
||||
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 TEST_VERBOSE
|
||||
Verilated::scopesDump();
|
||||
contextp->scopesDump();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if VM_TRACE
|
||||
Verilated::traceEverOn(true);
|
||||
contextp->traceEverOn(true);
|
||||
VL_PRINTF("Enabling waves...\n");
|
||||
VerilatedVcdC* tfp = new VerilatedVcdC;
|
||||
topp->trace(tfp, 99);
|
||||
|
|
@ -266,19 +267,19 @@ int main(int argc, char** argv, char** env) {
|
|||
|
||||
topp->eval();
|
||||
topp->clk = 0;
|
||||
main_time += 10;
|
||||
contextp->timeInc(10);
|
||||
|
||||
while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) {
|
||||
main_time += 1;
|
||||
while (contextp->time() < sim_time && !contextp->gotFinish()) {
|
||||
contextp->timeInc(1);
|
||||
topp->eval();
|
||||
VerilatedVpi::callValueCbs();
|
||||
topp->clk = !topp->clk;
|
||||
// mon_do();
|
||||
#if VM_TRACE
|
||||
if (tfp) tfp->dump(main_time);
|
||||
if (tfp) tfp->dump(contextp->time());
|
||||
#endif
|
||||
}
|
||||
if (!Verilated::gotFinish()) {
|
||||
if (!contextp->gotFinish()) {
|
||||
vl_fatal(FILENM, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
||||
}
|
||||
topp->final();
|
||||
|
|
@ -287,7 +288,6 @@ int main(int argc, char** argv, char** env) {
|
|||
if (tfp) tfp->close();
|
||||
#endif
|
||||
|
||||
VL_DO_DANGLING(delete topp, topp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,27 +22,27 @@
|
|||
|
||||
#include <iostream>
|
||||
|
||||
unsigned int main_time = 0;
|
||||
|
||||
//======================================================================
|
||||
|
||||
double sc_time_stamp() { return main_time; }
|
||||
|
||||
int main(int argc, char** argv, char** env) {
|
||||
uint64_t sim_time = 1100;
|
||||
Verilated::commandArgs(argc, argv);
|
||||
Verilated::debug(0);
|
||||
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||
|
||||
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
|
||||
#ifdef TEST_VERBOSE
|
||||
Verilated::scopesDump();
|
||||
contextp->scopesDump();
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
#if VM_TRACE
|
||||
Verilated::traceEverOn(true);
|
||||
contextp->traceEverOn(true);
|
||||
VL_PRINTF("Enabling waves...\n");
|
||||
VerilatedVcdC* tfp = new VerilatedVcdC;
|
||||
topp->trace(tfp, 99);
|
||||
|
|
@ -54,24 +54,24 @@ int main(int argc, char** argv, char** env) {
|
|||
topp->eval();
|
||||
topp->clk = 0;
|
||||
|
||||
while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) {
|
||||
main_time += 1;
|
||||
while (vl_time_stamp64() < sim_time && !contextp->gotFinish()) {
|
||||
contextp->timeInc(1);
|
||||
topp->eval();
|
||||
VerilatedVpi::callValueCbs();
|
||||
VerilatedVpi::callTimedCbs();
|
||||
if (main_time > 20) { // Else haven't registered callbacks
|
||||
TEST_CHECK_EQ(VerilatedVpi::cbNextDeadline(), main_time + 1);
|
||||
if (contextp->time() > 20) { // Else haven't registered callbacks
|
||||
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();
|
||||
#if VM_TRACE
|
||||
if (tfp) tfp->dump(main_time);
|
||||
if (tfp) tfp->dump(contextp->time());
|
||||
#endif
|
||||
}
|
||||
|
||||
VerilatedVpi::callCbs(cbEndOfSimulation);
|
||||
|
||||
if (!Verilated::gotFinish()) {
|
||||
if (!contextp->gotFinish()) {
|
||||
vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
||||
}
|
||||
topp->final();
|
||||
|
|
@ -80,6 +80,5 @@ int main(int argc, char** argv, char** env) {
|
|||
if (tfp) tfp->close();
|
||||
#endif
|
||||
|
||||
VL_DO_DANGLING(delete topp, topp);
|
||||
return errors ? 10 : 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@
|
|||
#define DEBUG \
|
||||
if (0) printf
|
||||
|
||||
unsigned int main_time = 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) {
|
||||
uint64_t sim_time = 1100;
|
||||
Verilated::commandArgs(argc, argv);
|
||||
Verilated::debug(0);
|
||||
// we're going to be checking for these errors do don't crash out
|
||||
Verilated::fatalOnVpiError(0);
|
||||
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||
|
||||
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 TEST_VERBOSE
|
||||
Verilated::scopesDump();
|
||||
contextp->scopesDump();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if VM_TRACE
|
||||
Verilated::traceEverOn(true);
|
||||
contextp->traceEverOn(true);
|
||||
VL_PRINTF("Enabling waves...\n");
|
||||
VerilatedVcdC* tfp = new VerilatedVcdC;
|
||||
topp->trace(tfp, 99);
|
||||
|
|
@ -210,20 +212,20 @@ int main(int argc, char** argv, char** env) {
|
|||
|
||||
topp->eval();
|
||||
topp->clk = 0;
|
||||
main_time += 10;
|
||||
contextp->timeInc(10);
|
||||
|
||||
while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) {
|
||||
main_time += 1;
|
||||
while (contextp->time() < sim_time && !contextp->gotFinish()) {
|
||||
contextp->timeInc(1);
|
||||
topp->eval();
|
||||
// VerilatedVpi::callValueCbs(); // Make sure can link without verilated_vpi.h included
|
||||
topp->clk = !topp->clk;
|
||||
// mon_do();
|
||||
#if VM_TRACE
|
||||
if (tfp) tfp->dump(main_time);
|
||||
if (tfp) tfp->dump(contextp->time());
|
||||
#endif
|
||||
}
|
||||
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");
|
||||
}
|
||||
topp->final();
|
||||
|
|
@ -232,6 +234,5 @@ int main(int argc, char** argv, char** env) {
|
|||
if (tfp) tfp->close();
|
||||
#endif
|
||||
|
||||
VL_DO_DANGLING(delete topp, topp);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -693,20 +693,24 @@ void (*vlog_startup_routines[])() = {vpi_compat_bootstrap, 0};
|
|||
|
||||
double sc_time_stamp() { return main_time; }
|
||||
int main(int argc, char** argv, char** env) {
|
||||
uint64_t sim_time = 1100;
|
||||
Verilated::commandArgs(argc, argv);
|
||||
Verilated::debug(0);
|
||||
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||
|
||||
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 TEST_VERBOSE
|
||||
Verilated::scopesDump();
|
||||
contextp->scopesDump();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if VM_TRACE
|
||||
Verilated::traceEverOn(true);
|
||||
contextp->traceEverOn(true);
|
||||
VL_PRINTF("Enabling waves...\n");
|
||||
VerilatedVcdC* tfp = new VerilatedVcdC;
|
||||
topp->trace(tfp, 99);
|
||||
|
|
@ -717,7 +721,7 @@ int main(int argc, char** argv, char** env) {
|
|||
topp->clk = 0;
|
||||
main_time += 10;
|
||||
|
||||
while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) {
|
||||
while (vl_time_stamp64() < sim_time && !contextp->gotFinish()) {
|
||||
main_time += 1;
|
||||
topp->eval();
|
||||
VerilatedVpi::callValueCbs();
|
||||
|
|
@ -731,7 +735,7 @@ int main(int argc, char** argv, char** env) {
|
|||
CHECK_RESULT(callback_count_half, 250);
|
||||
CHECK_RESULT(callback_count_quad, 2);
|
||||
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");
|
||||
}
|
||||
topp->final();
|
||||
|
|
@ -740,7 +744,6 @@ int main(int argc, char** argv, char** env) {
|
|||
if (tfp) tfp->close();
|
||||
#endif
|
||||
|
||||
VL_DO_DANGLING(delete topp, topp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@
|
|||
#include "TestVpi.h"
|
||||
|
||||
int errors = 0;
|
||||
unsigned int main_time = 0;
|
||||
unsigned int callback_count_zero_time = 0;
|
||||
unsigned int callback_count_start_of_sim = 0;
|
||||
|
||||
|
|
@ -105,25 +104,27 @@ void (*vlog_startup_routines[])() = {vpi_compat_bootstrap, 0};
|
|||
|
||||
#else
|
||||
|
||||
double sc_time_stamp() { return main_time; }
|
||||
|
||||
int main(int argc, char** argv, char** env) {
|
||||
uint64_t sim_time = 1100;
|
||||
Verilated::commandArgs(argc, argv);
|
||||
Verilated::debug(0);
|
||||
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||
|
||||
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
|
||||
#ifdef VERILATOR
|
||||
# ifdef TEST_VERBOSE
|
||||
Verilated::scopesDump();
|
||||
contextp->scopesDump();
|
||||
# endif
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
#if VM_TRACE
|
||||
Verilated::traceEverOn(true);
|
||||
contextp->traceEverOn(true);
|
||||
VL_PRINTF("Enabling waves...\n");
|
||||
VerilatedVcdC* tfp = new VerilatedVcdC;
|
||||
topp->trace(tfp, 99);
|
||||
|
|
@ -146,23 +147,23 @@ int main(int argc, char** argv, char** env) {
|
|||
|
||||
topp->eval();
|
||||
topp->clk = 0;
|
||||
main_time += 1;
|
||||
contextp->timeInc(1);
|
||||
|
||||
while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) {
|
||||
main_time += 1;
|
||||
while (contextp->time() < sim_time && !contextp->gotFinish()) {
|
||||
contextp->timeInc(1);
|
||||
topp->eval();
|
||||
VerilatedVpi::callValueCbs();
|
||||
VerilatedVpi::callTimedCbs();
|
||||
topp->clk = !topp->clk;
|
||||
// mon_do();
|
||||
#if VM_TRACE
|
||||
if (tfp) tfp->dump(main_time);
|
||||
if (tfp) tfp->dump(contextp->time());
|
||||
#endif
|
||||
}
|
||||
|
||||
VerilatedVpi::callCbs(cbEndOfSimulation);
|
||||
|
||||
if (!Verilated::gotFinish()) {
|
||||
if (!contextp->gotFinish()) {
|
||||
vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
||||
}
|
||||
topp->final();
|
||||
|
|
@ -171,7 +172,6 @@ int main(int argc, char** argv, char** env) {
|
|||
if (tfp) tfp->close();
|
||||
#endif
|
||||
|
||||
VL_DO_DANGLING(delete topp, topp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -92,6 +92,8 @@ int main(int argc, char** argv, char** env) {
|
|||
std::unique_ptr<VerilatedContext> context1p{new VerilatedContext};
|
||||
|
||||
// configuration
|
||||
context0p->threads(1);
|
||||
context1p->threads(1);
|
||||
context0p->fatalOnError(false);
|
||||
context1p->fatalOnError(false);
|
||||
context0p->traceEverOn(true);
|
||||
|
|
|
|||
|
|
@ -14,8 +14,9 @@ compile(
|
|||
make_top_shell => 0,
|
||||
make_main => 0,
|
||||
# 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"],
|
||||
threads => 1,
|
||||
make_flags => 'CPPFLAGS_ADD=-DVL_NO_LEGACY',
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -16,8 +16,9 @@ compile(
|
|||
make_top_shell => 0,
|
||||
make_main => 0,
|
||||
# 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"],
|
||||
threads => 1,
|
||||
make_flags => 'CPPFLAGS_ADD=-DVL_NO_LEGACY',
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -16,8 +16,9 @@ compile(
|
|||
make_top_shell => 0,
|
||||
make_main => 0,
|
||||
# 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"],
|
||||
threads => 1,
|
||||
make_flags => 'CPPFLAGS_ADD=-DVL_NO_LEGACY',
|
||||
);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue