forked from verilator/verilator
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathverilated_sc_trace.h
247 lines (224 loc) · 9.33 KB
/
verilated_sc_trace.h
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-2024 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
//
//=============================================================================
///
/// \file
/// \brief Verilated 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