scc  2024.06
SystemC components library
scv_tr_ftr.cpp
1 /*******************************************************************************
2  * Copyright 2018 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 #include <array>
17 #include <boost/filesystem.hpp>
18 #include <cmath>
19 #include <cstdio>
20 #include <cstring>
21 #include <fcntl.h>
22 #include <fstream>
23 #include <ftr/ftr_writer.h>
24 #include <iostream>
25 #include <sstream>
26 #include <stdexcept>
27 #include <string>
28 #include <unordered_map>
29 #include <unordered_set>
30 #include <vector>
31 // clang-format off
32 #ifdef HAS_SCV
33 #include <scv.h>
34 #else
35 #include <scv-tr.h>
36 namespace scv_tr {
37 #endif
38 // clang-format on
39 // ----------------------------------------------------------------------------
40 using namespace std;
41 using namespace ftr;
42 // ----------------------------------------------------------------------------
43 namespace {
44 template <bool COMPRESSED> struct tx_db {
45  static ftr_writer<COMPRESSED>* db;
46  static void dbCb(const scv_tr_db& _scv_tr_db, scv_tr_db::callback_reason reason, void* data) {
47  // This is called from the scv_tr_db ctor.
48  static string fName("DEFAULT_scv_tr_cbor");
49  switch(reason) {
50  case scv_tr_db::CREATE:
51  if((_scv_tr_db.get_name() != nullptr) && (strlen(_scv_tr_db.get_name()) != 0))
52  fName = _scv_tr_db.get_name();
53  try {
54  db = new ftr_writer<COMPRESSED>(fName + ".ftr");
55  } catch(...) {
56  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't open recording file");
57  }
58  if(!db->cw.enc.ofs.is_open()) {
59  delete db;
60  db = nullptr;
61  } else {
62  double secs = sc_core::sc_time::from_value(1ULL).to_seconds();
63  auto exp = rint(log(secs) / log(10.0));
64  db->writeInfo(static_cast<int8_t>(exp));
65  }
66  break;
67  case scv_tr_db::DELETE:
68  try {
69  delete db;
70  } catch(...) {
71  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't close recording file");
72  }
73  break;
74  default:
75  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Unknown reason in scv_tr_db callback");
76  }
77  }
78  // ----------------------------------------------------------------------------
79  static void streamCb(const scv_tr_stream& s, scv_tr_stream::callback_reason reason, void* data) {
80  if(db && reason == scv_tr_stream::CREATE) {
81  try {
82  db->writeStream(s.get_id(), s.get_name(), s.get_stream_kind());
83  } catch(std::runtime_error& e) {
84  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't create stream");
85  }
86  }
87  }
88  // ----------------------------------------------------------------------------
89  static inline void recordAttribute(uint64_t id, event_type event, const string& name, ftr::data_type type, const string& value) {
90  if(db)
91  try {
92  db->writeAttribute(id, event, name, type, value);
93  } catch(std::runtime_error& e) {
94  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't create attribute entry");
95  }
96  }
97  // ----------------------------------------------------------------------------
98  static inline void recordAttribute(uint64_t id, event_type event, const string& name, ftr::data_type type, char const* value) {
99  if(db)
100  try {
101  db->writeAttribute(id, event, name, type, value);
102  } catch(std::runtime_error& e) {
103  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't create attribute entry");
104  }
105  }
106  // ----------------------------------------------------------------------------
107  template <typename T>
108  static inline void recordAttribute(uint64_t id, event_type event, const string& name, ftr::data_type type, T value) {
109  if(db)
110  try {
111  db->writeAttribute(id, event, name, type, value);
112  } catch(std::runtime_error& e) {
113  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't create attribute entry");
114  }
115  }
116  // ----------------------------------------------------------------------------
117  static inline std::string get_name(const char* prefix, const scv_extensions_if* my_exts_p) {
118  string name{prefix};
119  if(!prefix || strlen(prefix) == 0) {
120  name = my_exts_p->get_name();
121  } else {
122  if((my_exts_p->get_name() != nullptr) && (strlen(my_exts_p->get_name()) > 0)) {
123  name += ".";
124  name += my_exts_p->get_name();
125  }
126  }
127  return (name == "") ? "<unnamed>" : name;
128  }
129  // ----------------------------------------------------------------------------
130  static void recordAttributes(uint64_t id, event_type eventType, char const* prefix, const scv_extensions_if* my_exts_p) {
131  if(!db || my_exts_p == nullptr)
132  return;
133  auto name = get_name(prefix, my_exts_p);
134  switch(my_exts_p->get_type()) {
135  case scv_extensions_if::RECORD: {
136  int num_fields = my_exts_p->get_num_fields();
137  if(num_fields > 0) {
138  for(int field_counter = 0; field_counter < num_fields; field_counter++) {
139  const scv_extensions_if* field_data_p = my_exts_p->get_field(field_counter);
140  recordAttributes(id, eventType, prefix, field_data_p);
141  }
142  }
143  } break;
144  case scv_extensions_if::ENUMERATION:
145  recordAttribute(id, eventType, name, ftr::data_type::ENUMERATION, my_exts_p->get_enum_string((int)(my_exts_p->get_integer())));
146  break;
147  case scv_extensions_if::BOOLEAN:
148  recordAttribute(id, eventType, name, ftr::data_type::BOOLEAN, my_exts_p->get_bool());
149  break;
150  case scv_extensions_if::INTEGER:
151  case scv_extensions_if::FIXED_POINT_INTEGER:
152  recordAttribute(id, eventType, name, ftr::data_type::INTEGER, my_exts_p->get_integer());
153  break;
154  case scv_extensions_if::UNSIGNED:
155  recordAttribute(id, eventType, name, ftr::data_type::UNSIGNED, my_exts_p->get_integer());
156  break;
157  case scv_extensions_if::POINTER:
158  recordAttribute(id, eventType, name, ftr::data_type::POINTER, (long long)my_exts_p->get_pointer());
159  break;
160  case scv_extensions_if::STRING:
161  recordAttribute(id, eventType, name, ftr::data_type::STRING, my_exts_p->get_string());
162  break;
163  case scv_extensions_if::FLOATING_POINT_NUMBER:
164  recordAttribute(id, eventType, name, ftr::data_type::FLOATING_POINT_NUMBER, my_exts_p->get_double());
165  break;
166  case scv_extensions_if::BIT_VECTOR: {
167  sc_bv_base tmp_bv(my_exts_p->get_bitwidth());
168  my_exts_p->get_value(tmp_bv);
169  recordAttribute(id, eventType, name, ftr::data_type::BIT_VECTOR, tmp_bv.to_string());
170  } break;
171  case scv_extensions_if::LOGIC_VECTOR: {
172  sc_lv_base tmp_lv(my_exts_p->get_bitwidth());
173  my_exts_p->get_value(tmp_lv);
174  recordAttribute(id, eventType, name, ftr::data_type::LOGIC_VECTOR, tmp_lv.to_string());
175  } break;
176  case scv_extensions_if::ARRAY:
177  for(int array_elt_index = 0; array_elt_index < my_exts_p->get_array_size(); array_elt_index++) {
178  const scv_extensions_if* field_data_p = my_exts_p->get_array_elt(array_elt_index);
179  recordAttributes(id, eventType, prefix, field_data_p);
180  }
181  break;
182  default: {
183  std::array<char, 100> tmpString;
184  sprintf(tmpString.data(), "Unsupported attribute type = %d", my_exts_p->get_type());
185  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, tmpString.data());
186  }
187  }
188  }
189  // ----------------------------------------------------------------------------
190  static void generatorCb(const scv_tr_generator_base& g, scv_tr_generator_base::callback_reason reason, void* data) {
191  if(db && reason == scv_tr_generator_base::CREATE) {
192  try {
193  db->writeGenerator(g.get_id(), g.get_name(), g.get_scv_tr_stream().get_id());
194  } catch(std::runtime_error& e) {
195  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't create generator entry");
196  }
197  }
198  }
199  // ----------------------------------------------------------------------------
200  static void transactionCb(const scv_tr_handle& t, scv_tr_handle::callback_reason reason, void* data) {
201  if(!db || !t.get_scv_tr_stream().get_scv_tr_db() || !t.get_scv_tr_stream().get_scv_tr_db()->get_recording())
202  return;
203  uint64_t id = t.get_id();
204  switch(reason) {
205  case scv_tr_handle::BEGIN: {
206  db->startTransaction(id, t.get_scv_tr_generator_base().get_id(), t.get_scv_tr_generator_base().get_scv_tr_stream().get_id(),
207  t.get_begin_sc_time() / sc_core::sc_time(1, sc_core::SC_PS));
208 
209  auto my_exts_p = t.get_begin_exts_p();
210  if(my_exts_p == nullptr)
211  my_exts_p = t.get_scv_tr_generator_base().get_begin_exts_p();
212  if(my_exts_p) {
213  auto tmp_str = t.get_scv_tr_generator_base().get_begin_attribute_name()
214  ? t.get_scv_tr_generator_base().get_begin_attribute_name()
215  : "";
216  recordAttributes(id, event_type::BEGIN, tmp_str, my_exts_p);
217  }
218  } break;
219  case scv_tr_handle::END: {
220  auto my_exts_p = t.get_end_exts_p();
221  if(my_exts_p == nullptr)
222  my_exts_p = t.get_scv_tr_generator_base().get_end_exts_p();
223  if(my_exts_p) {
224  auto tmp_str =
225  t.get_scv_tr_generator_base().get_end_attribute_name() ? t.get_scv_tr_generator_base().get_end_attribute_name() : "";
226  recordAttributes(id, event_type::END, tmp_str, my_exts_p);
227  }
228  db->endTransaction(id, t.get_end_sc_time() / sc_core::sc_time(1, sc_core::SC_PS));
229  } break;
230  default:;
231  }
232  }
233  // ----------------------------------------------------------------------------
234  static void attributeCb(const scv_tr_handle& t, const char* name, const scv_extensions_if* ext, void* data) {
235  if(!db || !t.get_scv_tr_stream().get_scv_tr_db() || !t.get_scv_tr_stream().get_scv_tr_db()->get_recording())
236  return;
237  recordAttributes(t.get_id(), event_type::RECORD, name == nullptr ? "" : name, ext);
238  }
239  // ----------------------------------------------------------------------------
240  static void relationCb(const scv_tr_handle& tr_1, const scv_tr_handle& tr_2, void* data, scv_tr_relation_handle_t relation_handle) {
241  auto& stream1 = tr_1.get_scv_tr_stream();
242  auto txdb = stream1.get_scv_tr_db();
243  if(!db || !txdb || !txdb->get_recording())
244  return;
245  try {
246  auto& stream2 = tr_2.get_scv_tr_stream();
247  db->writeRelation(txdb->get_relation_name(relation_handle), stream1.get_id(), tr_1.get_id(), stream2.get_id(), tr_2.get_id());
248  } catch(std::runtime_error& e) {
249  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't create transaction relation");
250  }
251  }
252 };
253 template <bool COMPRESSED> ftr_writer<COMPRESSED>* tx_db<COMPRESSED>::db{nullptr};
254 } // namespace
255 // ----------------------------------------------------------------------------
256 void scv_tr_ftr_init(bool compressed) {
257  if(compressed) {
258  scv_tr_db::register_class_cb(tx_db<true>::dbCb);
259  scv_tr_stream::register_class_cb(tx_db<true>::streamCb);
260  scv_tr_generator_base::register_class_cb(tx_db<true>::generatorCb);
261  scv_tr_handle::register_class_cb(tx_db<true>::transactionCb);
262  scv_tr_handle::register_record_attribute_cb(tx_db<true>::attributeCb);
263  scv_tr_handle::register_relation_cb(tx_db<true>::relationCb);
264 
265  } else {
266  scv_tr_db::register_class_cb(tx_db<false>::dbCb);
267  scv_tr_stream::register_class_cb(tx_db<false>::streamCb);
268  scv_tr_generator_base::register_class_cb(tx_db<false>::generatorCb);
269  scv_tr_handle::register_class_cb(tx_db<false>::transactionCb);
270  scv_tr_handle::register_record_attribute_cb(tx_db<false>::attributeCb);
271  scv_tr_handle::register_relation_cb(tx_db<false>::relationCb);
272  }
273 }
274 // ----------------------------------------------------------------------------
275 #ifndef HAS_SCV
276 }
277 #endif
log
enum defining the log levels
Definition: report.h:85
SystemC Verification Library (SCV) Transaction Recording.