17 #include "vcd_push_trace.hh"
18 #include "sc_vcd_trace.h"
19 #include "trace/vcd_trace.hh"
20 #include "utilities.h"
32 #include <unordered_map>
35 #define FPRINT(FP, FMTSTR) \
37 auto buf = fmt::format(FMTSTR); \
38 std::fwrite(buf.c_str(), 1, buf.size(), FP); \
40 #define FPRINTF(FP, FMTSTR, ...) \
42 auto buf = fmt::format(FMTSTR, __VA_ARGS__); \
43 std::fwrite(buf.c_str(), 1, buf.size(), FP); \
50 vcd_push_trace_file::vcd_push_trace_file(
const char* name, std::function<
bool()>& enable)
52 , check_enabled(enable) {
53 vcd_out = fopen(fmt::format(
"{}.vcd", name).c_str(),
"w");
55 #if defined(WITH_SC_TRACING_PHASE_CALLBACKS)
59 sc_object::register_simulation_phase_callback(SC_BEFORE_TIMESTEP);
61 sc_core::sc_get_curr_simcontext()->add_trace_file(
this);
65 vcd_push_trace_file::~vcd_push_trace_file() {
67 FPRINTF(vcd_out,
"#{}\n", sc_core::sc_time_stamp() / 1_ps);
70 for(
auto t : all_traces)
74 template <
typename T,
typename OT = T>
bool changed(trace::vcd_trace* trace) {
75 if(
reinterpret_cast<trace::vcd_trace_t<T, OT>*
>(trace)->changed()) {
76 reinterpret_cast<trace::vcd_trace_t<T, OT>*
>(trace)->update();
81 #define DECL_TRACE_METHOD_A(tp) \
82 void vcd_push_trace_file::trace(const tp& object, const std::string& name) { \
83 all_traces.emplace_back(this, &changed<tp>, new trace::vcd_trace_t<tp>(object, name)); \
85 #define DECL_TRACE_METHOD_B(tp) \
86 void vcd_push_trace_file::trace(const tp& object, const std::string& name, int width) { \
87 all_traces.emplace_back(this, &changed<tp>, new trace::vcd_trace_t<tp>(object, name)); \
89 #define DECL_TRACE_METHOD_C(tp, tpo) \
90 void vcd_push_trace_file::trace(const tp& object, const std::string& name) { \
91 all_traces.emplace_back(this, &changed<tp, tpo>, new trace::vcd_trace_t<tp, tpo>(object, name)); \
94 #if(SYSTEMC_VERSION >= 20171012)
95 void vcd_push_trace_file::trace(
const sc_core::sc_event&
object,
const std::string& name) {}
96 void vcd_push_trace_file::trace(
const sc_core::sc_time&
object,
const std::string& name) {}
98 DECL_TRACE_METHOD_A(
bool)
99 DECL_TRACE_METHOD_A(sc_dt::sc_bit)
100 DECL_TRACE_METHOD_A(sc_dt::sc_logic)
102 DECL_TRACE_METHOD_B(
unsigned char)
103 DECL_TRACE_METHOD_B(
unsigned short)
104 DECL_TRACE_METHOD_B(
unsigned int)
105 DECL_TRACE_METHOD_B(
unsigned long)
106 #ifdef SYSTEMC_64BIT_PATCHES
107 DECL_TRACE_METHOD_B(
unsigned long long)
109 DECL_TRACE_METHOD_B(
char)
110 DECL_TRACE_METHOD_B(
short)
111 DECL_TRACE_METHOD_B(
int)
112 DECL_TRACE_METHOD_B(
long)
113 DECL_TRACE_METHOD_B(sc_dt::int64)
114 DECL_TRACE_METHOD_B(sc_dt::uint64)
116 DECL_TRACE_METHOD_A(
float)
117 DECL_TRACE_METHOD_A(
double)
118 DECL_TRACE_METHOD_A(sc_dt::sc_int_base)
119 DECL_TRACE_METHOD_A(sc_dt::sc_uint_base)
120 DECL_TRACE_METHOD_A(sc_dt::sc_signed)
121 DECL_TRACE_METHOD_A(sc_dt::sc_unsigned)
123 DECL_TRACE_METHOD_A(sc_dt::sc_fxval)
124 DECL_TRACE_METHOD_A(sc_dt::sc_fxval_fast)
125 DECL_TRACE_METHOD_C(sc_dt::sc_fxnum, sc_dt::sc_fxval)
126 DECL_TRACE_METHOD_C(sc_dt::sc_fxnum_fast, sc_dt::sc_fxval_fast)
128 DECL_TRACE_METHOD_A(sc_dt::sc_bv_base)
129 DECL_TRACE_METHOD_A(sc_dt::sc_lv_base)
130 #undef DECL_TRACE_METHOD_A
131 #undef DECL_TRACE_METHOD_B
132 #undef DECL_TRACE_METHOD_C
134 void vcd_push_trace_file::trace(
const unsigned int&
object,
const std::string& name,
const char** enum_literals) {
135 all_traces.emplace_back(
this, &changed<unsigned int>,
new trace::vcd_trace_enum(
object, name, enum_literals));
138 #define DECL_REGISTER_METHOD_A(tp) \
139 observer::notification_handle* vcd_push_trace_file::observe(const tp& object, const std::string& name) { \
140 all_traces.emplace_back(this, &changed<tp>, new trace::vcd_trace_t<tp>(object, name)); \
141 all_traces.back().trc->is_triggered = true; \
142 return &all_traces.back(); \
144 #define DECL_REGISTER_METHOD_C(tp, tpo) \
145 observer::notification_handle* vcd_push_trace_file::observe(const tp& object, const std::string& name) { \
146 all_traces.emplace_back(this, &changed<tp, tpo>, new trace::vcd_trace_t<tp, tpo>(object, name)); \
147 all_traces.back().trc->is_triggered = true; \
148 return &all_traces.back(); \
150 #if(SYSTEMC_VERSION >= 20171012)
151 observer::notification_handle* vcd_push_trace_file::observe(
const sc_core::sc_event&
object,
const std::string& name) {
return nullptr; }
152 observer::notification_handle* vcd_push_trace_file::observe(
const sc_core::sc_time&
object,
const std::string& name) {
return nullptr; }
155 DECL_REGISTER_METHOD_A(
bool)
156 DECL_REGISTER_METHOD_A(sc_dt::sc_bit)
157 DECL_REGISTER_METHOD_A(sc_dt::sc_logic)
159 DECL_REGISTER_METHOD_A(
unsigned char)
160 DECL_REGISTER_METHOD_A(
unsigned short)
161 DECL_REGISTER_METHOD_A(
unsigned int)
162 DECL_REGISTER_METHOD_A(
unsigned long)
163 #ifdef SYSTEMC_64BIT_PATCHES
164 DECL_REGISTER_METHOD_A(
unsigned long long)
166 DECL_REGISTER_METHOD_A(
char)
167 DECL_REGISTER_METHOD_A(
short)
168 DECL_REGISTER_METHOD_A(
int)
169 DECL_REGISTER_METHOD_A(
long)
170 DECL_REGISTER_METHOD_A(sc_dt::int64)
171 DECL_REGISTER_METHOD_A(sc_dt::uint64)
173 DECL_REGISTER_METHOD_A(
float)
174 DECL_REGISTER_METHOD_A(
double)
175 DECL_REGISTER_METHOD_A(sc_dt::sc_int_base)
176 DECL_REGISTER_METHOD_A(sc_dt::sc_uint_base)
177 DECL_REGISTER_METHOD_A(sc_dt::sc_signed)
178 DECL_REGISTER_METHOD_A(sc_dt::sc_unsigned)
180 DECL_REGISTER_METHOD_A(sc_dt::sc_fxval)
181 DECL_REGISTER_METHOD_A(sc_dt::sc_fxval_fast)
182 DECL_REGISTER_METHOD_C(sc_dt::sc_fxnum, sc_dt::sc_fxval)
183 DECL_REGISTER_METHOD_C(sc_dt::sc_fxnum_fast, sc_dt::sc_fxval_fast)
185 DECL_REGISTER_METHOD_A(sc_dt::sc_bv_base)
186 DECL_REGISTER_METHOD_A(sc_dt::sc_lv_base)
187 #undef DECL_REGISTER_METHOD_A
188 #undef DECL_REGISTER_METHOD_C
190 bool vcd_push_trace_file::trace_entry::notify() {
191 if(!trc->is_alias && compare_and_update(trc))
192 that->triggered_traces.push_back(trc);
193 return !trc->is_alias;
196 std::string vcd_push_trace_file::obtain_name() {
197 const char first_type_used =
'a';
198 const int used_types_count =
'z' -
'a' + 1;
201 result = vcd_name_index;
202 char char6 =
static_cast<char>(vcd_name_index % used_types_count);
204 result = result / used_types_count;
205 char char5 =
static_cast<char>(result % used_types_count);
207 result = result / used_types_count;
208 char char4 =
static_cast<char>(result % used_types_count);
210 result = result / used_types_count;
211 char char3 =
static_cast<char>(result % used_types_count);
213 result = result / used_types_count;
214 char char2 =
static_cast<char>(result % used_types_count);
217 std::sprintf(buf,
"%c%c%c%c%c", char2 + first_type_used, char3 + first_type_used, char4 + first_type_used, char5 + first_type_used,
218 char6 + first_type_used);
220 return std::string(buf);
223 void vcd_push_trace_file::write_comment(
const std::string& comment) { FPRINTF(vcd_out,
"$comment\n{}\n$end\n\n", comment); }
225 void vcd_push_trace_file::init() {
226 std::vector<trace_entry*> traces;
227 traces.reserve(all_traces.size());
228 for(
auto& e : all_traces)
229 traces.push_back(&e);
230 std::sort(std::begin(traces), std::end(traces),
231 [](trace_entry
const* a, trace_entry
const* b) ->
bool {
return a->trc->name < b->trc->name; });
233 std::unordered_map<uintptr_t, std::string> alias_map;
234 trace::vcd_scope_stack<trace::vcd_trace> scope;
235 for(
auto e : traces) {
236 auto alias_it = alias_map.find(e->trc->get_hash());
237 e->trc->is_alias = alias_it != std::end(alias_map);
238 e->trc->trc_hndl = e->trc->is_alias ? alias_it->second : obtain_name();
239 if(!e->trc->is_alias)
240 alias_map.insert({e->trc->get_hash(), e->trc->trc_hndl});
241 scope.add_trace(e->trc);
243 std::copy_if(std::begin(traces), std::end(traces), std::back_inserter(pull_traces),
244 [](trace_entry
const* e) {
return !(e->trc->is_alias || e->trc->is_triggered); });
245 changed_traces.reserve(pull_traces.size());
246 triggered_traces.reserve(traces.size());
251 struct tm* p_tm = localtime(&long_time);
252 strftime(tbuf, 199,
"%b %d, %Y %H:%M:%S", p_tm);
253 FPRINTF(vcd_out,
"$date\n {}\n$end\n\n", tbuf);
255 FPRINTF(vcd_out,
"$version\n {}\n$end\n\n", sc_core::sc_version());
257 FPRINTF(vcd_out,
"$timescale\n {}\n$end\n\n", (1_ps).to_string());
258 std::stringstream ss;
259 ss <<
"tracing " << pull_traces.size() <<
" distinct traces out of " << all_traces.size() <<
" traces";
260 write_comment(ss.str());
261 scope.print(vcd_out);
264 std::string vcd_push_trace_file::prune_name(std::string
const& orig_name) {
265 static bool warned =
false;
266 bool braces_removed =
false;
267 std::string hier_name = orig_name;
268 for(
unsigned int i = 0; i < hier_name.length(); i++) {
269 if(hier_name[i] ==
'[') {
271 braces_removed =
true;
272 }
else if(hier_name[i] ==
']') {
274 braces_removed =
true;
278 if(braces_removed && !warned) {
279 std::stringstream ss;
282 "\tTraced objects found with name containing [], which may be\n"
283 "\tinterpreted by the waveform viewer in unexpected ways.\n"
284 "\tSo the [] is automatically replaced by ().";
286 SC_REPORT_WARNING(sc_core::SC_ID_TRACING_OBJECT_NAME_FILTERED_, ss.str().c_str());
291 void vcd_push_trace_file::cycle(
bool delta_cycle) {
294 if(last_emitted_ts == std::numeric_limits<uint64_t>::max()) {
296 FPRINT(vcd_out,
"$enddefinitions $end\n\n$dumpvars\n");
297 for(
auto& e : all_traces)
298 if(!e.trc->is_alias) {
299 e.compare_and_update(e.trc);
300 e.trc->record(vcd_out);
302 FPRINT(vcd_out,
"$end\n\n");
303 last_emitted_ts = sc_core::sc_time_stamp().value() / (1_ps).value();
305 if(check_enabled && !check_enabled())
307 for(
auto e : pull_traces) {
308 if(e->compare_and_update(e->trc))
309 changed_traces.push_back(e->trc);
311 if(triggered_traces.size() || changed_traces.size()) {
312 uint64_t time_stamp = sc_core::sc_time_stamp().value() / (1_ps).value();
313 FPRINTF(vcd_out,
"#{}\n", time_stamp);
314 auto end = std::unique(std::begin(triggered_traces), std::end(triggered_traces));
315 triggered_traces.erase(end, triggered_traces.end());
316 if(triggered_traces.size()) {
317 auto end = std::unique(std::begin(triggered_traces), std::end(triggered_traces));
318 for(
auto it = triggered_traces.begin(); it != end; ++it)
319 (*it)->record(vcd_out);
320 triggered_traces.clear();
322 if(changed_traces.size()) {
323 for(
auto t : changed_traces)
325 changed_traces.clear();
327 last_emitted_ts = time_stamp;
332 void vcd_push_trace_file::set_time_unit(
double v, sc_core::sc_time_unit tu) {}
334 void vcd_push_trace_file::set_time_unit(
int exponent10_seconds) {}
void close_vcd_push_trace_file(sc_core::sc_trace_file *tf)
close the VCD file
sc_core::sc_trace_file * create_vcd_push_trace_file(const char *name, std::function< bool()> enable=std::function< bool()>())
create VCD file which uses push mechanism