scc  2022.4.0
SystemC components library
hierarchy_dumper.cpp
1 /*******************************************************************************
2  * Copyright 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 #ifndef SC_INCLUDE_DYNAMIC_PROCESSES
18 #define SC_INCLUDE_DYNAMIC_PROCESSES
19 #endif
20 #include "hierarchy_dumper.h"
21 #include "configurer.h"
22 #include "perf_estimator.h"
23 #include "report.h"
24 #include "tracer.h"
25 #include <deque>
26 #include <fstream>
27 #include <iostream>
28 #include <memory>
29 #include <rapidjson/istreamwrapper.h>
30 #include <rapidjson/ostreamwrapper.h>
31 #include <rapidjson/prettywriter.h>
32 #include <rapidjson/rapidjson.h>
33 #include <regex>
34 #include <scc/utilities.h>
35 #include <sstream>
36 #include <tlm>
37 #include <unordered_map>
38 #include <unordered_set>
39 #ifdef FMT_SPDLOG_INTERNAL
40 #include <fmt/fmt.h>
41 #else
42 #include <fmt/format.h>
43 #endif
44 
45 #include <string>
46 #include <typeinfo>
47 #ifdef __GNUG__
48 #include <cstdlib>
49 #include <cxxabi.h>
50 #endif
51 
52 namespace scc {
53 using namespace rapidjson;
54 using writer_type = PrettyWriter<OStreamWrapper>;
55 
56 namespace {
57 #ifdef __GNUG__
58 std::string demangle(const char* name) {
59  int status = -4; // some arbitrary value to eliminate the compiler warning
60  // enable c++11 by passing the flag -std=c++11 to g++
61  std::unique_ptr<char, void (*)(void*)> res{abi::__cxa_demangle(name, NULL, NULL, &status), std::free};
62  return (status == 0) ? res.get() : name;
63 }
64 #else
65 // does nothing if not g++
66 std::string demangle(const char* name) { return name; }
67 #endif
68 std::string demangle(const char* name);
69 
70 template <class T> std::string type(const T& t) { return demangle(typeid(t).name()); }
71 
72 unsigned object_counter{0};
73 
74 struct Module;
75 
76 struct Port {
77  std::string const fullname;
78  std::string const name;
79  void const* port_if{nullptr};
80  bool input{false};
81  std::string const type;
82  std::string const sig_name;
83  std::string const id{fmt::format("{}", ++object_counter)};
84  Module* const owner;
85 
86  Port(std::string const& fullname, std::string const& name, void const* ptr, bool input, std::string const& type, Module& owner,
87  std::string const& sig_name = "")
88  : fullname(fullname)
89  , name(name)
90  , port_if(ptr)
91  , input(input)
92  , type(type)
93  , sig_name(sig_name)
94  , owner(&owner) {}
95 };
96 
97 struct Module {
98  std::string const fullname;
99  std::string const name;
100  std::string const type;
101  Module* const parent;
102  std::string const id{fmt::format("{}", ++object_counter)};
103  std::deque<Module> submodules;
104  std::deque<Port> ports;
105 
106  Module(std::string const& fullname, std::string const& name, std::string const& type, Module& parent)
107  : fullname(fullname)
108  , name(name)
109  , type(type)
110  , parent(&parent) {}
111  Module(std::string const& fullname, std::string const& name, std::string const& type)
112  : fullname(fullname)
113  , name(name)
114  , type(type)
115  , parent(nullptr) {}
116 };
117 
118 const std::unordered_set<std::string> ignored_entities = {"tlm_initiator_socket",
119  "sc_export",
120  "sc_thread_process",
121  "sc_signal",
122  "sc_object",
123  "sc_fifo",
124  "sc_method_process",
125  "sc_mutex",
126  "sc_vector",
127  "sc_semaphore_ordered",
128  "sc_variable",
129  "sc_prim_channel",
130  "tlm_signal",
131  "tlm_fifo",
132  "sc_register",
133  "sc_buffer"};
134 
135 const std::unordered_set<std::string> module_entities = {
136  "sc_module", "uvm::uvm_root", "uvm::uvm_test", "uvm::uvm_env", "uvm::uvm_component",
137  "uvm::uvm_agent", "uvm::uvm_monitor", "uvm::uvm_scoreboard", "uvm::uvm_driver", "uvm::uvm_sequencer"};
138 
139 std::string indent{" "};
140 std::string operator*(std::string const& str, const unsigned int level) {
141  std::ostringstream ss;
142  for(unsigned int i = 0; i < level; i++)
143  ss << str;
144  return ss.str();
145 }
146 
147 #if TLM_VERSION_MAJOR == 2 and TLM_VERSION_MINOR == 0
148 #if TLM_VERSION_PATCH == 6
149 #define GET_EXPORT_IF(tptr) tptr->get_base_export().get_interface()
150 #define GET_PORT_IF(tptr) tptr->get_base_port().get_interface()
151 #elif TLM_VERSION_PATCH == 5
152 #define GET_EXPORT_IF(tptr) tptr->get_export_base().get_interface()
153 #define GET_PORT_IF(tptr) tptr->get_port_base().get_interface()
154 #else
155 #define NO_TLM_EXTRACT
156 #endif
157 #endif
158 
159 std::vector<std::string> scan_object(sc_core::sc_object const* obj, Module& currentModule, unsigned const level) {
160  std::string name{obj->basename()};
161  if(name.substr(0, 3) == "$$$")
162  return {};
163  SCCDEBUG() << indent * level << obj->name() << "(" << obj->kind() << "), id=" << (object_counter + 1);
164  std::string kind{obj->kind()};
165  if(auto const* mod = dynamic_cast<sc_core::sc_module const*>(obj)) {
166  currentModule.submodules.push_back(Module(obj->name(), name, type(*obj), currentModule));
167  std::unordered_set<std::string> keep_outs;
168  for(auto* child : mod->get_child_objects()) {
169  const std::string child_name{child->basename()};
170  if(child_name.substr(0, 3) == "$$$")
171  continue;
172  if(!keep_outs.empty()) {
173  auto it = std::find_if(std::begin(keep_outs), std::end(keep_outs), [&child_name](std::string const& e) {
174  return child_name.size() > e.size() && child_name.substr(0, e.size()) == e;
175  });
176  if(it != std::end(keep_outs))
177  continue;
178  }
179  auto ks = scan_object(child, currentModule.submodules.back(), level + 1);
180  if(ks.size())
181  for(auto& s : ks)
182  keep_outs.insert(s);
183  }
184  } else if(kind == "sc_clock") {
185  sc_core::sc_prim_channel const* prim_chan = dynamic_cast<sc_core::sc_prim_channel const*>(obj);
186  currentModule.submodules.push_back(Module(obj->name(), name, type(*obj), currentModule));
187  currentModule.submodules.back().ports.push_back(Port(std::string(obj->name()) + "." + name, name, prim_chan, false, obj->kind(),
188  currentModule.submodules.back(), obj->basename()));
189 #ifndef NO_TLM_EXTRACT
190 #ifndef NCSC
191  } else if(auto const* tptr = dynamic_cast<tlm::tlm_base_socket_if const*>(obj)) {
192  auto cat = tptr->get_socket_category();
193  bool input = (cat & tlm::TLM_TARGET_SOCKET) == tlm::TLM_TARGET_SOCKET;
194  if(input) {
195  currentModule.ports.push_back(Port(obj->name(), name, GET_EXPORT_IF(tptr), input, kind, currentModule));
196  return {name + "_port", name + "_port_0"};
197  } else {
198  currentModule.ports.push_back(Port(obj->name(), name, GET_PORT_IF(tptr), input, kind, currentModule));
199  return {name + "_export", name + "_export_0"};
200  }
201 #endif
202 #endif
203  } else if(auto const* optr = dynamic_cast<sc_core::sc_port_base const*>(obj)) {
204  sc_core::sc_interface const* if_ptr = optr->get_interface();
205  sc_core::sc_prim_channel const* if_obj = dynamic_cast<sc_core::sc_prim_channel const*>(if_ptr);
206  bool is_input = kind == "sc_in" || kind == "sc_fifo_in";
207  currentModule.ports.push_back(Port(obj->name(), name, if_obj ? static_cast<void const*>(if_obj) : static_cast<void const*>(if_ptr),
208  is_input, obj->kind(), currentModule, if_obj ? if_obj->basename() : ""));
209  } else if(auto const* optr = dynamic_cast<sc_core::sc_export_base const*>(obj)) {
210  sc_core::sc_interface const* pointer = optr->get_interface();
211  currentModule.ports.push_back(Port(obj->name(), name, pointer, true, obj->kind(), currentModule));
212 #if defined(RECORD_UVM_ANALYSIS)
213  } else if(kind == "sc_object" && dynamic_cast<sc_core::sc_interface const*>(obj)) {
214  auto const* ifptr = dynamic_cast<sc_core::sc_interface const*>(obj);
215  currentModule.ports.push_back(Port(obj->name(), name, ifptr, false, obj->kind(), currentModule));
216 #endif
217  } else if(ignored_entities.find(kind) == ignored_entities.end()) {
218  SCCWARN() << "object not known (" << kind << ")";
219  }
220  return {};
221 }
222 
223 using stack_t = std::deque<Module const*>;
224 using registry_t = std::unordered_map<void const*, std::vector<Port*>>;
225 
226 void collect_ports_rec(Module& m, registry_t& registry) {
227  for(auto& port : m.ports)
228  registry[port.port_if].emplace_back(&port);
229  for(auto& child : m.submodules)
230  collect_ports_rec(child, registry);
231 }
232 
233 using breadcrumb_t = std::tuple<Module*, bool>;
234 bool get_path_to(Module const* i, std::vector<breadcrumb_t>& bread_crumb, std::unordered_set<Module*>& visited) {
235  auto current_mod = std::get<0>(bread_crumb.back());
236  bool upwards = std::get<1>(bread_crumb.back());
237  if(current_mod == i)
238  return true;
239  if(visited.count(current_mod))
240  return false;
241  visited.insert(current_mod);
242  for(auto& c : current_mod->submodules) {
243  bread_crumb.emplace_back(&c, false);
244  if(get_path_to(i, bread_crumb, visited))
245  return true;
246  bread_crumb.pop_back();
247  }
248  if(upwards && current_mod->parent) {
249  bread_crumb.emplace_back(current_mod->parent, true);
250  if(get_path_to(i, bread_crumb, visited))
251  return true;
252  bread_crumb.pop_back();
253  }
254  return false;
255 }
256 
257 void infer_implicit_ports(Module& m) {
258  registry_t registry;
259  collect_ports_rec(m, registry);
260  for(auto& entry : registry) {
261  auto& ports = entry.second;
262  if(ports.size() > 1) {
263  auto o = std::find_if(std::begin(ports), std::end(ports), [](Port const* p) -> bool { return !p->input; });
264  auto i = std::find_if(std::begin(ports), std::end(ports), [](Port const* p) -> bool { return p->input; });
265  while(o != std::end(ports)) {
266  Port* start_port = *o;
267  Module* start_mod = start_port->owner;
268  while(i != std::end(ports)) {
269  Port* end_port = *i;
270  std::vector<breadcrumb_t> bread_crumb{std::make_tuple(start_mod, true)};
271  std::unordered_set<Module*> visited;
272  if(get_path_to(end_port->owner, bread_crumb, visited) && bread_crumb.size() > 1) {
273  void const* port_if = end_port->port_if;
274  auto last_upwards = false;
275  while(bread_crumb.size() > 1) {
276  auto mod = std::get<0>(bread_crumb.back());
277  auto upwards = std::get<1>(bread_crumb.back());
278  auto port_iter = std::find_if(std::begin(mod->ports), std::end(mod->ports),
279  [port_if](Port const& p) -> bool { return p.port_if == port_if; });
280  if(port_iter == std::end(mod->ports) && upwards == last_upwards) {
281  std::ostringstream oss;
282  auto ref_port = upwards ? start_port : end_port;
283  oss << mod->fullname << "." << ref_port->name;
284  mod->ports.push_back(Port(oss.str(), ref_port->name, port_if, !upwards, ref_port->type, *mod));
285  }
286  last_upwards = upwards;
287  bread_crumb.pop_back();
288  }
289  }
290  i++;
291  }
292  o++;
293  }
294  }
295  }
296 }
297 void generate_elk(std::ostream& e, Module const& module, unsigned level = 0) {
298  SCCDEBUG() << module.name;
299  unsigned num_in{0}, num_out{0};
300  for(auto& port : module.ports)
301  if(port.input)
302  num_in++;
303  else
304  num_out++;
305  if(!module.ports.size() && !module.submodules.size())
306  return;
307  e << indent * level << "node " << module.name << " {"
308  << "\n";
309  level++;
310  e << indent * level << "layout [ size: 50, " << std::max(80U, std::max(num_in, num_out) * 20) << " ]\n";
311  e << indent * level << "portConstraints: FIXED_SIDE\n";
312  e << indent * level << "label \"" << module.name << "\"\n";
313 
314  for(auto& port : module.ports) {
315  SCCDEBUG() << " " << port.name << "\n";
316  auto side = port.input ? "WEST" : "EAST";
317  e << indent * level << "port " << port.name << " { ^port.side: " << side << " label '" << port.name << "' }\n";
318  }
319 
320  for(auto& m : module.submodules)
321  generate_elk(e, m, level);
322  // Draw edges module <-> submodule:
323  for(auto& srcport : module.ports) {
324  if(srcport.port_if)
325  for(auto& tgtmod : module.submodules) {
326  for(auto& tgtport : tgtmod.ports) {
327  if(tgtport.port_if == srcport.port_if)
328  e << indent * level << "edge " << srcport.fullname << " -> " << tgtport.fullname << "\n";
329  }
330  }
331  }
332  // Draw edges submodule -> submodule:
333  for(auto& srcmod : module.submodules) {
334  for(auto& srcport : srcmod.ports) {
335  if(!srcport.input && srcport.port_if)
336  for(auto& tgtmod : module.submodules) {
337  for(auto& tgtport : tgtmod.ports) {
338  if(srcmod.fullname == tgtmod.fullname && tgtport.fullname == srcport.fullname)
339  continue;
340  if(tgtport.port_if == srcport.port_if && tgtport.input)
341  e << indent * level << "edge " << srcport.fullname << " -> " << tgtport.fullname << "\n";
342  }
343  }
344  }
345  }
346  level--;
347  e << indent * level << "}\n"
348  << "\n";
349 }
350 
351 void generate_port_json(writer_type& writer, hierarchy_dumper::file_type type, const scc::Port& p) {
352  writer.StartObject();
353  {
354  writer.Key("id");
355  writer.String(p.id.c_str());
356  if(type != hierarchy_dumper::D3JSON) {
357  writer.Key("labels");
358  writer.StartArray();
359  {
360  writer.StartObject();
361  {
362  writer.Key("text");
363  writer.String(p.name.c_str());
364  }
365  writer.EndObject();
366  }
367  writer.EndArray();
368  writer.Key("width");
369  writer.Uint(6);
370  writer.Key("height");
371  writer.Uint(6);
372  writer.Key("layoutOptions");
373  writer.StartObject();
374  {
375  writer.Key("port.side");
376  writer.String(p.input ? "WEST" : "EAST");
377  }
378  writer.EndObject();
379  if(type == hierarchy_dumper::DBGJSON) {
380  writer.Key("type");
381  writer.String(p.type.c_str());
382  writer.Key("input");
383  writer.Bool(p.input);
384  writer.Key("interface");
385  writer.Uint64(reinterpret_cast<uintptr_t>(p.port_if));
386  }
387  } else {
388  writer.Key("direction");
389  writer.String(p.input ? "INPUT" : "OUTPUT");
390  writer.Key("hwMeta");
391  writer.StartObject();
392  {
393  writer.Key("name");
394  writer.String(p.name.c_str());
395  // writer.Key("cssClass"); writer.String("node-style0");
396  // writer.Key("cssStyle"); writer.String("fill:red");
397  writer.Key("connectedAsParent");
398  writer.Bool(false);
399  }
400  writer.EndObject();
401  writer.Key("properties");
402  writer.StartObject();
403  {
404  writer.Key("side");
405  writer.String(p.input ? "WEST" : "EAST");
406  // writer.Key("index"); writer.Int(0);
407  }
408  writer.EndObject();
409  writer.Key("children");
410  writer.StartArray();
411  writer.EndArray();
412  }
413  }
414  writer.EndObject();
415 }
416 
417 void generate_edge_json(writer_type& writer, const scc::Port& srcport, const scc::Port& tgtport) {
418  writer.StartObject();
419  {
420  auto edge_name = fmt::format("{}", ++object_counter);
421  writer.Key("id");
422  writer.String(edge_name.c_str());
423  writer.Key("sources");
424  writer.StartArray();
425  { writer.String(srcport.id.c_str()); }
426  writer.EndArray();
427  writer.Key("targets");
428  writer.StartArray();
429  { writer.String(tgtport.id.c_str()); }
430  writer.EndArray();
431  }
432  writer.EndObject();
433 }
434 
435 void generate_edge_d3_json(writer_type& writer, const scc::Module& srcmod, const scc::Port& srcport, const scc::Module& tgtmod,
436  const scc::Port& tgtport) {
437  writer.StartObject();
438  {
439  auto edge_name = fmt::format("{}", ++object_counter);
440  writer.Key("id");
441  writer.String(edge_name.c_str());
442  writer.Key("source");
443  writer.String(srcmod.id.c_str());
444  writer.Key("sourcePort");
445  writer.String(srcport.id.c_str());
446  writer.Key("target");
447  writer.String(tgtmod.id.c_str());
448  writer.Key("targetPort");
449  writer.String(tgtport.id.c_str());
450  writer.Key("hwMeta");
451  writer.StartObject();
452  {
453  if(srcport.sig_name.size()) {
454  writer.Key("name");
455  writer.String(srcport.sig_name.c_str());
456  } else if(tgtport.sig_name.size()) {
457  writer.Key("name");
458  writer.String(tgtport.sig_name.c_str());
459  } else {
460  writer.Key("name");
461  writer.String(fmt::format("{}_to_{}", srcport.name, tgtport.name).c_str());
462  }
463  // writer.Key("cssClass"); writer.String("link-style0");
464  // writer.Key("cssStyle"); writer.String("stroke:red");
465  }
466  writer.EndObject();
467  }
468  writer.EndObject();
469 }
470 
471 void generate_mod_json(writer_type& writer, hierarchy_dumper::file_type type, Module const& module, unsigned level = 0) {
472  unsigned num_in{0}, num_out{0};
473  for(auto& port : module.ports)
474  if(port.input)
475  num_in++;
476  else
477  num_out++;
478  writer.StartObject();
479  {
480  writer.Key("id");
481  writer.String(module.id.c_str());
482  // process ports
483  writer.Key("ports");
484  writer.StartArray();
485  {
486  for(auto& p : module.ports)
487  generate_port_json(writer, type, p);
488  }
489  writer.EndArray();
490  // process modules
491  if(type == hierarchy_dumper::D3JSON && module.parent)
492  writer.Key("_children");
493  else
494  writer.Key("children");
495  writer.StartArray();
496  {
497  for(auto& c : module.submodules)
498  generate_mod_json(writer, type, c, level * 1);
499  }
500  writer.EndArray();
501  // process connections
502  if(type == hierarchy_dumper::D3JSON && module.parent)
503  writer.Key("_edges");
504  else
505  writer.Key("edges");
506  writer.StartArray();
507  {
508  // Draw edges module <-> submodule:
509  for(auto& srcport : module.ports) {
510  if(srcport.port_if) {
511  for(auto& tgtmod : module.submodules) {
512  for(auto& tgtport : tgtmod.ports) {
513  if(tgtport.port_if == srcport.port_if)
514  if(type == hierarchy_dumper::D3JSON)
515  generate_edge_d3_json(writer, module, srcport, tgtmod, tgtport);
516  else
517  generate_edge_json(writer, srcport, tgtport);
518  }
519  }
520  }
521  }
522  // Draw edges submodule -> submodule:
523  for(auto& srcmod : module.submodules) {
524  for(auto& srcport : srcmod.ports) {
525  if(!srcport.input && srcport.port_if) {
526  for(auto& tgtmod : module.submodules) {
527  for(auto& tgtport : tgtmod.ports) {
528  if(srcmod.fullname == tgtmod.fullname && tgtport.fullname == srcport.fullname)
529  continue;
530  if(tgtport.port_if == srcport.port_if && tgtport.input)
531  if(type == hierarchy_dumper::D3JSON)
532  generate_edge_d3_json(writer, srcmod, srcport, tgtmod, tgtport);
533  else
534  generate_edge_json(writer, srcport, tgtport);
535  }
536  }
537  }
538  }
539  }
540  }
541  writer.EndArray();
542  if(type != hierarchy_dumper::D3JSON) {
543  writer.Key("labels");
544  writer.StartArray();
545  {
546  writer.StartObject();
547  {
548  writer.Key("text");
549  writer.String(module.name.c_str());
550  }
551  writer.EndObject();
552  }
553  writer.EndArray();
554  writer.Key("width");
555  writer.Uint(50);
556  writer.Key("height");
557  writer.Uint(std::max(80U, std::max(num_in, num_out) * 20));
558  if(type == hierarchy_dumper::DBGJSON) {
559  writer.Key("name");
560  writer.String(module.name.c_str());
561  writer.Key("type");
562  writer.String(module.type.c_str());
563  writer.Key("topmodule");
564  writer.Bool(!module.parent);
565  }
566  } else {
567  writer.Key("hwMeta");
568  writer.StartObject();
569  {
570  writer.Key("name");
571  writer.String(module.name.c_str());
572  writer.Key("cls");
573  writer.String(module.type.c_str());
574  // writer.Key("bodyText"); writer.String(module.type.c_str());
575  writer.Key("maxId");
576  writer.Uint(object_counter);
577  writer.Key("isExternalPort");
578  writer.Bool(false);
579  // writer.Key("cssClass"); writer.String("node-style0");
580  // writer.Key("cssStyle"); writer.String("fill:red");
581  }
582  writer.EndObject();
583  writer.Key("properties");
584  writer.StartObject();
585  {
586  writer.Key("org.eclipse.elk.layered.mergeEdges");
587  writer.Uint(1);
588  writer.Key("org.eclipse.elk.portConstraints");
589  writer.String("FIXED_SIDE");
590  }
591  writer.EndObject();
592  }
593  }
594  writer.EndObject();
595 }
596 
597 std::unique_ptr<Module> scan_object_tree() {
598  std::vector<sc_core::sc_object*> obja = sc_core::sc_get_top_level_objects();
599  if(obja.size() == 1 && std::string(obja[0]->kind()) == "sc_module" && std::string(obja[0]->basename()).substr(0, 3) != "$$$") {
600  SCCDEBUG() << obja[0]->name() << "(" << obja[0]->kind() << ")";
601  auto topModule = scc::make_unique<Module>(obja[0]->name(), obja[0]->basename(), type(*obja[0]));
602  for(auto* child : obja[0]->get_child_objects())
603  scan_object(child, *topModule, 1);
604  return topModule;
605  } else {
606  SCCDEBUG() << "sc_main ( function sc_main() )";
607  auto topModule = scc::make_unique<Module>("sc_main", "sc_main", "sc_main()");
608  for(auto* child : obja)
609  scan_object(child, *topModule, 1);
610  return topModule;
611  }
612 }
613 void dump_structure(std::ostream& e, hierarchy_dumper::file_type format) {
614  auto topModule = scan_object_tree();
615  infer_implicit_ports(*topModule);
616  if(format == hierarchy_dumper::ELKT) {
617  e << "algorithm: org.eclipse.elk.layered\n";
618  e << "edgeRouting: ORTHOGONAL\n";
619  generate_elk(e, *topModule);
620  SCCINFO() << "SystemC Structure Dumped to ELK file";
621  } else {
622  OStreamWrapper stream(e);
623  writer_type writer(stream);
624  writer.StartObject();
625  {
626  auto elems = util::split(sc_core::sc_argv()[0], '/');
627  writer.Key("id");
628  writer.String("0");
629  writer.Key("labels");
630  writer.StartArray();
631  {
632  writer.StartObject();
633  {
634  writer.Key("text");
635  writer.String(elems[elems.size() - 1].c_str());
636  }
637  writer.EndObject();
638  }
639  writer.EndArray();
640  writer.Key("layoutOptions");
641  writer.StartObject();
642  {
643  writer.Key("algorithm");
644  writer.String("layered");
645  }
646  writer.EndObject();
647  writer.Key("children");
648  writer.StartArray();
649  { generate_mod_json(writer, format, *topModule); }
650  writer.EndArray();
651  writer.Key("edges");
652  writer.StartArray();
653  writer.EndArray();
654  if(format == hierarchy_dumper::D3JSON) {
655  writer.Key("hwMeta");
656  writer.StartObject();
657  {
658  writer.Key("cls");
659  writer.Null();
660  writer.Key("maxId");
661  writer.Uint(65536);
662  writer.Key("name");
663  writer.String(elems[elems.size() - 1].c_str());
664  }
665  writer.EndObject();
666  writer.Key("properties");
667  writer.StartObject();
668  {
669  writer.Key("org.eclipse.elk.layered.mergeEdges");
670  writer.Uint(1);
671  writer.Key("org.eclipse.elk.portConstraints");
672  writer.String("FIXED_ORDER");
673  }
674  writer.EndObject();
675  }
676  }
677  writer.EndObject();
678  SCCINFO() << "SystemC Structure Dumped to JSON file";
679  }
680 }
681 } // namespace
682 
683 hierarchy_dumper::hierarchy_dumper(const std::string& filename, file_type format)
684 : sc_core::sc_module(sc_core::sc_module_name("$$$hierarchy_dumper$$$"))
685 , dump_hier_file_name{filename}
686 , dump_format{format} {}
687 
688 hierarchy_dumper::~hierarchy_dumper() {}
689 
690 void hierarchy_dumper::start_of_simulation() {
691  if(dump_hier_file_name.size()) {
692  std::ofstream of{dump_hier_file_name};
693  if(of.is_open())
694  dump_structure(of, dump_format);
695  }
696 }
697 } // namespace scc
SCC SystemC utilities.
std::vector< std::string > split(const std::string &s, char separator)
Definition: ities.h:192