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