HAL
result.cpp
Go to the documentation of this file.
2 
11 
12 #include <fstream>
13 
14 namespace hal
15 {
16  namespace dataflow
17  {
18  namespace
19  {
20  std::unordered_set<u32> nets_to_id_set(const std::unordered_set<Net*>& nets)
21  {
22  std::unordered_set<u32> ids;
23  for (const auto* net : nets)
24  {
25  ids.insert(net->get_id());
26  }
27  return ids;
28  }
29  } // namespace
30 
32  {
33  m_netlist = nl;
34 
35  const auto& na = grouping.netlist_abstr;
36  for (const auto* gate : na.target_gates)
37  {
38  auto gate_id = gate->get_id();
39 
40  if (const auto it = na.gate_to_successors.find(gate_id); it != na.gate_to_successors.end())
41  {
42  for (auto suc_gate_id : std::get<1>(*it))
43  {
44  this->m_gate_successors[gate].insert(nl->get_gate_by_id(suc_gate_id));
45  }
46  }
47 
48  if (const auto it = na.gate_to_predecessors.find(gate_id); it != na.gate_to_predecessors.end())
49  {
50  for (auto pred_gate_id : std::get<1>(*it))
51  {
52  this->m_gate_predecessors[gate].insert(nl->get_gate_by_id(pred_gate_id));
53  }
54  }
55 
56  if (const auto it = na.gate_to_control_signals.find(gate_id); it != na.gate_to_control_signals.end())
57  {
58  for (const auto& [type, signals] : std::get<1>(*it))
59  {
60  for (auto signal_net_id : signals)
61  {
62  this->m_gate_signals[gate][type].insert(nl->get_net_by_id(signal_net_id));
63  }
64  }
65  }
66  }
67 
68  for (const auto& [group_id, gate_ids] : grouping.gates_of_group)
69  {
70  std::unordered_set<Gate*> gates;
71  for (const auto gate_id : gate_ids)
72  {
73  auto* gate = m_netlist->get_gate_by_id(gate_id);
74  gates.insert(gate);
75  this->m_parent_group_of_gate[gate] = group_id;
76  }
77  m_gates_of_group[group_id] = gates;
78 
79  for (const auto& [type, signals] : grouping.get_control_signals_of_group(group_id))
80  {
81  for (auto signal_net_id : signals)
82  {
83  this->m_group_signals[group_id][type].insert(m_netlist->get_net_by_id(signal_net_id));
84  }
85  }
86 
87  if (auto suc_ids = grouping.get_successor_groups_of_group(group_id); !suc_ids.empty())
88  {
89  this->m_group_successors[group_id] = suc_ids;
90  }
91 
92  if (auto pred_ids = grouping.get_predecessor_groups_of_group(group_id); !pred_ids.empty())
93  {
94  this->m_group_predecessors[group_id] = pred_ids;
95  }
96 
97  this->m_last_id = std::max(this->m_last_id, group_id);
98  }
99  }
100 
102  {
103  return this->m_netlist;
104  }
105 
106  const std::unordered_map<u32, std::unordered_set<Gate*>>& dataflow::Result::get_groups() const
107  {
108  return this->m_gates_of_group;
109  }
110 
111  std::vector<Gate*> dataflow::Result::get_gates() const
112  {
113  std::vector<Gate*> gates;
114 
115  for (auto& group_gates : m_gates_of_group)
116  {
117  std::transform(std::get<1>(group_gates).begin(), std::get<1>(group_gates).end(), std::back_inserter(gates), [](auto* gate) { return gate; });
118  }
119 
120  return gates;
121  }
122 
124  {
125  if (const auto it = this->m_gates_of_group.find(group_id); it != this->m_gates_of_group.end())
126  {
127  return OK(it->second);
128  }
129  else
130  {
131  return ERR("invalid group ID.");
132  }
133  }
134 
136  {
137  if (!gate)
138  {
139  return ERR("gate is a nullptr.");
140  }
141 
142  if (const auto it = this->m_parent_group_of_gate.find(gate); it != this->m_parent_group_of_gate.end())
143  {
144  return OK(it->second);
145  }
146  else
147  {
148  return ERR("gate is not part of a group.");
149  }
150  }
151 
153  {
154  if (this->m_gates_of_group.find(group_id) == this->m_gates_of_group.end())
155  {
156  return ERR("invalid group ID.");
157  }
158 
159  if (const auto group_it = this->m_group_signals.find(group_id); group_it != this->m_group_signals.end())
160  {
161  const auto& type_map = std::get<1>(*group_it);
162  if (const auto type_it = type_map.find(type); type_it != type_map.end())
163  {
164  return OK(type_it->second);
165  }
166  }
167 
168  return OK({});
169  }
170 
172  {
173  if (this->m_parent_group_of_gate.find(gate) == this->m_parent_group_of_gate.end())
174  {
175  return ERR("gate is not part of a group.");
176  }
177 
178  if (const auto gate_it = this->m_gate_signals.find(gate); gate_it != this->m_gate_signals.end())
179  {
180  const auto& type_map = std::get<1>(*gate_it);
181  if (const auto type_it = type_map.find(type); type_it != type_map.end())
182  {
183  return OK(type_it->second);
184  }
185  }
186 
187  return OK({});
188  }
189 
191  {
192  if (this->m_gates_of_group.find(group_id) == this->m_gates_of_group.end())
193  {
194  return ERR("invalid group ID.");
195  }
196 
197  if (const auto it = this->m_group_successors.find(group_id); it != this->m_group_successors.end())
198  {
199  return OK(it->second);
200  }
201 
202  return OK({});
203  }
204 
206  {
207  if (this->m_parent_group_of_gate.find(gate) == this->m_parent_group_of_gate.end())
208  {
209  return ERR("gate is not part of a group.");
210  }
211 
212  if (const auto it = this->m_gate_successors.find(gate); it != this->m_gate_successors.end())
213  {
214  return OK(it->second);
215  }
216 
217  return OK({});
218  }
219 
221  {
222  if (this->m_gates_of_group.find(group_id) == this->m_gates_of_group.end())
223  {
224  return ERR("invalid group ID.");
225  }
226 
227  if (const auto it = this->m_group_predecessors.find(group_id); it != this->m_group_predecessors.end())
228  {
229  return OK(it->second);
230  }
231 
232  return OK({});
233  }
234 
236  {
237  if (this->m_parent_group_of_gate.find(gate) == this->m_parent_group_of_gate.end())
238  {
239  return ERR("gate is not part of a group.");
240  }
241 
242  if (const auto it = this->m_gate_predecessors.find(gate); it != this->m_gate_predecessors.end())
243  {
244  return OK(it->second);
245  }
246 
247  return OK({});
248  }
249 
250  void dataflow::Result::open_dot_in_viewer(const std::filesystem::path& out_path) const
251  {
253  if (!bpif)
254  {
255  log_info("dataflow", "Cannot find 'dot_viewer' plugin, dot graph not displayed.");
256  return;
257  }
259  if (!geif)
260  {
261  log_info("dataflow", "Cannot find dot_viewer GUI interface, dot graph not displayed.");
262  return;
263  }
264  std::vector<PluginParameter> params;
265  params.push_back(PluginParameter(PluginParameter::ExistingFile, "filename", "", out_path.string()));
266  params.push_back(PluginParameter(PluginParameter::String, "plugin", "", "dataflow"));
267  params.push_back(PluginParameter(PluginParameter::PushButton, "exec", "", "clicked"));
268  geif->set_parameter(params);
269  log_info("dataflow", "Request to display graph '{}' send to dot viewer.", out_path.string());
270  }
271 
272  hal::Result<std::filesystem::path> dataflow::Result::write_dot(const std::filesystem::path& out_path, const std::unordered_set<u32>& group_ids) const
273  {
274  auto write_path = out_path;
275 
276  if (write_path.empty())
277  {
278  return ERR("output path is empty.");
279  }
280 
281  if (std::filesystem::is_directory(write_path))
282  {
283  write_path /= "graph.dot";
284  }
285 
286  if (write_path.extension() != "dot")
287  {
288  log_info("dataflow", "replacing invalid file extension '{}' with '.dot' ...", write_path.extension().string());
289  write_path.replace_extension("dot");
290  }
291 
292  log_info("dataflow", "writing dataflow graph to '{}' ...", write_path.string());
293 
294  std::ofstream ofs(write_path, std::ofstream::out);
295  if (ofs)
296  {
297  ofs << "digraph {\n\tcomment=\"created by HAL plugin dataflow\"\n\tnode [shape=box fillcolor=white style=filled];\n";
298 
299  // print node
300  for (const auto& [group_id, gates] : this->get_groups())
301  {
302  if (!group_ids.empty() && group_ids.find(group_id) == group_ids.end())
303  {
304  continue;
305  }
306 
307  auto size = gates.size() * 0.1;
308  if (size < 1500)
309  {
310  size = size * 0.02;
311  }
312 
313  ofs << group_id << " [width=" << 0.05 * gates.size() << " label=\"" << gates.size() << " bit (id " << group_id << ")\"];\n";
314  }
315 
316  // print edges
317  for (const auto& [group_id, gates] : this->get_groups())
318  {
319  if (!group_ids.empty() && group_ids.find(group_id) == group_ids.end())
320  {
321  continue;
322  }
323 
324  auto sucs = this->get_group_successors(group_id).get();
325  for (auto suc_id : sucs)
326  {
327  if (!group_ids.empty() && group_ids.find(suc_id) == group_ids.end())
328  {
329  continue;
330  }
331  ofs << group_id << " -> " << suc_id << ";\n";
332  }
333  }
334 
335  ofs << "}";
336  ofs.close();
337 
338  log_info("dataflow", "successfully written dataflow graph to '{}'.", write_path.string());
339 
340  return OK({write_path});
341  }
342 
343  return ERR("failed to open file at '" + write_path.string() + "' for writing dataflow graph.");
344  }
345 
346  hal::Result<std::monostate> dataflow::Result::write_txt(const std::filesystem::path& out_path, const std::unordered_set<u32>& group_ids) const
347  {
348  auto write_path = out_path;
349 
350  if (write_path.empty())
351  {
352  return ERR("output path is empty.");
353  }
354 
355  if (std::filesystem::is_directory(write_path))
356  {
357  write_path /= "groups.txt";
358  }
359 
360  if (write_path.extension() != "txt")
361  {
362  log_info("dataflow", "replacing invalid file extension '{}' with '.txt' ...", write_path.extension().string());
363  write_path.replace_extension("txt");
364  }
365 
366  log_info("dataflow", "writing dataflow gate groups to '{}' ...", write_path.string());
367 
368  std::ofstream ofs(write_path, std::ofstream::out);
369  if (ofs)
370  {
371  ofs << "State:";
372  ofs << "\n\n";
373 
374  for (const auto& [group_id, gates] : this->get_groups())
375  {
376  if (!group_ids.empty() && group_ids.find(group_id) == group_ids.end())
377  {
378  continue;
379  }
380 
381  ofs << "ID:" << group_id << ", ";
382  ofs << "Size:" << gates.size() << ", ";
383  ofs << "CLK: {" << utils::join(", ", nets_to_id_set(this->get_group_control_nets(group_id, PinType::clock).get())) << "}, ";
384  ofs << "EN: {" << utils::join(", ", nets_to_id_set(this->get_group_control_nets(group_id, PinType::enable).get())) << "}, ";
385  ofs << "R: {" << utils::join(", ", nets_to_id_set(this->get_group_control_nets(group_id, PinType::reset).get())) << "}, ";
386  ofs << "S: {" << utils::join(", ", nets_to_id_set(this->get_group_control_nets(group_id, PinType::set).get())) << "}" << std::endl;
387 
388  if (auto res = this->get_group_successors(group_id); res.is_ok())
389  {
390  auto unsorted_successors = res.get();
391  ofs << " Successors: {" + utils::join(", ", std::set<u32>(unsorted_successors.begin(), unsorted_successors.end())) << "}" << std::endl;
392  }
393 
394  if (auto res = this->get_group_predecessors(group_id); res.is_ok())
395  {
396  auto unsorted_predecessors = res.get();
397  ofs << " Predecessors: {" + utils::join(", ", std::set<u32>(unsorted_predecessors.begin(), unsorted_predecessors.end())) << "}" << std::endl;
398  }
399 
400  std::unordered_map<u32, std::vector<std::string>> texts;
401  std::unordered_map<u32, u32> text_max_lengths;
402 
403  std::set<u32> gate_ids;
404  for (const auto& gate : gates)
405  {
406  auto name = gate->get_name() + ", ";
407  auto type = "type: " + gate->get_type()->get_name() + ", ";
408  auto id = "id: " + std::to_string(gate->get_id()) + ", ";
409  std::string stages = "RS: ";
410 
411  std::vector<std::string> data = {name, type, id, stages};
412  for (u32 i = 0; i < data.size(); ++i)
413  {
414  text_max_lengths[i] = std::max(text_max_lengths[i], (u32)data[i].size());
415  }
416 
417  u32 gate_id = gate->get_id();
418  texts.emplace(gate_id, data);
419  gate_ids.insert(gate_id);
420  }
421 
422  for (const auto& gate_id : gate_ids)
423  {
424  auto& data = texts[gate_id];
425  for (u32 i = 0; i < data.size(); ++i)
426  {
427  ofs << std::setw(text_max_lengths[i]) << std::left << data[i];
428  }
429  ofs << std::endl;
430  }
431  ofs << "\n";
432  }
433  ofs.close();
434 
435  log_info("dataflow", "successfully written dataflow gate groups to '{}'.", write_path.string());
436  return OK({});
437  }
438 
439  return ERR("failed to open file at '" + write_path.string() + "' for writing dataflow gate groups.");
440  }
441 
443  {
444  return create_modules(std::map<const GateType*, std::string>(), std::map<std::pair<PinDirection, std::string>, std::string>(), group_ids);
445  }
446 
447  hal::Result<std::unordered_map<u32, Module*>> dataflow::Result::create_modules(const std::map<const GateType*, std::string>& module_suffixes,
448  const std::map<std::pair<PinDirection, std::string>, std::string>& pin_prefixes,
449  const std::unordered_set<u32>& group_ids) const
450  {
451  auto* nl = this->get_netlist();
452 
453  // delete all modules that start with DANA
454  std::vector<Module*> modules_to_delete;
455  for (const auto mod : nl->get_modules())
456  {
457  if (utils::starts_with(mod->get_name(), std::string("DANA_")))
458  {
459  modules_to_delete.push_back(mod);
460  }
461  }
462 
463  for (auto* mod : modules_to_delete)
464  {
465  nl->delete_module(mod);
466  }
467  log_info("dataflow", "successfully deleted old DANA modules");
468 
469  // create new modules and try to keep hierarchy if possible
470  std::unordered_map<u32, Module*> group_to_module;
471  for (const auto& [group_id, group] : this->get_groups())
472  {
473  if (!group_ids.empty() && group_ids.find(group_id) == group_ids.end())
474  {
475  continue;
476  }
477 
478  bool gate_hierachy_matches_for_all = true;
479  bool gate_type_matches_for_all = true;
480  bool first_run = true;
481  const GateType* gate_type;
482  auto* reference_module = nl->get_top_module();
483 
484  std::vector<Gate*> gates;
485  for (const auto gate : group)
486  {
487  gates.push_back(gate);
488 
489  if (first_run)
490  {
491  reference_module = gate->get_module();
492  gate_type = gate->get_type();
493  first_run = false;
494  }
495  else if (gate->get_module() != reference_module)
496  {
497  gate_hierachy_matches_for_all = false;
498  }
499 
500  if (gate_type != gate->get_type())
501  {
502  gate_hierachy_matches_for_all = false;
503  }
504  }
505 
506  if (!gate_hierachy_matches_for_all)
507  {
508  reference_module = nl->get_top_module();
509  }
510 
511  std::string suffix;
512  if (const auto it = module_suffixes.find(gate_type); gate_type_matches_for_all && it != module_suffixes.end())
513  {
514  suffix = it->second;
515  }
516  else
517  {
518  suffix = "module";
519  }
520 
521  auto* new_mod = nl->create_module("DANA_" + suffix + "_" + std::to_string(group_id), reference_module, gates);
522  group_to_module[group_id] = new_mod;
523 
524  std::map<const std::pair<PinDirection, std::string>, PinGroup<ModulePin>*> pin_groups;
525  for (auto* pin : new_mod->get_pins())
526  {
527  if (pin->get_direction() == PinDirection::input)
528  {
529  const auto destinations = pin->get_net()->get_destinations([new_mod](const Endpoint* ep) { return ep->get_gate()->get_module() == new_mod; });
530 
531  const auto* first_pin = destinations.front()->get_pin();
532  auto pin_type = first_pin->get_type();
533  auto pin_name = first_pin->get_name();
534  if (std::all_of(destinations.begin(), destinations.end(), [pin_name](const Endpoint* ep) { return ep->get_pin()->get_name() == pin_name; }))
535  {
536  const auto pg_key = std::make_pair(PinDirection::input, pin_name);
537 
538  std::string prefix;
539  if (const auto prefix_it = pin_prefixes.find(pg_key); prefix_it != pin_prefixes.end())
540  {
541  prefix = prefix_it->second;
542  }
543  else
544  {
545  prefix = "i_" + pin_name;
546  }
547 
548  if (const auto pg_it = pin_groups.find(pg_key); pg_it == pin_groups.end())
549  {
550  auto pin_group = new_mod->create_pin_group(prefix, {pin}, PinDirection::input, pin_type, false, 0, true, true);
551  pin_groups[pg_key] = pin_group.get();
552  }
553  else
554  {
555  if (!new_mod->assign_pin_to_group(pg_it->second, pin))
556  {
557  log_warning("dataflow", "Assign pin to group failed.");
558  }
559  }
560 
561  new_mod->set_pin_name(pin, prefix + "(" + std::to_string(pin->get_group().second) + ")");
562  new_mod->set_pin_type(pin, pin_type);
563  }
564  }
565  else if (pin->get_direction() == PinDirection::output)
566  {
567  const auto sources = pin->get_net()->get_sources([new_mod](const Endpoint* ep) { return ep->get_gate()->get_module() == new_mod; });
568 
569  const auto* first_pin = sources.front()->get_pin();
570  auto pin_type = first_pin->get_type();
571  auto pin_name = first_pin->get_name();
572  if (sources.size() == 1)
573  {
574  const auto pg_key = std::make_pair(PinDirection::output, pin_name);
575 
576  std::string prefix;
577  if (const auto prefix_it = pin_prefixes.find(pg_key); prefix_it != pin_prefixes.end())
578  {
579  prefix = prefix_it->second;
580  }
581  else
582  {
583  prefix = "o_" + pin_name;
584  }
585 
586  if (const auto pg_it = pin_groups.find(pg_key); pg_it == pin_groups.end())
587  {
588  auto pin_group = new_mod->create_pin_group(prefix, {pin}, PinDirection::output, pin_type, false, 0, true, true);
589  pin_groups[pg_key] = pin_group.get();
590  }
591  else
592  {
593  if (!new_mod->assign_pin_to_group(pg_it->second, pin))
594  {
595  log_warning("dataflow", "Assign pin to group failed.");
596  }
597  }
598 
599  new_mod->set_pin_name(pin, prefix + "(" + std::to_string(pin->get_group().second) + ")");
600  new_mod->set_pin_type(pin, pin_type);
601  }
602  }
603  }
604 
605  // rename pins if only single pin in pin group (remove "(" and ")")
606  for (const auto* pin_group : new_mod->get_pin_groups())
607  {
608  if (pin_group->size() == 1)
609  {
610  auto* pin = pin_group->get_pins().front();
611  new_mod->set_pin_name(pin, pin_group->get_name());
612  }
613  }
614  }
615  return OK(group_to_module);
616  }
617 
618  hal::Result<std::unordered_map<u32, Module*>> dataflow::Result::create_modules(const std::map<GateTypeProperty, std::string>& module_suffixes,
619  const std::map<std::pair<PinDirection, std::string>, std::string>& pin_prefixes,
620  const std::unordered_set<u32>& group_ids) const
621  {
622  const auto* gl = this->m_netlist->get_gate_library();
623  std::map<const GateType*, std::string> gate_type_suffixes;
624  for (const auto& suffix : module_suffixes)
625  {
626  for (const auto& [_, type] : gl->get_gate_types([suffix](const GateType* gt) { return gt->has_property(suffix.first); }))
627  {
628  gate_type_suffixes[type] = suffix.second;
629  }
630  }
631 
632  return this->create_modules(gate_type_suffixes, pin_prefixes, group_ids);
633  }
634 
635  std::vector<std::vector<Gate*>> dataflow::Result::get_groups_as_list(const std::unordered_set<u32>& group_ids) const
636  {
637  std::vector<std::vector<Gate*>> groups;
638  for (const auto& [group_id, group] : this->get_groups())
639  {
640  if (!group_ids.empty() && group_ids.find(group_id) == group_ids.end())
641  {
642  continue;
643  }
644 
645  std::vector<Gate*> group_vector;
646  for (const auto& gate : group)
647  {
648  group_vector.push_back(gate);
649  }
650  groups.push_back(group_vector);
651  }
652  return groups;
653  }
654 
655  hal::Result<u32> dataflow::Result::merge_groups(const std::vector<u32>& group_ids)
656  {
657  if (group_ids.empty())
658  {
659  return ERR("no group IDs provided.");
660  }
661 
662  if (group_ids.size() < 2)
663  {
664  return ERR("at least two groups are required for merging.");
665  }
666 
667  if (const auto it = std::find_if(group_ids.begin(), group_ids.end(), [this](u32 id) { return this->m_gates_of_group.find(id) == this->m_gates_of_group.end(); }); it != group_ids.end())
668  {
669  return ERR("a group with ID " + std::to_string(*it) + " does not exist.");
670  }
671 
672  u32 target_group_id = ++(this->m_last_id);
673 
674  // iterate set to make sure that every ID is contained only once
675  std::unordered_set<u32> group_ids_set(group_ids.begin(), group_ids.end());
676  for (auto group_id : group_ids_set)
677  {
678  // new group
679  auto& gates_at_i = this->m_gates_of_group.at(group_id);
680  this->m_gates_of_group[target_group_id].insert(gates_at_i.begin(), gates_at_i.end());
681  this->m_gates_of_group.erase(group_id);
682 
683  std::for_each(gates_at_i.begin(), gates_at_i.end(), [this, target_group_id](const Gate* g) { this->m_parent_group_of_gate.at(g) = target_group_id; });
684 
685  // signals
686  if (const auto signals_it = this->m_group_signals.find(group_id); signals_it != this->m_group_signals.end())
687  {
688  for (auto& signals_of_type : std::get<1>(*signals_it))
689  {
690  auto& signals = std::get<1>(signals_of_type);
691  this->m_group_signals[target_group_id][signals_of_type.first].insert(signals.begin(), signals.end());
692  }
693  this->m_group_signals.erase(signals_it);
694  }
695 
696  // successors / predecessors
697  if (const auto suc_it = this->m_group_successors.find(group_id); suc_it != this->m_group_successors.end())
698  {
699  auto& target_suc_ids = this->m_group_successors[target_group_id];
700  for (auto suc_id : std::get<1>(*suc_it))
701  {
702  auto& pred_ids = this->m_group_predecessors.at(suc_id);
703  pred_ids.insert(target_group_id);
704  target_suc_ids.insert(suc_id);
705  pred_ids.erase(group_id);
706  }
707  }
708 
709  if (const auto pred_it = this->m_group_predecessors.find(group_id); pred_it != this->m_group_predecessors.end())
710  {
711  auto& target_pred_ids = this->m_group_predecessors[target_group_id];
712  for (auto pred_id : std::get<1>(*pred_it))
713  {
714  auto& suc_ids = this->m_group_successors.at(pred_id);
715  suc_ids.insert(target_group_id);
716  target_pred_ids.insert(pred_id);
717  suc_ids.erase(group_id);
718  }
719  }
720 
721  this->m_group_successors.erase(group_id);
722  this->m_group_predecessors.erase(group_id);
723  }
724 
725  return OK(target_group_id);
726  }
727 
728  hal::Result<std::vector<u32>> dataflow::Result::split_group(u32 group_id, const std::vector<std::unordered_set<Gate*>>& new_groups)
729  {
730  if (new_groups.empty())
731  {
732  return ERR("no gates provided to define splits.");
733  }
734 
735  const auto group_it = this->m_gates_of_group.find(group_id);
736  if (group_it == this->m_gates_of_group.end())
737  {
738  return ERR("a group with ID " + std::to_string(group_id) + " does not exist.");
739  }
740 
741  const auto& group_gates = std::get<1>(*group_it);
742 
743  std::unordered_set<const Gate*> seen;
744  for (const auto& gates : new_groups)
745  {
746  for (auto* g : gates)
747  {
748  if (!g)
749  {
750  return ERR("gate is a nullptr.");
751  }
752 
753  if (group_gates.find(g) == group_gates.end())
754  {
755  return ERR("gate '" + g->get_name() + "' with ID " + std::to_string(g->get_id()) + " does not belong to group with ID " + std::to_string(group_id) + ".");
756  }
757 
758  if (seen.find(g) != seen.end())
759  {
760  return ERR("gate '" + g->get_name() + "' with ID " + std::to_string(g->get_id()) + " cannot be assigned to two groups after splitting.");
761  }
762  seen.insert(g);
763  }
764  }
765 
766  if (seen.size() != group_gates.size())
767  {
768  return ERR("size of the target group does not match combined size of the split groups.");
769  }
770 
771  this->m_gates_of_group.erase(group_id);
772  this->m_group_successors.erase(group_id);
773  this->m_group_predecessors.erase(group_id);
774  this->m_group_signals.erase(group_id);
775 
776  std::vector<u32> new_group_ids;
777  for (const auto& gates : new_groups)
778  {
779  auto current_id = ++(this->m_last_id);
780 
781  // new group
782  this->m_gates_of_group[current_id] = gates;
783 
784  for (const auto* g : gates)
785  {
786  this->m_parent_group_of_gate.at(g) = current_id;
787 
788  // signals
789  if (const auto signals_it = this->m_gate_signals.find(g); signals_it != this->m_gate_signals.end())
790  {
791  const auto& signals = std::get<1>(*signals_it);
792 
793  for (const auto type : std::vector<PinType>({PinType::clock, PinType::enable, PinType::reset, PinType::set}))
794  {
795  if (const auto nets_it = signals.find(type); nets_it != signals.end())
796  {
797  const auto& nets = std::get<1>(*nets_it);
798  this->m_group_signals[current_id][type].insert(nets.begin(), nets.end());
799  }
800  }
801  }
802  }
803 
804  new_group_ids.push_back(current_id);
805  }
806 
807  // successors / predecessors (can only be inferred once all new groups have been created)
808  for (const auto current_id : new_group_ids)
809  {
810  for (const auto* g : this->m_gates_of_group.at(current_id))
811  {
812  if (const auto suc_it = this->m_gate_successors.find(g); suc_it != this->m_gate_successors.end())
813  {
814  for (const auto* suc_g : std::get<1>(*suc_it))
815  {
816  this->m_group_successors[current_id].insert(this->m_parent_group_of_gate.at(suc_g));
817  }
818  }
819 
820  if (const auto pred_it = this->m_gate_predecessors.find(g); pred_it != this->m_gate_predecessors.end())
821  {
822  for (const auto* pred_g : std::get<1>(*pred_it))
823  {
824  this->m_group_predecessors[current_id].insert(this->m_parent_group_of_gate.at(pred_g));
825  }
826  }
827  }
828  }
829 
830  return OK(new_group_ids);
831  }
832  } // namespace dataflow
833 } // namespace hal
Gate * get_gate() const
Definition: endpoint.cpp:23
Definition: gate.h:58
virtual void set_parameter(const std::vector< PluginParameter > &params)
Gate * get_gate_by_id(const u32 gate_id) const
Definition: netlist.cpp:193
Net * get_net_by_id(u32 net_id) const
Definition: netlist.cpp:353
PinType get_type() const
Definition: pin_group.h:170
hal::Result< u32 > merge_groups(const std::vector< u32 > &group_ids)
Merge multiple groups specified by ID.
Definition: result.cpp:655
hal::Result< std::unordered_set< Gate * > > get_gates_of_group(const u32 group_id) const
Get the gates of the specified group of sequential gates.
Definition: result.cpp:123
hal::Result< std::unordered_set< u32 > > get_group_predecessors(const u32 group_id) const
Get the predecessor groups of the group with the given ID.
Definition: result.cpp:220
hal::Result< std::vector< u32 > > split_group(u32 group_id, const std::vector< std::unordered_set< Gate * >> &new_groups)
Split a group into multiple smaller groups specified by sets of gates.
Definition: result.cpp:728
std::vector< std::vector< Gate * > > get_groups_as_list(const std::unordered_set< u32 > &group_ids={}) const
Get the groups of the dataflow analysis result as a list.
Definition: result.cpp:635
hal::Result< std::filesystem::path > write_dot(const std::filesystem::path &out_path, const std::unordered_set< u32 > &group_ids={}) const
Write the dataflow graph as a DOT graph to the specified location.
Definition: result.cpp:272
hal::Result< std::unordered_map< u32, Module * > > create_modules(const std::unordered_set< u32 > &group_ids={}) const
Create modules for the dataflow analysis result.
Definition: result.cpp:442
hal::Result< std::monostate > write_txt(const std::filesystem::path &out_path, const std::unordered_set< u32 > &group_ids={}) const
Write the groups resulting from dataflow analysis to a .txt file.
Definition: result.cpp:346
hal::Result< std::unordered_set< Net * > > get_group_control_nets(const u32 group_id, const PinType type) const
Get the control nets of the group with the given group ID that are connected to a pin of the specifie...
Definition: result.cpp:152
hal::Result< std::unordered_set< Gate * > > get_gate_successors(const Gate *gate) const
Get the sequential successor gates of the given sequential gate.
Definition: result.cpp:205
const std::unordered_map< u32, std::unordered_set< Gate * > > & get_groups() const
Get the groups of sequential gates resulting from dataflow analysis.
Definition: result.cpp:106
hal::Result< u32 > get_group_id_of_gate(const Gate *gate) const
Get the group ID of the group that contains the given gate.
Definition: result.cpp:135
hal::Result< std::unordered_set< Net * > > get_gate_control_nets(const Gate *gate, const PinType type) const
Get the control nets of the given gate that are connected to a pin of the specified type.
Definition: result.cpp:171
Result(Netlist *nl, const Grouping &grouping)
Definition: result.cpp:31
Netlist * get_netlist() const
Get the netlist on which dataflow analysis has been performed.
Definition: result.cpp:101
hal::Result< std::unordered_set< u32 > > get_group_successors(const u32 group_id) const
Get the successor groups of the group with the given ID.
Definition: result.cpp:190
hal::Result< std::unordered_set< Gate * > > get_gate_predecessors(const Gate *gate) const
Get the sequential predecessor gates of the given sequential gate.
Definition: result.cpp:235
std::vector< Gate * > get_gates() const
Get all gates contained in any of the groups groups.
Definition: result.cpp:111
void open_dot_in_viewer(const std::filesystem::path &out_path) const
Open DOT graph in dot viewer if appropriate plugin was loaded.
Definition: result.cpp:250
#define log_info(channel,...)
Definition: log.h:70
#define log_warning(channel,...)
Definition: log.h:76
#define ERR(message)
Definition: result.h:53
#define OK(...)
Definition: result.h:49
BasePluginInterface * get_plugin_instance(const std::string &plugin_name, bool initialize, bool silent)
CORE_API bool starts_with(const T &s, const T &start)
Definition: utils.h:167
CORE_API std::string join(const std::string &joiner, const Iterator &begin, const Iterator &end, const Transform &transform)
Definition: utils.h:412
PinType
Definition: pin_type.h:36
quint32 u32
PinType type
Net * net
std::string name
i32 id
This file contains the struct that holds all information on the result of a dataflow analysis run.
Grouping used during dataflow analysis.
Definition: grouping.h:55
std::unordered_map< u32, std::unordered_set< u32 > > gates_of_group
Definition: grouping.h:89
const NetlistAbstraction & netlist_abstr
Definition: grouping.h:79
std::unordered_set< u32 > get_predecessor_groups_of_group(u32 group_id) const
Get the predecessor groups of a group.
Definition: grouping.cpp:204
std::unordered_set< u32 > get_successor_groups_of_group(u32 group_id) const
Get the successor groups of a group.
Definition: grouping.cpp:173
std::map< PinType, std::unordered_set< u32 > > get_control_signals_of_group(u32 group_id) const
Get the control signals of a group as a map from the control pin type to the connected net IDs.
Definition: grouping.cpp:109