Fix trace when using SystemC with certain configurations (#4676)

This commit is contained in:
Anthony Donlon 2023-11-09 12:48:23 +00:00 committed by GitHub
parent 9a65ed4ce2
commit ab06ace1f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 239 additions and 197 deletions

View File

@ -220,12 +220,6 @@ This is done for you if you are using the Verilator :vlopt:`--binary` or
You can call :code:`->trace()` on multiple Verilated objects with the same
trace file if you want all data to land in the same output file.
When using SystemC 2.3, the SystemC library must have been built with the
experimental simulation phase callback-based tracing disabled. This is
disabled by default when building SystemC with its configure based build
system, but when building SystemC with CMake, you must pass
``-DENABLE_PHASE_CALLBACKS_TRACING=OFF`` to disable this feature.
How do I generate FST waveforms (traces) in C++ or SystemC?
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

View File

@ -210,7 +210,7 @@ public:
/// Return if file is open
bool isOpen() const VL_MT_SAFE { return m_sptrace.isOpen(); }
/// Open a new FST file
void open(const char* filename) VL_MT_SAFE { m_sptrace.open(filename); }
virtual void open(const char* filename) VL_MT_SAFE { m_sptrace.open(filename); }
/// Close dump
void close() VL_MT_SAFE { m_sptrace.close(); }
/// Flush dump

View File

@ -12,8 +12,7 @@
/// \file
/// \brief Verilated tracing in FST format for SystemC header
///
/// User wrapper code should use this header when creating FST SystemC
/// traces.
/// User wrapper code should use this header when creating FST SystemC traces.
///
/// This class is not threadsafe, as the SystemC kernel is not threadsafe.
///
@ -25,115 +24,33 @@
#include "verilatedos.h"
#include "verilated_fst_c.h"
#include "verilated_sc.h"
#include <string>
#include "verilated_sc_trace.h"
//=============================================================================
// VerilatedFstSc
///
/// Class representing a Verilator-friendly FST trace format registered
/// with the SystemC simulation kernel, just like a SystemC-documented
/// trace format.
/// Trace file used to create FST dump for SystemC version of Verilated models. It's very similar
/// to its C version (see the class VerilatedFstC)
class VerilatedFstSc final : sc_core::sc_trace_file, public VerilatedFstC {
class VerilatedFstSc final : VerilatedScTraceBase, public VerilatedFstC {
// CONSTRUCTORS
VL_UNCOPYABLE(VerilatedFstSc);
public:
/// Construct a SC trace object, and register with the SystemC kernel
VerilatedFstSc() {
sc_core::sc_get_curr_simcontext()->add_trace_file(this);
// 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) {
const sc_core::sc_time tunits{1.0 / t1sec.to_default_time_units(), sc_core::SC_SEC};
spTrace()->set_time_unit(tunits.to_string());
}
spTrace()->set_time_resolution(sc_core::sc_get_time_resolution().to_string());
}
/// Destruct, flush, and close the dump
~VerilatedFstSc() override { close(); }
// METHODS - for SC kernel
// Called by SystemC simulate()
void cycle(bool delta_cycle) override {
if (!delta_cycle) this->dump(sc_core::sc_time_stamp().to_double());
spTrace()->set_time_unit(VerilatedScTraceBase::getScTimeUnit());
spTrace()->set_time_resolution(VerilatedScTraceBase::getScTimeResolution());
}
// METHODS
// Override VerilatedFstC. Must be called after starting simulation.
// Note: this is not a virtual function in the base class, so no 'override'
virtual void open(const char* filename) VL_MT_SAFE {
if (VL_UNLIKELY(!sc_core::sc_get_curr_simcontext()->elaboration_done())) {
Verilated::scTraceBeforeElaborationError();
}
void open(const char* filename) override VL_MT_SAFE {
VerilatedScTraceBase::checkScElaborationDone();
VerilatedFstC::open(filename);
}
private:
// METHODS - Fake outs for linker
#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(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
// LCOV_EXCL_START
#if (SYSTEMC_VERSION >= 20171012)
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
// METHODS - for SC kernel
// Called from SystemC kernel
void cycle() override { VerilatedFstC::dump(sc_core::sc_time_stamp().to_double()); }
};
#endif // Guard

View File

@ -0,0 +1,212 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//=============================================================================
//
// Copyright 2001-2023 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's simulation phase callback introduced in 2.3.1
#define _VERILATOR_SYSTEMC_NO_PHASE_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,
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) {
#ifndef _VERILATOR_SYSTEMC_NO_PHASE_CALLBACK
using namespace sc_core;
// 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
m_enableDeltaCycles = flag;
}
protected:
VerilatedScTraceBase()
: sc_object(sc_core::sc_gen_unique_name("$$$$verilator_sc_trace$$$$"))
, sc_trace_file() {
registerTraceCallback();
};
~VerilatedScTraceBase() override {
#if SYSTEMC_VERSION >= 20140417 // remove_trace_file added in 2.3.1
// 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);
#endif
};
void registerTraceCallback() {
#ifndef _VERILATOR_SYSTEMC_NO_PHASE_CALLBACK
using namespace sc_core;
// 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
// Phase callback not enabled, use trace file instead
simcontext()->add_trace_file(this);
m_traceFileAdded = true;
#ifndef _VERILATOR_SYSTEMC_NO_PHASE_CALLBACK
}
// Restore the old handler
sc_report_handler::set_handler(oldHandler);
#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
#ifndef _VERILATOR_SYSTEMC_NO_PHASE_CALLBACK
// Override sc_object. Called if using phase callback
void simulation_phase_callback() 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(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 _VERILATOR_SYSTEMC_NO_PHASE_CALLBACK
#undef _VERILATOR_SYSTEMC_NO_PHASE_CALLBACK
#endif
#endif // Guard

View File

@ -12,8 +12,7 @@
/// \file
/// \brief Verilated tracing in VCD format for SystemC header
///
/// User wrapper code should use this header when creating VCD SystemC
/// traces.
/// User wrapper code should use this header when creating VCD SystemC traces.
///
/// This class is not threadsafe, as the SystemC kernel is not threadsafe.
///
@ -24,115 +23,35 @@
#include "verilatedos.h"
#include "verilated_sc.h"
#include "verilated_sc_trace.h"
#include "verilated_vcd_c.h"
#include <string>
//=============================================================================
// VerilatedVcdSc
///
/// Class representing a Verilator-friendly VCD trace format registered
/// with the SystemC simulation kernel, just like a SystemC-documented
/// trace format.
/// Trace file used to create VCD dump for SystemC version of Verilated models. It's very similar
/// to its C version (see the class VerilatedVcdC)
class VerilatedVcdSc final : sc_core::sc_trace_file, public VerilatedVcdC {
class VerilatedVcdSc final : VerilatedScTraceBase, public VerilatedVcdC {
// CONSTRUCTORS
VL_UNCOPYABLE(VerilatedVcdSc);
public:
/// Construct a SC trace object, and register with the SystemC kernel
VerilatedVcdSc() {
sc_core::sc_get_curr_simcontext()->add_trace_file(this);
// 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) {
const sc_core::sc_time tunits{1.0 / t1sec.to_default_time_units(), sc_core::SC_SEC};
spTrace()->set_time_unit(tunits.to_string());
}
spTrace()->set_time_resolution(sc_core::sc_get_time_resolution().to_string());
}
/// Destruct, flush, and close the dump
~VerilatedVcdSc() override { close(); }
// METHODS - for SC kernel
// Called by SystemC simulate()
void cycle(bool delta_cycle) override {
if (!delta_cycle) this->dump(sc_core::sc_time_stamp().to_double());
spTrace()->set_time_unit(VerilatedScTraceBase::getScTimeUnit());
spTrace()->set_time_resolution(VerilatedScTraceBase::getScTimeResolution());
VerilatedScTraceBase::enableDeltaCycles(false);
}
// METHODS
// Override VerilatedVcdC. Must be called after starting simulation.
void open(const char* filename) override VL_MT_SAFE {
if (VL_UNLIKELY(!sc_core::sc_get_curr_simcontext()->elaboration_done())) {
Verilated::scTraceBeforeElaborationError();
}
VerilatedScTraceBase::checkScElaborationDone();
VerilatedVcdC::open(filename);
}
private:
// METHODS - Fake outs for linker
#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(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
// LCOV_EXCL_START
#if (SYSTEMC_VERSION >= 20171012)
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
// METHODS - for SC kernel
// Called from SystemC kernel
void cycle() override { VerilatedVcdC::dump(sc_core::sc_time_stamp().to_double()); }
};
#endif // Guard