1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
//=============================================================================
//
// Copyright 2001-2025 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 tracing for SystemC implementation code
///
///
///
//=============================================================================
#ifndef VERILATOR_VERILATED_SC_TRACE_H_
#define VERILATOR_VERILATED_SC_TRACE_H_
#include "verilatedos.h"
#include "verilated.h"
#include "verilated_sc.h"
#if SYSTEMC_VERSION >= 20140417 && SYSTEMC_VERSION < 20231124
// SystemC's simulation phase callback introduced in 2.3.1, and removed since 3.0.0 (PubRev)
#define _VL_HAVE_SYSTEMC_PHASE_CALLBACK
#endif
#if SYSTEMC_VERSION >= 20231124
// SystemC's stage callback introduced in 3.0.0 (PubRev)
#define _VL_HAVE_SYSTEMC_STAGE_CALLBACK
#endif
//=============================================================================
// VerilatedScTraceBase
// Base class for VCD/FST trace format on SystemC
// This is an internally used class - see VerilatedVcdSc and VerilatedFstSc for what to call from
// applications
//
/// This class utilizes SystemC's callbacks, which allows to dump signals inside the Verilated
/// module automatically as time advances.
///
/// For SystemC prior to 2.3.1, the only approach for being notified after each update is by adding
/// a trace file (sc_trace_file) to the simulation context. And after this version the simulation
/// phase callback approach has been introduced (sc_trace_file also utilizes this), which is
/// presented only if it's enabled with the `--enable-phase-callbacks` option. However, when it's
/// enabled with `--enable-phase-callbacks=tracing`, trace files will be therefore disabled, thus
/// failing to provide its functionality.
///
/// To provide a universal way for tracing, the class attempts to register a phase callback first.
/// If it fails (proving that the feature has been disabled), it'll use the trace file approach
/// instead.
class VerilatedScTraceBase VL_NOT_FINAL : private sc_core::sc_object,
#ifdef _VL_HAVE_SYSTEMC_STAGE_CALLBACK
private sc_core::sc_stage_callback_if,
#endif
private sc_core::sc_trace_file {
bool m_enableDeltaCycles = false;
bool m_traceFileAdded = false;
static void stubReportHandler(const sc_core::sc_report&, const sc_core::sc_actions&){};
public:
void enableDeltaCycles(bool flag = true) {
using namespace sc_core;
#ifdef _VL_HAVE_SYSTEMC_PHASE_CALLBACK
// Save old report handler before overriding it
const auto oldHandler = sc_report_handler::get_handler();
// Override the old handler to hide 'phase callbacks not enabled' message
sc_report_handler::set_handler(&stubReportHandler);
if (flag) {
// Register simulation phase callback for delta cycles
sc_object::register_simulation_phase_callback(SC_END_OF_UPDATE);
} else {
sc_object::unregister_simulation_phase_callback(SC_END_OF_UPDATE);
}
// Restore the old handler
sc_report_handler::set_handler(oldHandler);
#endif
#ifdef _VL_HAVE_SYSTEMC_STAGE_CALLBACK
if (flag) {
sc_register_stage_callback(*this, SC_POST_UPDATE);
} else {
sc_unregister_stage_callback(*this, SC_POST_UPDATE);
}
#endif
m_enableDeltaCycles = flag;
}
protected:
VerilatedScTraceBase()
: sc_object(sc_core::sc_gen_unique_name("$$$$verilator_sc_trace$$$$"))
, sc_trace_file() {
registerTraceCallback();
};
~VerilatedScTraceBase() override {
using namespace sc_core;
#ifdef _VL_HAVE_SYSTEMC_PHASE_CALLBACK
// remove_trace_file added in 2.3.1 and removed in 3.0.0
// Phase callback is automatically unregistered in ~sc_object(). Only the trace file is
// needed to be removed here
if (m_traceFileAdded) simcontext()->remove_trace_file(this);
#else
(void)m_traceFileAdded;
#endif
#ifdef _VL_HAVE_SYSTEMC_STAGE_CALLBACK
sc_unregister_stage_callback(*this, SC_PRE_TIMESTEP | SC_POST_UPDATE);
#endif
};
void registerTraceCallback() {
using namespace sc_core;
#ifdef _VL_HAVE_SYSTEMC_PHASE_CALLBACK
// Save old report handler before overriding it
const auto oldHandler = sc_report_handler::get_handler();
// Override the old handler to hide 'phase callbacks not enabled' message
sc_report_handler::set_handler(&stubReportHandler);
// Register regular simulation phase (non-delta cycle) callback
phase_cb_mask cb_mask = sc_object::register_simulation_phase_callback(SC_BEFORE_TIMESTEP);
if (cb_mask == SC_UNITIALIZED) {
#endif
#if SYSTEMC_VERSION < 20231124 // add_trace_file removed in 3.0.0
// Phase callback not enabled, use trace file instead
simcontext()->add_trace_file(this);
m_traceFileAdded = true;
#endif
#ifdef _VL_HAVE_SYSTEMC_PHASE_CALLBACK
}
// Restore the old handler
sc_report_handler::set_handler(oldHandler);
#endif
#ifdef _VL_HAVE_SYSTEMC_STAGE_CALLBACK
sc_register_stage_callback(*this, SC_PRE_TIMESTEP);
#endif
}
static std::string getScTimeUnit() {
// We want to avoid a depreciated warning, but still be back compatible.
// Turning off the message just for this still results in an
// annoying "to turn off" message.
const sc_core::sc_time t1sec{1, sc_core::SC_SEC};
if (t1sec.to_default_time_units() == 0) {
VL_FATAL_MT(__FILE__, __LINE__, "", // LCOV_EXCL_LINE
"Cannot to get valid SystemC default time unit for trace file");
}
const sc_core::sc_time tunits{1.0 / t1sec.to_default_time_units(), sc_core::SC_SEC};
return tunits.to_string();
}
static std::string getScTimeResolution() {
return sc_core::sc_get_time_resolution().to_string();
}
static void checkScElaborationDone() {
if (!sc_core::sc_get_curr_simcontext()->elaboration_done()) {
Verilated::scTraceBeforeElaborationError();
}
}
// METHODS - for SC kernel
#ifdef _VL_HAVE_SYSTEMC_PHASE_CALLBACK
// Override sc_object. Called if using phase callback
void simulation_phase_callback() final { cycle(); }
#endif
#ifdef _VL_HAVE_SYSTEMC_STAGE_CALLBACK
// Override sc_stage_callback_if. Called if using stage callback
void stage_callback(const sc_core::sc_stage&) final { cycle(); }
#endif
// Override sc_trace_file. Called if using trace file
void cycle(bool delta_cycle) final {
if (!delta_cycle || m_enableDeltaCycles) cycle();
}
// METHODS - callbacks
// Subclasses should implement this callback method
virtual void cycle() = 0;
private:
// METHODS - Fake outs for linker
// LCOV_EXCL_START
#ifdef NC_SYSTEMC
// Cadence Incisive has these as abstract functions so we must create them
void set_time_unit(int exponent10_seconds) override {} // deprecated
#endif
void set_time_unit(double v, sc_core::sc_time_unit tu) override {} // LCOV_EXCL_LINE
//--------------------------------------------------
// SystemC 2.1.v1
void write_comment(const std::string&) override {}
void trace(sc_core::sc_trace_file*) const override {}
void trace(const unsigned int&, const std::string&, const char**) override {}
#define DECL_TRACE_METHOD_A(tp) \
void trace(const tp& object, const std::string& name) override {}
#define DECL_TRACE_METHOD_B(tp) \
void trace(const tp& object, const std::string& name, int width) override {}
// clang-format off
// Formatting matches that of sc_trace.h
#if SYSTEMC_VERSION >= 20171012 // SystemC >= 2.3.2
DECL_TRACE_METHOD_A( sc_core::sc_event )
DECL_TRACE_METHOD_A( sc_core::sc_time )
#endif
DECL_TRACE_METHOD_A( bool )
DECL_TRACE_METHOD_A( sc_dt::sc_bit )
DECL_TRACE_METHOD_A( sc_dt::sc_logic )
DECL_TRACE_METHOD_B( unsigned char )
DECL_TRACE_METHOD_B( unsigned short )
DECL_TRACE_METHOD_B( unsigned int )
DECL_TRACE_METHOD_B( unsigned long )
DECL_TRACE_METHOD_B( char )
DECL_TRACE_METHOD_B( short )
DECL_TRACE_METHOD_B( int )
DECL_TRACE_METHOD_B( long )
DECL_TRACE_METHOD_B( sc_dt::int64 )
DECL_TRACE_METHOD_B( sc_dt::uint64 )
DECL_TRACE_METHOD_A( float )
DECL_TRACE_METHOD_A( double )
DECL_TRACE_METHOD_A( sc_dt::sc_int_base )
DECL_TRACE_METHOD_A( sc_dt::sc_uint_base )
DECL_TRACE_METHOD_A( sc_dt::sc_signed )
DECL_TRACE_METHOD_A( sc_dt::sc_unsigned )
DECL_TRACE_METHOD_A( sc_dt::sc_fxval )
DECL_TRACE_METHOD_A( sc_dt::sc_fxval_fast )
DECL_TRACE_METHOD_A( sc_dt::sc_fxnum )
DECL_TRACE_METHOD_A( sc_dt::sc_fxnum_fast )
DECL_TRACE_METHOD_A( sc_dt::sc_bv_base )
DECL_TRACE_METHOD_A( sc_dt::sc_lv_base )
// LCOV_EXCL_STOP
// clang-format on
#undef DECL_TRACE_METHOD_A
#undef DECL_TRACE_METHOD_B
};
#ifdef _VL_HAVE_SYSTEMC_PHASE_CALLBACK
#undef _VL_HAVE_SYSTEMC_PHASE_CALLBACK
#endif
#ifdef _VL_HAVE_SYSTEMC_STAGE_CALLBACK
#undef _VL_HAVE_SYSTEMC_STAGE_CALLBACK
#endif
#endif // Guard
|