verilator/include/verilated.h
2024-11-12 11:28:39 -05:00

1063 lines
46 KiB
C++

// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
//
// Code available from: https://verilator.org
//
// Copyright 2003-2024 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
//
//*************************************************************************
///
/// \file
/// \brief Verilated common header, include for all Verilated C files
///
/// This file is included automatically by Verilator at the top of all C++
/// files it generates. It contains standard macros and classes required
/// by the Verilated code.
///
/// User wrapper code may need to include this to get appropriate
/// structures, however they would generally just include the
/// Verilated-model's header instead (which then includes this).
///
/// Those macro/function/variable starting or ending in _ are internal,
/// however many of the other function/macros here are also internal.
///
//*************************************************************************
#ifndef VERILATOR_VERILATED_H_
#define VERILATOR_VERILATED_H_
#define VERILATOR_VERILATED_H_INTERNAL_
#ifdef VERILATOR_INTERNAL_
// This file contains definition of VerilationMutex that should
// only be used by verilated code. Verilator itself should use
// mutex from V3Mutex.h. Make sure this file isn't included in
// verilator code.
#error "verilated.h should only be included in verilated code"
#endif
// clang-format off
#include "verilatedos.h"
#include "verilated_config.h"
#if VM_SC
# include "verilated_sc.h" // Get SYSTEMC_VERSION and time declarations
#endif
#include <algorithm>
#include <array>
#include <cassert>
#include <cmath>
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <deque>
#include <functional>
#include <limits>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <unordered_set>
#include <vector>
// <iostream> avoided to reduce compile time
#include <atomic>
#include <mutex>
#include <thread>
// Allow user to specify their own include file
#ifdef VL_VERILATED_INCLUDE
// cppcheck-suppress preprocessorErrorDirective
# include VL_VERILATED_INCLUDE
#endif
// clang-format on
using namespace std::literals; // "<std::string literal>"s; see SF.7 core guideline
//=============================================================================
// Switches
// clang-format off
#if VM_TRACE // Verilator tracing requested
# define WAVES 1 // Set backward compatibility flag
#endif
// Version check
#if defined(SYSTEMC_VERSION) && (SYSTEMC_VERSION < 20111121)
# warning "Verilator requires SystemC 2.3.* or newer."
#endif
// clang-format on
class VerilatedContext;
class VerilatedContextImp;
class VerilatedContextImpData;
class VerilatedCovContext;
class VerilatedEvalMsgQueue;
class VerilatedFst;
class VerilatedFstC;
class VerilatedFstSc;
class VerilatedScope;
class VerilatedScopeNameMap;
template <class, class>
class VerilatedTrace;
class VerilatedTraceBaseC;
class VerilatedTraceConfig;
class VerilatedVar;
class VerilatedVarNameMap;
class VerilatedVcd;
class VerilatedVcdC;
class VerilatedVcdSc;
//=========================================================================
// Basic types
// clang-format off
// P // Packed data of bit type (C/S/I/Q/W)
using CData = uint8_t; ///< Data representing 'bit' of 1-8 packed bits
using SData = uint16_t; ///< Data representing 'bit' of 9-16 packed bits
using IData = uint32_t; ///< Data representing 'bit' of 17-32 packed bits
using QData = uint64_t; ///< Data representing 'bit' of 33-64 packed bits
using EData = uint32_t; ///< Data representing one element of WData array
using WData = EData; ///< Data representing >64 packed bits (used as pointer)
// F = float; // No typedef needed; Verilator uses float
// D = double; // No typedef needed; Verilator uses double
// N = std::string; // No typedef needed; Verilator uses string
// clang-format on
using WDataInP = const WData*; ///< 'bit' of >64 packed bits as array input to a function
using WDataOutP = WData*; ///< 'bit' of >64 packed bits as array output from a function
enum VerilatedVarType : uint8_t {
VLVT_UNKNOWN = 0,
VLVT_PTR, // Pointer to something
VLVT_UINT8, // AKA CData
VLVT_UINT16, // AKA SData
VLVT_UINT32, // AKA IData
VLVT_UINT64, // AKA QData
VLVT_WDATA, // AKA WData
VLVT_STRING, // C++ string
VLVT_REAL // AKA double
};
enum VerilatedVarFlags {
VLVD_0 = 0, // None
VLVD_IN = 1, // == vpiInput
VLVD_OUT = 2, // == vpiOutput
VLVD_INOUT = 3, // == vpiInOut
VLVD_NODIR = 5, // == vpiNoDirection
VLVF_MASK_DIR = 7, // Bit mask for above directions
// Flags
VLVF_PUB_RD = (1 << 8), // Public readable
VLVF_PUB_RW = (1 << 9), // Public writable
VLVF_DPI_CLAY = (1 << 10) // DPI compatible C standard layout
};
// IEEE 1800-2023 Table 20-6
enum class VerilatedAssertType : uint8_t {
ASSERT_TYPE_CONCURRENT = (1 << 0),
ASSERT_TYPE_SIMPLE_IMMEDIATE = (1 << 1),
ASSERT_TYPE_OBSERVED_DEFERRED_IMMEDIATE = (1 << 2),
ASSERT_TYPE_FINAL_DEFERRED_IMMEDIATE = (1 << 3),
ASSERT_TYPE_EXPECT = (1 << 4),
ASSERT_TYPE_UNIQUE = (1 << 5),
ASSERT_TYPE_UNIQUE0 = (1 << 6),
ASSERT_TYPE_PRIORITY = (1 << 7),
};
// IEEE 1800-2023 Table 20-7
enum class VerilatedAssertDirectiveType : uint8_t {
DIRECTIVE_TYPE_ASSERT = (1 << 0),
DIRECTIVE_TYPE_COVER = (1 << 1),
DIRECTIVE_TYPE_ASSUME = (1 << 2),
};
using VerilatedAssertType_t = std::underlying_type<VerilatedAssertType>::type;
using VerilatedAssertDirectiveType_t = std::underlying_type<VerilatedAssertDirectiveType>::type;
//=============================================================================
// Utility functions
template <size_t N>
inline constexpr size_t roundUpToMultipleOf(size_t value) {
static_assert((N & (N - 1)) == 0, "'N' must be a power of 2");
return (value + N - 1) & ~(N - 1);
}
//=========================================================================
// Mutex and threading support
// Return current thread ID (or 0), not super fast, cache if needed
extern uint32_t VL_THREAD_ID() VL_MT_SAFE;
#ifndef VL_LOCK_SPINS
#define VL_LOCK_SPINS 50000 /// Number of times to spin for a mutex before yielding
#endif
/// Mutex, wrapped to allow -fthread_safety checks
class VL_CAPABILITY("mutex") VerilatedMutex final {
private:
std::mutex m_mutex; // Mutex
public:
/// Construct mutex (without locking it)
VerilatedMutex() = default;
~VerilatedMutex() = default;
VL_UNCOPYABLE(VerilatedMutex);
const VerilatedMutex& operator!() const { return *this; } // For -fthread_safety
/// Acquire/lock mutex
void lock() VL_ACQUIRE() VL_MT_SAFE {
// Try to acquire the lock by spinning. If the wait is short,
// avoids a trap to the OS plus OS scheduler overhead.
if (VL_LIKELY(try_lock())) return; // Short circuit loop
for (int i = 0; i < VL_LOCK_SPINS; ++i) {
if (VL_LIKELY(try_lock())) return;
VL_CPU_RELAX();
}
// Spinning hasn't worked, pay the cost of blocking.
m_mutex.lock();
}
/// Release/unlock mutex
void unlock() VL_RELEASE() VL_MT_SAFE { m_mutex.unlock(); }
/// Try to acquire mutex. Returns true on success, and false on failure.
bool try_lock() VL_TRY_ACQUIRE(true) VL_MT_SAFE { return m_mutex.try_lock(); }
};
/// Lock guard for mutex (ala std::unique_lock), wrapped to allow -fthread_safety checks
class VL_SCOPED_CAPABILITY VerilatedLockGuard final {
VL_UNCOPYABLE(VerilatedLockGuard);
private:
VerilatedMutex& m_mutexr;
public:
/// Construct and hold given mutex lock until destruction or unlock()
explicit VerilatedLockGuard(VerilatedMutex& mutexr) VL_ACQUIRE(mutexr) VL_MT_SAFE
: m_mutexr(mutexr) { // Need () or GCC 4.8 false warning
mutexr.lock();
}
/// Destruct and unlock the mutex
~VerilatedLockGuard() VL_RELEASE() { m_mutexr.unlock(); }
};
// Internals: Remember the calling thread at construction time, and make
// sure later calls use same thread
class VerilatedAssertOneThread final {
// MEMBERS
#ifdef VL_DEBUG
uint32_t m_threadid; // Thread that is legal
public:
// CONSTRUCTORS
// The constructor establishes the thread id for all later calls.
// If necessary, a different class could be made that inits it otherwise.
VerilatedAssertOneThread()
: m_threadid{VL_THREAD_ID()} {}
~VerilatedAssertOneThread() { check(); }
// METHODS
// Check that the current thread ID is the same as the construction thread ID
void check() VL_MT_UNSAFE_ONE {
if (VL_UNCOVERABLE(m_threadid != VL_THREAD_ID())) {
if (m_threadid == 0) {
m_threadid = VL_THREAD_ID();
} else {
fatal_different(); // LCOV_EXCL_LINE
}
}
}
static void fatal_different() VL_MT_SAFE;
#else // !VL_DEBUG
public:
void check() {}
#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()
VerilatedContext* contextp() const VL_MT_SAFE { 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;
private:
// The following are for use by Verilator internals only
template <class, class>
friend class VerilatedTrace;
// Run-time trace configuration requested by this model
virtual std::unique_ptr<VerilatedTraceConfig> traceConfig() const;
};
//=========================================================================
/// Base class for all Verilated module classes.
class VerilatedModule VL_NOT_FINAL {
VL_UNCOPYABLE(VerilatedModule);
private:
const char* m_namep; // Module name
public:
explicit VerilatedModule(const char* namep); // Create module with given hierarchy name
~VerilatedModule();
const char* name() const VL_MT_SAFE_POSTINIT { return m_namep; } ///< Return name of module
};
//=========================================================================
// Functions overridable by user defines
// (Internals however must use VL_PRINTF_MT, which calls these.)
// clang-format off
#ifndef VL_PRINTF
# define VL_PRINTF printf ///< Print ala printf, called from main thread; redefine if desired
#endif
#ifndef VL_VPRINTF
# define VL_VPRINTF vprintf ///< Print ala vprintf, called from main thread; redefine if desired
#endif
// clang-format on
//===========================================================================
// Internal: Base class to allow virtual destruction
class VerilatedVirtualBase VL_NOT_FINAL {
public:
VerilatedVirtualBase() = default;
virtual ~VerilatedVirtualBase() = default;
};
//===========================================================================
/// Verilator simulation context
///
/// The VerilatedContext contains the information common across all models
/// that are interconnected, for example this contains the simulation time
/// and if $finish was executed.
///
/// VerilatedContexts maybe created by the user wrapper code and passed
/// when a model is created. If this is not done, then Verilator will use
/// the Verilated::defaultContextp()'s global context.
class VerilatedContext VL_NOT_FINAL {
friend class VerilatedContextImp;
private:
// MEMBERS
// Numer of assertion directive type members. Then each of them will represented as 1-bit in a
// mask.
static constexpr size_t ASSERT_DIRECTIVE_TYPE_MASK_WIDTH = 3;
// Specifies how many groups of directive type bit groups there are based on a number of
// assertion types.
// Note: we add one bit to store information whether Verilator's internal
// directive types are enabled, for example `violation if`s.
static constexpr size_t ASSERT_ON_WIDTH
= ASSERT_DIRECTIVE_TYPE_MASK_WIDTH * std::numeric_limits<VerilatedAssertType_t>::digits
+ 1;
protected:
// TYPES
using traceBaseModelCb_t
= std::function<void(VerilatedTraceBaseC*, int, int)>; // Type of traceBaseModel callbacks
// MEMBERS
// Slow path variables
mutable VerilatedMutex m_mutex; // Mutex for most s_s/s_ns members
struct Serialized final { // All these members serialized/deserialized
// No std::strings or pointers or will serialize badly!
// Fast path
uint64_t m_time = 0; // Current $time (unscaled), 0=at zero, or legacy
std::atomic<uint32_t> m_assertOn{
std::numeric_limits<uint32_t>::max()}; // Enabled assertions,
// for each VerilatedAssertType we store
// 3-bits, one for each directive type. Last
// bit guards internal directive types.
bool m_calcUnusedSigs = false; // Waves file on, need all signals calculated
bool m_fatalOnError = true; // Fatal on $stop/non-fatal error
bool m_fatalOnVpiError = true; // Fatal on vpi error/unsupported
bool m_gotError = false; // A $finish statement executed
bool m_gotFinish = false; // A $finish or $stop statement executed
bool m_quiet = false; // Quiet, no summary report
// Slow path
int8_t m_timeunit; // Time unit as 0..15
int8_t m_timeprecision; // Time precision as 0..15
int m_errorCount = 0; // Number of errors
int m_errorLimit = 1; // Stop on error number
int m_randReset = 0; // Random reset: 0=all 0s, 1=all 1s, 2=random
int m_randSeed = 0; // Random seed: 0=random
enum { UNITS_NONE = 99 }; // Default based on precision
int m_timeFormatUnits = UNITS_NONE; // $timeformat units
int m_timeFormatPrecision = 0; // $timeformat number of decimal places
int m_timeFormatWidth = 20; // $timeformat character width
// CONSTRUCTORS
Serialized();
~Serialized() = default;
} m_s;
mutable VerilatedMutex m_timeDumpMutex; // Protect misc slow strings
std::string m_timeFormatSuffix VL_GUARDED_BY(m_timeDumpMutex); // $timeformat printf format
std::string m_dumpfile VL_GUARDED_BY(m_timeDumpMutex); // $dumpfile setting
struct NonSerialized final { // Non-serialized information
// These are reloaded from on command-line settings, so do not need to persist
// Fast path
uint64_t m_profExecStart = 1; // +prof+exec+start time
uint32_t m_profExecWindow = 2; // +prof+exec+window size
// Slow path
std::string m_coverageFilename; // +coverage+file filename
std::string m_profExecFilename; // +prof+exec+file filename
std::string m_profVltFilename; // +prof+vlt filename
std::string m_solverProgram; // SMT solver program
VlOs::DeltaCpuTime m_cpuTimeStart{false}; // CPU time, starts when create first model
VlOs::DeltaWallTime m_wallTimeStart{false}; // Wall time, starts when create first model
std::vector<traceBaseModelCb_t> m_traceBaseModelCbs; // Callbacks to traceRegisterModel
} m_ns;
mutable VerilatedMutex m_argMutex; // Protect m_argVec, m_argVecLoaded
// no need to be save-restored (serialized) the
// assumption is that the restore is allowed to pass different arguments
struct NonSerializedCommandArgs final {
// Medium speed
std::vector<std::string> m_argVec; // Argument list
bool m_argVecLoaded = false; // Ever loaded argument list
} m_args VL_GUARDED_BY(m_argMutex);
// Implementation details
const std::unique_ptr<VerilatedContextImpData> m_impdatap;
// Number of threads to use for simulation (size of m_threadPool + 1 for main thread)
unsigned m_threads = std::thread::hardware_concurrency();
// Number of threads in added models
unsigned m_threadsInModels = 0;
// 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()
// File I/O
// Not serialized
mutable VerilatedMutex m_fdMutex; // Protect m_fdps, m_fdFree
std::vector<FILE*> m_fdps VL_GUARDED_BY(m_fdMutex); // File descriptors
// List of free descriptors (SLOW - FOPEN/CLOSE only)
std::vector<IData> m_fdFree VL_GUARDED_BY(m_fdMutex);
// List of free descriptors in the MCT region [4, 32)
std::vector<IData> m_fdFreeMct VL_GUARDED_BY(m_fdMutex);
// Magic to check for bad construction
static constexpr uint64_t MAGIC = 0xC35F9A6E5298EE6EULL; // SHA256 "VerilatedContext"
uint64_t m_magic = MAGIC;
private:
// CONSTRUCTORS
VL_UNCOPYABLE(VerilatedContext);
public:
/// Construct context. Also sets Verilated::threadContextp to the created context.
VerilatedContext();
~VerilatedContext();
// METHODS - User called
/// Return if assertions enabled
bool assertOn() const VL_MT_SAFE;
/// Enable all assertion types
void assertOn(bool flag) VL_MT_SAFE;
/// Get enabled status for given assertion types
bool assertOnGet(VerilatedAssertType_t type,
VerilatedAssertDirectiveType_t directive) const VL_MT_SAFE;
/// Set enabled status for given assertion types
void assertOnSet(VerilatedAssertType_t types,
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE;
/// Clear enabled status for given assertion types
void assertOnClear(VerilatedAssertType_t types,
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE;
/// Return if calculating of unused signals (for traces)
bool calcUnusedSigs() const VL_MT_SAFE { return m_s.m_calcUnusedSigs; }
/// Enable calculation of unused signals (for traces)
void calcUnusedSigs(bool flag) VL_MT_SAFE;
/// Record command-line arguments, for retrieval by $test$plusargs/$value$plusargs,
/// and for parsing +verilator+ run-time arguments.
/// This should be called before the first model is created.
void commandArgs(int argc, const char** argv) VL_MT_SAFE_EXCLUDES(m_argMutex);
void commandArgs(int argc, char** argv) VL_MT_SAFE {
commandArgs(argc, const_cast<const char**>(argv));
}
/// Add a command-line argument to existing arguments
void commandArgsAdd(int argc, const char** argv) VL_MT_SAFE_EXCLUDES(m_argMutex);
/// Match plusargs with a given prefix. Returns static char* valid only for a single call
const char* commandArgsPlusMatch(const char* prefixp) VL_MT_SAFE_EXCLUDES(m_argMutex);
/// Return VerilatedCovContext, allocate if needed
/// Note if get unresolved reference then likely forgot to link verilated_cov.cpp
VerilatedCovContext* coveragep() VL_MT_SAFE;
/// Return debug level
static inline int debug() VL_MT_SAFE; /// Set debug level
/// Debug is currently global, but for forward compatibility have a per-context method
static inline void debug(int val) VL_MT_SAFE;
/// Return current number of errors/assertions
int errorCount() const VL_MT_SAFE { return m_s.m_errorCount; }
/// Set current number of errors/assertions
void errorCount(int val) VL_MT_SAFE;
/// Increment current number of errors/assertions
void errorCountInc() VL_MT_SAFE;
/// Return number of errors/assertions before stop
int errorLimit() const VL_MT_SAFE { return m_s.m_errorLimit; }
/// Set number of errors/assertions before stop
void errorLimit(int val) VL_MT_SAFE;
/// Return if to throw fatal error on $stop/non-fatal
bool fatalOnError() const VL_MT_SAFE { return m_s.m_fatalOnError; }
/// Set to throw fatal error on $stop/non-fatal error
void fatalOnError(bool flag) VL_MT_SAFE;
/// Return if to throw fatal error on VPI errors
bool fatalOnVpiError() const VL_MT_SAFE { return m_s.m_fatalOnVpiError; }
/// Set to throw fatal error on VPI errors
void fatalOnVpiError(bool flag) VL_MT_SAFE;
/// Return if got a $stop or non-fatal error
bool gotError() const VL_MT_SAFE { return m_s.m_gotError; }
/// Set if got a $stop or non-fatal error
void gotError(bool flag) VL_MT_SAFE;
/// Return if got a $finish or $stop/error
bool gotFinish() const VL_MT_SAFE { return m_s.m_gotFinish; }
/// Set if got a $finish or $stop/error
void gotFinish(bool flag) VL_MT_SAFE;
/// Return if quiet enabled
bool quiet() const VL_MT_SAFE { return m_s.m_quiet; }
/// Enable quiet (also prevents need for OS calls to get CPU time)
void quiet(bool flag) VL_MT_SAFE;
/// Return randReset value
int randReset() VL_MT_SAFE { return m_s.m_randReset; }
/// Select initial value of otherwise uninitialized signals.
/// 0 = Set to zeros
/// 1 = Set all bits to one
/// 2 = Randomize all bits
void randReset(int val) VL_MT_SAFE;
/// Set default random seed, 0 = seed it automatically
int randSeed() const VL_MT_SAFE { return m_s.m_randSeed; }
/// Return default random seed
void randSeed(int val) VL_MT_SAFE;
/// Return statistic: CPU time delta from model created until now
double statCpuTimeSinceStart() const VL_MT_SAFE_EXCLUDES(m_mutex);
/// Return statistic: Wall time delta from model created until now
double statWallTimeSinceStart() const VL_MT_SAFE_EXCLUDES(m_mutex);
/// Print statistics summary (if not quiet)
void statsPrintSummary() VL_MT_UNSAFE;
// Time handling
/// Returns current simulation time in units of timeprecision().
///
/// How Verilator runtime gets the current simulation time:
///
/// * If using SystemC, time comes from the SystemC kernel-defined
/// sc_time_stamp64(). User's wrapper must not call
/// SimulationContext::time(value) nor timeInc(value).
///
/// * Else, if SimulationContext::time(value) or
/// SimulationContext::timeInc(value) is ever called with non-zero,
/// then time will come via the context. This allows multiple contexts
/// to exist and have different simulation times. This must not be used
/// with SystemC. Note Verilated::time(value) and
/// Verilated::timeInc(value) call into SimulationContext::time and
/// timeInc, operating on the thread's context.
///
/// * Else, if VL_TIME_STAMP64 is defined, time comes from the legacy
/// 'uint64_t vl_time_stamp64()' which must a function be defined by
/// the user's wrapper.
///
/// * Else, time comes from the legacy 'double sc_time_stamp()' which
/// must be a function defined by the user's wrapper.
inline uint64_t time() const VL_MT_SAFE;
/// Set current simulation time. See time() for side effect details
void time(uint64_t value) VL_MT_SAFE { m_s.m_time = value; }
/// Advance current simulation time. See time() for side effect details
void timeInc(uint64_t add) VL_MT_UNSAFE { m_s.m_time += add; }
/// Return time units as power-of-ten
int timeunit() const VL_MT_SAFE { return -m_s.m_timeunit; }
/// Set time units as power-of-ten
void timeunit(int value) VL_MT_SAFE;
/// Return time units as IEEE-standard text
const char* timeunitString() const VL_MT_SAFE;
/// Get time precision as power-of-ten
int timeprecision() const VL_MT_SAFE { return -m_s.m_timeprecision; }
/// Return time precision as power-of-ten
inline void timeprecision(int value) VL_MT_SAFE;
/// 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; }
/// Get number of threads in added models (for statistical use only)
unsigned threadsInModels() const { return m_threadsInModels; }
/// 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);
/// Trace signals in models within the context; called by application code
void trace(VerilatedTraceBaseC* tfp, int levels, int options = 0);
/// Allow traces to at some point be enabled (disables some optimizations)
void traceEverOn(bool flag) VL_MT_SAFE {
if (flag) calcUnusedSigs(true);
}
/// For debugging, print much of the Verilator internal state.
/// The output of this function may change in future
/// releases - contact the authors before production use.
void internalsDump() const VL_MT_SAFE;
/// For debugging, print text list of all scope names with
/// dpiImport/Export context. This function may change in future
/// releases - contact the authors before production use.
void scopesDump() const VL_MT_SAFE;
// METHODS - public but for internal use only
// Internal: access to implementation class
VerilatedContextImp* impp() VL_MT_SAFE { return reinterpret_cast<VerilatedContextImp*>(this); }
const VerilatedContextImp* impp() const VL_MT_SAFE {
return reinterpret_cast<const VerilatedContextImp*>(this);
}
// Internal: Model and thread setup
void addModel(VerilatedModel*);
VerilatedVirtualBase* threadPoolp();
void prepareClone();
VerilatedVirtualBase* threadPoolpOnClone();
VerilatedVirtualBase*
enableExecutionProfiler(VerilatedVirtualBase* (*construct)(VerilatedContext&));
// Internal: coverage
std::string coverageFilename() const VL_MT_SAFE;
void coverageFilename(const std::string& flag) VL_MT_SAFE;
// Internal: $dumpfile
std::string dumpfile() const VL_MT_SAFE_EXCLUDES(m_timeDumpMutex);
void dumpfile(const std::string& flag) VL_MT_SAFE_EXCLUDES(m_timeDumpMutex);
std::string dumpfileCheck() const VL_MT_SAFE_EXCLUDES(m_timeDumpMutex);
// Internal: --prof-exec related settings
uint64_t profExecStart() const VL_MT_SAFE { return m_ns.m_profExecStart; }
void profExecStart(uint64_t flag) VL_MT_SAFE;
uint32_t profExecWindow() const VL_MT_SAFE { return m_ns.m_profExecWindow; }
void profExecWindow(uint64_t flag) VL_MT_SAFE;
std::string profExecFilename() const VL_MT_SAFE;
void profExecFilename(const std::string& flag) VL_MT_SAFE;
std::string profVltFilename() const VL_MT_SAFE;
void profVltFilename(const std::string& flag) VL_MT_SAFE;
// Internal: SMT solver program
std::string solverProgram() const VL_MT_SAFE;
void solverProgram(const std::string& flag) VL_MT_SAFE;
// Internal: Find scope
const VerilatedScope* scopeFind(const char* namep) const VL_MT_SAFE;
const VerilatedScopeNameMap* scopeNameMap() VL_MT_SAFE;
// Internal: Serialization setup
static constexpr size_t serialized1Size() VL_PURE { return sizeof(m_s); }
void* serialized1Ptr() VL_MT_UNSAFE { return &m_s; }
// Internal: trace registration
void traceBaseModelCbAdd(traceBaseModelCb_t cb) VL_MT_SAFE;
// Internal: Check magic number
static void checkMagic(const VerilatedContext* contextp);
void selfTestClearMagic() { m_magic = 0x2; }
};
//===========================================================================
// Verilator symbol table base class
// Used for internal VPI implementation, and introspection into scopes
class VerilatedSyms VL_NOT_FINAL {
public: // But for internal use only
// MEMBERS
// Keep first so is at zero offset for fastest code
VerilatedContext* const _vm_contextp__; // Context for current model
VerilatedEvalMsgQueue* __Vm_evalMsgQp;
explicit VerilatedSyms(VerilatedContext* contextp); // Pass null for default context
~VerilatedSyms();
VL_UNCOPYABLE(VerilatedSyms);
};
//===========================================================================
// Verilator scope information class
// Used for internal VPI implementation, and introspection into scopes
class VerilatedScope final {
public:
enum Type : uint8_t {
SCOPE_MODULE,
SCOPE_OTHER,
SCOPE_PACKAGE
}; // Type of a scope, currently only module and package are interesting
private:
// Fastpath:
VerilatedSyms* m_symsp = nullptr; // Symbol table
void** m_callbacksp = nullptr; // Callback table pointer (Fastpath)
int m_funcnumMax = 0; // Maximum function number stored (Fastpath)
// 4 bytes padding (on -m64), for rent.
VerilatedVarNameMap* m_varsp = nullptr; // Variable map
const char* m_namep = nullptr; // Scope name (Slowpath)
const char* m_identifierp = nullptr; // Identifier of scope (with escapes removed)
const char* m_defnamep = nullptr; // Definition name (SCOPE_MODULE only)
int8_t m_timeunit = 0; // Timeunit in negative power-of-10
Type m_type = SCOPE_OTHER; // Type of the scope
public: // But internals only - called from VerilatedModule's
VerilatedScope() = default;
~VerilatedScope();
void configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp,
const char* identifier, const char* defnamep, int8_t timeunit,
const Type& type) VL_MT_UNSAFE;
void exportInsert(int finalize, const char* namep, void* cb) VL_MT_UNSAFE;
void varInsert(int finalize, const char* namep, void* datap, bool isParam,
VerilatedVarType vltype, int vlflags, int dims, ...) VL_MT_UNSAFE;
// ACCESSORS
const char* name() const VL_MT_SAFE_POSTINIT { return m_namep; }
const char* identifier() const VL_MT_SAFE_POSTINIT { return m_identifierp; }
const char* defname() const VL_MT_SAFE_POSTINIT { return m_defnamep; }
int8_t timeunit() const VL_MT_SAFE_POSTINIT { return m_timeunit; }
VerilatedSyms* symsp() const VL_MT_SAFE_POSTINIT { return m_symsp; }
VerilatedVar* varFind(const char* namep) const VL_MT_SAFE_POSTINIT;
VerilatedVarNameMap* varsp() const VL_MT_SAFE_POSTINIT { return m_varsp; }
void scopeDump() const;
void* exportFindError(int funcnum) const VL_MT_SAFE;
static void* exportFindNullError(int funcnum) VL_MT_SAFE;
static void* exportFind(const VerilatedScope* scopep, int funcnum) VL_MT_SAFE {
if (VL_UNLIKELY(!scopep)) return exportFindNullError(funcnum);
if (VL_LIKELY(funcnum < scopep->m_funcnumMax)) {
// m_callbacksp must be declared, as Max'es are > 0
return scopep->m_callbacksp[funcnum];
} else { // LCOV_EXCL_LINE
return scopep->exportFindError(funcnum); // LCOV_EXCL_LINE
}
}
Type type() const { return m_type; }
};
class VerilatedHierarchy final {
public:
static void add(VerilatedScope* fromp, VerilatedScope* top);
static void remove(VerilatedScope* fromp, VerilatedScope* top);
};
//===========================================================================
/// Verilator global static information class
class Verilated final {
// MEMBERS
// Internal Note: There should be no Serialized state in Verilated::,
// instead serialized state should all be in VerilatedContext:: as by
// definition it needs to vary per-simulation
// Internal note: Globals may multi-construct, see verilated.cpp top.
// Debug is reloaded from on command-line settings, so do not need to persist
static int s_debug; // See accessors... only when VL_DEBUG set
static VerilatedContext* s_lastContextp; // Last context constructed/attached
// Not covered by mutex, as per-thread
static thread_local struct ThreadLocal {
// No non-POD objects here due to this:
// Internal note: Globals may multi-construct, see verilated.cpp top.
// Fast path
VerilatedContext* t_contextp = nullptr; // Thread's context
uint32_t t_mtaskId = 0; // mtask# executing on this thread
// Messages maybe pending on thread, needs end-of-eval calls
uint32_t t_endOfEvalReqd = 0;
const VerilatedScope* t_dpiScopep = nullptr; // DPI context scope
const char* t_dpiFilename = nullptr; // DPI context filename
int t_dpiLineno = 0; // DPI context line number
ThreadLocal() = default;
~ThreadLocal() = default;
} t_s;
friend struct VerilatedInitializer;
// CONSTRUCTORS
VL_UNCOPYABLE(Verilated);
public:
// METHODS - User called
#ifdef VL_DEBUG
/// Return debug level
/// When multithreaded this may not immediately react to another thread
/// changing the level (no mutex)
static int debug() VL_MT_SAFE { return s_debug; }
#else
/// Return constant 0 debug level, so C++'s optimizer rips up
static constexpr int debug() VL_PURE { return 0; }
#endif
/// Enable debug of internal verilated code
static void debug(int level) VL_MT_SAFE;
/// Set the last VerilatedContext accessed
/// Generally threadContextp(value) should be called instead
static void lastContextp(VerilatedContext* contextp) VL_MT_SAFE { s_lastContextp = contextp; }
/// Return the last VerilatedContext accessed
/// Generally threadContextp() should be called instead
static VerilatedContext* lastContextp() VL_MT_SAFE {
if (!s_lastContextp) lastContextp(defaultContextp());
return s_lastContextp;
}
/// Set the VerilatedContext used by the current thread
/// If using multiple contexts, and threads are created by the user's
/// wrapper (not Verilator itself) then this must be called to set the
/// context that applies to each thread
static void threadContextp(VerilatedContext* contextp) VL_MT_SAFE {
t_s.t_contextp = contextp;
lastContextp(contextp);
}
/// Return the VerilatedContext for the current thread
static VerilatedContext* threadContextp() VL_MT_SAFE {
if (VL_UNLIKELY(!t_s.t_contextp)) t_s.t_contextp = lastContextp();
return t_s.t_contextp;
}
/// Return the global VerilatedContext, used if none created by user
static VerilatedContext* defaultContextp() VL_MT_SAFE {
static VerilatedContext s_s;
return &s_s;
}
#ifndef VL_NO_LEGACY
/// Return VerilatedContext::assertOn() using current thread's VerilatedContext
static bool assertOn() VL_MT_SAFE { return Verilated::threadContextp()->assertOn(); }
/// Call VerilatedContext::assertOn using current thread's VerilatedContext
static void assertOn(bool flag) VL_MT_SAFE { Verilated::threadContextp()->assertOn(flag); }
/// Return VerilatedContext::calcUnusedSigs using current thread's VerilatedContext
static bool calcUnusedSigs() VL_MT_SAFE {
return Verilated::threadContextp()->calcUnusedSigs();
}
/// Call VerilatedContext::calcUnusedSigs using current thread's VerilatedContext
static void calcUnusedSigs(bool flag) VL_MT_SAFE {
Verilated::threadContextp()->calcUnusedSigs(flag);
}
/// Call VerilatedContext::commandArgs using current thread's VerilatedContext
static void commandArgs(int argc, const char** argv) VL_MT_SAFE {
Verilated::threadContextp()->commandArgs(argc, argv);
}
static void commandArgs(int argc, char** argv) VL_MT_SAFE {
commandArgs(argc, const_cast<const char**>(argv));
}
/// Call VerilatedContext::commandArgsAdd using current thread's VerilatedContext
static void commandArgsAdd(int argc, const char** argv) {
Verilated::threadContextp()->commandArgsAdd(argc, argv);
}
/// Return VerilatedContext::commandArgsPlusMatch using current thread's VerilatedContext
static const char* commandArgsPlusMatch(const char* prefixp) VL_MT_SAFE {
return Verilated::threadContextp()->commandArgsPlusMatch(prefixp);
}
/// Return VerilatedContext::errorLimit using current thread's VerilatedContext
static int errorLimit() VL_MT_SAFE { return Verilated::threadContextp()->errorLimit(); }
/// Call VerilatedContext::errorLimit using current thread's VerilatedContext
static void errorLimit(int val) VL_MT_SAFE { Verilated::threadContextp()->errorLimit(val); }
/// Return VerilatedContext::fatalOnError using current thread's VerilatedContext
static bool fatalOnError() VL_MT_SAFE { return Verilated::threadContextp()->fatalOnError(); }
/// Call VerilatedContext::fatalOnError using current thread's VerilatedContext
static void fatalOnError(bool flag) VL_MT_SAFE {
Verilated::threadContextp()->fatalOnError(flag);
}
/// Return VerilatedContext::fatalOnVpiError using current thread's VerilatedContext
static bool fatalOnVpiError() VL_MT_SAFE {
return Verilated::threadContextp()->fatalOnVpiError();
}
/// Call VerilatedContext::fatalOnVpiError using current thread's VerilatedContext
static void fatalOnVpiError(bool flag) VL_MT_SAFE {
Verilated::threadContextp()->fatalOnVpiError(flag);
}
/// Return VerilatedContext::gotError using current thread's VerilatedContext
static bool gotError() VL_MT_SAFE { return Verilated::threadContextp()->gotError(); }
/// Call VerilatedContext::gotError using current thread's VerilatedContext
static void gotError(bool flag) VL_MT_SAFE { Verilated::threadContextp()->gotError(flag); }
/// Return VerilatedContext::gotFinish using current thread's VerilatedContext
static bool gotFinish() VL_MT_SAFE { return Verilated::threadContextp()->gotFinish(); }
/// Call VerilatedContext::gotFinish using current thread's VerilatedContext
static void gotFinish(bool flag) VL_MT_SAFE { Verilated::threadContextp()->gotFinish(flag); }
/// Return VerilatedContext::randReset using current thread's VerilatedContext
static int randReset() VL_MT_SAFE { return Verilated::threadContextp()->randReset(); }
/// Call VerilatedContext::randReset using current thread's VerilatedContext
static void randReset(int val) VL_MT_SAFE { Verilated::threadContextp()->randReset(val); }
/// Return VerilatedContext::randSeed using current thread's VerilatedContext
static int randSeed() VL_MT_SAFE { return Verilated::threadContextp()->randSeed(); }
/// Call VerilatedContext::randSeed using current thread's VerilatedContext
static void randSeed(int val) VL_MT_SAFE { Verilated::threadContextp()->randSeed(val); }
/// Return VerilatedContext::time using current thread's VerilatedContext
static uint64_t time() VL_MT_SAFE { return Verilated::threadContextp()->time(); }
/// Call VerilatedContext::time using current thread's VerilatedContext
static void time(uint64_t val) VL_MT_SAFE { Verilated::threadContextp()->time(val); }
/// Call VerilatedContext::timeInc using current thread's VerilatedContext
static void timeInc(uint64_t add) VL_MT_UNSAFE { Verilated::threadContextp()->timeInc(add); }
// Deprecated
static int timeunit() VL_MT_SAFE { return Verilated::threadContextp()->timeunit(); }
static int timeprecision() VL_MT_SAFE { return Verilated::threadContextp()->timeprecision(); }
/// Call VerilatedContext::tracesEverOn using current thread's VerilatedContext
static void traceEverOn(bool flag) VL_MT_SAFE {
Verilated::threadContextp()->traceEverOn(flag);
}
#endif
/// Callback typedef for addFlushCb, addExitCb
using VoidPCb = void (*)(void*);
/// Add callback to run on global flush
static void addFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE;
/// Remove callback to run on global flush
static void removeFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE;
/// Run flush callbacks registered with addFlushCb
static void runFlushCallbacks() VL_MT_SAFE;
#ifndef VL_NO_LEGACY
static void flushCall() VL_MT_SAFE { runFlushCallbacks(); } // Deprecated
#endif
/// Add callback to run prior to exit termination
static void addExitCb(VoidPCb cb, void* datap) VL_MT_SAFE;
/// Remove callback to run prior to exit termination
static void removeExitCb(VoidPCb cb, void* datap) VL_MT_SAFE;
/// Run exit callbacks registered with addExitCb
static void runExitCallbacks() VL_MT_SAFE;
/// Return product name for (at least) VPI
static const char* productName() VL_PURE;
/// Return product version for (at least) VPI
static const char* productVersion() VL_PURE;
/// Call OS to make a directory
static void mkdir(const char* dirname) VL_MT_UNSAFE;
/// When multithreaded, quiesce the model to prepare for trace/saves/coverage
/// This may only be called when no locks are held.
static void quiesce() VL_MT_SAFE;
#ifndef VL_NO_LEGACY
/// For debugging, print much of the Verilator internal state.
/// The output of this function may change in future
/// releases - contact the authors before production use.
static void internalsDump() VL_MT_SAFE { Verilated::threadContextp()->internalsDump(); }
/// For debugging, print text list of all scope names with
/// dpiImport/Export context. This function may change in future
/// releases - contact the authors before production use.
static void scopesDump() VL_MT_SAFE { Verilated::threadContextp()->scopesDump(); }
// Internal: Find scope
static const VerilatedScope* scopeFind(const char* namep) VL_MT_SAFE {
return Verilated::threadContextp()->scopeFind(namep);
}
static const VerilatedScopeNameMap* scopeNameMap() VL_MT_SAFE {
return Verilated::threadContextp()->scopeNameMap();
}
#endif
// METHODS - INTERNAL USE ONLY (but public due to what uses it)
// Internal: Create a new module name by concatenating two strings
// Returns pointer to thread-local static data (overwritten on next call)
static const char* catName(const char* n1, const char* n2,
const char* delimiter = ".") VL_MT_SAFE;
// Internal: Throw signal assertion
static void nullPointerError(const char* filename, int linenum) VL_ATTR_NORETURN VL_MT_SAFE;
static void overWidthError(const char* signame) VL_ATTR_NORETURN VL_MT_SAFE;
static void scTimePrecisionError(int sc_prec, int vl_prec) VL_ATTR_NORETURN VL_MT_SAFE;
static void scTraceBeforeElaborationError() VL_ATTR_NORETURN VL_MT_SAFE;
static void stackCheck(QData needSize) VL_MT_UNSAFE;
// Internal: Get and set DPI context
static const VerilatedScope* dpiScope() VL_MT_SAFE { return t_s.t_dpiScopep; }
static void dpiScope(const VerilatedScope* scopep) VL_MT_SAFE { t_s.t_dpiScopep = scopep; }
static void dpiContext(const VerilatedScope* scopep, const char* filenamep,
int lineno) VL_MT_SAFE {
t_s.t_dpiScopep = scopep;
t_s.t_dpiFilename = filenamep;
t_s.t_dpiLineno = lineno;
}
static void dpiClearContext() VL_MT_SAFE { t_s.t_dpiScopep = nullptr; }
static bool dpiInContext() VL_MT_SAFE { return t_s.t_dpiScopep != nullptr; }
static const char* dpiFilenamep() VL_MT_SAFE { return t_s.t_dpiFilename; }
static int dpiLineno() VL_MT_SAFE { return t_s.t_dpiLineno; }
static int exportFuncNum(const char* namep) VL_MT_SAFE;
// Internal: Set the mtaskId, called when an mtask starts
// Per thread, so no need to be in VerilatedContext
static uint32_t mtaskId() VL_MT_SAFE { return t_s.t_mtaskId; }
static void mtaskId(uint32_t id) VL_MT_SAFE { t_s.t_mtaskId = id; }
static void endOfEvalReqdInc() VL_MT_SAFE { ++t_s.t_endOfEvalReqd; }
static void endOfEvalReqdDec() VL_MT_SAFE { --t_s.t_endOfEvalReqd; }
// Internal: Called at end of each thread mtask, before finishing eval
static void endOfThreadMTask(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
mtaskId(0);
if (VL_UNLIKELY(t_s.t_endOfEvalReqd)) endOfThreadMTaskGuts(evalMsgQp);
}
// Internal: Called at end of eval loop
static void endOfEval(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE;
private:
static void endOfThreadMTaskGuts(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE;
};
void VerilatedContext::debug(int val) VL_MT_SAFE { Verilated::debug(val); }
int VerilatedContext::debug() VL_MT_SAFE { return Verilated::debug(); }
//=========================================================================
// Data Types
#include "verilated_types.h"
//=========================================================================
// Functions
#include "verilated_funcs.h"
//======================================================================
void VerilatedContext::timeprecision(int value) VL_MT_SAFE {
if (value < 0) value = -value; // Stored as 0..15
#if VM_SC
int sc_prec = 99;
#endif
{
const VerilatedLockGuard lock{m_mutex};
m_s.m_timeprecision = value;
#if VM_SC
const sc_core::sc_time sc_res = sc_core::sc_get_time_resolution();
if (sc_res == sc_core::sc_time(1, sc_core::SC_SEC)) {
sc_prec = 0;
} else if (sc_res == sc_core::sc_time(1, sc_core::SC_MS)) {
sc_prec = 3;
} else if (sc_res == sc_core::sc_time(1, sc_core::SC_US)) {
sc_prec = 6;
} else if (sc_res == sc_core::sc_time(1, sc_core::SC_NS)) {
sc_prec = 9;
} else if (sc_res == sc_core::sc_time(1, sc_core::SC_PS)) {
sc_prec = 12;
} else if (sc_res == sc_core::sc_time(1, sc_core::SC_FS)) {
sc_prec = 15;
}
// SC_AS, SC_ZS, SC_YS not supported as no Verilog equivalent; will error below
#endif
}
#if VM_SC
if (VL_UNLIKELY(value != sc_prec)) Verilated::scTimePrecisionError(sc_prec, value);
#endif
}
#undef VERILATOR_VERILATED_H_INTERNAL_
#endif // Guard