18 std::unordered_set<u32> nets_to_id_set(
const std::unordered_set<Net*>& nets)
20 std::unordered_set<u32> ids;
21 for (
const auto*
net : nets)
23 ids.insert(
net->get_id());
34 for (
const auto* gate : na.target_gates)
36 auto gate_id = gate->get_id();
38 if (
const auto it = na.gate_to_successors.find(gate_id); it != na.gate_to_successors.end())
40 for (
auto suc_gate_id : std::get<1>(*it))
42 this->m_gate_successors[gate].insert(nl->
get_gate_by_id(suc_gate_id));
46 if (
const auto it = na.gate_to_predecessors.find(gate_id); it != na.gate_to_predecessors.end())
48 for (
auto pred_gate_id : std::get<1>(*it))
50 this->m_gate_predecessors[gate].insert(nl->
get_gate_by_id(pred_gate_id));
54 if (
const auto it = na.gate_to_control_signals.find(gate_id); it != na.gate_to_control_signals.end())
56 for (
const auto& [
type, signals] : std::get<1>(*it))
58 for (
auto signal_net_id : signals)
68 std::unordered_set<Gate*> gates;
69 for (
const auto gate_id : gate_ids)
71 auto* gate = m_netlist->get_gate_by_id(gate_id);
73 this->m_parent_group_of_gate[gate] = group_id;
75 m_gates_of_group[group_id] = gates;
79 for (
auto signal_net_id : signals)
81 this->m_group_signals[group_id][
type].insert(m_netlist->get_net_by_id(signal_net_id));
87 this->m_group_successors[group_id] = suc_ids;
92 this->m_group_predecessors[group_id] = pred_ids;
95 this->m_last_id = std::max(this->m_last_id, group_id);
101 return this->m_netlist;
106 return this->m_gates_of_group;
111 std::vector<Gate*> gates;
113 for (
auto& group_gates : m_gates_of_group)
115 std::transform(std::get<1>(group_gates).begin(), std::get<1>(group_gates).end(), std::back_inserter(gates), [](
auto* gate) {
return gate; });
123 if (
const auto it = this->m_gates_of_group.find(group_id); it != this->m_gates_of_group.end())
125 return OK(it->second);
129 return ERR(
"invalid group ID.");
137 return ERR(
"gate is a nullptr.");
140 if (
const auto it = this->m_parent_group_of_gate.find(gate); it != this->m_parent_group_of_gate.end())
142 return OK(it->second);
146 return ERR(
"gate is not part of a group.");
152 if (this->m_gates_of_group.find(group_id) == this->m_gates_of_group.end())
154 return ERR(
"invalid group ID.");
157 if (
const auto group_it = this->m_group_signals.find(group_id); group_it != this->m_group_signals.end())
159 const auto& type_map = std::get<1>(*group_it);
160 if (
const auto type_it = type_map.find(
type); type_it != type_map.end())
162 return OK(type_it->second);
171 if (this->m_parent_group_of_gate.find(gate) == this->m_parent_group_of_gate.end())
173 return ERR(
"gate is not part of a group.");
176 if (
const auto gate_it = this->m_gate_signals.find(gate); gate_it != this->m_gate_signals.end())
178 const auto& type_map = std::get<1>(*gate_it);
179 if (
const auto type_it = type_map.find(
type); type_it != type_map.end())
181 return OK(type_it->second);
190 if (this->m_gates_of_group.find(group_id) == this->m_gates_of_group.end())
192 return ERR(
"invalid group ID.");
195 if (
const auto it = this->m_group_successors.find(group_id); it != this->m_group_successors.end())
197 return OK(it->second);
205 if (this->m_parent_group_of_gate.find(gate) == this->m_parent_group_of_gate.end())
207 return ERR(
"gate is not part of a group.");
210 if (
const auto it = this->m_gate_successors.find(gate); it != this->m_gate_successors.end())
212 return OK(it->second);
220 if (this->m_gates_of_group.find(group_id) == this->m_gates_of_group.end())
222 return ERR(
"invalid group ID.");
225 if (
const auto it = this->m_group_predecessors.find(group_id); it != this->m_group_predecessors.end())
227 return OK(it->second);
235 if (this->m_parent_group_of_gate.find(gate) == this->m_parent_group_of_gate.end())
237 return ERR(
"gate is not part of a group.");
240 if (
const auto it = this->m_gate_predecessors.find(gate); it != this->m_gate_predecessors.end())
242 return OK(it->second);
250 auto write_path = out_path;
252 if (write_path.empty())
254 return ERR(
"output path is empty.");
257 if (std::filesystem::is_directory(write_path))
259 write_path /=
"graph.dot";
262 if (write_path.extension() !=
"dot")
264 log_info(
"dataflow",
"replacing invalid file extension '{}' with '.dot' ...", write_path.extension().string());
265 write_path.replace_extension(
"dot");
268 log_info(
"dataflow",
"writing dataflow graph to '{}' ...", write_path.string());
270 std::ofstream ofs(write_path, std::ofstream::out);
273 ofs <<
"digraph {\n\tnode [shape=box fillcolor=white style=filled];\n";
276 for (
const auto& [group_id, gates] : this->get_groups())
278 if (!group_ids.empty() && group_ids.find(group_id) == group_ids.end())
283 auto size = gates.size() * 0.1;
289 ofs << group_id <<
" [width=" << 0.05 * gates.size() <<
" label=\"" << gates.size() <<
" bit (id " << group_id <<
")\"];\n";
293 for (
const auto& [group_id, gates] : this->get_groups())
295 if (!group_ids.empty() && group_ids.find(group_id) == group_ids.end())
300 auto sucs = this->get_group_successors(group_id).get();
301 for (
auto suc_id : sucs)
303 if (!group_ids.empty() && group_ids.find(suc_id) == group_ids.end())
307 ofs << group_id <<
" -> " << suc_id <<
";\n";
314 log_info(
"dataflow",
"successfully written dataflow graph to '{}'.", write_path.string());
318 return ERR(
"failed to open file at '" + write_path.string() +
"' for writing dataflow graph.");
323 auto write_path = out_path;
325 if (write_path.empty())
327 return ERR(
"output path is empty.");
330 if (std::filesystem::is_directory(write_path))
332 write_path /=
"groups.txt";
335 if (write_path.extension() !=
"txt")
337 log_info(
"dataflow",
"replacing invalid file extension '{}' with '.txt' ...", write_path.extension().string());
338 write_path.replace_extension(
"txt");
341 log_info(
"dataflow",
"writing dataflow gate groups to '{}' ...", write_path.string());
343 std::ofstream ofs(write_path, std::ofstream::out);
349 for (
const auto& [group_id, gates] : this->get_groups())
351 if (!group_ids.empty() && group_ids.find(group_id) == group_ids.end())
356 ofs <<
"ID:" << group_id <<
", ";
357 ofs <<
"Size:" << gates.size() <<
", ";
358 ofs <<
"CLK: {" <<
utils::join(
", ", nets_to_id_set(this->get_group_control_nets(group_id,
PinType::clock).get())) <<
"}, ";
360 ofs <<
"R: {" <<
utils::join(
", ", nets_to_id_set(this->get_group_control_nets(group_id,
PinType::reset).get())) <<
"}, ";
361 ofs <<
"S: {" <<
utils::join(
", ", nets_to_id_set(this->get_group_control_nets(group_id,
PinType::set).get())) <<
"}" << std::endl;
363 if (
auto res = this->get_group_successors(group_id); res.is_ok())
365 auto unsorted_successors = res.get();
366 ofs <<
" Successors: {" +
utils::join(
", ", std::set<u32>(unsorted_successors.begin(), unsorted_successors.end())) <<
"}" << std::endl;
369 if (
auto res = this->get_group_predecessors(group_id); res.is_ok())
371 auto unsorted_predecessors = res.get();
372 ofs <<
" Predecessors: {" +
utils::join(
", ", std::set<u32>(unsorted_predecessors.begin(), unsorted_predecessors.end())) <<
"}" << std::endl;
375 std::unordered_map<u32, std::vector<std::string>> texts;
376 std::unordered_map<u32, u32> text_max_lengths;
378 std::set<u32> gate_ids;
379 for (
const auto& gate : gates)
381 auto name = gate->get_name() +
", ";
382 auto type =
"type: " + gate->get_type()->get_name() +
", ";
383 auto id =
"id: " + std::to_string(gate->get_id()) +
", ";
384 std::string stages =
"RS: ";
387 for (
u32 i = 0; i <
data.size(); ++i)
389 text_max_lengths[i] = std::max(text_max_lengths[i], (
u32)
data[i].size());
392 u32 gate_id = gate->get_id();
393 texts.emplace(gate_id,
data);
394 gate_ids.insert(gate_id);
397 for (
const auto& gate_id : gate_ids)
399 auto&
data = texts[gate_id];
400 for (
u32 i = 0; i <
data.size(); ++i)
402 ofs << std::setw(text_max_lengths[i]) << std::left <<
data[i];
410 log_info(
"dataflow",
"successfully written dataflow gate groups to '{}'.", write_path.string());
414 return ERR(
"failed to open file at '" + write_path.string() +
"' for writing dataflow gate groups.");
419 return create_modules(std::map<const GateType*, std::string>(), std::map<std::pair<PinDirection, std::string>, std::string>(), group_ids);
423 const std::map<std::pair<PinDirection, std::string>, std::string>& pin_prefixes,
424 const std::unordered_set<u32>& group_ids)
const
426 auto* nl = this->get_netlist();
429 std::vector<Module*> modules_to_delete;
430 for (
const auto mod : nl->get_modules())
434 modules_to_delete.push_back(mod);
438 for (
auto* mod : modules_to_delete)
440 nl->delete_module(mod);
442 log_info(
"dataflow",
"successfully deleted old DANA modules");
445 std::unordered_map<u32, Module*> group_to_module;
446 for (
const auto& [group_id, group] : this->get_groups())
448 if (!group_ids.empty() && group_ids.find(group_id) == group_ids.end())
453 bool gate_hierachy_matches_for_all =
true;
454 bool gate_type_matches_for_all =
true;
455 bool first_run =
true;
457 auto* reference_module = nl->get_top_module();
459 std::vector<Gate*> gates;
460 for (
const auto gate : group)
462 gates.push_back(gate);
466 reference_module = gate->get_module();
467 gate_type = gate->get_type();
470 else if (gate->get_module() != reference_module)
472 gate_hierachy_matches_for_all =
false;
475 if (gate_type != gate->get_type())
477 gate_hierachy_matches_for_all =
false;
481 if (!gate_hierachy_matches_for_all)
483 reference_module = nl->get_top_module();
487 if (
const auto it = module_suffixes.find(gate_type); gate_type_matches_for_all && it != module_suffixes.end())
496 auto* new_mod = nl->create_module(
"DANA_" + suffix +
"_" + std::to_string(group_id), reference_module, gates);
497 group_to_module[group_id] = new_mod;
500 for (
auto* pin : new_mod->get_pins())
504 const auto destinations = pin->get_net()->get_destinations([new_mod](
const Endpoint* ep) {
return ep->
get_gate()->get_module() == new_mod; });
506 const auto* first_pin = destinations.front()->get_pin();
507 auto pin_type = first_pin->
get_type();
508 auto pin_name = first_pin->get_name();
509 if (std::all_of(destinations.begin(), destinations.end(), [pin_name](
const Endpoint* ep) { return ep->get_pin()->get_name() == pin_name; }))
514 if (
const auto prefix_it = pin_prefixes.find(pg_key); prefix_it != pin_prefixes.end())
516 prefix = prefix_it->second;
520 prefix =
"i_" + pin_name;
523 if (
const auto pg_it = pin_groups.find(pg_key); pg_it == pin_groups.end())
525 auto* pin_group = pin->get_group().first;
526 pin_groups[pg_key] = pin_group;
527 new_mod->set_pin_group_name(pin_group, prefix);
528 new_mod->set_pin_group_type(pin_group, pin_type);
532 if (!new_mod->assign_pin_to_group(pg_it->second, pin))
534 log_warning(
"dataflow",
"Assign pin to group failed.");
538 new_mod->set_pin_name(pin, prefix +
"(" + std::to_string(pin->get_group().second) +
")");
539 new_mod->set_pin_type(pin, pin_type);
544 const auto sources = pin->get_net()->get_sources([new_mod](
const Endpoint* ep) {
return ep->
get_gate()->get_module() == new_mod; });
546 const auto* first_pin = sources.front()->get_pin();
547 auto pin_type = first_pin->get_type();
548 auto pin_name = first_pin->get_name();
549 if (sources.size() == 1)
554 if (
const auto prefix_it = pin_prefixes.find(pg_key); prefix_it != pin_prefixes.end())
556 prefix = prefix_it->second;
560 prefix =
"o_" + pin_name;
563 if (
const auto pg_it = pin_groups.find(pg_key); pg_it == pin_groups.end())
565 auto* pin_group = pin->get_group().first;
566 pin_groups[pg_key] = pin_group;
567 new_mod->set_pin_group_name(pin_group, prefix);
568 new_mod->set_pin_group_type(pin_group, pin_type);
572 if (!new_mod->assign_pin_to_group(pg_it->second, pin))
574 log_warning(
"dataflow",
"Assign pin to group failed.");
578 new_mod->set_pin_name(pin, prefix +
"(" + std::to_string(pin->get_group().second) +
")");
579 new_mod->set_pin_type(pin, pin_type);
585 for (
const auto* pin_group : new_mod->get_pin_groups())
587 if (pin_group->size() == 1)
589 auto* pin = pin_group->get_pins().front();
590 new_mod->set_pin_name(pin, pin_group->get_name());
594 return OK(group_to_module);
598 const std::map<std::pair<PinDirection, std::string>, std::string>& pin_prefixes,
599 const std::unordered_set<u32>& group_ids)
const
601 const auto* gl = this->m_netlist->get_gate_library();
602 std::map<const GateType*, std::string> gate_type_suffixes;
603 for (
const auto& suffix : module_suffixes)
605 for (
const auto& [_,
type] : gl->get_gate_types([suffix](
const GateType* gt) { return gt->has_property(suffix.first); }))
607 gate_type_suffixes[
type] = suffix.second;
611 return this->create_modules(gate_type_suffixes, pin_prefixes, group_ids);
616 std::vector<std::vector<Gate*>> groups;
617 for (
const auto& [group_id, group] : this->get_groups())
619 if (!group_ids.empty() && group_ids.find(group_id) == group_ids.end())
624 std::vector<Gate*> group_vector;
625 for (
const auto& gate : group)
627 group_vector.push_back(gate);
629 groups.push_back(group_vector);
636 if (group_ids.empty())
638 return ERR(
"no group IDs provided.");
641 if (group_ids.size() < 2)
643 return ERR(
"at least two groups are required for merging.");
646 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())
648 return ERR(
"a group with ID " + std::to_string(*it) +
" does not exist.");
651 u32 target_group_id = ++(this->m_last_id);
654 std::unordered_set<u32> group_ids_set(group_ids.begin(), group_ids.end());
655 for (
auto group_id : group_ids_set)
658 auto& gates_at_i = this->m_gates_of_group.at(group_id);
659 this->m_gates_of_group[target_group_id].insert(gates_at_i.begin(), gates_at_i.end());
660 this->m_gates_of_group.erase(group_id);
662 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; });
665 if (
const auto signals_it = this->m_group_signals.find(group_id); signals_it != this->m_group_signals.end())
667 for (
auto& signals_of_type : std::get<1>(*signals_it))
669 auto& signals = std::get<1>(signals_of_type);
670 this->m_group_signals[target_group_id][signals_of_type.first].insert(signals.begin(), signals.end());
672 this->m_group_signals.erase(signals_it);
676 if (
const auto suc_it = this->m_group_successors.find(group_id); suc_it != this->m_group_successors.end())
678 auto& target_suc_ids = this->m_group_successors[target_group_id];
679 for (
auto suc_id : std::get<1>(*suc_it))
681 auto& pred_ids = this->m_group_predecessors.at(suc_id);
682 pred_ids.insert(target_group_id);
683 target_suc_ids.insert(suc_id);
684 pred_ids.erase(group_id);
688 if (
const auto pred_it = this->m_group_predecessors.find(group_id); pred_it != this->m_group_predecessors.end())
690 auto& target_pred_ids = this->m_group_predecessors[target_group_id];
691 for (
auto pred_id : std::get<1>(*pred_it))
693 auto& suc_ids = this->m_group_successors.at(pred_id);
694 suc_ids.insert(target_group_id);
695 target_pred_ids.insert(pred_id);
696 suc_ids.erase(group_id);
700 this->m_group_successors.erase(group_id);
701 this->m_group_predecessors.erase(group_id);
704 return OK(target_group_id);
709 if (new_groups.empty())
711 return ERR(
"no gates provided to define splits.");
714 const auto group_it = this->m_gates_of_group.find(group_id);
715 if (group_it == this->m_gates_of_group.end())
717 return ERR(
"a group with ID " + std::to_string(group_id) +
" does not exist.");
720 const auto& group_gates = std::get<1>(*group_it);
722 std::unordered_set<const Gate*> seen;
723 for (
const auto& gates : new_groups)
725 for (
auto*
g : gates)
729 return ERR(
"gate is a nullptr.");
732 if (group_gates.find(
g) == group_gates.end())
734 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) +
".");
737 if (seen.find(
g) != seen.end())
739 return ERR(
"gate '" +
g->get_name() +
"' with ID " + std::to_string(
g->get_id()) +
" cannot be assigned to two groups after splitting.");
745 if (seen.size() != group_gates.size())
747 return ERR(
"size of the target group does not match combined size of the split groups.");
750 this->m_gates_of_group.erase(group_id);
751 this->m_group_successors.erase(group_id);
752 this->m_group_predecessors.erase(group_id);
753 this->m_group_signals.erase(group_id);
755 std::vector<u32> new_group_ids;
756 for (
const auto& gates : new_groups)
758 auto current_id = ++(this->m_last_id);
761 this->m_gates_of_group[current_id] = gates;
763 for (
const auto*
g : gates)
765 this->m_parent_group_of_gate.at(
g) = current_id;
768 if (
const auto signals_it = this->m_gate_signals.find(
g); signals_it != this->m_gate_signals.end())
770 const auto& signals = std::get<1>(*signals_it);
774 if (
const auto nets_it = signals.find(
type); nets_it != signals.end())
776 const auto& nets = std::get<1>(*nets_it);
777 this->m_group_signals[current_id][
type].insert(nets.begin(), nets.end());
783 new_group_ids.push_back(current_id);
787 for (
const auto current_id : new_group_ids)
789 for (
const auto*
g : this->m_gates_of_group.at(current_id))
791 if (
const auto suc_it = this->m_gate_successors.find(
g); suc_it != this->m_gate_successors.end())
793 for (
const auto* suc_g : std::get<1>(*suc_it))
795 this->m_group_successors[current_id].insert(this->m_parent_group_of_gate.at(suc_g));
799 if (
const auto pred_it = this->m_gate_predecessors.find(
g); pred_it != this->m_gate_predecessors.end())
801 for (
const auto* pred_g : std::get<1>(*pred_it))
803 this->m_group_predecessors[current_id].insert(this->m_parent_group_of_gate.at(pred_g));
809 return OK(new_group_ids);
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::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.
hal::Result< std::monostate > 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.
#define log_info(channel,...)
#define log_warning(channel,...)
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.