scc  2022.4.0
SystemC components library
scv_tr_compressed.cpp
1 // -*- C++ -*- <this line is for emacs to recognize it as C++ code>
2 /*****************************************************************************
3 
4  Licensed to Accellera Systems Initiative Inc. (Accellera)
5  under one or more contributor license agreements. See the
6  NOTICE file distributed with this work for additional
7  information regarding copyright ownership. Accellera licenses
8  this file to you under the Apache License, Version 2.0 (the
9  "License"); you may not use this file except in compliance
10  with the License. You may obtain a copy of the License at
11 
12  http://www.apache.org/licenses/LICENSE-2.0
13 
14  Unless required by applicable law or agreed to in writing,
15  software distributed under the License is distributed on an
16  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17  KIND, either express or implied. See the License for the
18  specific language governing permissions and limitations
19  under the License.
20 
21  *****************************************************************************/
22 
23 /*****************************************************************************
24 
25  scv_tr_text.cpp -- This is the implementation of the transaction recording
26  text facility, which uses callbacks in scv_tr.h
27 
28  Original Authors (Cadence Design Systems, Inc):
29  Norris Ip, Dean Shea, John Rose, Jasvinder Singh, William Paulsen,
30  John Pierce, Rachida Kebichi, Ted Elkind, David Bailey
31  2002-09-23
32 
33  *****************************************************************************/
34 
35 /*****************************************************************************
36 
37  MODIFICATION LOG - modifiers, enter your name, affiliation, date and
38  changes you are making here.
39 
40  Name, Affiliation, Date: Torsten Maehne,
41  Universite Pierre et Marie Curie, 2013-04-30
42  Description of Modification: Fix memory leak caused by not free()-ing
43  C-strings duplicated using strdup() in the
44  function scv_tr_db_cbf() by changing the type
45  of the concerned static variable
46  my_text_file_namefrom char* to string.
47  Remove the now unused internal
48  static scv_tr_strdup() function, which is anyway
49  not exported by the linker.
50 
51  *****************************************************************************/
52 
53 /*
54  * Here's the format of the text file:
55 
56  scv_tr_stream (ID <id>, name "<full_name>", kind "<kind>")
57 
58  scv_tr_generator (ID <id>, name "<name>", scv_tr_stream <id>,
59  begin_attribute (ID <id1>, name "<name1>", type <"type_name">)
60  begin_attribute (ID <id2>, name "<name2>", type <"type_name">)
61  end_attribute (ID <id3>, name "<name3>", type <"type_name">)
62  end_attribute (ID <id4>, name "<name4>", type <"type_name">)
63  ... )
64 
65  tx_begin <this_transaction_id> <generator_id> <begin_time>
66  a <value>
67  a <value>
68 
69  tx_end <this_transaction_id> <generator_id> <end_time>
70  a <value>
71  a <value>
72 
73  tx_relation <"relation_name"> <tx_id_1> <tx_id_2>
74 
75  *
76  */
77 
78 #include <string>
79 // clang-format off
80 #include <array>
81 #include <zlib.h>
82 #include <sstream>
83 #ifdef HAS_SCV
84 #include <scv.h>
85 #else
86 #include <scv-tr.h>
87 namespace scv_tr {
88 #endif
89 // clang-format on
90 // ----------------------------------------------------------------------------
91 
92 #ifdef _MSC_VER
93 #define scv_tr_TEXT_LLU "%I64u"
94 #define scv_tr_TEXT_LLX "%I64x"
95 #else
96 #define scv_tr_TEXT_LLU "%llu"
97 #define scv_tr_TEXT_LLX "%llx"
98 #endif
99 
100 //#define scv_tr_TRACE
101 
102 // ----------------------------------------------------------------------------
103 
104 static gzFile my_text_file_p = nullptr;
105 
106 static void scv_tr_db_cbf(const scv_tr_db& _scv_tr_db, scv_tr_db::callback_reason reason, void* user_data_p) {
107  // This is called from the scv_tr_db ctor.
108 
109  static std::string my_text_file_name("DEFAULT_scv_tr_TEXT.txt");
110 
111  switch(reason) {
112 
113  case scv_tr_db::CREATE:
114  if((_scv_tr_db.get_name() != nullptr) && (strlen(_scv_tr_db.get_name()) != 0)) {
115  my_text_file_name = _scv_tr_db.get_name();
116  }
117 
118  my_text_file_p = gzopen(my_text_file_name.c_str(), "wb1"); // f, h, R
119 
120  if(my_text_file_p == nullptr) {
121  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't open text recording file");
122  } else {
123  std::stringstream ss;
124  ss << "opening file " << my_text_file_name;
125  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL_INFO, ss.str().c_str());
126  }
127  break;
128 
129  case scv_tr_db::DELETE:
130  if(my_text_file_p != nullptr) {
131  std::stringstream ss;
132  ss << "closing file " << my_text_file_name;
133  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL_INFO, ss.str().c_str());
134  gzclose(my_text_file_p);
135  my_text_file_p = nullptr;
136  }
137  break;
138 
139  default:
140  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Unknown reason in scv_tr_db callback");
141  }
142 }
143 
144 // ----------------------------------------------------------------------------
145 
146 static void scv_tr_stream_cbf(const scv_tr_stream& s, scv_tr_stream::callback_reason reason, void* user_data_p) {
147  if(reason == scv_tr_stream::CREATE) {
148 
149  if(my_text_file_p == nullptr)
150  return;
151 
152  gzprintf(my_text_file_p, "scv_tr_stream (ID " scv_tr_TEXT_LLU ", name \"%s\", kind \"%s\")\n", s.get_id(), s.get_name(),
153  s.get_stream_kind() ? s.get_stream_kind() : "<no_stream_kind>");
154  }
155 }
156 
157 // ----------------------------------------------------------------------------
158 
159 //#define TRACE_DO_ATTRIBUTES
160 
161 static void do_attributes(bool declare_attributes, // If false then print the values
162  bool undefined_values, bool is_record_attribute, std::string& prefix_name, const std::string& exts_kind,
163  const scv_extensions_if* my_exts_p,
164  int* index) // The attribute index number
165 {
166  // This function can be called recursively, for nested data types.
167  if(my_exts_p == nullptr)
168  return;
169 
170  std::string full_name;
171 
172  if(prefix_name == "") {
173  full_name = my_exts_p->get_name();
174  } else {
175  if((my_exts_p->get_name() == nullptr) || (strlen(my_exts_p->get_name()) == 0)) {
176  full_name = prefix_name;
177  } else {
178  full_name = prefix_name + "." + my_exts_p->get_name();
179  }
180  }
181 
182  if(full_name == "") {
183  full_name = "<anonymous>";
184  }
185 
186  switch(my_exts_p->get_type()) {
187 
188  case scv_extensions_if::RECORD: {
189  int num_fields = my_exts_p->get_num_fields();
190  int field_counter;
191 
192  if(num_fields > 0) {
193  for(field_counter = 0; field_counter < num_fields; field_counter++) {
194 
195  const scv_extensions_if* field_data_p = my_exts_p->get_field(field_counter);
196 
197  do_attributes(declare_attributes, undefined_values, is_record_attribute, prefix_name, exts_kind, field_data_p, index);
198  }
199  }
200  } break;
201 
202  case scv_extensions_if::ENUMERATION: {
203  if(declare_attributes) {
204  gzprintf(my_text_file_p, "%s (ID %d, name \"%s\", type \"ENUMERATION\")\n",
205  exts_kind.c_str(), // begin_attribute or end_attribute
206  *index, full_name.c_str());
207  (*index)++;
208  } else if(undefined_values) {
209  gzprintf(my_text_file_p, "a UNDEFINED\n");
210  } else {
211  if(is_record_attribute) {
212  gzprintf(my_text_file_p, R"(%s "%s" ENUMERATION = )", exts_kind.c_str(), full_name.c_str());
213  } else {
214  gzprintf(my_text_file_p, "a ");
215  }
216  gzprintf(my_text_file_p, "\"%s\"\n", my_exts_p->get_enum_string((int)my_exts_p->get_integer()));
217  }
218  } break;
219 
220  case scv_extensions_if::BOOLEAN: {
221  if(declare_attributes) {
222  gzprintf(my_text_file_p, "%s (ID %d, name \"%s\", type \"BOOLEAN\")\n",
223  exts_kind.c_str(), // begin_attribute or end_attribute
224  *index, full_name.c_str());
225  (*index)++;
226  } else if(undefined_values) {
227  gzprintf(my_text_file_p, "a UNDEFINED\n");
228  } else {
229  if(is_record_attribute) {
230  gzprintf(my_text_file_p, R"(%s "%s" BOOLEAN = )", exts_kind.c_str(), full_name.c_str());
231  } else {
232  gzprintf(my_text_file_p, "a ");
233  }
234  gzprintf(my_text_file_p, "%s\n", my_exts_p->get_bool() ? "true" : "false");
235  }
236  } break;
237 
238  case scv_extensions_if::INTEGER:
239  case scv_extensions_if::FIXED_POINT_INTEGER: {
240  if(declare_attributes) {
241  gzprintf(my_text_file_p, "%s (ID %d, name \"%s\", type \"INTEGER\")\n",
242  exts_kind.c_str(), // begin_attribute or end_attribute
243  *index, full_name.c_str());
244  (*index)++;
245  } else if(undefined_values) {
246  gzprintf(my_text_file_p, "a UNDEFINED\n");
247  } else {
248  if(is_record_attribute) {
249  gzprintf(my_text_file_p, R"(%s "%s" INTEGER = )", exts_kind.c_str(), full_name.c_str());
250  } else {
251  gzprintf(my_text_file_p, "a ");
252  }
253  if(my_exts_p->get_bitwidth() == 64) {
254  gzprintf(my_text_file_p, scv_tr_TEXT_LLU "\n", my_exts_p->get_integer());
255  } else {
256  auto tmp_int = (int)my_exts_p->get_integer();
257  gzprintf(my_text_file_p, "%d\n", tmp_int);
258  }
259  }
260  } break;
261 
262  case scv_extensions_if::UNSIGNED: {
263  if(declare_attributes) {
264  gzprintf(my_text_file_p, "%s (ID %d, name \"%s\", type \"UNSIGNED\")\n",
265  exts_kind.c_str(), // begin_attribute or end_attribute
266  *index, full_name.c_str());
267  (*index)++;
268  } else if(undefined_values) {
269  gzprintf(my_text_file_p, "a UNDEFINED\n");
270  } else {
271  if(is_record_attribute) {
272  gzprintf(my_text_file_p, R"(%s "%s" UNSIGNED = )", exts_kind.c_str(), full_name.c_str());
273  } else {
274  gzprintf(my_text_file_p, "a ");
275  }
276  gzprintf(my_text_file_p, scv_tr_TEXT_LLU "\n", my_exts_p->get_unsigned());
277  }
278  } break;
279 
280  case scv_extensions_if::POINTER: {
281  const scv_extensions_if* field_data_p = my_exts_p->get_pointer();
282 
283  // Extensions are not yet implemented for pointers, so the only thing
284  // to do here is to simply print the value of the pointer.
285 
286  if(declare_attributes) {
287  gzprintf(my_text_file_p, "%s (ID %d, name \"%s\", type \"POINTER\")\n",
288  exts_kind.c_str(), // begin_attribute or end_attribute
289  *index, full_name.c_str());
290  (*index)++;
291  } else if(undefined_values) {
292  gzprintf(my_text_file_p, "a UNDEFINED\n");
293  } else {
294  if(is_record_attribute) {
295  gzprintf(my_text_file_p, R"(%s "%s" POINTER = )", exts_kind.c_str(), full_name.c_str());
296  } else {
297  gzprintf(my_text_file_p, "a ");
298  }
299  gzprintf(my_text_file_p, "%ld\n", (long)field_data_p);
300  }
301  } break;
302 
303  case scv_extensions_if::STRING: {
304  if(declare_attributes) {
305  gzprintf(my_text_file_p, "%s (ID %d, name \"%s\", type \"STRING\")\n",
306  exts_kind.c_str(), // begin_attribute or end_attribute
307  *index, full_name.c_str());
308  (*index)++;
309  } else if(undefined_values) {
310  gzprintf(my_text_file_p, "a UNDEFINED\n");
311  } else {
312  if(is_record_attribute) {
313  gzprintf(my_text_file_p, R"(%s "%s" STRING = )", exts_kind.c_str(), full_name.c_str());
314  } else {
315  gzprintf(my_text_file_p, "a ");
316  }
317  gzprintf(my_text_file_p, "\"%s\"\n", my_exts_p->get_string().c_str());
318  }
319  } break;
320 
321  case scv_extensions_if::FLOATING_POINT_NUMBER: {
322  if(declare_attributes) {
323  gzprintf(my_text_file_p, "%s (ID %d, name \"%s\", type \"FLOATING_POINT_NUMBER\")\n",
324  exts_kind.c_str(), // begin_attribute or end_attribute
325  *index, full_name.c_str());
326  (*index)++;
327  } else if(undefined_values) {
328  gzprintf(my_text_file_p, "a UNDEFINED\n");
329  } else {
330  if(is_record_attribute) {
331  gzprintf(my_text_file_p, R"(%s "%s" FLOATING_POINT_NUMBER = )", exts_kind.c_str(), full_name.c_str());
332  } else {
333  gzprintf(my_text_file_p, "a ");
334  }
335  gzprintf(my_text_file_p, "%f\n", my_exts_p->get_double());
336  }
337  } break;
338 
339  case scv_extensions_if::BIT_VECTOR: {
340  if(declare_attributes) {
341  gzprintf(my_text_file_p, "%s (ID %d, name \"%s\", type \"BIT_VECTOR[%d]\")\n",
342  exts_kind.c_str(), // begin_attribute or end_attribute
343  *index, full_name.c_str(), my_exts_p->get_bitwidth());
344  (*index)++;
345  } else if(undefined_values) {
346  gzprintf(my_text_file_p, "a UNDEFINED\n");
347  } else {
348  if(is_record_attribute) {
349  gzprintf(my_text_file_p, R"(%s "%s" BIT_VECTOR = )", exts_kind.c_str(), full_name.c_str());
350  } else {
351  gzprintf(my_text_file_p, "a ");
352  }
353  sc_bv_base tmp_bv(my_exts_p->get_bitwidth());
354  my_exts_p->get_value(tmp_bv);
355  gzprintf(my_text_file_p, "\"%s\"\n", tmp_bv.to_string().c_str());
356  }
357  } break;
358 
359  case scv_extensions_if::LOGIC_VECTOR: {
360  if(declare_attributes) {
361  gzprintf(my_text_file_p, "%s (ID %d, name \"%s\", type \"LOGIC_VECTOR[%d]\")\n",
362  exts_kind.c_str(), // begin_attribute or end_attribute
363  *index, full_name.c_str(), my_exts_p->get_bitwidth());
364  (*index)++;
365  } else if(undefined_values) {
366  gzprintf(my_text_file_p, "a UNDEFINED\n");
367  } else {
368  if(is_record_attribute) {
369  gzprintf(my_text_file_p, R"(%s "%s" LOGIC_VECTOR = )", exts_kind.c_str(), full_name.c_str());
370  } else {
371  gzprintf(my_text_file_p, "a ");
372  }
373  sc_lv_base tmp_lv(my_exts_p->get_bitwidth());
374  my_exts_p->get_value(tmp_lv);
375 
376  gzprintf(my_text_file_p, "\"%s\"\n", tmp_lv.to_string().c_str());
377  }
378  } break;
379 
380  case scv_extensions_if::ARRAY: {
381  int array_elt_index = 0;
382 
383  for(; array_elt_index < my_exts_p->get_array_size(); array_elt_index++) {
384 
385  const scv_extensions_if* field_data_p = my_exts_p->get_array_elt(array_elt_index);
386 
387  do_attributes(declare_attributes, undefined_values, is_record_attribute, prefix_name, exts_kind, field_data_p, index);
388  }
389  } break;
390 
391  default: {
392  std::array<char, 100> tmpString{};
393  sprintf(tmpString.data(), "Unsupported attribute type = %d", my_exts_p->get_type());
394 
395  _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, tmpString.data());
396  }
397  }
398 }
399 
400 // ----------------------------------------------------------------------------
401 
402 static void scv_tr_generator_cbf(const scv_tr_generator_base& g, scv_tr_generator_base::callback_reason reason, void* user_data_p) {
403  if(reason != scv_tr_generator_base::CREATE) {
404  return;
405  }
406 
407  if(my_text_file_p == nullptr)
408  return;
409 
410  gzprintf(my_text_file_p, "scv_tr_generator (ID " scv_tr_TEXT_LLU ", name \"%s\", scv_tr_stream " scv_tr_TEXT_LLU ",\n", g.get_id(),
411  g.get_name(), g.get_scv_tr_stream().get_id());
412 
413  std::string exts_kind;
414  int index = 0;
415 
416  const scv_extensions_if* my_begin_exts_p = g.get_begin_exts_p();
417  if(my_begin_exts_p != nullptr) {
418  exts_kind = "begin_attribute";
419  std::string tmp_str = g.get_begin_attribute_name() ? g.get_begin_attribute_name() : "";
420  do_attributes(true, false, false, tmp_str, exts_kind, my_begin_exts_p, &index);
421  }
422 
423  const scv_extensions_if* my_end_exts_p = g.get_end_exts_p();
424  if(my_end_exts_p != nullptr) {
425  exts_kind = "end_attribute";
426  std::string tmp_str = g.get_end_attribute_name() ? g.get_end_attribute_name() : "";
427  do_attributes(true, false, false, tmp_str, exts_kind, my_end_exts_p, &index);
428  }
429 
430  gzprintf(my_text_file_p, ")\n");
431 }
432 
433 // ----------------------------------------------------------------------------
434 
435 static void scv_tr_handle_cbf(const scv_tr_handle& t, scv_tr_handle::callback_reason reason, void* user_data_p) {
436  if(my_text_file_p == nullptr)
437  return;
438 
439  int i = 0;
440 
441  // This callback function is called when a transaction is begun or ended,
442  // or deleted.
443 
444  // First check to be sure transaction recording is enabled:
445  //
446  if(t.get_scv_tr_stream().get_scv_tr_db() == nullptr)
447  return;
448  if(t.get_scv_tr_stream().get_scv_tr_db()->get_recording() == false)
449  return;
450 
451  const scv_extensions_if* my_exts_p;
452 
453  switch(reason) {
454 
455  case scv_tr_handle::BEGIN: {
456  // The beginning of a transaction
457  gzprintf(my_text_file_p, "tx_begin " scv_tr_TEXT_LLU " " scv_tr_TEXT_LLU " %s\n", t.get_id(),
458  t.get_scv_tr_generator_base().get_id(), t.get_begin_sc_time().to_string().c_str());
459 
460  my_exts_p = t.get_begin_exts_p();
461 
462  std::string exts_kind = "begin_attributes";
463  bool default_values = false;
464 
465  if(my_exts_p == nullptr) {
466  // For this transaction, the default attributes are used.
467  my_exts_p = t.get_scv_tr_generator_base().get_begin_exts_p();
468  default_values = true;
469  }
470 
471  std::string tmp_str =
472  t.get_scv_tr_generator_base().get_begin_attribute_name() ? t.get_scv_tr_generator_base().get_begin_attribute_name() : "";
473 
474  do_attributes(false, default_values, false, tmp_str, exts_kind, my_exts_p, &i);
475 
476  } break;
477 
478  case scv_tr_handle::END: {
479  // The end of a transaction
480  gzprintf(my_text_file_p, "tx_end " scv_tr_TEXT_LLU " " scv_tr_TEXT_LLU " %s\n", t.get_id(), t.get_scv_tr_generator_base().get_id(),
481  t.get_end_sc_time().to_string().c_str());
482 
483  my_exts_p = t.get_end_exts_p();
484 
485  std::string exts_kind = "end_attributes";
486  bool default_values = false;
487 
488  if(my_exts_p == nullptr) {
489  // For this transaction, the default attributes are used.
490  my_exts_p = t.get_scv_tr_generator_base().get_end_exts_p();
491  default_values = true;
492  }
493 
494  std::string tmp_str =
495  t.get_scv_tr_generator_base().get_end_attribute_name() ? t.get_scv_tr_generator_base().get_end_attribute_name() : "";
496 
497  do_attributes(false, default_values, false, tmp_str, exts_kind, my_exts_p, &i);
498  } break;
499 
500  default:;
501  }
502 }
503 
504 // ----------------------------------------------------------------------------
505 
506 static void scv_tr_handle_record_attribute_cbf(const scv_tr_handle& t, const char* attribute_name, const scv_extensions_if* my_exts_p,
507  void* user_data_p) {
508  // First check to be sure transaction recording is enabled:
509  //
510  if(t.get_scv_tr_stream().get_scv_tr_db() == nullptr)
511  return;
512  if(t.get_scv_tr_stream().get_scv_tr_db()->get_recording() == false)
513  return;
514 
515  if(my_text_file_p == nullptr)
516  return;
517 
518  std::string tmp_str;
519 
520  if(attribute_name == nullptr) {
521  tmp_str = "";
522  } else {
523  tmp_str = attribute_name;
524  }
525 
526  std::array<char, 100> tmp_str2{};
527  sprintf(tmp_str2.data(), "tx_record_attribute " scv_tr_TEXT_LLU, t.get_id());
528  std::string exts_kind = tmp_str2.data();
529 
530  do_attributes(false, false, true, tmp_str, exts_kind, my_exts_p, nullptr);
531 }
532 
533 // ----------------------------------------------------------------------------
534 
535 static void scv_tr_handle_relation_cbf(const scv_tr_handle& tr_1, const scv_tr_handle& tr_2, void* user_data_p,
536  scv_tr_relation_handle_t relation_handle) {
537  // First check to be sure transaction recording is enabled:
538  //
539  if(tr_1.get_scv_tr_stream().get_scv_tr_db() == nullptr)
540  return;
541  if(tr_1.get_scv_tr_stream().get_scv_tr_db()->get_recording() == false)
542  return;
543 
544  if(my_text_file_p == nullptr)
545  return;
546 
547  if(my_text_file_p) {
548  gzprintf(my_text_file_p, "tx_relation \"%s\" " scv_tr_TEXT_LLU " " scv_tr_TEXT_LLU "\n",
549  tr_1.get_scv_tr_stream().get_scv_tr_db()->get_relation_name(relation_handle), tr_1.get_id(), tr_2.get_id());
550  }
551 }
552 
553 // ----------------------------------------------------------------------------
554 // ----------------------------------------------------------------------------
555 
557  scv_tr_db::register_class_cb(scv_tr_db_cbf);
558  scv_tr_stream::register_class_cb(scv_tr_stream_cbf);
559  scv_tr_generator_base::register_class_cb(scv_tr_generator_cbf);
560  scv_tr_handle::register_class_cb(scv_tr_handle_cbf);
561  scv_tr_handle::register_record_attribute_cb(scv_tr_handle_record_attribute_cbf);
562  scv_tr_handle::register_relation_cb(scv_tr_handle_relation_cbf);
563 }
564 
565 // ----------------------------------------------------------------------------
566 #ifndef HAS_SCV
567 }
568 #endif
SystemC Verification Library (SCV) Transaction Recording.
void scv_tr_compressed_init()
initializes the infrastructure to use a gzip compressed text based transaction recording database