diff --git a/docs/guide/faq.rst b/docs/guide/faq.rst index d02559a7b..4e790363e 100644 --- a/docs/guide/faq.rst +++ b/docs/guide/faq.rst @@ -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? """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" diff --git a/include/verilated_fst_c.h b/include/verilated_fst_c.h index 0331ca5e9..c19402b5e 100644 --- a/include/verilated_fst_c.h +++ b/include/verilated_fst_c.h @@ -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 diff --git a/include/verilated_fst_sc.h b/include/verilated_fst_sc.h index af288f11b..9e3215f0c 100644 --- a/include/verilated_fst_sc.h +++ b/include/verilated_fst_sc.h @@ -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 +#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 diff --git a/include/verilated_sc_trace.h b/include/verilated_sc_trace.h new file mode 100644 index 000000000..81af75244 --- /dev/null +++ b/include/verilated_sc_trace.h @@ -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 diff --git a/include/verilated_vcd_sc.h b/include/verilated_vcd_sc.h index 53d5efe43..2fc295c53 100644 --- a/include/verilated_vcd_sc.h +++ b/include/verilated_vcd_sc.h @@ -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 - //============================================================================= // 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