17 #include "fst_trace.hh"
19 #include "trace/types.hh"
20 #include "utilities.h"
30 #include <unordered_map>
31 #include <util/ities.h>
36 inline size_t get_buffer_size(
int length) {
37 size_t sz = (
static_cast<size_t>(length) + 4096) & (~static_cast<size_t>(4096 - 1));
38 return std::max<decltype(sz)>(1024UL, sz);
41 inline unsigned get_bits(
const char** literals) {
43 for(nliterals = 0; literals[nliterals]; nliterals++)
45 return scc::ilog2(nliterals);
50 fst_trace(std::string
const& nm, trace_type type,
unsigned bits)
55 virtual void record(
void* m_fst) = 0;
57 virtual void update_and_record(
void* m_fst) = 0;
59 virtual uintptr_t get_hash() = 0;
63 const std::string name;
64 fstHandle fst_hndl{0};
66 bool is_triggered{
false};
67 const unsigned bits{0};
68 const trace_type type;
72 fst_trace_enum(
const unsigned int& object_,
const std::string& name,
const char** literals)
73 :
fst_trace(name, trace::WIRE, get_bits(literals))
76 , literals{literals} {}
78 uintptr_t get_hash()
override {
return reinterpret_cast<uintptr_t
>(&act_val); }
80 inline bool changed() {
return !is_alias && old_val != act_val; }
82 inline void update() { old_val = act_val; }
84 void record(
void* os)
override { fstWriterEmitValueChange64(os, fst_hndl, bits, old_val); }
86 void update_and_record(
void* os)
override {
92 const unsigned int& act_val;
93 const char** literals;
97 fst_trace_t(
const T& object_,
const std::string& name,
int width = -1)
100 , old_val(object_) {}
102 uintptr_t get_hash()
override {
return reinterpret_cast<uintptr_t
>(&act_val); }
104 inline bool changed() {
return !is_alias && old_val != act_val; }
106 inline void update() { old_val = act_val; }
108 void record(
void* m_fst)
override;
110 void update_and_record(
void* m_fst)
override {
120 static std::vector<char> rawdata(65);
121 char* s = &rawdata[0];
122 for(
size_t i = 0; i < 8 *
sizeof(T); ++i)
123 *s++ =
'0' + ((old_val >> (8 *
sizeof(T) - i - 1)) & 1);
125 fstWriterEmitValueChange(m_fst, fst_hndl, &rawdata[0]);
127 template <>
void fst_trace_t<bool, bool>::record(
void* m_fst) { fstWriterEmitValueChange(m_fst, fst_hndl, old_val ?
"1" :
"0"); }
128 template <>
void fst_trace_t<sc_dt::sc_bit, sc_dt::sc_bit>::record(
void* m_fst) {
129 fstWriterEmitValueChange(m_fst, fst_hndl, old_val ?
"1" :
"0");
131 template <>
void fst_trace_t<sc_dt::sc_logic, sc_dt::sc_logic>::record(
void* m_fst) {
132 char buf[2] = {0, 0};
133 buf[0] = old_val.to_char();
134 fstWriterEmitValueChange(m_fst, fst_hndl, buf);
136 template <>
void fst_trace_t<float, float>::record(
void* m_fst) {
137 double val = old_val;
138 fstWriterEmitValueChange(m_fst, fst_hndl, &val);
140 template <>
void fst_trace_t<double, double>::record(
void* m_fst) { fstWriterEmitValueChange(m_fst, fst_hndl, &old_val); }
141 template <>
void fst_trace_t<sc_dt::sc_int_base, sc_dt::sc_int_base>::record(
void* m_fst) {
142 static std::vector<char> rawdata(1024);
143 if(rawdata.size() < old_val.length() + 1)
144 rawdata.resize(old_val.length() + 1);
145 char* rawdata_ptr = &rawdata[0];
146 for(
int bitindex = old_val.length() - 1; bitindex >= 0; --bitindex)
147 *rawdata_ptr++ =
'0' + old_val[bitindex].value();
149 fstWriterEmitValueChange(m_fst, fst_hndl, &rawdata[0]);
151 template <>
void fst_trace_t<sc_dt::sc_uint_base, sc_dt::sc_uint_base>::record(
void* m_fst) {
152 static std::vector<char> rawdata(1024);
153 if(rawdata.size() < old_val.length() + 1)
154 rawdata.resize(old_val.length() + 1);
155 char* rawdata_ptr = &rawdata[0];
156 for(
int bitindex = old_val.length() - 1; bitindex >= 0; --bitindex)
157 *rawdata_ptr++ =
'0' + old_val[bitindex].value();
159 fstWriterEmitValueChange(m_fst, fst_hndl, &rawdata[0]);
161 template <>
void fst_trace_t<sc_dt::sc_signed, sc_dt::sc_signed>::record(
void* m_fst) {
162 static std::vector<char> rawdata(1024);
163 if(rawdata.size() < old_val.length() + 1)
164 rawdata.resize(old_val.length() + 1);
165 char* rawdata_ptr = &rawdata[0];
166 for(
int bitindex = old_val.length() - 1; bitindex >= 0; --bitindex)
167 *rawdata_ptr++ =
'0' + old_val[bitindex].value();
169 fstWriterEmitValueChange(m_fst, fst_hndl, &rawdata[0]);
171 template <>
void fst_trace_t<sc_dt::sc_unsigned, sc_dt::sc_unsigned>::record(
void* m_fst) {
172 static std::vector<char> rawdata(1024);
173 if(rawdata.size() < old_val.length() + 1)
174 rawdata.resize(old_val.length() + 1);
175 char* rawdata_ptr = &rawdata[0];
176 for(
int bitindex = old_val.length() - 1; bitindex >= 0; --bitindex)
177 *rawdata_ptr++ =
'0' + old_val[bitindex].value();
179 fstWriterEmitValueChange(m_fst, fst_hndl, &rawdata[0]);
181 template <>
void fst_trace_t<sc_dt::sc_fxval, sc_dt::sc_fxval>::record(
void* m_fst) {
182 auto val = old_val.to_double();
183 fstWriterEmitValueChange(m_fst, fst_hndl, &val);
185 template <>
void fst_trace_t<sc_dt::sc_fxval_fast, sc_dt::sc_fxval_fast>::record(
void* m_fst) {
186 auto val = old_val.to_double();
187 fstWriterEmitValueChange(m_fst, fst_hndl, &val);
189 template <>
void fst_trace_t<sc_dt::sc_fxnum, sc_dt::sc_fxval>::record(
void* m_fst) {
190 fstWriterEmitValueChange32(m_fst, fst_hndl, 64, *
reinterpret_cast<uint64_t*
>(&old_val));
192 template <>
void fst_trace_t<sc_dt::sc_fxnum_fast, sc_dt::sc_fxval_fast>::record(
void* m_fst) {
193 auto val = old_val.to_double();
194 fstWriterEmitValueChange(m_fst, fst_hndl, &val);
196 template <>
void fst_trace_t<sc_dt::sc_bv_base, sc_dt::sc_bv_base>::record(
void* m_fst) {
197 auto str = old_val.to_string();
198 auto* cstr = str.c_str();
201 while(c == *(cstr + 1))
203 fstWriterEmitValueChange(m_fst, fst_hndl, str.c_str());
205 template <>
void fst_trace_t<sc_dt::sc_lv_base, sc_dt::sc_lv_base>::record(
void* m_fst) {
206 auto str = old_val.to_string();
207 auto* cstr = str.c_str();
210 while(c == *(cstr + 1))
212 fstWriterEmitValueChange(m_fst, fst_hndl, str.c_str());
216 fst_trace_file::fst_trace_file(
const char* name, std::function<
bool()>& enable)
217 : check_enabled(enable) {
218 std::stringstream ss;
219 ss << name <<
".fst";
220 m_fst = fstWriterCreate(ss.str().c_str(), 1);
222 fprintf(stderr,
"Could not open '%s', exiting.\n", ss.str().c_str());
225 fstWriterSetPackType(m_fst, FST_WR_PT_FASTLZ);
226 fstWriterSetRepackOnClose(m_fst, 1);
227 fstWriterSetParallelMode(m_fst, 0);
228 fstWriterSetTimescale(m_fst, -12);
229 fstWriterSetTimezero(m_fst, 0);
233 struct tm* p_tm = localtime(&long_time);
234 strftime(tbuf, 199,
"%b %d, %Y\t%H:%M:%S", p_tm);
235 fstWriterSetDate(m_fst, tbuf);
237 #if defined(WITH_SC_TRACING_PHASE_CALLBACKS)
241 sc_object::register_simulation_phase_callback(SC_BEFORE_TIMESTEP);
243 sc_core::sc_get_curr_simcontext()->add_trace_file(
this);
247 fst_trace_file::~fst_trace_file() {
248 for(
auto t : all_traces)
252 fstWriterClose(m_fst);
256 template <
typename T,
typename OT = T>
bool changed(trace::fst_trace* trace) {
257 if(
reinterpret_cast<trace::fst_trace_t<T, OT>*
>(trace)->changed()) {
258 reinterpret_cast<trace::fst_trace_t<T, OT>*
>(trace)->update();
263 #define DECL_TRACE_METHOD_A(tp) \
264 void fst_trace_file::trace(const tp& object, const std::string& name) { \
265 all_traces.emplace_back(this, &changed<tp>, new trace::fst_trace_t<tp>(object, name)); \
267 #define DECL_TRACE_METHOD_B(tp) \
268 void fst_trace_file::trace(const tp& object, const std::string& name, int width) { \
269 all_traces.emplace_back(this, &changed<tp>, new trace::fst_trace_t<tp>(object, name)); \
271 #define DECL_TRACE_METHOD_C(tp, tpo) \
272 void fst_trace_file::trace(const tp& object, const std::string& name) { \
273 all_traces.emplace_back(this, &changed<tp, tpo>, new trace::fst_trace_t<tp, tpo>(object, name)); \
276 #if(SYSTEMC_VERSION >= 20171012)
277 void fst_trace_file::trace(
const sc_core::sc_event&
object,
const std::string& name) {}
278 void fst_trace_file::trace(
const sc_core::sc_time&
object,
const std::string& name) {}
280 DECL_TRACE_METHOD_A(
bool)
281 DECL_TRACE_METHOD_A(sc_dt::sc_bit)
282 DECL_TRACE_METHOD_A(sc_dt::sc_logic)
284 DECL_TRACE_METHOD_B(
unsigned char)
285 DECL_TRACE_METHOD_B(
unsigned short)
286 DECL_TRACE_METHOD_B(
unsigned int)
287 DECL_TRACE_METHOD_B(
unsigned long)
288 #ifdef SYSTEMC_64BIT_PATCHES
289 DECL_TRACE_METHOD_B(
unsigned long long)
291 DECL_TRACE_METHOD_B(
char)
292 DECL_TRACE_METHOD_B(
short)
293 DECL_TRACE_METHOD_B(
int)
294 DECL_TRACE_METHOD_B(
long)
295 DECL_TRACE_METHOD_B(sc_dt::int64)
296 DECL_TRACE_METHOD_B(sc_dt::uint64)
298 DECL_TRACE_METHOD_A(
float)
299 DECL_TRACE_METHOD_A(
double)
300 DECL_TRACE_METHOD_A(sc_dt::sc_int_base)
301 DECL_TRACE_METHOD_A(sc_dt::sc_uint_base)
302 DECL_TRACE_METHOD_A(sc_dt::sc_signed)
303 DECL_TRACE_METHOD_A(sc_dt::sc_unsigned)
305 DECL_TRACE_METHOD_A(sc_dt::sc_fxval)
306 DECL_TRACE_METHOD_A(sc_dt::sc_fxval_fast)
307 DECL_TRACE_METHOD_C(sc_dt::sc_fxnum, sc_dt::sc_fxval)
308 DECL_TRACE_METHOD_C(sc_dt::sc_fxnum_fast, sc_dt::sc_fxval_fast)
310 DECL_TRACE_METHOD_A(sc_dt::sc_bv_base)
311 DECL_TRACE_METHOD_A(sc_dt::sc_lv_base)
312 #undef DECL_TRACE_METHOD_A
313 #undef DECL_TRACE_METHOD_B
314 #undef DECL_TRACE_METHOD_C
316 void fst_trace_file::trace(
const unsigned int&
object,
const std::string& name,
const char** enum_literals) {
320 #define DECL_REGISTER_METHOD_A(tp) \
321 observer::notification_handle* fst_trace_file::observe(const tp& object, const std::string& name) { \
322 all_traces.emplace_back(this, &changed<tp>, new trace::fst_trace_t<tp>(object, name)); \
323 all_traces.back().trc->is_triggered = true; \
324 return &all_traces.back(); \
326 #define DECL_REGISTER_METHOD_C(tp, tpo) \
327 observer::notification_handle* fst_trace_file::observe(const tp& object, const std::string& name) { \
328 all_traces.emplace_back(this, &changed<tp, tpo>, new trace::fst_trace_t<tp, tpo>(object, name)); \
329 all_traces.back().trc->is_triggered = true; \
330 return &all_traces.back(); \
332 #if(SYSTEMC_VERSION >= 20171012)
333 observer::notification_handle* fst_trace_file::observe(
const sc_core::sc_event&
object,
const std::string& name) {
return nullptr; }
334 observer::notification_handle* fst_trace_file::observe(
const sc_core::sc_time&
object,
const std::string& name) {
return nullptr; }
337 DECL_REGISTER_METHOD_A(
bool)
338 DECL_REGISTER_METHOD_A(sc_dt::sc_bit)
339 DECL_REGISTER_METHOD_A(sc_dt::sc_logic)
341 DECL_REGISTER_METHOD_A(
unsigned char)
342 DECL_REGISTER_METHOD_A(
unsigned short)
343 DECL_REGISTER_METHOD_A(
unsigned int)
344 DECL_REGISTER_METHOD_A(
unsigned long)
345 #ifdef SYSTEMC_64BIT_PATCHES
346 DECL_REGISTER_METHOD_A(
unsigned long long)
348 DECL_REGISTER_METHOD_A(
char)
349 DECL_REGISTER_METHOD_A(
short)
350 DECL_REGISTER_METHOD_A(
int)
351 DECL_REGISTER_METHOD_A(
long)
352 DECL_REGISTER_METHOD_A(sc_dt::int64)
353 DECL_REGISTER_METHOD_A(sc_dt::uint64)
355 DECL_REGISTER_METHOD_A(
float)
356 DECL_REGISTER_METHOD_A(
double)
357 DECL_REGISTER_METHOD_A(sc_dt::sc_int_base)
358 DECL_REGISTER_METHOD_A(sc_dt::sc_uint_base)
359 DECL_REGISTER_METHOD_A(sc_dt::sc_signed)
360 DECL_REGISTER_METHOD_A(sc_dt::sc_unsigned)
362 DECL_REGISTER_METHOD_A(sc_dt::sc_fxval)
363 DECL_REGISTER_METHOD_A(sc_dt::sc_fxval_fast)
364 DECL_REGISTER_METHOD_C(sc_dt::sc_fxnum, sc_dt::sc_fxval)
365 DECL_REGISTER_METHOD_C(sc_dt::sc_fxnum_fast, sc_dt::sc_fxval_fast)
367 DECL_REGISTER_METHOD_A(sc_dt::sc_bv_base)
368 DECL_REGISTER_METHOD_A(sc_dt::sc_lv_base)
369 #undef DECL_REGISTER_METHOD_A
370 #undef DECL_REGISTER_METHOD_C
372 bool fst_trace_file::trace_entry::notify() {
373 if(!trc->is_alias && compare_and_update(trc))
374 that->triggered_traces.push_back(trc);
375 return !trc->is_alias;
378 void fst_trace_file::write_comment(
const std::string& comment) {}
381 void add_trace(trace::fst_trace* trace) {
383 add_trace_rec(std::begin(hier), std::end(hier), trace);
386 void writeScopes(
void* fst, std::unordered_map<uintptr_t, fstHandle>& alias_map,
const char* scope_name =
nullptr) {
387 if(m_traces.size() || scope_name) {
388 fstWriterSetScope(fst, FST_ST_VCD_SCOPE, scope_name ? scope_name :
"SystemC",
nullptr);
389 for(
auto& e : m_traces) {
390 auto hier_tokens =
util::split(e.second->name,
'.');
391 auto sig_name = hier_tokens.back();
392 auto alias_it = alias_map.find(e.second->get_hash());
393 e.second->is_alias = alias_it != std::end(alias_map);
395 fstWriterCreateVar(fst, e.second->type == trace::REAL ? FST_VT_VCD_REAL : FST_VT_VCD_WIRE, FST_VD_IMPLICIT,
396 e.second->bits, sig_name.c_str(), e.second->is_alias ? alias_it->second : 0);
397 if(!e.second->is_alias)
398 alias_map.insert({e.second->get_hash(), e.second->fst_hndl});
400 for(
auto& e : m_scopes)
401 e.second->writeScopes(fst, alias_map, e.first.c_str());
402 fstWriterSetUpscope(fst);
404 for(
auto& e : m_scopes)
405 e.second->writeScopes(fst, alias_map, e.first.c_str());
409 for(
auto& s : m_scopes)
414 void add_trace_rec(std::vector<std::string>::iterator beg, std::vector<std::string>::iterator
const& end, trace::fst_trace* trace) {
415 if(std::distance(beg, end) == 1) {
416 m_traces.push_back(std::make_pair(*beg, trace));
418 auto sc = m_scopes.find(*beg);
419 if(sc == std::end(m_scopes))
420 sc = m_scopes.insert({*beg,
new scope_stack}).first;
421 sc->second->add_trace_rec(++beg, end, trace);
424 std::vector<std::pair<std::string, trace::fst_trace*>> m_traces{0};
425 std::unordered_map<std::string, scope_stack*> m_scopes{0};
429 void fst_trace_file::init() {
430 std::vector<trace_entry*> traces;
431 traces.reserve(all_traces.size());
433 for(
auto& e : all_traces) {
434 scope.add_trace(e.trc);
435 traces.push_back(&e);
437 std::unordered_map<uintptr_t, fstHandle> alias_map;
438 scope.writeScopes(m_fst, alias_map);
439 std::copy_if(std::begin(traces), std::end(traces), std::back_inserter(pull_traces),
440 [](trace_entry
const* e) {
return !(e->trc->is_alias || e->trc->is_triggered); });
441 changed_traces.reserve(pull_traces.size());
442 triggered_traces.reserve(all_traces.size());
445 void fst_trace_file::cycle(
bool delta_cycle) {
448 if(last_emitted_ts == std::numeric_limits<uint64_t>::max())
450 if(last_emitted_ts == std::numeric_limits<uint64_t>::max()) {
451 uint64_t time_stamp = sc_core::sc_time_stamp().value() / (1_ps).value();
452 fstWriterEmitTimeChange(m_fst, time_stamp);
453 for(
auto& e : all_traces)
455 e.trc->update_and_record(m_fst);
456 last_emitted_ts = time_stamp;
458 if(check_enabled && !check_enabled())
460 for(
auto e : pull_traces) {
461 if(e->compare_and_update(e->trc))
462 changed_traces.push_back(e->trc);
464 if(triggered_traces.size() || changed_traces.size()) {
465 uint64_t time_stamp = sc_core::sc_time_stamp().value() / (1_ps).value();
466 if(last_emitted_ts < time_stamp)
467 fstWriterEmitTimeChange(m_fst, time_stamp);
468 if(triggered_traces.size()) {
469 auto end = std::unique(std::begin(triggered_traces), std::end(triggered_traces));
470 triggered_traces.erase(end, triggered_traces.end());
471 for(
auto t : triggered_traces)
473 triggered_traces.clear();
475 if(changed_traces.size()) {
476 for(
auto t : changed_traces)
478 changed_traces.clear();
480 last_emitted_ts = time_stamp;
485 void fst_trace_file::set_time_unit(
double v, sc_core::sc_time_unit tu) {}
487 void fst_trace_file::set_time_unit(
int exponent10_seconds) {}
sc_core::sc_trace_file * create_fst_trace_file(const char *name, std::function< bool()> enable)
create FST file which uses pull mechanism
void close_fst_trace_file(sc_core::sc_trace_file *tf)
close the FST file
std::vector< std::string > split(const std::string &s, char separator)