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