scc  2024.06
SystemC components library
vcd_trace.hh
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 #ifndef _SCC_TRACE_VCD_TRACE_HH_
17 #define _SCC_TRACE_VCD_TRACE_HH_
18 
19 #include "types.hh"
20 #ifndef FWRITE
21 #include <cstdio>
22 #define FWRITE(BUF, SZ, LEN, FP) std::fwrite(BUF, SZ, LEN, FP)
23 #define FPTR FILE*
24 #endif
25 #include <util/ities.h>
26 #include <scc/utilities.h>
27 #include <fmt/format.h>
28 #include <vector>
29 #include <unordered_map>
30 
31 
32 namespace scc {
33 namespace trace {
34 
35 inline void vcdEmitValueChange(FPTR os, std::string const& handle, unsigned bits, const char *val) {
36  auto buf = bits==1?fmt::format("{}{}\n", *val, handle):fmt::format("b{} {}\n", val, handle);
37  FWRITE(buf.c_str(), 1, buf.size(), os);
38 }
39 
40 inline void vcdEmitValueChange32(FPTR os, std::string const& handle, unsigned bits, uint32_t val){
41  auto buf = fmt::format("b{:b} {}\n", val&((1ull<<bits)-1), handle);
42  FWRITE(buf.c_str(), 1, buf.size(), os);
43 }
44 
45 inline void vcdEmitValueChange64(FPTR os, std::string const& handle, unsigned bits, uint64_t val){
46  auto buf = fmt::format("b{:b} {}\n", val&((1ul<<std::min(63u,bits))-1), handle);
47  FWRITE(buf.c_str(), 1, buf.size(), os);
48 }
49 
50 template<typename T>
51 inline void vcdEmitValueChangeReal(FPTR os, std::string const& handle, unsigned bits, T val){
52  auto buf = fmt::format("r{:.16g} {}\n", static_cast<double>(val), handle);
53  FWRITE(buf.c_str(), 1, buf.size(), os);
54 }
55 
56 inline size_t get_buffer_size(int length){
57  size_t sz = ( static_cast<size_t>(length) + 4096 ) & (~static_cast<size_t>(4096-1));
58  return std::max<uint64_t>(1024UL, sz);
59 }
60 
61 /*******************************************************************************************************
62  *
63  *******************************************************************************************************/
64 template<typename T>
66  void add_trace(T *trace){
67  auto hier = util::split(trace->name, '.');
68  add_trace_rec(std::begin(hier), std::end(hier), trace);
69  }
70 
71  void print(FPTR os, const char *scope_name = "SystemC"){
72  auto buf = fmt::format("$scope module {} $end\n", scope_name);
73  FWRITE(buf.c_str(), 1, buf.size(), os);
74  for (auto& e : m_traces)
75  print_variable_declaration_line(os, e.first.c_str(), e.second);
76  for (auto& e : m_scopes)
77  e.second->print(os,e.first.c_str());
78  std::string end = "$upscope $end\n";
79  FWRITE(end.c_str(), 1, end.size(), os);
80  }
81 
82  ~vcd_scope_stack(){
83  for (auto& s : m_scopes)
84  delete s.second;
85  }
86 private:
87  void add_trace_rec(std::vector<std::string>::iterator beg, std::vector<std::string>::iterator const& end, T *trace){
88  if(std::distance(beg, end)==1){
89  m_traces.push_back(std::make_pair(*beg, trace));
90  } else {
91  auto sc = m_scopes.find(*beg);
92  if(sc == std::end(m_scopes))
93  sc = m_scopes.insert({*beg, new vcd_scope_stack}).first;
94  sc->second->add_trace_rec(++beg, end, trace);
95  }
96  }
97  void print_variable_declaration_line(FPTR os, const char* scoped_name, T* trc){
98  char buf[2000];
99  switch(trc->bits){
100  case 0:{
101  std::stringstream ss;
102  ss << "'" << scoped_name << "' has 0 bits";
103  SC_REPORT_ERROR(sc_core::SC_ID_TRACING_OBJECT_IGNORED_, ss.str().c_str() );
104  return;
105  }
106  case 1:
107  if(trc->type==WIRE) {
108  auto buf = fmt::format("$var wire {} {} {} $end\n", trc->bits, trc->trc_hndl, scoped_name);
109  FWRITE(buf.c_str(), 1, buf.size(), os);
110  } else {
111  auto buf = fmt::format("$var real {} {} {} $end\n", trc->bits, trc->trc_hndl, scoped_name);
112  FWRITE(buf.c_str(), 1, buf.size(), os);
113  }
114  break;
115  default: {
116  auto buf = fmt::format("$var wire {} {} {} [{}:0] $end\n", trc->bits, trc->trc_hndl, scoped_name, trc->bits-1);
117  FWRITE(buf.c_str(), 1, buf.size(), os);
118  }
119  }
120  }
121 
122  std::vector<std::pair<std::string,T*> > m_traces{0};
123  std::unordered_map<std::string, vcd_scope_stack*> m_scopes{0};
124 };
125 
126 struct vcd_trace {
127  vcd_trace(std::string const& nm, trace_type t, unsigned bits): name{nm}, bits{bits}, type{t}{}
128 
129  virtual void record(FPTR os) = 0;
130 
131  virtual void update() = 0;
132 
133  virtual uintptr_t get_hash() = 0;
134 
135  virtual ~vcd_trace(){};
136 
137  const std::string name;
138  std::string trc_hndl{};
139  bool is_alias{false};
140  bool is_triggered{false};
141  const unsigned bits;
142  const trace_type type;
143 };
144 
145 namespace {
146 
147 inline unsigned get_bits(const char** literals) {
148  unsigned nliterals;
149  for (nliterals = 0; literals[nliterals]; nliterals++) continue;
150  return scc::ilog2(nliterals);
151 }
152 
153 struct vcd_trace_enum : public vcd_trace {
154  vcd_trace_enum( const unsigned int& object_,
155  const std::string& name, const char** literals)
156  : vcd_trace( name, trace::WIRE, get_bits(literals))
157  , act_val( object_ )
158  , old_val( object_ )
159  , literals{literals}
160  {}
161 
162  uintptr_t get_hash() override { return reinterpret_cast<uintptr_t>(&act_val);}
163 
164  inline bool changed() { return !is_alias && old_val!=act_val; }
165 
166  void update() override { old_val=act_val; }
167 
168  void record(FPTR os) override { vcdEmitValueChange64(os, trc_hndl, bits, old_val); }
169 
170  unsigned int old_val;
171  const unsigned int& act_val;
172  const char** literals;
173 };
174 
175 template<typename T, typename OT=T>
176 struct vcd_trace_t : public vcd_trace {
177  vcd_trace_t( const T& object_,
178  const std::string& name)
179  : vcd_trace( name, trace::traits<T>::get_type(), trace::traits<T>::get_bits(object_))
180  , act_val( object_ )
181  , old_val( object_ )
182  {}
183 
184  uintptr_t get_hash() override { return reinterpret_cast<uintptr_t>(&act_val);}
185 
186  inline bool changed() { return !is_alias && old_val!=act_val; }
187 
188  void update() override { old_val=act_val; }
189 
190  void record(FPTR os) override;
191 
192  OT old_val;
193  const T& act_val;
194 };
195 
196 template<typename T, typename OT>
197 void vcd_trace_t<T, OT>::record(FPTR os) {
198  if(sizeof(T)<=4)
199  vcdEmitValueChange32(os, trc_hndl, bits, old_val);
200  else
201  vcdEmitValueChange64(os, trc_hndl, bits, old_val);
202 }
203 template<> void vcd_trace_t<sc_core::sc_time, sc_core::sc_time>::record(FPTR os){
204  vcdEmitValueChange64(os, trc_hndl, bits, old_val.value());
205 }
206 template<> void vcd_trace_t<bool, bool>::record(FPTR os){
207  vcdEmitValueChange(os, trc_hndl, 1, old_val ? "1" : "0");
208 }
209 template<> void vcd_trace_t<sc_dt::sc_bit, sc_dt::sc_bit>::record(FPTR os){
210  vcdEmitValueChange(os, trc_hndl, 1, old_val ? "1" : "0");
211 }
212 template<> void vcd_trace_t<sc_dt::sc_logic, sc_dt::sc_logic>::record(FPTR os){
213  char buf[2] = {0, 0};
214  buf[0]=old_val.to_char();
215  vcdEmitValueChange(os, trc_hndl, 1, buf);
216 }
217 template<> void vcd_trace_t<float, float>::record(FPTR os){
218  vcdEmitValueChangeReal(os, trc_hndl, 32, old_val);
219 }
220 template<> void vcd_trace_t<double, double>::record(FPTR os){
221  vcdEmitValueChangeReal(os, trc_hndl, 64, old_val);
222 }
223 template<> void vcd_trace_t<sc_dt::sc_int_base, sc_dt::sc_int_base>::record(FPTR os){
224  static std::vector<char> rawdata(get_buffer_size(old_val.length()));
225  char *rawdata_ptr = &rawdata[0];
226  for (int bitindex = old_val.length() - 1; bitindex >= 0; --bitindex) {
227  *rawdata_ptr++ = '0'+old_val[bitindex].value();
228  }
229  vcdEmitValueChange(os, trc_hndl, bits, &rawdata[0]);
230 }
231 template<> void vcd_trace_t<sc_dt::sc_uint_base, sc_dt::sc_uint_base>::record(FPTR os){
232  static std::vector<char> rawdata(get_buffer_size(old_val.length()));
233  char *rawdata_ptr = &rawdata[0];
234  for (int bitindex = old_val.length() - 1; bitindex >= 0; --bitindex) {
235  *rawdata_ptr++ = '0'+old_val[bitindex].value();
236  }
237  vcdEmitValueChange(os, trc_hndl, bits, &rawdata[0]);
238 }
239 template<> void vcd_trace_t<sc_dt::sc_signed, sc_dt::sc_signed>::record(FPTR os){
240  static std::vector<char> rawdata(get_buffer_size(old_val.length()));
241  char *rawdata_ptr = &rawdata[0];
242  bool is_started=false;
243  int bitindex = old_val.length() - 1;
244  *rawdata_ptr++ = '0'+old_val[bitindex--].value();
245  for (; bitindex >= 0; --bitindex) {
246  auto c = '0'+old_val[bitindex].value();
247  if(is_started)
248  *rawdata_ptr++ = c;
249  else if(c=='1' || *(rawdata_ptr-1)!=c ) {
250  *rawdata_ptr++ = c;
251  is_started=true;
252  }
253  }
254  vcdEmitValueChange(os, trc_hndl, bits, &rawdata[0]);
255 }
256 template<> void vcd_trace_t<sc_dt::sc_unsigned, sc_dt::sc_unsigned>::record(FPTR os){
257  static std::vector<char> rawdata(get_buffer_size(old_val.length()));
258  char *rawdata_ptr = &rawdata[0];
259  bool is_started=false;
260  int bitindex = old_val.length() - 1;
261  *rawdata_ptr++ = '0'+old_val[bitindex--].value();
262  for (; bitindex >= 0; --bitindex) {
263  auto c = '0'+old_val[bitindex].value();
264  if(is_started)
265  *rawdata_ptr++ = c;
266  else if(c=='1' || *(rawdata_ptr-1)!=c ) {
267  *rawdata_ptr++ = c;
268  is_started=true;
269  }
270  }
271  vcdEmitValueChange(os, trc_hndl, bits, &rawdata[0]);
272 }
273 template<> void vcd_trace_t<sc_dt::sc_fxval, sc_dt::sc_fxval>::record(FPTR os){
274  vcdEmitValueChangeReal(os, trc_hndl, bits, old_val);
275 }
276 template<> void vcd_trace_t<sc_dt::sc_fxval_fast, sc_dt::sc_fxval_fast>::record(FPTR os){
277  vcdEmitValueChangeReal(os, trc_hndl, bits, old_val);
278 }
279 template<> void vcd_trace_t<sc_dt::sc_fxnum, sc_dt::sc_fxval>::record(FPTR os){
280  vcdEmitValueChangeReal(os, trc_hndl, bits, old_val);
281 }
282 template<> void vcd_trace_t<sc_dt::sc_fxnum_fast, sc_dt::sc_fxval_fast>::record(FPTR os){
283  vcdEmitValueChangeReal(os, trc_hndl, bits, old_val);
284 }
285 template<> void vcd_trace_t<sc_dt::sc_bv_base, sc_dt::sc_bv_base>::record(FPTR os){
286  auto str = old_val.to_string();
287  auto* cstr = str.c_str();
288  auto c=*cstr;
289  if(c!='1') while(c == *(cstr+1)) cstr++;
290  vcdEmitValueChange(os, trc_hndl, bits, cstr);
291 }
292 template<> void vcd_trace_t<sc_dt::sc_lv_base, sc_dt::sc_lv_base>::record(FPTR os){
293  auto str = old_val.to_string();
294  auto* cstr = str.c_str();
295  auto c=*cstr;
296  if(c!='1') while(c == *(cstr+1)) cstr++;
297  vcdEmitValueChange(os, trc_hndl, bits, cstr);
298 }
299 } // namespace anonymous
300 } // namespace trace
301 } // namespace scc
302 #endif //_SCC_TRACE_VCD_TRACE_HH_
SCC TLM utilities.
std::vector< std::string > split(const std::string &s, char separator)
Definition: ities.h:223