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