mirror of
https://github.com/verilator/verilator.git
synced 2026-09-04 08:33:38 +02:00
The loops modelling the SystemVerilog scheduling regions are no longer generated. They now live in 'VerilatedEvalLoop' in the runtime library. The generated model holds one as a member, passing itself to it, and exposes each evaluation entry point to it as a pure virtual method on VerilatedModel. The model's 'eval' and 'eval_step' remain the top level entry points, and are backward compatible. V3Sched no longer emits '_eval' or '_eval_settle', etc.. Instead every evaluation entry point called from the runtime is enumerated by 'VEval', Scheduling creates all entry points, for all scheduling regions, even if they are empty, and the runtime eval loop calls everything unconditionally. If regions are empty, this is simply a call to an empty function. This will hurt performance on very small models, but should not be noticeable on anything meaningful, so it is likely best to keep to reduce complexity. A scheduling entry points evaluate a single iteration and returns whether it did any work, they are effectively the previous `_eval_phase_*` functions.
1280 lines
56 KiB
C++
1280 lines
56 KiB
C++
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
|
//*************************************************************************
|
|
//
|
|
// Code available from: https://verilator.org
|
|
//
|
|
// 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-FileCopyrightText: 2003-2026 Wilson Snyder
|
|
// 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 "verilated_config.h"
|
|
#include "verilatedos.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 <typename, typename>
|
|
class VerilatedTrace;
|
|
class VerilatedTraceBaseC;
|
|
class VerilatedTraceConfig;
|
|
class VerilatedVar;
|
|
class VerilatedVarNameMap;
|
|
class VerilatedVcd;
|
|
class VerilatedVcdC;
|
|
class VerilatedVcdSc;
|
|
|
|
//=========================================================================
|
|
// Basic types
|
|
|
|
// Type letters
|
|
// 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 VlWide
|
|
// 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
|
|
// U = VlUnpacked;
|
|
// R = VlQueue;
|
|
// clang-format on
|
|
|
|
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 VlWide
|
|
VLVT_STRING, // C++ string
|
|
VLVT_REAL, // AKA double
|
|
VLVT_STRUCT, // SystemVerilog unpacked struct
|
|
VLVT_UNION // SystemVerilog unpacked union
|
|
};
|
|
|
|
enum VerilatedVarFlags : uint32_t {
|
|
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
|
|
VLVF_CONTINUOUSLY = (1 << 11), // Is continously assigned
|
|
VLVF_FORCEABLE = (1 << 12), // Forceable
|
|
VLVF_SIGNED = (1 << 13), // Signed integer
|
|
VLVF_BITVAR = (1 << 14), // Four state bit (vs two state logic)
|
|
VLVF_NET = (1 << 15) // Net object
|
|
};
|
|
|
|
// One VPI-visible variable, consumed by VerilatedScope::varsInsertFromTable();
|
|
// replaces per-variable varInsert() calls, which compiles faster at scale.
|
|
struct VlVarTableEntry final {
|
|
static constexpr int kMaxDims = 3; // Max packed+unpacked dims a table row holds
|
|
const char* namep; // VPI-facing (protected) variable name, string literal
|
|
size_t byteOffset; // offsetof of storage member from module instance base
|
|
VerilatedVarType vltype;
|
|
uint32_t vlflags; // Direction + flags (VLVD_*/VLVF_*)
|
|
uint8_t udims; // udims + pdims <= kMaxDims
|
|
uint8_t pdims;
|
|
// (left,right) pairs: unpacked dims first, then packed; int32_t since large
|
|
// unpacked memories exceed int16 range
|
|
int32_t dims[kMaxDims * 2];
|
|
};
|
|
|
|
// 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),
|
|
};
|
|
|
|
/// Runtime query selector for assertion-control state
|
|
enum class VerilatedAssertCtlQuery : uint8_t {
|
|
ASSERT_CTL_ON,
|
|
ASSERT_CTL_KILL,
|
|
ASSERT_CTL_PASS_ON_VACUOUS,
|
|
ASSERT_CTL_PASS_ON_NONVACUOUS,
|
|
ASSERT_CTL_FAIL_ON,
|
|
};
|
|
using VerilatedAssertType_t = std::underlying_type<VerilatedAssertType>::type;
|
|
using VerilatedAssertDirectiveType_t = std::underlying_type<VerilatedAssertDirectiveType>::type;
|
|
|
|
// Type trait: whether T is a user-defined custom struct
|
|
template <typename>
|
|
struct VlIsCustomStruct : public std::false_type {};
|
|
|
|
// Type trait: used to detect if array element is a custom struct (e.g. for struct arrays)
|
|
template <typename T>
|
|
struct VlContainsCustomStruct : VlIsCustomStruct<T> {};
|
|
|
|
//=========================================================================
|
|
// 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
|
|
};
|
|
|
|
class VlExecutionProfilerBase;
|
|
|
|
//=========================================================================
|
|
/// 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:
|
|
bool m_didInit = false; // Time 0 initialization has run
|
|
|
|
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 <typename, typename>
|
|
friend class VerilatedTrace;
|
|
friend class VerilatedEvalLoop;
|
|
|
|
// Run-time trace configuration requested by this model
|
|
virtual std::unique_ptr<VerilatedTraceConfig> traceConfig() const;
|
|
|
|
// Entry points called by VerilatedEvalLoop
|
|
virtual void evalBegin() = 0;
|
|
virtual void evalEnd() = 0;
|
|
virtual void evalStatic() = 0;
|
|
virtual void evalInitial() = 0;
|
|
virtual void evalSample() = 0;
|
|
virtual bool evalStl(bool firstIteration) = 0;
|
|
virtual bool evalIco(bool firstIteration) = 0;
|
|
virtual bool evalAct() = 0;
|
|
virtual bool evalInact() = 0;
|
|
virtual bool evalNba() = 0;
|
|
virtual bool evalObs() = 0;
|
|
virtual bool evalReact() = 0;
|
|
virtual void evalPostponed() = 0;
|
|
virtual void dumpTriggersStl() = 0;
|
|
virtual void dumpTriggersIco() = 0;
|
|
virtual void dumpTriggersAct() = 0;
|
|
virtual void dumpTriggersNba() = 0;
|
|
virtual void dumpTriggersObs() = 0;
|
|
virtual void dumpTriggersReact() = 0;
|
|
|
|
// Runs 'final' blocks at the end of the simulation
|
|
virtual void evalFinal() = 0;
|
|
};
|
|
|
|
//=========================================================================
|
|
/// Evaluation loop calling a VerilatedModel's entry points
|
|
|
|
class VerilatedEvalLoop final {
|
|
VL_UNCOPYABLE(VerilatedEvalLoop);
|
|
|
|
// MEMBERS
|
|
VerilatedModel& m_model; // The model this loop evaluates
|
|
const uint32_t m_convergeLimit; // --converge-limit from compiler command line
|
|
// Where to record --prof-exec sections, or null if not profiling
|
|
VlExecutionProfilerBase* m_profilerp = nullptr;
|
|
// Whether this is the top level model during profiling
|
|
bool m_profTopLevel = false;
|
|
|
|
public:
|
|
// CONSTRUCTORS
|
|
VerilatedEvalLoop(VerilatedModel& model, uint32_t convergeLimit)
|
|
: m_model{model}
|
|
, m_convergeLimit{convergeLimit} {}
|
|
|
|
// METHODS
|
|
// Evaluate a single time step of the SV scheduling model
|
|
void eval() {
|
|
if (VL_UNLIKELY(m_profilerp)) {
|
|
evalImpl<true>();
|
|
} else {
|
|
evalImpl<false>();
|
|
}
|
|
}
|
|
// Set --prof-exec profiler
|
|
void profiler(VlExecutionProfilerBase* profilerp, bool topLevel) {
|
|
m_profilerp = profilerp;
|
|
m_profTopLevel = topLevel;
|
|
}
|
|
|
|
private:
|
|
// Evaluate a time step, recording --prof-exec sections iff 'Profiling'.
|
|
template <bool Profiling>
|
|
void evalImpl();
|
|
// Check the iteration convergence
|
|
void checkConvergence(uint32_t iterCount, const char* namep,
|
|
void (VerilatedModel::*dumpTriggersp)() = nullptr) {
|
|
if (VL_UNLIKELY(iterCount > m_convergeLimit)) didNotConverge(namep, dumpTriggersp);
|
|
}
|
|
// Dump the region's triggers, if it has any, then report non-convergence and abort
|
|
void didNotConverge(const char* namep, void (VerilatedModel::*dumpTriggersp)());
|
|
};
|
|
|
|
//=========================================================================
|
|
// 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;
|
|
};
|
|
|
|
//===========================================================================
|
|
// Internal: Base of the '--prof-exec' execution profiler
|
|
//
|
|
// Implemented by VlExecutionProfiler, see verilated_profiler.h. Declared here
|
|
// so the evaluation loop can drive the profiler without naming it, as it is
|
|
// only linked when Verilated with --prof-exec.
|
|
|
|
class VlExecutionProfilerBase VL_NOT_FINAL : public VerilatedVirtualBase {
|
|
public:
|
|
// Mark the beginning of a section of execution
|
|
virtual void sectionPush(const char* namep) = 0;
|
|
// Mark the end of the innermost open section
|
|
virtual void sectionPop() = 0;
|
|
// Advance the profiling window at the start of a time step
|
|
virtual void configure() = 0;
|
|
};
|
|
|
|
//===========================================================================
|
|
/// 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;
|
|
// Build the assertion-control bit mask for the given assertion x directive types.
|
|
static uint32_t assertOnMask(VerilatedAssertType_t types,
|
|
VerilatedAssertDirectiveType_t directives) VL_PURE;
|
|
static constexpr size_t ASSERT_CONTROL_SLOT_COUNT = ASSERT_ON_WIDTH - 1;
|
|
// No termination request has stamped m_finishPendingTime yet
|
|
static constexpr uint64_t TIME_UNSET = ~0ULL;
|
|
|
|
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.
|
|
std::atomic<uint32_t> m_assertLock{0}; // Locked assertion bits (IEEE 1800-2023 20.11
|
|
// Lock/Unlock); same layout as m_assertOn. While
|
|
// a bit is locked, On/Off/Kill leave it unchanged.
|
|
std::atomic<uint32_t> m_assertPassOnVacuous{
|
|
std::numeric_limits<uint32_t>::max()}; // Enabled vacuous pass actions
|
|
std::atomic<uint32_t> m_assertPassOnNonvacuous{
|
|
std::numeric_limits<uint32_t>::max()}; // Enabled nonvacuous pass actions
|
|
std::atomic<uint32_t> m_assertFailOn{
|
|
std::numeric_limits<uint32_t>::max()}; // Enabled fail actions
|
|
std::array<std::atomic<uint32_t>, ASSERT_CONTROL_SLOT_COUNT> m_assertKill{};
|
|
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 = 1; // Random seed (default 1; +verilator+seed+0 picks at parse time)
|
|
static constexpr int 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
|
|
// A worker queues $finish before the main thread callback can set m_gotFinish.
|
|
std::atomic<uint32_t> m_finishPending{0}; // Number of queued $finish callbacks
|
|
std::atomic<uint64_t> m_finishPendingTime{TIME_UNSET}; // Time of the first callback
|
|
std::atomic<bool> m_assertCtlsLocked{
|
|
false}; // When true, all assertion-control updates are ignored
|
|
int m_stopReserved = 0; // Posted $stop requests not yet executed
|
|
bool m_executingFinal = false; // Running generated final() code
|
|
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_logFilename; // +log+file filename
|
|
std::string m_profExecFilename; // +prof+exec+file filename
|
|
std::string m_profVltFilename; // +prof+vlt filename
|
|
std::string m_solverLogFilename; // SMT solver log filename
|
|
std::string m_solverProgram; // SMT solver program
|
|
bool m_warnUnsatConstr = true; // Warn on unsatisfied constraints
|
|
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
|
|
int m_stdoutFD; // Duplicated stdout file descriptor
|
|
int m_stderrFD; // Duplicated stderr file descriptor
|
|
int m_logFD; // Log file descriptor
|
|
} 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 = VlOs::getProcessDefaultParallelism();
|
|
// Use numa automatic CPU-to-thread assignment
|
|
bool m_useNumaAssign = false;
|
|
// 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 assertion-control updates are locked. When locked, RTL assert
|
|
// control statements ($asserton/$assertoff/$assertcontrol) are ignored, as
|
|
// are updates from the C++ API.
|
|
bool assertCtlsLocked() const VL_MT_SAFE;
|
|
/// Lock/unlock assertion-control updates.
|
|
void assertCtlsLocked(bool flag) VL_MT_SAFE;
|
|
/// Apply assertion control for given control, assertion, and directive types
|
|
void assertCtl(uint32_t controlType, VerilatedAssertType_t types,
|
|
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE;
|
|
/// Get assertion-control runtime state. Boolean queries return 0/1, Kill returns
|
|
/// the generation count.
|
|
uint32_t assertCtlGet(VerilatedAssertCtlQuery query, VerilatedAssertType_t type,
|
|
VerilatedAssertDirectiveType_t directive) const 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;
|
|
/// Check if generated final() code is executing
|
|
bool executingFinal() const VL_MT_SAFE;
|
|
/// Set if generated final() code is executing
|
|
void executingFinal(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() const 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;
|
|
/// Return default random seed
|
|
int randSeed() const VL_MT_SAFE { return m_s.m_randSeed; }
|
|
/// Set default random seed, 0 = seed it automatically
|
|
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 as unit string
|
|
std::string timeWithUnitString() const VL_MT_SAFE;
|
|
/// 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);
|
|
|
|
/// Use numa automatic CPU-to-thread assignment.
|
|
bool useNumaAssign() const VL_MT_SAFE { return m_useNumaAssign; }
|
|
/// Set numa assignment of threads to cores
|
|
/// Defaults false; set true automatically when threads() called;
|
|
/// call this to override back to false if numa assignment not wanted.
|
|
void useNumaAssign(bool flag);
|
|
|
|
/// 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: Track $finish/$stop callbacks queued by worker threads
|
|
bool finishPending() const VL_MT_SAFE { return m_ns.m_finishPending.load() != 0; }
|
|
void finishPendingInc() VL_MT_SAFE {
|
|
++m_ns.m_finishPending;
|
|
uint64_t unset = TIME_UNSET;
|
|
m_ns.m_finishPendingTime.compare_exchange_strong(unset, time());
|
|
}
|
|
void finishPendingDec() VL_MT_SAFE {
|
|
const uint32_t previous = m_ns.m_finishPending.fetch_sub(1);
|
|
assert(previous > 0);
|
|
if (previous == 1 && !gotFinish()) m_ns.m_finishPendingTime = TIME_UNSET;
|
|
}
|
|
// Internal: Time of the first termination request, else the current time
|
|
uint64_t finishPendingTime() const VL_MT_SAFE {
|
|
const uint64_t stamped = m_ns.m_finishPendingTime.load();
|
|
return stamped == TIME_UNSET ? time() : stamped;
|
|
}
|
|
// Internal: Reserve a posted $stop, returning true if it reaches the termination limit
|
|
bool stopRequestReserve(bool maybe) VL_MT_SAFE;
|
|
void stopRequestRelease() VL_MT_SAFE;
|
|
|
|
// 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(const VerilatedModel* modelp);
|
|
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: logfile
|
|
std::string logFilename() const VL_MT_SAFE;
|
|
void logFilename(const std::string& flag) VL_MT_SAFE;
|
|
bool logOutputToFile() const VL_MT_SAFE;
|
|
void logOutputToFile(bool append) VL_MT_SAFE;
|
|
void logRestoreOutput() 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: Solver log filename
|
|
std::string solverLogFilename() const VL_MT_SAFE;
|
|
void solverLogFilename(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: Control display of unsatisfied constraints
|
|
bool warnUnsatConstr() const VL_MT_SAFE { return m_ns.m_warnUnsatConstr; }
|
|
void warnUnsatConstr(bool flag) VL_MT_SAFE { m_ns.m_warnUnsatConstr = flag; }
|
|
|
|
// 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);
|
|
|
|
virtual const char* name() const = 0;
|
|
};
|
|
|
|
//===========================================================================
|
|
// Verilator scope information class
|
|
// Used for internal VPI implementation, and introspection into scopes
|
|
|
|
struct VlScopeTableEntry; // Defined below VerilatedScope; used by scopesConstructFromTable()
|
|
|
|
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* const m_symsp; // 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* const m_namep; // Scope name (Slowpath)
|
|
const char* const m_identifierp; // Identifier of scope (with escapes removed)
|
|
const char* const m_defnamep; // Definition name (SCOPE_MODULE only)
|
|
const int8_t m_timeunit; // Timeunit in negative power-of-10
|
|
const Type m_type; // Type of the scope
|
|
|
|
public: // But internals only - called from verilated modules, VerilatedSyms
|
|
VerilatedScope(VerilatedSyms* symsp, const char* suffixp, const char* identifier,
|
|
const char* defnamep, int8_t timeunit, Type type);
|
|
~VerilatedScope();
|
|
|
|
void exportInsert(int finalize, const char* namep, void* cb) VL_MT_UNSAFE;
|
|
VerilatedVar* varInsert(const char* namep, void* datap, bool isParam, VerilatedVarType vltype,
|
|
int vlflags, int udims, int pdims, ...) VL_MT_UNSAFE;
|
|
VerilatedVar* varInsertSized(const char* namep, void* datap, bool isParam,
|
|
VerilatedVarType vltype, int vlflags, int udims, uint32_t entSize,
|
|
...) VL_MT_UNSAFE;
|
|
VerilatedVar* forceableVarInsert(const char* namep, void* datap, bool isParam,
|
|
VerilatedVarType vltype, int vlflags,
|
|
void* forceReadSignalData, const char* forceReadSignalName,
|
|
std::pair<VerilatedVar*, VerilatedVar*> forceControlSignals,
|
|
int udims, int pdims...) VL_MT_UNSAFE;
|
|
void varsInsertFromTable(const VlVarTableEntry* entp, size_t n, void* basep) VL_MT_UNSAFE;
|
|
static void scopesConstructFromTable(const VlScopeTableEntry* entp, size_t n,
|
|
VerilatedSyms* symsp) 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;
|
|
Type type() const { return m_type; }
|
|
};
|
|
|
|
// One scope, consumed by VerilatedScope::scopesConstructFromTable(); replaces
|
|
// per-scope 'new VerilatedScope{...}' statements, which compiles faster at scale.
|
|
struct VlScopeTableEntry final {
|
|
size_t ptrOffset; // offsetof of the target __Vscopep_* member within the Syms object
|
|
const char* namep; // Scope suffix name (protected), string literal
|
|
const char* identp; // Identifier with escapes removed (protected)
|
|
const char* defnamep; // Definition name (SCOPE_MODULE only), else "<null>"
|
|
int8_t timeunit; // Timeunit in negative power-of-10
|
|
VerilatedScope::Type type;
|
|
};
|
|
|
|
class VerilatedHierarchy final {
|
|
public:
|
|
static void add(const VerilatedScope* fromp, const VerilatedScope* top);
|
|
static void remove(const VerilatedScope* fromp, const VerilatedScope* top);
|
|
static void clear();
|
|
};
|
|
|
|
//===========================================================================
|
|
/// 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: Load a VPI shared library (+verilator+vpi+<lib>[:<bootstrap>])
|
|
static void loadVpiLib(const std::string& arg) 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();
|
|
double mult = 1.0;
|
|
for (int i = 0; i < 16; i++) {
|
|
if (sc_res == sc_core::sc_time(mult, sc_core::SC_FS)) {
|
|
sc_prec = 15 - i;
|
|
break;
|
|
}
|
|
mult *= 10.0;
|
|
}
|
|
// 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
|