scc  2024.06
SystemC components library
vcd_pull_trace.cpp
1 /*******************************************************************************
2  * Copyright 2021 MINRES Technologies GmbH
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *******************************************************************************/
16 
17 #include "vcd_pull_trace.hh"
18 #include "sc_vcd_trace.h"
19 #include "trace/vcd_trace.hh"
20 #include "utilities.h"
21 
22 #include <cmath>
23 #include <cstdio>
24 #include <cstdlib>
25 #include <cstring>
26 #include <deque>
27 #include <iomanip>
28 #include <limits>
29 #include <map>
30 #include <sstream>
31 #include <stdexcept>
32 #include <string>
33 #include <unordered_map>
34 #include <vector>
35 
36 #define FPRINT(FP, FMTSTR) \
37  { \
38  auto buf = fmt::format(FMTSTR); \
39  std::fwrite(buf.c_str(), 1, buf.size(), FP); \
40  }
41 #define FPRINTF(FP, FMTSTR, ...) \
42  { \
43  auto buf = fmt::format(FMTSTR, __VA_ARGS__); \
44  std::fwrite(buf.c_str(), 1, buf.size(), FP); \
45  }
46 
47 namespace scc {
48 /*******************************************************************************************************
49  *
50  *******************************************************************************************************/
51 vcd_pull_trace_file::vcd_pull_trace_file(const char* name, std::function<bool()>& enable)
52 : name(name)
53 , check_enabled(enable) {
54  vcd_out = fopen(fmt::format("{}.vcd", name).c_str(), "w");
55 
56 #if SC_VERSION_MAJOR < 3
57 #if defined(WITH_SC_TRACING_PHASE_CALLBACKS)
58  // remove from hierarchy
59  sc_object::detach();
60  // register regular (non-delta) callbacks
61  sc_object::register_simulation_phase_callback(SC_BEFORE_TIMESTEP);
62 #else // explicitly register with simcontext
63  sc_core::sc_get_curr_simcontext()->add_trace_file(this);
64 #endif
65 #endif
66 }
67 
68 vcd_pull_trace_file::~vcd_pull_trace_file() {
69  if(vcd_out) {
70  FPRINTF(vcd_out, "#{}\n", sc_core::sc_time_stamp() / 1_ps);
71  fclose(vcd_out);
72  }
73  for(auto t : all_traces)
74  delete t.trc;
75 }
76 
77 template <typename T, typename OT = T> bool changed(trace::vcd_trace* trace) {
78  if(reinterpret_cast<trace::vcd_trace_t<T, OT>*>(trace)->changed()) {
79  reinterpret_cast<trace::vcd_trace_t<T, OT>*>(trace)->update();
80  return true;
81  } else
82  return false;
83 }
84 #define DECL_TRACE_METHOD_A(tp) \
85  void vcd_pull_trace_file::trace(const tp& object, const std::string& name) { \
86  all_traces.emplace_back(&changed<tp>, new trace::vcd_trace_t<tp>(object, name)); \
87  }
88 #define DECL_TRACE_METHOD_B(tp) \
89  void vcd_pull_trace_file::trace(const tp& object, const std::string& name, int width) { \
90  all_traces.emplace_back(&changed<tp>, new trace::vcd_trace_t<tp>(object, name)); \
91  }
92 #define DECL_TRACE_METHOD_C(tp, tpo) \
93  void vcd_pull_trace_file::trace(const tp& object, const std::string& name) { \
94  all_traces.emplace_back(&changed<tp, tpo>, new trace::vcd_trace_t<tp, tpo>(object, name)); \
95  }
96 
97 #if(SYSTEMC_VERSION >= 20171012)
98 void vcd_pull_trace_file::trace(const sc_core::sc_event& object, const std::string& name) {}
99 // void vcd_pull_trace_file::trace(const sc_core::sc_time& object, const std::string& name){}
100 DECL_TRACE_METHOD_A(sc_core::sc_time)
101 #endif
102 DECL_TRACE_METHOD_A(bool)
103 DECL_TRACE_METHOD_A(sc_dt::sc_bit)
104 DECL_TRACE_METHOD_A(sc_dt::sc_logic)
105 
106 DECL_TRACE_METHOD_B(unsigned char)
107 DECL_TRACE_METHOD_B(unsigned short)
108 DECL_TRACE_METHOD_B(unsigned int)
109 DECL_TRACE_METHOD_B(unsigned long)
110 #ifdef SYSTEMC_64BIT_PATCHES
111 DECL_TRACE_METHOD_B(unsigned long long)
112 #endif
113 DECL_TRACE_METHOD_B(char)
114 DECL_TRACE_METHOD_B(short)
115 DECL_TRACE_METHOD_B(int)
116 DECL_TRACE_METHOD_B(long)
117 DECL_TRACE_METHOD_B(sc_dt::int64)
118 DECL_TRACE_METHOD_B(sc_dt::uint64)
119 
120 DECL_TRACE_METHOD_A(float)
121 DECL_TRACE_METHOD_A(double)
122 DECL_TRACE_METHOD_A(sc_dt::sc_int_base)
123 DECL_TRACE_METHOD_A(sc_dt::sc_uint_base)
124 DECL_TRACE_METHOD_A(sc_dt::sc_signed)
125 DECL_TRACE_METHOD_A(sc_dt::sc_unsigned)
126 
127 DECL_TRACE_METHOD_A(sc_dt::sc_fxval)
128 DECL_TRACE_METHOD_A(sc_dt::sc_fxval_fast)
129 DECL_TRACE_METHOD_C(sc_dt::sc_fxnum, sc_dt::sc_fxval)
130 DECL_TRACE_METHOD_C(sc_dt::sc_fxnum_fast, sc_dt::sc_fxval_fast)
131 
132 DECL_TRACE_METHOD_A(sc_dt::sc_bv_base)
133 DECL_TRACE_METHOD_A(sc_dt::sc_lv_base)
134 #undef DECL_TRACE_METHOD_A
135 #undef DECL_TRACE_METHOD_B
136 
137 void vcd_pull_trace_file::trace(const unsigned int& object, const std::string& name, const char** enum_literals) {
138  all_traces.emplace_back(&changed<unsigned int>, new trace::vcd_trace_enum(object, name, enum_literals));
139 }
140 
141 std::string vcd_pull_trace_file::obtain_name() {
142  const char first_type_used = 'a';
143  const int used_types_count = 'z' - 'a' + 1;
144  int result;
145 
146  result = vcd_name_index;
147  char char6 = static_cast<char>(vcd_name_index % used_types_count);
148 
149  result = result / used_types_count;
150  char char5 = static_cast<char>(result % used_types_count);
151 
152  result = result / used_types_count;
153  char char4 = static_cast<char>(result % used_types_count);
154 
155  result = result / used_types_count;
156  char char3 = static_cast<char>(result % used_types_count);
157 
158  result = result / used_types_count;
159  char char2 = static_cast<char>(result % used_types_count);
160 
161  char buf[20];
162  std::sprintf(buf, "%c%c%c%c%c", char2 + first_type_used, char3 + first_type_used, char4 + first_type_used, char5 + first_type_used,
163  char6 + first_type_used);
164  vcd_name_index++;
165  return std::string(buf);
166 }
167 
168 void vcd_pull_trace_file::write_comment(const std::string& comment) { FPRINTF(vcd_out, "$comment\n{}\n$end\n\n", comment); }
169 
170 void vcd_pull_trace_file::init() {
171  std::sort(std::begin(all_traces), std::end(all_traces),
172  [](trace_entry const& a, trace_entry const& b) -> bool { return a.trc->name < b.trc->name; });
173  std::unordered_map<uintptr_t, std::string> alias_map;
174 
175  trace::vcd_scope_stack<trace::vcd_trace> scope;
176  for(auto& e : all_traces) {
177  auto alias_it = alias_map.find(e.trc->get_hash());
178  e.trc->is_alias = alias_it != std::end(alias_map);
179  e.trc->trc_hndl = e.trc->is_alias ? alias_it->second : obtain_name();
180  if(!e.trc->is_alias)
181  alias_map.insert({e.trc->get_hash(), e.trc->trc_hndl});
182  scope.add_trace(e.trc);
183  }
184  std::copy_if(std::begin(all_traces), std::end(all_traces), std::back_inserter(active_traces),
185  [](trace_entry const& e) { return !e.trc->is_alias; });
186  changed_traces.reserve(active_traces.size());
187  // date:
188  char tbuf[200];
189  time_t long_time;
190  time(&long_time);
191  struct tm* p_tm = localtime(&long_time);
192  strftime(tbuf, 199, "%b %d, %Y %H:%M:%S", p_tm);
193  FPRINTF(vcd_out, "$date\n {}\n$end\n\n", tbuf);
194  // version:
195  FPRINTF(vcd_out, "$version\n {}\n$end\n\n", sc_core::sc_version());
196  // timescale:
197  FPRINTF(vcd_out, "$timescale\n {}\n$end\n\n", (1_ps).to_string());
198  std::stringstream ss;
199  ss << "tracing " << active_traces.size() << " distinct traces out of " << all_traces.size() << " traces";
200  write_comment(ss.str());
201  scope.print(vcd_out);
202 }
203 
204 std::string vcd_pull_trace_file::prune_name(std::string const& orig_name) {
205  static bool warned = false;
206  bool braces_removed = false;
207  std::string hier_name = orig_name;
208  for(unsigned int i = 0; i < hier_name.length(); i++) {
209  if(hier_name[i] == '[') {
210  hier_name[i] = '(';
211  braces_removed = true;
212  } else if(hier_name[i] == ']') {
213  hier_name[i] = ')';
214  braces_removed = true;
215  }
216  }
217 
218  if(braces_removed && !warned) {
219  std::stringstream ss;
220  ss << name
221  << ":\n"
222  "\tTraced objects found with name containing [], which may be\n"
223  "\tinterpreted by the waveform viewer in unexpected ways.\n"
224  "\tSo the [] is automatically replaced by ().";
225 
226  SC_REPORT_WARNING(sc_core::SC_ID_TRACING_OBJECT_NAME_FILTERED_, ss.str().c_str());
227  }
228  return hier_name;
229 }
230 
231 void vcd_pull_trace_file::cycle(bool delta_cycle) {
232  if(delta_cycle)
233  return;
234  if(!initialized) {
235  init();
236  initialized = true;
237  FPRINT(vcd_out, "$enddefinitions $end\n\n$dumpvars\n");
238  for(auto& e : active_traces) {
239  e.compare_and_update(e.trc);
240  e.trc->record(vcd_out);
241  }
242  FPRINT(vcd_out, "$end\n\n");
243  } else {
244  if(check_enabled && !check_enabled())
245  return;
246  changed_traces.clear();
247  for(auto& e : active_traces) {
248  if(e.compare_and_update(e.trc))
249  changed_traces.push_back(e.trc);
250  }
251  if(changed_traces.size()) {
252  FPRINTF(vcd_out, "#{}\n", sc_core::sc_time_stamp() / 1_ps);
253  for(auto& t : changed_traces)
254  t->record(vcd_out);
255  }
256  }
257 }
258 
259 void vcd_pull_trace_file::set_time_unit(double v, sc_core::sc_time_unit tu) {}
260 #ifdef NCSC
261 void vcd_pull_trace_file::set_time_unit(int exponent10_seconds) {}
262 #endif
263 
264 sc_core::sc_trace_file* create_vcd_pull_trace_file(const char* name, std::function<bool()> enable) {
265  return new vcd_pull_trace_file(name, enable);
266 }
267 
268 void close_vcd_pull_trace_file(sc_core::sc_trace_file* tf) {
269  vcd_pull_trace_file* vcd_tf = static_cast<vcd_pull_trace_file*>(tf);
270  delete vcd_tf;
271 }
272 
273 } // namespace scc
SCC TLM utilities.
sc_core::sc_trace_file * create_vcd_pull_trace_file(const char *name, std::function< bool()> enable=std::function< bool()>())
create VCD file which uses pull mechanism
void close_vcd_pull_trace_file(sc_core::sc_trace_file *tf)
close the VCD file