scc 2025.09
SystemC components library
configurer.cpp
1/*******************************************************************************
2 * Copyright 2017-2022 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
17#include "configurer.h"
18#include "rapidjson/document.h"
19#include "rapidjson/error/en.h"
20#include "report.h"
21#include <cci_configuration>
22#include <cerrno>
23#include <cstdlib>
24#include <cstring>
25#include <fmt/format.h>
26#include <fstream>
27#include <limits>
28#include <rapidjson/istreamwrapper.h>
29#include <rapidjson/ostreamwrapper.h>
30#include <rapidjson/prettywriter.h>
31#include <unordered_map>
32#ifdef HAS_YAMPCPP
33#include <yaml-cpp/exceptions.h>
34#include <yaml-cpp/node/parse.h>
35#include <yaml-cpp/yaml.h>
36
37namespace {
38template <typename T> struct optional {
39 T val{};
40 bool initialized{false};
41 optional& operator=(T&& val) {
42 this->val = std::move(val);
43 initialized = true;
44 return *this;
45 }
46 operator bool() const { return initialized; }
47 T value() { return val; }
48};
49} // namespace
50
51namespace YAML {
52template <typename T> struct as_if<T, optional<T>> {
53 explicit as_if(const YAML::Node& node_)
54 : node(node_) {}
55 const YAML::Node& node;
56 const optional<T> operator()() const {
57 optional<T> val;
58 T t;
59 if(node.m_pNode && YAML::convert<T>::decode(node, t))
60 val = std::move(t);
61 return val;
62 }
63};
64
65// There is already a std::string partial specialisation, so we need a full specialisation here
66template <> struct as_if<std::string, optional<std::string>> {
67 explicit as_if(const YAML::Node& node_)
68 : node(node_) {}
69 const YAML::Node& node;
70 const optional<std::string> operator()() const {
71 optional<std::string> val;
72 std::string t;
73 if(node.m_pNode && YAML::convert<std::string>::decode(node, t))
74 val = std::move(t);
75 return val;
76 }
77};
78} // namespace YAML
79#endif
80namespace scc {
81namespace {
82inline auto get_sc_objects(sc_core::sc_object* obj = nullptr) -> const std::vector<sc_core::sc_object*>& {
83 if(obj)
84 return obj->get_child_objects();
85 else
86 return sc_core::sc_get_top_level_objects();
87}
88
89#ifdef WIN32
90#define DIR_SEPARATOR '\\'
91#else
92#define DIR_SEPARATOR '/'
93#endif
94
95struct config_reader {
96 std::vector<std::string> includes{"."};
97 void add_to_includes(std::string const& path) {
98 for(auto& e : includes) {
99 if(e == path)
100 return;
101 }
102 includes.push_back(path);
103 }
104
105 std::string find_in_include_path(std::string const& file_name) {
106 if(file_name[0] == '/' || file_name[0] == '\\')
107 return file_name;
108 else
109 for(auto& incl : includes) {
110 auto full_name = incl + DIR_SEPARATOR + file_name;
111 std::ifstream ifs(full_name);
112 if(ifs.is_open())
113 return full_name;
114 }
115 return file_name;
116 }
117};
118/*************************************************************************************************
119 * JSON config start
120 ************************************************************************************************/
121using namespace rapidjson;
122using writer_type = PrettyWriter<OStreamWrapper>;
123
124#define FDECL(TYPE, FUNC) \
125 inline void writeValue(writer_type& writer, std::string const& key, TYPE value) { \
126 writer.Key(key.c_str()); \
127 writer.FUNC(value); \
128 }
129FDECL(int, Int)
130FDECL(unsigned int, Uint)
131FDECL(long, Int64)
132FDECL(unsigned long, Uint64)
133FDECL(long long, Int64)
134FDECL(unsigned long long, Uint64)
135FDECL(bool, Bool)
136FDECL(float, Double)
137FDECL(double, Double)
138FDECL(char const*, String)
139inline void writeValue(writer_type& writer, std::string const& key, std::string const& value) {
140 writer.Key(key.c_str());
141 writer.String(value.c_str());
142}
143
144inline bool start_object(writer_type& writer, char const* key, bool started) {
145 if(!started) {
146 writer.Key(key);
147 writer.StartObject();
148 }
149 return true;
150}
151
152struct json_config_dumper {
153 configurer::broker_t const& broker;
154 std::vector<std::string> const& stop_list;
155 std::unordered_map<std::string, std::vector<cci::cci_param_untyped_handle>> lut;
156 json_config_dumper(configurer::broker_t const& broker, std::vector<std::string> const& stop_list)
157 : broker(broker)
158 , stop_list(stop_list) {
159 for(auto& h : broker.get_param_handles()) {
160 auto value = h.get_cci_value();
161 std::string paramname{h.name()};
162 auto sep = paramname.rfind('.');
163 auto basename = paramname.substr(0, sep);
164 lut[basename].push_back(h);
165 }
166 }
167
168 void dump_config(sc_core::sc_object* obj, writer_type& writer) {
169 auto basename = std::string(obj->basename());
170 if(basename.substr(0, 3) == "$$$" || std::find(std::begin(stop_list), std::end(stop_list), obj->name()) != std::end(stop_list))
171 return;
172 auto obj_started = false;
173 auto log_lvl_set = false;
174 auto it = lut.find(obj->name());
175 if(it != lut.end())
176 for(auto& h : it->second) {
177 obj_started = start_object(writer, obj->basename(), obj_started);
178 auto value = h.get_cci_value();
179 std::string paramname{h.name()};
180 auto basename = paramname.substr(paramname.rfind('.') + 1);
181 if(basename == SCC_LOG_LEVEL_PARAM_NAME)
182 log_lvl_set = true;
183 if(value.is_bool())
184 writeValue(writer, basename, (bool)value.get_bool());
185 else if(value.is_int())
186 writeValue(writer, basename, (int)value.get_int());
187 else if(value.is_int64())
188 writeValue(writer, basename, static_cast<int64_t>(value.get_int64()));
189 else if(value.is_uint())
190 writeValue(writer, basename, value.get_uint());
191 else if(value.is_uint64())
192 writeValue(writer, basename, static_cast<uint64_t>(value.get_uint64()));
193 else if(value.is_double())
194 writeValue(writer, basename, value.get_double());
195 else if(value.is_string())
196 writeValue(writer, basename, value.get_string().c_str());
197 }
198 auto mod = dynamic_cast<sc_core::sc_module*>(obj);
199 if(scc::is_logging_initialized() && !log_lvl_set && mod) {
200 obj_started = start_object(writer, obj->basename(), obj_started);
201 auto val = broker.get_preset_cci_value(fmt::format("{}.{}", obj->name(), SCC_LOG_LEVEL_PARAM_NAME));
202 if(basename.substr(0, 3) != "$$$")
203 writeValue(writer, SCC_LOG_LEVEL_PARAM_NAME, val.is_int() ? val.get_int() : static_cast<int>(get_logging_level()));
204 }
205 for(auto* o : get_sc_objects(obj)) {
206 obj_started = start_object(writer, obj->basename(), obj_started);
207 dump_config(o, writer);
208 }
209 if(obj_started)
210 writer.EndObject();
211 }
212};
213
214struct json_config_reader : public config_reader {
215 configurer::broker_t& broker;
216 Document document;
217 bool valid{false};
218 bool empty{false};
219
220 json_config_reader(configurer::broker_t& broker)
221 : broker(broker) {}
222
223 void parse(std::istream& is) {
224 IStreamWrapper stream(is);
225 document.ParseStream(stream);
226 valid = !document.HasParseError();
227 empty = document.IsNull();
228 }
229 std::string get_error_msg() {
230 std::ostringstream os;
231 os << " location " << (unsigned)document.GetErrorOffset() << ", reason: " << GetParseError_En(document.GetParseError());
232 return os.str();
233 }
234
235 inline void configure_cci() { configure_cci_hierarchical(document, ""); }
236
237 void configure_cci_hierarchical(Value const& value, std::string prefix) {
238 if(value.IsObject()) {
239 auto o = value.GetObject();
240 for(auto itr = o.MemberBegin(); itr != o.MemberEnd(); ++itr) {
241 if(!itr->name.IsString())
242 return;
243 std::string key_name = itr->name.GetString();
244 Value const& val = itr->value;
245 auto hier_name = prefix.size() ? prefix + "." + key_name : key_name;
246 if(val.IsNull() || val.IsArray())
247 return;
248 else if(val.IsObject())
249 configure_cci_hierarchical(val, hier_name);
250 else {
251 if(key_name == "!include") {
252 json_config_reader sub_reader(broker);
253 std::ifstream ifs(find_in_include_path(val.GetString()));
254 if(ifs.is_open()) {
255 sub_reader.parse(ifs);
256 if(sub_reader.valid) {
257 sub_reader.configure_cci_hierarchical(sub_reader.document, prefix);
258 } else {
259 std::ostringstream os;
260 os << "Could not parse include file " << val.GetString();
261 throw std::runtime_error(os.str());
262 }
263 } else {
264 std::ostringstream os;
265 os << "Could not open include file " << val.GetString();
266 throw std::runtime_error(os.str());
267 }
268 } else {
269 auto param_handle = broker.get_param_handle(hier_name);
270 if(param_handle.is_valid()) {
271 if(val.IsString()) {
272 param_handle.set_cci_value(cci::cci_value(std::string(val.GetString())));
273 } else if(val.IsBool()) {
274 param_handle.set_cci_value(cci::cci_value(val.Get<bool>()));
275 } else if(val.IsInt()) {
276 param_handle.set_cci_value(cci::cci_value(val.Get<int>()));
277 } else if(val.IsInt64()) {
278 param_handle.set_cci_value(cci::cci_value(val.Get<int64_t>()));
279 } else if(val.IsUint()) {
280 param_handle.set_cci_value(cci::cci_value(val.Get<unsigned>()));
281 } else if(val.IsUint64()) {
282 param_handle.set_cci_value(cci::cci_value(val.Get<uint64_t>()));
283 } else if(val.IsDouble()) {
284 param_handle.set_cci_value(cci::cci_value(val.Get<double>()));
285 }
286 } else {
287 if(val.IsString()) {
288 broker.set_preset_cci_value(hier_name, cci::cci_value(std::string(val.GetString())));
289 } else if(val.IsBool()) {
290 broker.set_preset_cci_value(hier_name, cci::cci_value(val.Get<bool>()));
291 } else if(val.IsInt()) {
292 broker.set_preset_cci_value(hier_name, cci::cci_value(val.Get<int>()));
293 } else if(val.IsInt64()) {
294 broker.set_preset_cci_value(hier_name, cci::cci_value(val.Get<int64_t>()));
295 } else if(val.IsUint()) {
296 broker.set_preset_cci_value(hier_name, cci::cci_value(val.Get<unsigned>()));
297 } else if(val.IsUint64()) {
298 broker.set_preset_cci_value(hier_name, cci::cci_value(val.Get<uint64_t>()));
299 } else if(val.IsDouble()) {
300 broker.set_preset_cci_value(hier_name, cci::cci_value(val.Get<double>()));
301 }
302 }
303 }
304 }
305 }
306 }
307 }
308};
309/*************************************************************************************************
310 * JSON config end
311 ************************************************************************************************/
312#ifdef HAS_YAMPCPP
313/*************************************************************************************************
314 * YAML config start
315 ************************************************************************************************/
316struct yaml_config_dumper {
317 configurer::broker_t const& broker;
318 bool with_description{false};
319 bool complete{true};
320 std::vector<std::string> const& stop_list;
321 std::unordered_map<std::string, std::vector<cci::cci_param_untyped_handle>> lut;
322 std::vector<cci::cci_param_untyped_handle> tl_lut;
323 yaml_config_dumper(configurer::broker_t const& broker, bool with_description, bool complete, std::vector<std::string> const& stop_list)
324 : broker(broker)
325 , with_description(with_description)
326 , complete(complete)
327 , stop_list(stop_list) {
328 for(auto& h : broker.get_param_handles()) {
329 auto value = h.get_cci_value();
330 std::string paramname{h.name()};
331 auto sep = paramname.rfind('.');
332 if(sep == std::string::npos) {
333 tl_lut.push_back(h);
334 } else {
335 auto basename = paramname.substr(0, sep);
336 lut[basename].push_back(h);
337 }
338 }
339 }
340
341 void dump_config(YAML::Node& base_node) {
342 copy2yaml(tl_lut, base_node);
343 for(auto* o : sc_core::sc_get_top_level_objects()) {
344 dump_config(o, base_node);
345 }
346 }
347
348 void dump_config(sc_core::sc_object* obj, YAML::Node& base_node) {
349 auto basename = std::string(obj->basename());
350 if(basename.substr(0, 3) == "$$$" || std::find(std::begin(stop_list), std::end(stop_list), obj->name()) != std::end(stop_list))
351 return;
352 auto obj_started = false;
353 auto log_lvl_set = false;
354 auto it = lut.find(obj->name());
355 YAML::Node this_node;
356 if(it != lut.end())
357 log_lvl_set |= copy2yaml(it->second, this_node);
358 auto mod = dynamic_cast<sc_core::sc_module*>(obj);
359 if(!log_lvl_set && mod && complete) {
360 auto val = broker.get_preset_cci_value(fmt::format("{}.{}", obj->name(), SCC_LOG_LEVEL_PARAM_NAME));
361 auto global_verb = static_cast<int>(get_logging_level());
362 if(basename.substr(0, 11) != "scc_tracer")
363 this_node["log_level"] = val.is_int() ? val.get_int() : global_verb;
364 }
365 for(auto* o : get_sc_objects(obj)) {
366 dump_config(o, this_node);
367 }
368 if(this_node.size())
369 base_node[obj->basename()] = this_node;
370 }
371
372private:
373 bool copy2yaml(const std::vector<cci::cci_param_untyped_handle>& params, YAML::Node& this_node) {
374 bool log_lvl_set = false;
375 for(auto& h : params) {
376 auto value = h.get_cci_value();
377 std::string paramname{h.name()};
378 auto basename = paramname.substr(paramname.rfind('.') + 1);
379 if(basename == SCC_LOG_LEVEL_PARAM_NAME)
380 log_lvl_set = true;
381
382 auto descr = h.get_description();
383 if(with_description && descr.size()) {
384 auto descr_name = fmt::format("{}::descr", basename);
385 this_node[descr_name] = descr;
386 this_node[descr_name].SetTag("desc");
387 }
388 sc_core::sc_time t;
389 if(value.is_bool())
390 this_node[basename] = (bool)(value.get_bool());
391 else if(value.is_int())
392 this_node[basename] = (int)(value.get_int());
393 else if(value.is_int64())
394 this_node[basename] = static_cast<int64_t>(value.get_int64());
395 else if(value.is_uint())
396 this_node[basename] = value.get_uint();
397 else if(value.is_uint64())
398 this_node[basename] = static_cast<uint64_t>(value.get_uint64());
399 else if(value.is_double())
400 this_node[basename] = value.get_double();
401 else if(value.is_string())
402 this_node[basename] = value.get_string().c_str();
403 else if(value.try_get(t))
404 this_node[basename] = t.to_string();
405 }
406 return log_lvl_set;
407 }
408};
409
410struct yaml_config_reader : public config_reader {
411 configurer::broker_t& broker;
412 YAML::Node document;
413 bool valid{false};
414 bool empty{true};
415
416 yaml_config_reader(configurer::broker_t& broker)
417 : broker(broker) {}
418
419 void parse(std::istream& is) {
420 std::string buf((std::istreambuf_iterator<char>(is)), std::istreambuf_iterator<char>());
421 document = YAML::Load(buf);
422 valid = document.IsDefined() && (document.IsMap() || document.IsNull());
423 empty = document.IsNull();
424 }
425
426 std::string get_error_msg() { return "YAML file does not start with a map"; }
427
428 inline void configure_cci() {
429 try {
430 configure_cci_hierarchical(document, "");
431 } catch(YAML::ParserException& e) {
432 throw std::runtime_error(e.what());
433 } catch(YAML::BadFile& e) {
434 throw std::runtime_error(e.what());
435 } catch(YAML::Exception& e) {
436 throw std::runtime_error(e.what());
437 }
438 }
439
440 void configure_cci_hierarchical(YAML::Node const& value, std::string const& prefix) {
441 if(value.IsMap()) {
442 for(auto it = value.begin(); it != value.end(); ++it) {
443 auto key_name = it->first.as<std::string>();
444 YAML::Node const& val = it->second;
445 auto hier_name = prefix.size() ? prefix + "." + key_name : key_name;
446 if(!val.IsDefined() || val.IsSequence())
447 return;
448 else if(val.IsMap())
449 configure_cci_hierarchical(val, hier_name);
450 else if(val.IsScalar()) {
451 auto& tag = val.Tag();
452 if(tag == "!include") {
453 yaml_config_reader sub_reader(broker);
454 std::ifstream ifs(find_in_include_path(val.as<std::string>()));
455 if(ifs.is_open()) {
456 sub_reader.parse(ifs);
457 if(sub_reader.valid) {
458 sub_reader.configure_cci_hierarchical(sub_reader.document, hier_name);
459 } else {
460 std::ostringstream os;
461 os << "Could not parse include file " << val.as<std::string>();
462 throw std::runtime_error(os.str());
463 }
464 } else {
465 std::ostringstream os;
466 os << "Could not open include file " << val.as<std::string>();
467 throw std::runtime_error(os.str());
468 }
469 } else if(tag.size() && tag[0] == '?') {
470 auto param_handle = broker.get_param_handle(hier_name);
471 if(param_handle.is_valid()) {
472 auto param = param_handle.get_cci_value();
473 if(param.is_bool()) {
474 param.set_bool(val.as<bool>());
475 } else if(param.is_int()) {
476 param.set_int(val.as<int>());
477 } else if(param.is_uint()) {
478 param.set_uint(val.as<unsigned>());
479 } else if(param.is_int64()) {
480 param.set_int64(val.as<int64_t>());
481 } else if(param.is_uint64()) {
482 param.set_uint64(val.as<uint64_t>());
483 } else if(param.is_double()) {
484 param.set_double(val.as<double>());
485 } else if(param.is_string()) {
486 param.set_string(val.as<std::string>());
487 }
488 } else {
489 if(auto res = YAML::as_if<bool, optional<bool>>(val)()) {
490 broker.set_preset_cci_value(hier_name, cci::cci_value(res.value()));
491 } else if(auto res = YAML::as_if<int, optional<int>>(val)()) {
492 broker.set_preset_cci_value(hier_name, cci::cci_value(res.value()));
493 } else if(auto res = YAML::as_if<int64_t, optional<int64_t>>(val)()) {
494 broker.set_preset_cci_value(hier_name, cci::cci_value(res.value()));
495 } else if(auto res = YAML::as_if<unsigned, optional<unsigned>>(val)()) {
496 broker.set_preset_cci_value(hier_name, cci::cci_value(res.value()));
497 } else if(auto res = YAML::as_if<uint64_t, optional<uint64_t>>(val)()) {
498 broker.set_preset_cci_value(hier_name, cci::cci_value(res.value()));
499 } else if(auto res = YAML::as_if<double, optional<double>>(val)()) {
500 broker.set_preset_cci_value(hier_name, cci::cci_value(res.value()));
501 } else if(auto res = YAML::as_if<std::string, optional<std::string>>(val)()) {
502 broker.set_preset_cci_value(hier_name, cci::cci_value(res.value()));
503 }
504 }
505 } else if(tag.size() && tag[0] == '!') {
506 auto param_handle = broker.get_param_handle(hier_name);
507 if(param_handle.is_valid()) {
508 auto param = param_handle.get_cci_value();
509 if(param.is_string()) {
510 param.set_string(val.as<std::string>());
511 }
512 } else {
513 if(auto res = YAML::as_if<std::string, optional<std::string>>(val)()) {
514 broker.set_preset_cci_value(hier_name, cci::cci_value(res.value()));
515 }
516 }
517 }
518 }
519 }
520 }
521 }
522};
523/*************************************************************************************************
524 * YAML config end
525 ************************************************************************************************/
526#endif
527template <typename T>
528inline bool create_cci_param(sc_core::sc_attr_base* base_attr, const std::string& hier_name, configurer::cci_param_cln& params,
529 configurer::broker_t& broker, cci::cci_originator& cci_originator) {
530 if(auto attr = dynamic_cast<sc_core::sc_attribute<T>*>(base_attr)) {
531 auto par = new cci::cci_param_typed<T>(hier_name, attr->value, broker, "", cci::CCI_ABSOLUTE_NAME, cci_originator);
532 params.emplace_back(cci::cci_param_post_write_callback_untyped([attr](const cci::cci_param_write_event<>& ev) {
533 T result;
534 if(ev.new_value.try_get(result))
535 attr->value = result;
536 }),
537 par);
538 par->register_post_write_callback(params.back().first);
539 attr->value = par->get_value(); // if we have a preset
540 return true;
541 }
542 return false;
543}
544
545template <>
546inline bool create_cci_param<char*>(sc_core::sc_attr_base* base_attr, const std::string& hier_name, configurer::cci_param_cln& params,
547 configurer::broker_t& broker, cci::cci_originator& cci_originator) {
548 if(auto attr = dynamic_cast<sc_core::sc_attribute<char*>*>(base_attr)) {
549 auto par = new cci::cci_param_typed<std::string>(hier_name, attr->value, broker, "", cci::CCI_ABSOLUTE_NAME);
550 params.emplace_back(cci::cci_param_post_write_callback_untyped([attr](const cci::cci_param_write_event<>& ev) {
551 if(attr->value)
552 free(attr->value);
553 attr->value = strdup(ev.new_value.get<std::string>().c_str());
554 }),
555 par);
556 par->register_post_write_callback(params.back().first);
557 attr->value = strdup(par->get_value().c_str()); // if we have a preset
558 return true;
559 }
560 return false;
561}
562
563template <typename T> inline bool update_cci_param(cci::cci_param_untyped_handle& param_handle, sc_core::sc_attr_base* base_attr) {
564 if(auto attr = dynamic_cast<sc_core::sc_attribute<T>*>(base_attr)) {
565 param_handle.set_cci_value(cci::cci_value(attr->value));
566 return true;
567 }
568 return false;
569}
570
571template <> inline bool update_cci_param<char*>(cci::cci_param_untyped_handle& param_handle, sc_core::sc_attr_base* base_attr) {
572 if(auto attr = dynamic_cast<sc_core::sc_attribute<char*>*>(base_attr)) {
573 param_handle.set_cci_value(cci::cci_value(std::string(attr->value)));
574 return true;
575 }
576 return false;
577}
578
579inline bool mirror_sc_attribute(configurer::broker_t& broker, configurer::cci_param_cln& params, cci::cci_originator& cci_originator,
580 std::string hier_name, sc_core::sc_attr_base* base_attr, bool update = false) {
581 auto param_handle = broker.get_param_handle(hier_name);
582 if(!param_handle.is_valid()) {
583 if(create_cci_param<int>(base_attr, hier_name, params, broker, cci_originator))
584 return true;
585 if(create_cci_param<unsigned>(base_attr, hier_name, params, broker, cci_originator))
586 return true;
587 if(create_cci_param<long>(base_attr, hier_name, params, broker, cci_originator))
588 return true;
589 if(create_cci_param<unsigned long>(base_attr, hier_name, params, broker, cci_originator))
590 return true;
591 if(create_cci_param<long long>(base_attr, hier_name, params, broker, cci_originator))
592 return true;
593 if(create_cci_param<unsigned long long>(base_attr, hier_name, params, broker, cci_originator))
594 return true;
595 if(create_cci_param<bool>(base_attr, hier_name, params, broker, cci_originator))
596 return true;
597 if(create_cci_param<float>(base_attr, hier_name, params, broker, cci_originator))
598 return true;
599 if(create_cci_param<double>(base_attr, hier_name, params, broker, cci_originator))
600 return true;
601 if(create_cci_param<std::string>(base_attr, hier_name, params, broker, cci_originator))
602 return true;
603 if(create_cci_param<char*>(base_attr, hier_name, params, broker, cci_originator))
604 return true;
605 } else if(update) {
606 if(update_cci_param<int>(param_handle, base_attr))
607 return true;
608 if(update_cci_param<unsigned>(param_handle, base_attr))
609 return true;
610 if(update_cci_param<long>(param_handle, base_attr))
611 return true;
612 if(update_cci_param<unsigned long>(param_handle, base_attr))
613 return true;
614 if(update_cci_param<long long>(param_handle, base_attr))
615 return true;
616 if(update_cci_param<unsigned long long>(param_handle, base_attr))
617 return true;
618 if(update_cci_param<bool>(param_handle, base_attr))
619 return true;
620 if(update_cci_param<float>(param_handle, base_attr))
621 return true;
622 if(update_cci_param<double>(param_handle, base_attr))
623 return true;
624 if(update_cci_param<std::string>(param_handle, base_attr))
625 return true;
626 if(update_cci_param<char*>(param_handle, base_attr))
627 return true;
628 }
629 return false;
630}
631
632void mirror_sc_attributes(configurer::broker_t& broker, configurer::cci_param_cln& params, cci::cci_originator& cci_originator,
633 sc_core::sc_object* topobj = nullptr, bool update = false) {
634 for(auto obj : get_sc_objects(topobj)) {
635 if(auto mod = dynamic_cast<sc_core::sc_module*>(obj)) {
636 for(auto base_attr : mod->attr_cltn()) {
637 std::string hier_name = fmt::format("{}.{}", mod->name(), base_attr->name());
638 mirror_sc_attribute(broker, params, cci_originator, hier_name, base_attr, update);
639 }
640 mirror_sc_attributes(broker, params, cci_originator, mod, update);
641 }
642 }
643}
644
645bool cci_name_ignore(std::pair<std::string, cci::cci_value> const& preset_value) {
646 std::string ending(SCC_LOG_LEVEL_PARAM_NAME);
647 auto& name = preset_value.first;
648 if(name.length() >= ending.length()) {
649 return (0 == name.compare(name.length() - ending.length(), ending.length(), ending));
650 } else {
651 return false;
652 }
653}
654} // namespace
655#ifdef HAS_YAMPCPP
656struct configurer::ConfigHolder : public yaml_config_reader {
657 ConfigHolder(configurer::broker_t& broker)
658 : yaml_config_reader(broker) {}
659};
660#else
661struct configurer::ConfigHolder : public json_config_reader {
662 ConfigHolder(configurer::broker_t& broker)
663 : json_config_reader(broker) {}
664};
665#endif
666
667configurer::configurer(const std::string& filename, unsigned config_phases)
668: configurer(filename, config_phases, "$$$configurer$$$") {}
669
670configurer::configurer(const std::string& filename, unsigned config_phases, sc_core::sc_module_name nm)
671: base_type(nm)
672, config_phases(config_phases)
673, cci_broker(cci::cci_get_broker())
674, cci_originator(cci_broker.get_originator())
675, root(new ConfigHolder(cci_broker)) {
676 if(filename.length() > 0)
677 read_input_file(filename);
678}
679
680configurer::~configurer() {}
681
682void configurer::read_input_file(const std::string& filename) {
683 root->add_to_includes(util::dir_name(filename));
684 std::ifstream is(filename);
685 if(is.is_open()) {
686 try {
687 root->parse(is);
688 if(!root->valid) {
689 SCCERR() << "Could not parse input file " << filename << ", " << root->get_error_msg();
690 } else if(!root->empty) {
691 root->configure_cci();
692 }
693 } catch(std::runtime_error& e) {
694 SCCERR() << "Could not parse input file " << filename << ", reason: " << e.what();
695 }
696 } else {
697 SCCWARN() << "Could not open input file " << filename;
698 }
699}
700
701void configurer::dump_configuration(std::ostream& os, bool as_yaml, bool with_description, bool complete, sc_core::sc_object* obj) {
702#ifdef HAS_YAMPCPP
703 if(as_yaml) {
704 YAML::Node root; // starts out as null
705 yaml_config_dumper dumper(cci_broker, with_description, complete, stop_list);
706 if(obj)
707 for(auto* o : obj->get_child_objects()) {
708 dumper.dump_config(o, root);
709 }
710 else
711 dumper.dump_config(root);
712 os << root;
713 return;
714 }
715#endif
716 OStreamWrapper stream(os);
717 writer_type writer(stream);
718 writer.StartObject();
719 json_config_dumper dumper(cci_broker, stop_list);
720 for(auto* o : get_sc_objects(obj)) {
721 dumper.dump_config(o, writer);
722 }
723 writer.EndObject();
724}
725
726void configurer::configure() { mirror_sc_attributes(cci_broker, cci2sc_attr, cci_originator); }
727
728void configurer::set_configuration_value(sc_core::sc_attr_base* attr_base, sc_core::sc_object* owner) {
729 std::string hier_name = fmt::format("{}.{}", owner->name(), attr_base->name());
730 mirror_sc_attribute(cci_broker, cci2sc_attr, cci_originator, hier_name, attr_base);
731}
732
733inline std::string hier_name_as_regex(std::string const& parname) {
734 if(parname.find_first_of("*?[") != std::string::npos) {
735 return util::glob_to_regex(parname);
736 } else if(parname[0] == '^') {
737 return parname;
738 } else
739 return "";
740}
741
742void configurer::set_value(const std::string& hier_name, cci::cci_value value) {
743 auto regex_str = hier_name_as_regex(hier_name);
744 if(regex_str.length()) {
745 auto rr = std::regex(regex_str);
746 cci::cci_param_predicate pred = [rr](cci::cci_param_untyped_handle const& hndl) { return regex_match(hndl.name(), rr); };
747 for(auto& hndl : cci_broker.get_param_handles(pred)) {
748 hndl.set_cci_value(value);
749 }
750 } else {
751 cci::cci_param_handle param_handle = cci_broker.get_param_handle(hier_name);
752 if(param_handle.is_valid()) {
753 param_handle.set_cci_value(value);
754 return;
755 }
756 }
757 cci_broker.set_preset_cci_value(hier_name, value);
758}
759
760void configurer::set_value_from_str(const std::string& hier_name, const std::string& value) {
761 auto sign = 1;
762 std::string int_str = value;
763 if(value[0] == '-') {
764 sign = -1;
765 int_str = value.substr(1);
766 }
767 int int_base = 10;
768 if(int_str[0] == '0') {
769 if(int_str[1] == 'x' || int_str[1] == 'X') {
770 int_base = 16;
771 int_str = int_str.substr(2);
772 } else {
773 int_base = 8;
774 int_str = int_str.substr(1);
775 }
776 }
777
778 char* end_str;
779 errno = 0;
780 auto ull = std::strtoull(int_str.c_str(), &end_str, int_base);
781 if((end_str - int_str.c_str()) == int_str.length() && !errno) {
782 if(sign < 0) {
783 if(ull <= std::numeric_limits<int64_t>::max()) {
784 int64_t ll = sign * ull;
785 if(ll >= std::numeric_limits<int>::min()) {
786 set_value(hier_name, static_cast<int>(ll));
787 return;
788 }
789 if(ll >= std::numeric_limits<long>::min()) {
790 set_value(hier_name, static_cast<long>(ll));
791 return;
792 }
793 if(ll >= std::numeric_limits<long long>::min()) {
794 set_value(hier_name, static_cast<long long>(ll));
795 return;
796 }
797 }
798 } else {
799 if(ull <= std::numeric_limits<int>::max()) {
800 set_value(hier_name, static_cast<int>(ull));
801 return;
802 }
803 if(ull <= std::numeric_limits<unsigned int>::max()) {
804 set_value(hier_name, static_cast<unsigned int>(ull));
805 return;
806 }
807 if(ull <= std::numeric_limits<long>::max()) {
808 set_value(hier_name, static_cast<long>(ull));
809 return;
810 }
811 if(ull <= std::numeric_limits<unsigned long>::max()) {
812 set_value(hier_name, static_cast<unsigned long>(ull));
813 return;
814 }
815 if(ull <= std::numeric_limits<long long>::max()) {
816 set_value(hier_name, static_cast<long long>(ull));
817 return;
818 }
819 if(ull <= std::numeric_limits<unsigned long long>::max()) {
820 set_value(hier_name, static_cast<unsigned long long>(ull));
821 return;
822 }
823 }
824 }
825 errno = 0;
826 auto f = std::strtof(int_str.c_str(), &end_str);
827 if(!errno && (end_str - int_str.c_str()) == int_str.length()) {
828 set_value(hier_name, f);
829 return;
830 }
831 auto d = std::strtod(int_str.c_str(), &end_str);
832 if(!errno && (end_str - int_str.c_str()) == int_str.length()) {
833 set_value(hier_name, d);
834 return;
835 }
836 auto lower_value = util::str_tolower(value);
837 if(lower_value == "true") {
838 set_value(hier_name, true);
839 return;
840 }
841 if(lower_value == "false") {
842 set_value(hier_name, false);
843 return;
844 }
845 set_value(hier_name, value);
846}
847
848void configurer::config_check() {
849 try {
850 cci_broker.ignore_unconsumed_preset_values(&cci_name_ignore);
851 auto res = cci_broker.get_unconsumed_preset_values();
852 if(res.size()) {
853 std::ostringstream oss;
854 for(auto& val : res)
855 oss << "\t - " << val.first << "\n";
856 if(res.size() == 1) {
857 SCCWARN("scc::configurer") << "There is " << res.size() << " unused CCI preset value:\n"
858 << oss.str() << "Please check your setup!";
859 } else {
860 SCCWARN("scc::configurer") << "There are " << res.size() << " unused CCI preset values:\n"
861 << oss.str() << "Please check your setup!";
862 }
863 }
864 } catch(std::domain_error& e) {
865 SCCFATAL("scc::configurer") << "Illegal hierarchy name: '" << e.what() << "'";
866 } catch(std::invalid_argument& e) {
867 SCCFATAL("scc::configurer") << "Illegal parameter name: '" << e.what() << "'";
868 }
869}
870
871void configurer::start_of_simulation() {
872 if(config_phases & START_OF_SIMULATION)
873 configure();
874 config_check();
875 if(dump_file_name.size()) {
876 auto as_json = util::ends_with(dump_file_name, "json");
877 std::ofstream of{dump_file_name};
878 if(of.is_open()) {
879 mirror_sc_attributes(cci_broker, cci2sc_attr, cci_originator, nullptr, true);
880 dump_configuration(of, !as_json, with_description, complete);
881 }
882 }
883}
884
885} // namespace scc
void set_configuration_value(sc_core::sc_attr_base *attr_base, sc_core::sc_object *owner)
void dump_configuration(std::string const &file_name, bool with_description=false, bool complete=true, std::vector< std::string > stop_list=std::vector< std::string >{})
Definition configurer.h:84
void set_value_from_str(const std::string &hier_name, const std::string &value)
configurer(std::string const &filename, unsigned sc_attr_config_phases=BEFORE_END_OF_ELABORATION)
void set_value(std::string const &hier_name, T value)
Definition configurer.h:113
SCC TLM utilities.
bool is_logging_initialized()
get the state of the SCC logging system
Definition report.cpp:500
log get_logging_level()
get the SystemC logging level
Definition report.cpp:524
std::string glob_to_regex(std::string val)
Definition ities.h:457
std::string str_tolower(std::string str)
Definition ities.h:347
T dir_name(T const &path, T const &delims="/\\")
Definition ities.h:424