17 #include "vcd_mt_trace.hh"
18 #include "trace/gz_writer.hh"
19 #define FWRITE(BUF, SZ, LEN, FP) FP->write(BUF, SZ* LEN)
20 #define FPTR gz_writer*
21 #include "sc_vcd_trace.h"
22 #include "trace/vcd_trace.hh"
23 #include "utilities.h"
34 #include <unordered_map>
37 #define FPRINT(FP, FMTSTR) FP->write_single(fmt::format(FMTSTR));
38 #define FPRINTF(FP, FMTSTR, ...) FP->write_single(fmt::format(FMTSTR, __VA_ARGS__));
44 vcd_mt_trace_file::vcd_mt_trace_file(
const char* name, std::function<
bool()>& enable)
46 , check_enabled(enable) {
47 vcd_out = scc::make_unique<trace::gz_writer>(fmt::format(
"{}.vcd.gz", name));
49 #if SC_VERSION_MAJOR < 3
50 #if defined(WITH_SC_TRACING_PHASE_CALLBACKS)
54 sc_object::register_simulation_phase_callback(SC_BEFORE_TIMESTEP);
56 sc_core::sc_get_curr_simcontext()->add_trace_file(
this);
61 vcd_mt_trace_file::~vcd_mt_trace_file() {
63 FPRINTF(vcd_out,
"#{}\n", sc_core::sc_time_stamp() / 1_ps);
65 for(
auto t : all_traces)
69 template <
typename T,
typename OT = T>
bool changed(trace::vcd_trace* trace) {
70 if(
reinterpret_cast<trace::vcd_trace_t<T, OT>*
>(trace)->changed()) {
71 reinterpret_cast<trace::vcd_trace_t<T, OT>*
>(trace)->update();
76 #define DECL_TRACE_METHOD_A(tp) \
77 void vcd_mt_trace_file::trace(const tp& object, const std::string& name) { \
78 all_traces.emplace_back(this, &changed<tp>, new trace::vcd_trace_t<tp>(object, name)); \
80 #define DECL_TRACE_METHOD_B(tp) \
81 void vcd_mt_trace_file::trace(const tp& object, const std::string& name, int width) { \
82 all_traces.emplace_back(this, &changed<tp>, new trace::vcd_trace_t<tp>(object, name)); \
84 #define DECL_TRACE_METHOD_C(tp, tpo) \
85 void vcd_mt_trace_file::trace(const tp& object, const std::string& name) { \
86 all_traces.emplace_back(this, &changed<tp, tpo>, new trace::vcd_trace_t<tp, tpo>(object, name)); \
89 #if(SYSTEMC_VERSION >= 20171012)
90 void vcd_mt_trace_file::trace(
const sc_core::sc_event&
object,
const std::string& name) {}
91 void vcd_mt_trace_file::trace(
const sc_core::sc_time&
object,
const std::string& name) {}
93 DECL_TRACE_METHOD_A(
bool)
94 DECL_TRACE_METHOD_A(sc_dt::sc_bit)
95 DECL_TRACE_METHOD_A(sc_dt::sc_logic)
97 DECL_TRACE_METHOD_B(
unsigned char)
98 DECL_TRACE_METHOD_B(
unsigned short)
99 DECL_TRACE_METHOD_B(
unsigned int)
100 DECL_TRACE_METHOD_B(
unsigned long)
101 #ifdef SYSTEMC_64BIT_PATCHES
102 DECL_TRACE_METHOD_B(
unsigned long long)
104 DECL_TRACE_METHOD_B(
char)
105 DECL_TRACE_METHOD_B(
short)
106 DECL_TRACE_METHOD_B(
int)
107 DECL_TRACE_METHOD_B(
long)
108 DECL_TRACE_METHOD_B(sc_dt::int64)
109 DECL_TRACE_METHOD_B(sc_dt::uint64)
111 DECL_TRACE_METHOD_A(
float)
112 DECL_TRACE_METHOD_A(
double)
113 DECL_TRACE_METHOD_A(sc_dt::sc_int_base)
114 DECL_TRACE_METHOD_A(sc_dt::sc_uint_base)
115 DECL_TRACE_METHOD_A(sc_dt::sc_signed)
116 DECL_TRACE_METHOD_A(sc_dt::sc_unsigned)
118 DECL_TRACE_METHOD_A(sc_dt::sc_fxval)
119 DECL_TRACE_METHOD_A(sc_dt::sc_fxval_fast)
120 DECL_TRACE_METHOD_C(sc_dt::sc_fxnum, sc_dt::sc_fxval)
121 DECL_TRACE_METHOD_C(sc_dt::sc_fxnum_fast, sc_dt::sc_fxval_fast)
123 DECL_TRACE_METHOD_A(sc_dt::sc_bv_base)
124 DECL_TRACE_METHOD_A(sc_dt::sc_lv_base)
125 #undef DECL_TRACE_METHOD_A
126 #undef DECL_TRACE_METHOD_B
127 #undef DECL_TRACE_METHOD_C
129 void vcd_mt_trace_file::trace(
const unsigned int&
object,
const std::string& name,
const char** enum_literals) {
130 all_traces.emplace_back(
this, &changed<unsigned int>,
new trace::vcd_trace_enum(
object, name, enum_literals));
133 #define DECL_REGISTER_METHOD_A(tp) \
134 observer::notification_handle* vcd_mt_trace_file::observe(const tp& object, const std::string& name) { \
135 all_traces.emplace_back(this, &changed<tp>, new trace::vcd_trace_t<tp>(object, name)); \
136 all_traces.back().trc->is_triggered = true; \
137 return &all_traces.back(); \
139 #define DECL_REGISTER_METHOD_C(tp, tpo) \
140 observer::notification_handle* vcd_mt_trace_file::observe(const tp& object, const std::string& name) { \
141 all_traces.emplace_back(this, &changed<tp, tpo>, new trace::vcd_trace_t<tp, tpo>(object, name)); \
142 all_traces.back().trc->is_triggered = true; \
143 return &all_traces.back(); \
146 #if(SYSTEMC_VERSION >= 20171012)
147 observer::notification_handle* vcd_mt_trace_file::observe(
const sc_core::sc_event&
object,
const std::string& name) {
return nullptr; }
148 observer::notification_handle* vcd_mt_trace_file::observe(
const sc_core::sc_time&
object,
const std::string& name) {
return nullptr; }
151 DECL_REGISTER_METHOD_A(
bool)
152 DECL_REGISTER_METHOD_A(sc_dt::sc_bit)
153 DECL_REGISTER_METHOD_A(sc_dt::sc_logic)
155 DECL_REGISTER_METHOD_A(
unsigned char)
156 DECL_REGISTER_METHOD_A(
unsigned short)
157 DECL_REGISTER_METHOD_A(
unsigned int)
158 DECL_REGISTER_METHOD_A(
unsigned long)
159 #ifdef SYSTEMC_64BIT_PATCHES
160 DECL_REGISTER_METHOD_A(
unsigned long long)
162 DECL_REGISTER_METHOD_A(
char)
163 DECL_REGISTER_METHOD_A(
short)
164 DECL_REGISTER_METHOD_A(
int)
165 DECL_REGISTER_METHOD_A(
long)
166 DECL_REGISTER_METHOD_A(sc_dt::int64)
167 DECL_REGISTER_METHOD_A(sc_dt::uint64)
169 DECL_REGISTER_METHOD_A(
float)
170 DECL_REGISTER_METHOD_A(
double)
171 DECL_REGISTER_METHOD_A(sc_dt::sc_int_base)
172 DECL_REGISTER_METHOD_A(sc_dt::sc_uint_base)
173 DECL_REGISTER_METHOD_A(sc_dt::sc_signed)
174 DECL_REGISTER_METHOD_A(sc_dt::sc_unsigned)
176 DECL_REGISTER_METHOD_A(sc_dt::sc_fxval)
177 DECL_REGISTER_METHOD_A(sc_dt::sc_fxval_fast)
178 DECL_REGISTER_METHOD_C(sc_dt::sc_fxnum, sc_dt::sc_fxval)
179 DECL_REGISTER_METHOD_C(sc_dt::sc_fxnum_fast, sc_dt::sc_fxval_fast)
181 DECL_REGISTER_METHOD_A(sc_dt::sc_bv_base)
182 DECL_REGISTER_METHOD_A(sc_dt::sc_lv_base)
183 #undef DECL_REGISTER_METHOD_A
184 #undef DECL_REGISTER_METHOD_C
186 bool vcd_mt_trace_file::trace_entry::notify() {
187 if(!trc->is_alias && compare_and_update(trc))
188 that->triggered_traces.push_back(trc);
189 return !trc->is_alias;
192 std::string vcd_mt_trace_file::obtain_name() {
193 const char first_type_used =
'a';
194 const int used_types_count =
'z' -
'a' + 1;
197 result = vcd_name_index;
198 char char6 =
static_cast<char>(vcd_name_index % used_types_count);
200 result = result / used_types_count;
201 char char5 =
static_cast<char>(result % used_types_count);
203 result = result / used_types_count;
204 char char4 =
static_cast<char>(result % used_types_count);
206 result = result / used_types_count;
207 char char3 =
static_cast<char>(result % used_types_count);
209 result = result / used_types_count;
210 char char2 =
static_cast<char>(result % used_types_count);
213 std::sprintf(buf,
"%c%c%c%c%c", char2 + first_type_used, char3 + first_type_used, char4 + first_type_used, char5 + first_type_used,
214 char6 + first_type_used);
216 return std::string(buf);
219 void vcd_mt_trace_file::write_comment(
const std::string& comment) { FPRINTF(vcd_out,
"$comment\n{}\n$end\n\n", comment); }
221 void vcd_mt_trace_file::init() {
222 std::sort(std::begin(all_traces), std::end(all_traces),
223 [](trace_entry
const& a, trace_entry
const& b) ->
bool {
return a.trc->name < b.trc->name; });
224 std::unordered_map<uintptr_t, std::string> alias_map;
226 trace::vcd_scope_stack<trace::vcd_trace> scope;
227 for(
auto& e : all_traces) {
228 auto alias_it = alias_map.find(e.trc->get_hash());
229 e.trc->is_alias = alias_it != std::end(alias_map);
230 e.trc->trc_hndl = e.trc->is_alias ? alias_it->second : obtain_name();
232 alias_map.insert({e.trc->get_hash(), e.trc->trc_hndl});
233 scope.add_trace(e.trc);
235 std::copy_if(std::begin(all_traces), std::end(all_traces), std::back_inserter(active_traces),
236 [](trace_entry
const& e) {
return !(e.trc->is_alias || e.trc->is_triggered); });
237 changed_traces.reserve(active_traces.size());
238 triggered_traces.reserve(active_traces.size());
243 struct tm* p_tm = localtime(&long_time);
244 strftime(tbuf, 199,
"%b %d, %Y %H:%M:%S", p_tm);
245 FPRINTF(vcd_out,
"$date\n {}\n$end\n\n", tbuf);
247 FPRINTF(vcd_out,
"$version\n {}\n$end\n\n", sc_core::sc_version());
249 FPRINTF(vcd_out,
"$timescale\n {}\n$end\n\n", (1_ps).to_string());
250 write_comment(
"create using SCC VCD compressed writer");
251 std::stringstream ss;
252 ss <<
"tracing " << active_traces.size() <<
" distinct traces out of " << all_traces.size() <<
" traces";
253 write_comment(ss.str());
254 scope.print(vcd_out.get());
257 std::string vcd_mt_trace_file::prune_name(std::string
const& orig_name) {
258 static bool warned =
false;
259 bool braces_removed =
false;
260 std::string hier_name = orig_name;
261 for(
unsigned int i = 0; i < hier_name.length(); i++) {
262 if(hier_name[i] ==
'[') {
264 braces_removed =
true;
265 }
else if(hier_name[i] ==
']') {
267 braces_removed =
true;
271 if(braces_removed && !warned) {
272 std::stringstream ss;
275 "\tTraced objects found with name containing [], which may be\n"
276 "\tinterpreted by the waveform viewer in unexpected ways.\n"
277 "\tSo the [] is automatically replaced by ().";
279 SC_REPORT_WARNING(sc_core::SC_ID_TRACING_OBJECT_NAME_FILTERED_, ss.str().c_str());
284 void record_changes(FILE* vcd_out, std::vector<trace::vcd_trace*>
const& changed, std::vector<trace::vcd_trace*>
const& triggered) {}
286 void vcd_mt_trace_file::cycle(
bool delta_cycle) {
293 scc::trace::gz_writer::lock_type lock(vcd_out->writer_mtx);
294 vcd_out->write(
"$enddefinitions $end\n\n$dumpvars\n");
295 for(
auto& e : all_traces)
296 if(!e.trc->is_alias) {
297 e.compare_and_update(e.trc);
298 e.trc->record(vcd_out.get());
300 vcd_out->write(
"$end\n\n");
303 if(check_enabled && !check_enabled())
305 for(
auto& e : active_traces) {
306 if(e.compare_and_update(e.trc))
307 changed_traces.push_back(e.trc);
309 if(triggered_traces.size() || changed_traces.size()) {
310 scc::trace::gz_writer::lock_type lock(vcd_out->writer_mtx);
311 vcd_out->write(fmt::format(
"#{}\n", sc_core::sc_time_stamp() / 1_ps));
312 if(triggered_traces.size()) {
313 auto end = std::unique(std::begin(triggered_traces), std::end(triggered_traces));
314 for(
auto it = triggered_traces.begin(); it != end; ++it)
315 (*it)->record(vcd_out.get());
316 triggered_traces.clear();
318 if(changed_traces.size()) {
319 for(
auto t : changed_traces)
320 t->record(vcd_out.get());
321 changed_traces.clear();
327 void vcd_mt_trace_file::set_time_unit(
double v, sc_core::sc_time_unit tu) {}
329 void vcd_mt_trace_file::set_time_unit(
int exponent10_seconds) {}
void close_vcd_mt_trace_file(sc_core::sc_trace_file *tf)
close the VCD file
sc_core::sc_trace_file * create_vcd_mt_trace_file(const char *name, std::function< bool()> enable=std::function< bool()>())
create compressed VCD file which uses push mechanism and multithreading