20 std::unordered_set<u32> nets_to_id_set(
const std::unordered_set<Net*>& nets)
22 std::unordered_set<u32> ids;
23 for (
const auto*
net : nets)
25 ids.insert(
net->get_id());
36 for (
const auto* gate : na.target_gates)
38 auto gate_id = gate->get_id();
40 if (
const auto it = na.gate_to_successors.find(gate_id); it != na.gate_to_successors.end())
42 for (
auto suc_gate_id : std::get<1>(*it))
44 this->m_gate_successors[gate].insert(nl->
get_gate_by_id(suc_gate_id));
48 if (
const auto it = na.gate_to_predecessors.find(gate_id); it != na.gate_to_predecessors.end())
50 for (
auto pred_gate_id : std::get<1>(*it))
52 this->m_gate_predecessors[gate].insert(nl->
get_gate_by_id(pred_gate_id));
56 if (
const auto it = na.gate_to_control_signals.find(gate_id); it != na.gate_to_control_signals.end())
58 for (
const auto& [
type, signals] : std::get<1>(*it))
60 for (
auto signal_net_id : signals)
70 std::unordered_set<Gate*> gates;
71 for (
const auto gate_id : gate_ids)
73 auto* gate = m_netlist->get_gate_by_id(gate_id);
75 this->m_parent_group_of_gate[gate] = group_id;
77 m_gates_of_group[group_id] = gates;
81 for (
auto signal_net_id : signals)
83 this->m_group_signals[group_id][
type].insert(m_netlist->get_net_by_id(signal_net_id));
89 this->m_group_successors[group_id] = suc_ids;
94 this->m_group_predecessors[group_id] = pred_ids;
97 this->m_last_id = std::max(this->m_last_id, group_id);
103 return this->m_netlist;
108 return this->m_gates_of_group;
113 std::vector<Gate*> gates;
115 for (
auto& group_gates : m_gates_of_group)
117 std::transform(std::get<1>(group_gates).begin(), std::get<1>(group_gates).end(), std::back_inserter(gates), [](
auto* gate) {
return gate; });
125 if (
const auto it = this->m_gates_of_group.find(group_id); it != this->m_gates_of_group.end())
127 return OK(it->second);
131 return ERR(
"invalid group ID.");
139 return ERR(
"gate is a nullptr.");
142 if (
const auto it = this->m_parent_group_of_gate.find(gate); it != this->m_parent_group_of_gate.end())
144 return OK(it->second);
148 return ERR(
"gate is not part of a group.");
154 if (this->m_gates_of_group.find(group_id) == this->m_gates_of_group.end())
156 return ERR(
"invalid group ID.");
159 if (
const auto group_it = this->m_group_signals.find(group_id); group_it != this->m_group_signals.end())
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())
164 return OK(type_it->second);
173 if (this->m_parent_group_of_gate.find(gate) == this->m_parent_group_of_gate.end())
175 return ERR(
"gate is not part of a group.");
178 if (
const auto gate_it = this->m_gate_signals.find(gate); gate_it != this->m_gate_signals.end())
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())
183 return OK(type_it->second);
192 if (this->m_gates_of_group.find(group_id) == this->m_gates_of_group.end())
194 return ERR(
"invalid group ID.");
197 if (
const auto it = this->m_group_successors.find(group_id); it != this->m_group_successors.end())
199 return OK(it->second);
207 if (this->m_parent_group_of_gate.find(gate) == this->m_parent_group_of_gate.end())
209 return ERR(
"gate is not part of a group.");
212 if (
const auto it = this->m_gate_successors.find(gate); it != this->m_gate_successors.end())
214 return OK(it->second);
222 if (this->m_gates_of_group.find(group_id) == this->m_gates_of_group.end())
224 return ERR(
"invalid group ID.");
227 if (
const auto it = this->m_group_predecessors.find(group_id); it != this->m_group_predecessors.end())
229 return OK(it->second);
237 if (this->m_parent_group_of_gate.find(gate) == this->m_parent_group_of_gate.end())
239 return ERR(
"gate is not part of a group.");
242 if (
const auto it = this->m_gate_predecessors.find(gate); it != this->m_gate_predecessors.end())
244 return OK(it->second);
255 log_info(
"dataflow",
"Cannot find 'dot_viewer' plugin, dot graph not displayed.");
261 log_info(
"dataflow",
"Cannot find dot_viewer GUI interface, dot graph not displayed.");
264 std::vector<PluginParameter> params;
269 log_info(
"dataflow",
"Request to display graph '{}' send to dot viewer.", out_path.string());
274 auto write_path = out_path;
276 if (write_path.empty())
278 return ERR(
"output path is empty.");
281 if (std::filesystem::is_directory(write_path))
283 write_path /=
"graph.dot";
286 if (write_path.extension() !=
"dot")
288 log_info(
"dataflow",
"replacing invalid file extension '{}' with '.dot' ...", write_path.extension().string());
289 write_path.replace_extension(
"dot");
292 log_info(
"dataflow",
"writing dataflow graph to '{}' ...", write_path.string());
294 std::ofstream ofs(write_path, std::ofstream::out);
297 ofs <<
"digraph {\n\tcomment=\"created by HAL plugin dataflow\"\n\tnode [shape=box fillcolor=white style=filled];\n";
300 for (
const auto& [group_id, gates] : this->get_groups())
302 if (!group_ids.empty() && group_ids.find(group_id) == group_ids.end())
307 auto size = gates.size() * 0.1;
313 ofs << group_id <<
" [width=" << 0.05 * gates.size() <<
" label=\"" << gates.size() <<
" bit (id " << group_id <<
")\"];\n";
317 for (
const auto& [group_id, gates] : this->get_groups())
319 if (!group_ids.empty() && group_ids.find(group_id) == group_ids.end())
324 auto sucs = this->get_group_successors(group_id).get();
325 for (
auto suc_id : sucs)
327 if (!group_ids.empty() && group_ids.find(suc_id) == group_ids.end())
331 ofs << group_id <<
" -> " << suc_id <<
";\n";
338 log_info(
"dataflow",
"successfully written dataflow graph to '{}'.", write_path.string());
340 return OK({write_path});
343 return ERR(
"failed to open file at '" + write_path.string() +
"' for writing dataflow graph.");
348 auto write_path = out_path;
350 if (write_path.empty())
352 return ERR(
"output path is empty.");
355 if (std::filesystem::is_directory(write_path))
357 write_path /=
"groups.txt";
360 if (write_path.extension() !=
"txt")
362 log_info(
"dataflow",
"replacing invalid file extension '{}' with '.txt' ...", write_path.extension().string());
363 write_path.replace_extension(
"txt");
366 log_info(
"dataflow",
"writing dataflow gate groups to '{}' ...", write_path.string());
368 std::ofstream ofs(write_path, std::ofstream::out);
374 for (
const auto& [group_id, gates] : this->get_groups())
376 if (!group_ids.empty() && group_ids.find(group_id) == group_ids.end())
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())) <<
"}, ";
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;
388 if (
auto res = this->get_group_successors(group_id); res.is_ok())
390 auto unsorted_successors = res.get();
391 ofs <<
" Successors: {" +
utils::join(
", ", std::set<u32>(unsorted_successors.begin(), unsorted_successors.end())) <<
"}" << std::endl;
394 if (
auto res = this->get_group_predecessors(group_id); res.is_ok())
396 auto unsorted_predecessors = res.get();
397 ofs <<
" Predecessors: {" +
utils::join(
", ", std::set<u32>(unsorted_predecessors.begin(), unsorted_predecessors.end())) <<
"}" << std::endl;
400 std::unordered_map<u32, std::vector<std::string>> texts;
401 std::unordered_map<u32, u32> text_max_lengths;
403 std::set<u32> gate_ids;
404 for (
const auto& gate : gates)
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: ";
412 for (
u32 i = 0; i <
data.size(); ++i)
414 text_max_lengths[i] = std::max(text_max_lengths[i], (
u32)
data[i].size());
417 u32 gate_id = gate->get_id();
418 texts.emplace(gate_id,
data);
419 gate_ids.insert(gate_id);
422 for (
const auto& gate_id : gate_ids)
424 auto&
data = texts[gate_id];
425 for (
u32 i = 0; i <
data.size(); ++i)
427 ofs << std::setw(text_max_lengths[i]) << std::left <<
data[i];
435 log_info(
"dataflow",
"successfully written dataflow gate groups to '{}'.", write_path.string());
439 return ERR(
"failed to open file at '" + write_path.string() +
"' for writing dataflow gate groups.");
444 return create_modules(std::map<const GateType*, std::string>(), std::map<std::pair<PinDirection, std::string>, std::string>(), group_ids);
448 const std::map<std::pair<PinDirection, std::string>, std::string>& pin_prefixes,
449 const std::unordered_set<u32>& group_ids)
const
451 auto* nl = this->get_netlist();
454 std::vector<Module*> modules_to_delete;
455 for (
const auto mod : nl->get_modules())
459 modules_to_delete.push_back(mod);
463 for (
auto* mod : modules_to_delete)
465 nl->delete_module(mod);
467 log_info(
"dataflow",
"successfully deleted old DANA modules");
470 std::unordered_map<u32, Module*> group_to_module;
471 for (
const auto& [group_id, group] : this->get_groups())
473 if (!group_ids.empty() && group_ids.find(group_id) == group_ids.end())
478 bool gate_hierachy_matches_for_all =
true;
479 bool gate_type_matches_for_all =
true;
480 bool first_run =
true;
482 auto* reference_module = nl->get_top_module();
484 std::vector<Gate*> gates;
485 for (
const auto gate : group)
487 gates.push_back(gate);
491 reference_module = gate->get_module();
492 gate_type = gate->get_type();
495 else if (gate->get_module() != reference_module)
497 gate_hierachy_matches_for_all =
false;
500 if (gate_type != gate->get_type())
502 gate_hierachy_matches_for_all =
false;
506 if (!gate_hierachy_matches_for_all)
508 reference_module = nl->get_top_module();
512 if (
const auto it = module_suffixes.find(gate_type); gate_type_matches_for_all && it != module_suffixes.end())
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;
525 for (
auto* pin : new_mod->get_pins())
529 const auto destinations = pin->get_net()->get_destinations([new_mod](
const Endpoint* ep) {
return ep->
get_gate()->get_module() == new_mod; });
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; }))
539 if (
const auto prefix_it = pin_prefixes.find(pg_key); prefix_it != pin_prefixes.end())
541 prefix = prefix_it->second;
545 prefix =
"i_" + pin_name;
548 if (
const auto pg_it = pin_groups.find(pg_key); pg_it == pin_groups.end())
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();
555 if (!new_mod->assign_pin_to_group(pg_it->second, pin))
557 log_warning(
"dataflow",
"Assign pin to group failed.");
561 new_mod->set_pin_name(pin, prefix +
"(" + std::to_string(pin->get_group().second) +
")");
562 new_mod->set_pin_type(pin, pin_type);
567 const auto sources = pin->get_net()->get_sources([new_mod](
const Endpoint* ep) {
return ep->
get_gate()->get_module() == new_mod; });
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)
577 if (
const auto prefix_it = pin_prefixes.find(pg_key); prefix_it != pin_prefixes.end())
579 prefix = prefix_it->second;
583 prefix =
"o_" + pin_name;
586 if (
const auto pg_it = pin_groups.find(pg_key); pg_it == pin_groups.end())
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();
593 if (!new_mod->assign_pin_to_group(pg_it->second, pin))
595 log_warning(
"dataflow",
"Assign pin to group failed.");
599 new_mod->set_pin_name(pin, prefix +
"(" + std::to_string(pin->get_group().second) +
")");
600 new_mod->set_pin_type(pin, pin_type);
606 for (
const auto* pin_group : new_mod->get_pin_groups())
608 if (pin_group->size() == 1)
610 auto* pin = pin_group->get_pins().front();
611 new_mod->set_pin_name(pin, pin_group->get_name());
615 return OK(group_to_module);
619 const std::map<std::pair<PinDirection, std::string>, std::string>& pin_prefixes,
620 const std::unordered_set<u32>& group_ids)
const
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)
626 for (
const auto& [_,
type] : gl->get_gate_types([suffix](
const GateType* gt) { return gt->has_property(suffix.first); }))
628 gate_type_suffixes[
type] = suffix.second;
632 return this->create_modules(gate_type_suffixes, pin_prefixes, group_ids);
637 std::vector<std::vector<Gate*>> groups;
638 for (
const auto& [group_id, group] : this->get_groups())
640 if (!group_ids.empty() && group_ids.find(group_id) == group_ids.end())
645 std::vector<Gate*> group_vector;
646 for (
const auto& gate : group)
648 group_vector.push_back(gate);
650 groups.push_back(group_vector);
657 if (group_ids.empty())
659 return ERR(
"no group IDs provided.");
662 if (group_ids.size() < 2)
664 return ERR(
"at least two groups are required for merging.");
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())
669 return ERR(
"a group with ID " + std::to_string(*it) +
" does not exist.");
672 u32 target_group_id = ++(this->m_last_id);
675 std::unordered_set<u32> group_ids_set(group_ids.begin(), group_ids.end());
676 for (
auto group_id : group_ids_set)
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);
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; });
686 if (
const auto signals_it = this->m_group_signals.find(group_id); signals_it != this->m_group_signals.end())
688 for (
auto& signals_of_type : std::get<1>(*signals_it))
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());
693 this->m_group_signals.erase(signals_it);
697 if (
const auto suc_it = this->m_group_successors.find(group_id); suc_it != this->m_group_successors.end())
699 auto& target_suc_ids = this->m_group_successors[target_group_id];
700 for (
auto suc_id : std::get<1>(*suc_it))
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);
709 if (
const auto pred_it = this->m_group_predecessors.find(group_id); pred_it != this->m_group_predecessors.end())
711 auto& target_pred_ids = this->m_group_predecessors[target_group_id];
712 for (
auto pred_id : std::get<1>(*pred_it))
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);
721 this->m_group_successors.erase(group_id);
722 this->m_group_predecessors.erase(group_id);
725 return OK(target_group_id);
730 if (new_groups.empty())
732 return ERR(
"no gates provided to define splits.");
735 const auto group_it = this->m_gates_of_group.find(group_id);
736 if (group_it == this->m_gates_of_group.end())
738 return ERR(
"a group with ID " + std::to_string(group_id) +
" does not exist.");
741 const auto& group_gates = std::get<1>(*group_it);
743 std::unordered_set<const Gate*> seen;
744 for (
const auto& gates : new_groups)
746 for (
auto*
g : gates)
750 return ERR(
"gate is a nullptr.");
753 if (group_gates.find(
g) == group_gates.end())
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) +
".");
758 if (seen.find(
g) != seen.end())
760 return ERR(
"gate '" +
g->get_name() +
"' with ID " + std::to_string(
g->get_id()) +
" cannot be assigned to two groups after splitting.");
766 if (seen.size() != group_gates.size())
768 return ERR(
"size of the target group does not match combined size of the split groups.");
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);
776 std::vector<u32> new_group_ids;
777 for (
const auto& gates : new_groups)
779 auto current_id = ++(this->m_last_id);
782 this->m_gates_of_group[current_id] = gates;
784 for (
const auto*
g : gates)
786 this->m_parent_group_of_gate.at(
g) = current_id;
789 if (
const auto signals_it = this->m_gate_signals.find(
g); signals_it != this->m_gate_signals.end())
791 const auto& signals = std::get<1>(*signals_it);
795 if (
const auto nets_it = signals.find(
type); nets_it != signals.end())
797 const auto& nets = std::get<1>(*nets_it);
798 this->m_group_signals[current_id][
type].insert(nets.begin(), nets.end());
804 new_group_ids.push_back(current_id);
808 for (
const auto current_id : new_group_ids)
810 for (
const auto*
g : this->m_gates_of_group.at(current_id))
812 if (
const auto suc_it = this->m_gate_successors.find(
g); suc_it != this->m_gate_successors.end())
814 for (
const auto* suc_g : std::get<1>(*suc_it))
816 this->m_group_successors[current_id].insert(this->m_parent_group_of_gate.at(suc_g));
820 if (
const auto pred_it = this->m_gate_predecessors.find(
g); pred_it != this->m_gate_predecessors.end())
822 for (
const auto* pred_g : std::get<1>(*pred_it))
824 this->m_group_predecessors[current_id].insert(this->m_parent_group_of_gate.at(pred_g));
830 return OK(new_group_ids);
T * get_first_extension() const
virtual void set_parameter(const std::vector< PluginParameter > ¶ms)
Gate * get_gate_by_id(const u32 gate_id) const
Net * get_net_by_id(u32 net_id) const
hal::Result< u32 > merge_groups(const std::vector< u32 > &group_ids)
Merge multiple groups specified by ID.
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.
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.
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.
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.
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.
hal::Result< std::unordered_map< u32, Module * > > create_modules(const std::unordered_set< u32 > &group_ids={}) const
Create modules for the dataflow analysis result.
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.
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...
hal::Result< std::unordered_set< Gate * > > get_gate_successors(const Gate *gate) const
Get the sequential successor gates of the given sequential gate.
const std::unordered_map< u32, std::unordered_set< Gate * > > & get_groups() const
Get the groups of sequential gates resulting from dataflow analysis.
hal::Result< u32 > get_group_id_of_gate(const Gate *gate) const
Get the group ID of the group that contains the given gate.
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.
Result(Netlist *nl, const Grouping &grouping)
Netlist * get_netlist() const
Get the netlist on which dataflow analysis has been performed.
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.
hal::Result< std::unordered_set< Gate * > > get_gate_predecessors(const Gate *gate) const
Get the sequential predecessor gates of the given sequential gate.
std::vector< Gate * > get_gates() const
Get all gates contained in any of the groups groups.
void open_dot_in_viewer(const std::filesystem::path &out_path) const
Open DOT graph in dot viewer if appropriate plugin was loaded.
#define log_info(channel,...)
#define log_warning(channel,...)
BasePluginInterface * get_plugin_instance(const std::string &plugin_name, bool initialize, bool silent)
CORE_API bool starts_with(const T &s, const T &start)
CORE_API std::string join(const std::string &joiner, const Iterator &begin, const Iterator &end, const Transform &transform)
This file contains the struct that holds all information on the result of a dataflow analysis run.
Grouping used during dataflow analysis.
std::unordered_map< u32, std::unordered_set< u32 > > gates_of_group
const NetlistAbstraction & netlist_abstr
std::unordered_set< u32 > get_predecessor_groups_of_group(u32 group_id) const
Get the predecessor groups of a group.
std::unordered_set< u32 > get_successor_groups_of_group(u32 group_id) const
Get the successor groups of a group.
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.