16 #include "nlohmann/json.hpp"
17 #include "rapidjson/document.h"
28 namespace netlist_preprocessing
38 GateScope(
const std::vector<Gate*>& gates) : m_all(gates.empty())
43 if (m_lookup.insert(g).second)
50 bool contains(
const Gate* g)
const
52 return m_all || m_lookup.find(g) != m_lookup.end();
59 std::vector<Gate*> gates(
const Netlist* nl,
const std::function<
bool(
const Gate*)>& type_filter =
nullptr)
const
63 return type_filter ? nl->get_gates(type_filter) : nl->get_gates();
66 std::vector<Gate*> res;
67 for (
auto* g : m_gates)
69 if (!type_filter || type_filter(g))
79 std::vector<Gate*> m_gates;
80 std::unordered_set<const Gate*> m_lookup;
90 if (gnd_gates.empty())
92 return ERR(
"could not remove unused LUT endpoints from netlist with ID " + std::to_string(nl->
get_id()) +
": no GND net available within netlist");
94 Net* gnd_net = gnd_gates.front()->get_fan_out_nets().front();
96 const GateScope scope(gates);
99 for (
const auto& gate : scope.gates(nl, [](
const Gate* g) { return g->get_type()->has_property(GateTypeProperty::c_lut); }))
101 std::vector<Endpoint*> fan_in = gate->get_fan_in_endpoints();
102 std::unordered_map<std::string, BooleanFunction> functions = gate->get_boolean_functions();
105 if (functions.size() != 1)
111 auto active_pins = functions.begin()->second.get_variable_names();
114 if (fan_in.size() > active_pins.size())
116 for (
const auto& ep : fan_in)
118 if (ep->get_net()->is_gnd_net() || ep->get_net()->is_vcc_net())
123 if (std::find(active_pins.begin(), active_pins.end(), ep->get_pin()->get_name()) == active_pins.end())
126 if (!ep->get_net()->remove_destination(gate, pin))
129 "netlist_preprocessing",
"failed to remove unused input from LUT gate '{}' with ID {} from netlist with ID {}.", gate->get_name(), gate->get_id(), nl->
get_id());
135 "failed to reconnect unused input of LUT gate '{}' with ID {} to GND in netlist with ID {}.",
147 log_info(
"netlist_preprocessing",
"removed {} unused LUT endpoints from netlist with ID {}.", num_eps, nl->
get_id());
157 std::queue<Gate*> gates_to_be_deleted;
159 const GateScope scope(gates);
161 for (
const auto& gate : scope.gates(nl))
163 std::vector<Endpoint*> fan_out = gate->get_fan_out_endpoints();
174 if (fan_out.size() != 1)
181 if (functions.size() != 1)
187 Endpoint* out_endpoint = *(fan_out.begin());
193 std::vector<Endpoint*> fan_in = gate->get_fan_in_endpoints();
198 if (substitute_res.is_error())
201 "Cannot replace buffers: failed to substitute pins with constants at gate " + gate->get_name() +
" with ID " + std::to_string(gate->get_id()));
213 for (
Endpoint* in_endpoint : fan_in)
215 Net* in_net = in_endpoint->get_net();
220 if (merge_res.is_error())
222 log_warning(
"netlist_preprocessing",
"{}", merge_res.get_error().get());
232 "failed to remove destination from input net '{}' with ID {} of buffer gate '{}' with ID {} from netlist with ID {}.",
250 gates_to_be_deleted.push(gate);
371 log_debug(
"netlist_preprocessing",
"removing {} buffer gates...", gates_to_be_deleted.size());
373 while (!gates_to_be_deleted.empty())
375 Gate* gate = gates_to_be_deleted.front();
376 gates_to_be_deleted.pop();
379 log_warning(
"netlist_preprocessing",
"failed to remove buffer gate '{}' with ID {} from netlist with ID {}.", gate->
get_name(), gate->
get_id(), nl->
get_id());
385 log_info(
"netlist_preprocessing",
"removed {} buffer gates from netlist with ID {}.", num_gates, nl->
get_id());
386 return OK(num_gates);
391 std::unordered_map<Gate*, std::vector<std::string>> restore_ff_replacements(
const Netlist* nl)
393 std::unordered_map<Gate*, std::vector<std::string>> replacements;
397 if (g->has_data(
"preprocessing_information",
"replaced_gates"))
399 const auto& [_, s] = g->get_data(
"preprocessing_information",
"replaced_gates");
401 replacements.insert({g, replaced_gate_names});
408 void update_ff_replacements(std::unordered_map<Gate*, std::vector<std::string>>& replacements)
410 for (
auto& [g, r] : replacements)
412 const nlohmann::json j = r;
413 const std::string s = j.dump();
415 g->set_data(
"preprocessing_information",
"replaced_gates",
"string", s);
421 void annotate_ff_survivor(std::unordered_map<Gate*, std::vector<std::string>>& replacements, Gate* survivor, Gate* to_be_replaced)
423 auto& it_s = replacements[survivor];
425 if (
const auto& it = replacements.find(to_be_replaced); it != replacements.end())
427 for (
const auto& s : it->second)
431 replacements.erase(it);
434 it_s.push_back(to_be_replaced->get_name());
444 const GateScope scope(gates);
448 #ifdef BITWUZLA_LIBRARY
451 config = config.with_solver(s_type).with_call(s_call);
453 struct GateFingerprint
456 std::map<GatePin*, Net*> ordered_fan_in = {};
457 std::set<Net*> unordered_fan_in = {};
458 u8 truth_table_hw = 0;
459 std::vector<std::string> init_data = {};
461 bool operator<(
const GateFingerprint& other)
const
463 return std::tie(
type, ordered_fan_in, unordered_fan_in, truth_table_hw, init_data)
464 < std::tie(other.type, other.ordered_fan_in, other.unordered_fan_in, other.truth_table_hw, other.init_data);
468 static std::vector<u8> hw_map = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
473 std::vector<Gate*> target_gates;
489 auto ff_replacements = restore_ff_replacements(nl);
493 std::map<GateFingerprint, std::vector<Gate*>> fingerprinted_gates;
497 for (
auto* gate : target_gates)
499 GateFingerprint fingerprint;
500 fingerprint.type = gate->get_type();
503 const auto& fan_in_nets = gate->get_fan_in_nets();
504 fingerprint.unordered_fan_in.insert(fan_in_nets.cbegin(), fan_in_nets.cend());
507 auto lut_out_pins = fingerprint.type->get_pins([](
const GatePin* p) {
511 if (!lut_out_pins.empty())
514 if (lc_fp !=
nullptr)
515 if (
const auto res = lc_fp->get_init_string(gate, lut_out_pins.front()); res.is_ok())
517 const auto& init_str = res.get();
518 for (
const auto c : init_str)
520 u8 tmp = std::toupper(c) - 0x30;
525 fingerprint.truth_table_hw += hw_map.at(tmp);
533 for (
const auto& ep : gate->get_fan_in_endpoints())
535 fingerprint.ordered_fan_in[ep->get_pin()] = ep->get_net();
542 if (
const auto* init_component = fingerprint.type->get_component_as<
InitComponent>([](
const GateTypeComponent* c) { return c->get_type() == GateTypeComponent::ComponentType::init; });
543 init_component !=
nullptr)
545 for (
const auto&
identifier : init_component->get_init_identifiers())
547 fingerprint.init_data.push_back(std::get<1>(gate->get_data(init_component->get_init_category(),
identifier)));
552 fingerprinted_gates[fingerprint].push_back(gate);
555 std::vector<std::vector<Gate*>> duplicate_gates;
556 for (
const auto& [fingerprint, gates] : fingerprinted_gates)
558 if (gates.size() == 1)
564 if (std::none_of(gates.begin(), gates.end(), [&scope](
const Gate* g) { return scope.contains(g); }))
571 std::set<const Gate*> visited;
572 for (
size_t i = 0; i < gates.size(); i++)
574 Gate* master_gate = gates.at(i);
576 if (visited.find(master_gate) != visited.cend())
581 std::vector<Gate*> current_duplicates = {master_gate};
583 for (
size_t j = i + 1; j < gates.size(); j++)
585 Gate* current_gate = gates.at(j);
587 for (
const auto* pin : fingerprint.type->get_output_pins())
589 const auto solver_res =
599 if (solver_res.is_error() || !solver_res.get().is_unsat())
607 current_duplicates.push_back(current_gate);
608 visited.insert(current_gate);
612 if (current_duplicates.size() > 1)
614 duplicate_gates.push_back(current_duplicates);
620 duplicate_gates.push_back(std::move(gates));
624 std::set<Gate*> affected_gates;
625 for (
auto& current_duplicates : duplicate_gates)
627 std::sort(current_duplicates.begin(), current_duplicates.end(), [](
const auto& g1,
const auto& g2) { return g1->get_name().length() < g2->get_name().length(); });
631 std::stable_partition(current_duplicates.begin(), current_duplicates.end(), [&scope](
const Gate* g) { return !scope.contains(g); });
633 auto* survivor_gate = current_duplicates.front();
634 std::map<GatePin*, Net*> out_pins_to_nets;
635 for (
auto* ep : survivor_gate->get_fan_out_endpoints())
637 Net* out_net = ep->get_net();
638 out_pins_to_nets[ep->get_pin()] = out_net;
641 auto* dst_gate = dst->get_gate();
642 auto* dst_type = dst_gate->get_type();
645 affected_gates.insert(dst_gate);
650 for (
u32 k = 1; k < current_duplicates.size(); k++)
652 auto* current_gate = current_duplicates.at(k);
655 if (!scope.contains(current_gate))
660 for (
auto* ep : current_gate->get_fan_out_endpoints())
662 auto* ep_net = ep->get_net();
663 auto* ep_pin = ep->get_pin();
665 if (
auto it = out_pins_to_nets.find(ep_pin); it != out_pins_to_nets.cend())
668 for (
auto* dst : ep_net->get_destinations())
670 auto* dst_gate = dst->get_gate();
671 auto* dst_pin = dst->get_pin();
673 it->second->add_destination(dst_gate, dst_pin);
675 auto* dst_type = dst_gate->get_type();
678 affected_gates.insert(dst_gate);
683 log_warning(
"netlist_preprocessing",
"could not delete net '{}' with ID {} from netlist with ID {}.", ep_net->get_name(), ep_net->get_id(), nl->
get_id());
689 ep_net->add_source(survivor_gate, ep_pin);
690 out_pins_to_nets[ep_pin] = ep_net;
691 for (
auto* dst : ep_net->get_destinations())
693 auto* dst_gate = dst->get_gate();
694 auto* dst_type = dst_gate->get_type();
697 affected_gates.insert(dst_gate);
703 annotate_ff_survivor(ff_replacements, survivor_gate, current_gate);
705 affected_gates.erase(current_gate);
708 log_warning(
"netlist_preprocessing",
"could not delete gate '{}' with ID {} from netlist with ID {}.", current_gate->get_name(), current_gate->get_id(), nl->
get_id());
717 target_gates = std::vector<Gate*>(affected_gates.cbegin(), affected_gates.cend());
720 update_ff_replacements(ff_replacements);
722 log_info(
"netlist_preprocessing",
"removed {} redundant gates from netlist with ID {}.", num_gates, nl->
get_id());
723 return OK(num_gates);
728 struct LoopFingerprint
730 std::map<const GateType*, u32> types;
731 std::set<std::string> external_variable_names;
732 std::set<const Net*> ff_control_nets;
734 bool operator<(
const LoopFingerprint& other)
const
736 return (other.types < types) || (other.types == types && other.external_variable_names < external_variable_names)
737 || (other.types == types && other.external_variable_names == external_variable_names && other.ff_control_nets < ff_control_nets);
743 #ifdef BITWUZLA_LIBRARY
746 config = config.with_solver(s_type).with_call(s_call);
751 auto ff_replacements = restore_ff_replacements(nl);
757 std::unordered_map<Gate*, std::unordered_set<Gate*>> loops_by_start_gate;
758 for (
auto* start_ff : nl->
get_gates([](
const Gate* g) { return g->get_type()->has_property(GateTypeProperty::ff); }))
760 std::vector<Gate*> stack = {start_ff};
761 std::vector<Gate*> previous_gates;
762 std::unordered_set<Gate*> visited_gates;
763 std::unordered_set<Gate*> cache;
765 while (!stack.empty())
767 auto* current_gate = stack.back();
769 if (!previous_gates.empty() && current_gate == previous_gates.back())
772 previous_gates.pop_back();
776 visited_gates.insert(current_gate);
779 for (
const auto* suc_ep : current_gate->get_successors())
781 if (ff_control_pin_types.find(suc_ep->get_pin()->get_type()) != ff_control_pin_types.end())
786 auto* suc_gate = suc_ep->get_gate();
787 if (suc_gate == start_ff || cache.find(suc_gate) != cache.end())
789 loops_by_start_gate[start_ff].insert(current_gate);
790 cache.insert(current_gate);
791 for (
auto it = ++(previous_gates.begin()); it != previous_gates.end(); it++)
794 loops_by_start_gate[start_ff].insert(*it);
799 if (visited_gates.find(suc_gate) == visited_gates.end())
801 stack.push_back(suc_gate);
809 previous_gates.push_back(current_gate);
818 std::map<LoopFingerprint, std::vector<std::pair<std::vector<Gate*>,
BooleanFunction>>> fingerprinted_loops;
819 for (
const auto& [start_ff, comb_gates] : loops_by_start_gate)
821 LoopFingerprint fingerprint;
824 if (comb_gates.size() > 30)
830 std::vector<const Endpoint*> data_in;
831 for (
const auto* ep : start_ff->get_fan_in_endpoints())
833 auto pin_type = ep->get_pin()->get_type();
834 if (ff_control_pin_types.find(pin_type) != ff_control_pin_types.end())
836 fingerprint.ff_control_nets.insert(ep->get_net());
840 data_in.push_back(ep);
844 if (data_in.size() != 1)
850 fingerprint.types[start_ff->get_type()] = 1;
851 for (
const auto* g : comb_gates)
854 if (
const auto type_it = fingerprint.types.find(gt); type_it == fingerprint.types.end())
856 fingerprint.types[gt] = 0;
858 fingerprint.types[gt]++;
861 std::vector<const Gate*> comb_gates_vec(comb_gates.cbegin(), comb_gates.cend());
869 for (
const auto* ep : start_ff->get_fan_out_endpoints())
872 it != fingerprint.external_variable_names.end())
874 function =
function.substitute(*it, ep->get_pin()->get_name());
875 fingerprint.external_variable_names.erase(it);
879 std::vector<Gate*> loop_gates = {start_ff};
880 loop_gates.insert(loop_gates.end(), comb_gates.begin(), comb_gates.end());
881 fingerprinted_loops[fingerprint].push_back(std::make_pair(loop_gates, std::move(
function)));
885 std::vector<std::vector<std::vector<Gate*>>> duplicate_loops;
886 for (
const auto& [_, loops] : fingerprinted_loops)
888 if (loops.size() == 1)
893 std::set<u32> visited;
894 for (
u32 i = 0; i < loops.size(); i++)
896 if (visited.find(i) != visited.cend())
901 const auto& master_loop = loops.at(i);
903 std::vector<std::vector<Gate*>> current_duplicates = {std::get<0>(master_loop)};
905 for (
size_t j = i + 1; j < loops.size(); j++)
907 const auto& current_loop = loops.at(j);
908 const auto solver_res =
909 BooleanFunction::Eq(std::get<1>(master_loop).clone(), std::get<1>(current_loop).clone(), 1)
913 if (solver_res.is_ok() && solver_res.get().is_unsat())
915 current_duplicates.push_back(std::get<0>(current_loop));
920 if (current_duplicates.size() > 1)
922 duplicate_loops.push_back(std::move(current_duplicates));
927 for (
const auto& current_duplicates : duplicate_loops)
930 const auto& survivor_loop = current_duplicates.front();
931 auto* survivor_ff = survivor_loop.front();
933 std::map<GatePin*, Net*> out_pins_to_nets;
934 for (
auto* ep : survivor_ff->get_fan_out_endpoints())
936 Net* out_net = ep->get_net();
937 out_pins_to_nets[ep->get_pin()] = out_net;
940 for (
u32 i = 1; i < current_duplicates.size(); i++)
942 auto* current_ff = current_duplicates.at(i).front();
943 for (
auto* ep : current_ff->get_fan_out_endpoints())
945 auto* ep_net = ep->get_net();
946 auto* ep_pin = ep->get_pin();
948 if (
auto it = out_pins_to_nets.find(ep_pin); it != out_pins_to_nets.cend())
951 for (
auto* dst : ep_net->get_destinations())
953 auto* dst_gate = dst->get_gate();
954 auto* dst_pin = dst->get_pin();
956 it->second->add_destination(dst_gate, dst_pin);
960 log_warning(
"netlist_preprocessing",
"could not delete net '{}' with ID {} from netlist with ID {}.", ep_net->get_name(), ep_net->get_id(), nl->
get_id());
966 ep_net->add_source(survivor_ff, ep_pin);
967 out_pins_to_nets[ep_pin] = ep_net;
971 annotate_ff_survivor(ff_replacements, survivor_ff, current_ff);
975 log_warning(
"netlist_preprocessing",
"could not delete gate '{}' with ID {} from netlist with ID {}.", current_ff->get_name(), current_ff->get_id(), nl->
get_id());
984 update_ff_replacements(ff_replacements);
986 log_info(
"netlist_preprocessing",
"removed {} redundant loops from netlist with ID {}.", num_gates, nl->
get_id());
987 return OK(num_gates);
992 struct TreeFingerprint
994 std::set<const Net*> external_inputs;
997 bool operator<(
const TreeFingerprint& other)
const
999 return (other.external_inputs < external_inputs);
1006 std::map<TreeFingerprint, std::set<Net*>> fingerprint_to_nets;
1007 if (!all_comb_gates_vec.empty())
1011 auto cache_res = subgraph_dec.make_subgraph_function_cache(all_comb_gates_vec);
1012 if (cache_res.is_error())
1014 return ERR_APPEND(cache_res.get_error(),
"Unable to remove redundant logic trees: failed to create subgraph function cache");
1016 auto cache = cache_res.get();
1018 for (
const auto& g : all_comb_gates_vec)
1020 for (
const auto& out_ep : g->get_fan_out_endpoints())
1025 const auto& out_net = out_ep->get_net();
1026 auto inputs_res = subgraph_dec.get_subgraph_function_inputs(out_net, cache);
1027 if (inputs_res.is_error())
1030 "Unable to remove redundant logic trees: failed to gather inputs for net " + out_net->get_name() +
" with ID " + std::to_string(out_net->get_id()));
1033 tf.external_inputs = inputs_res.get();
1036 fingerprint_to_nets[tf].insert(out_net);
1042 std::vector<std::vector<Net*>> equality_classes;
1044 for (
const auto& [_fingerprint, nets] : fingerprint_to_nets)
1058 std::vector<Net*> current_candidate_nets = {nets.begin(), nets.end()};
1059 std::vector<Net*> next_candidate_nets;
1061 while (!current_candidate_nets.empty())
1063 const auto n = current_candidate_nets.back();
1064 current_candidate_nets.pop_back();
1066 std::vector<Net*> new_equality_class = {n};
1068 for (
const auto& m : current_candidate_nets)
1071 if (comp_res.is_error())
1074 "Unable to remove redundant logic trees: failed to compare net " + n->get_name() +
" with ID " + std::to_string(n->get_id()) +
" with net "
1075 + m->get_name() +
" with ID " + std::to_string(m->get_id()));
1077 const auto are_equal = comp_res.get();
1081 new_equality_class.push_back(m);
1085 next_candidate_nets.push_back(m);
1089 equality_classes.push_back(new_equality_class);
1090 current_candidate_nets = next_candidate_nets;
1091 next_candidate_nets.clear();
1096 for (
const auto& eq_class : equality_classes)
1105 auto survivor_net = eq_class.front();
1107 for (
u32 i = 1; i < eq_class.size(); i++)
1109 auto victim_net = eq_class.at(i);
1110 for (
const auto& dst : victim_net->get_destinations())
1112 auto dst_gate = dst->get_gate();
1113 auto dst_pin = dst->get_pin();
1115 if (!victim_net->remove_destination(dst))
1117 return ERR(
"Unable to remove redundant logic trees: failed to remove destination of net " + victim_net->get_name() +
" with ID " + std::to_string(victim_net->get_id())
1118 +
" at gate " + dst_gate->get_name() +
" with ID " + std::to_string(dst_gate->get_id()) +
" and pin " + dst_pin->get_name());
1120 if (!survivor_net->add_destination(dst_gate, dst_pin))
1122 return ERR(
"Unable to remove redundant logic trees: failed to add destination to net " + survivor_net->get_name() +
" with ID " + std::to_string(survivor_net->get_id())
1123 +
" at gate " + dst_gate->get_name() +
" with ID " + std::to_string(dst_gate->get_id()) +
" and pin " + dst_pin->get_name());
1132 if (clean_up_res.is_error())
1134 return ERR_APPEND(clean_up_res.get_error(),
"Unable to remove redundant logic trees: failed to clean up dangling trees");
1137 return OK(clean_up_res.get() + counter);
1143 const GateScope scope(gates);
1146 std::vector<Gate*> candidates = scope.gates(nl);
1148 std::vector<Gate*> to_delete;
1153 for (
const auto& g : candidates)
1155 bool is_unconnected =
true;
1156 for (
const auto& on : g->get_fan_out_nets())
1158 if (!on->get_destinations().empty() || on->is_global_output_net())
1160 is_unconnected =
false;
1166 to_delete.push_back(g);
1170 for (
const auto& g : to_delete)
1174 log_warning(
"netlist_preprocessing",
"could not delete gate '{}' with ID {} from netlist with ID {}.", g->get_name(), g->get_id(), nl->
get_id());
1184 if (!to_delete.empty())
1186 const std::unordered_set<Gate*> handled(to_delete.begin(), to_delete.end());
1187 candidates.erase(std::remove_if(candidates.begin(), candidates.end(), [&handled](
Gate* g) { return handled.find(g) != handled.end(); }), candidates.end());
1189 }
while (!to_delete.empty());
1191 log_info(
"netlist_preprocessing",
"removed {} unconnected gates from netlist with ID {}.", num_gates, nl->
get_id());
1192 return OK(num_gates);
1199 std::vector<Net*> to_delete;
1201 for (
const auto& n : nl->
get_nets())
1203 if (!n->is_global_input_net() && n->get_sources().empty() && !n->is_global_output_net() && n->get_destinations().empty())
1205 to_delete.push_back(n);
1209 for (
const auto& n : to_delete)
1213 log_warning(
"netlist_preprocessing",
"could not delete net '{}' with ID {} from netlist with ID {}.", n->get_name(), n->get_id(), nl->
get_id());
1221 log_info(
"netlist_preprocessing",
"removed {} unconnected nets from netlist with ID {}.", num_nets, nl->
get_id());
1222 return OK(num_nets);
1227 u32 total_removed = 0;
1232 if (gate_res.is_error())
1234 return ERR_APPEND(gate_res.get_error(),
"unable to execute clean up loop: failed to remove unconnected gates");
1238 if (net_res.is_error())
1240 return ERR_APPEND(net_res.get_error(),
"unable to execute clean up loop: failed to remove unconnected nets");
1243 const u32 removed = gate_res.get() + net_res.get();
1244 total_removed += removed;
1251 return OK(total_removed);
1263 u32 delete_count = 0;
1264 std::vector<Gate*> delete_gate_q;
1266 for (
const auto& g : muxes)
1276 if (data_pins.size() < 2)
1281 if (out_pins.size() != 1)
1286 bool preceded_by_inv =
true;
1287 for (
const auto& pin : data_pins)
1292 preceded_by_inv =
false;
1297 if (!preceded_by_inv)
1302 bool succeded_by_inv =
true;
1303 for (
const auto& pin : out_pins)
1308 succeded_by_inv =
false;
1313 if (!succeded_by_inv)
1319 for (
const auto& pin : data_pins)
1327 auto in_net = pred->get_gate()->get_fan_in_nets().front();
1328 in_net->add_destination(g, pin);
1331 if (pred->get_gate()->get_successors().empty())
1333 delete_gate_q.push_back(pred->get_gate());
1337 for (
const auto& pin : out_pins)
1345 auto in_net = suc->get_gate()->get_fan_out_nets().front();
1346 in_net->add_source(g, pin);
1349 if (suc->get_gate()->get_predecessors().empty())
1351 delete_gate_q.push_back(suc->get_gate());
1356 for (
auto g : delete_gate_q)
1362 log_info(
"netlist_preprocessing",
"removed {} encasing inverters", delete_count);
1364 return OK(delete_count);
1367 struct MuxFingerprint
1372 bool operator<(
const MuxFingerprint& other)
const
1374 return (other.type <
type) || (other.type ==
type && other.inverters <
inverters);
1378 Result<u32> unify_inverted_select_signals(Netlist* nl, GateLibrary* mux_inv_gl)
1382 return ERR(
"netlist is a nullptr");
1385 if (mux_inv_gl ==
nullptr)
1387 return ERR(
"gate library is a nullptr");
1391 if (base_path_res.is_error())
1393 return ERR_APPEND(base_path_res.get_error(),
"unable to resynthesize boolean functions with yosys: failed to get unique temp directory");
1395 const std::filesystem::path base_path = base_path_res.get();
1396 const std::filesystem::path genlib_path = base_path /
"mux_inv.genlib";
1397 std::filesystem::create_directory(base_path);
1402 return ERR(
"unable to unify muxe select signals: failed to save gate library " + mux_inv_gl->get_name() +
" to location " + genlib_path.string());
1405 const i64 initial_size = nl->get_gates().size();
1410 std::vector<Gate*> muxes = nl->get_gates([](
const Gate* g) {
return (g->get_type()->get_name().find(
"HAL_MUX") != std::string::npos); });
1412 std::map<MuxFingerprint, std::unique_ptr<Netlist>> resynth_cache;
1414 for (
const auto& g : muxes)
1418 mf.type = g->get_type();
1421 std::map<GatePin*, Net*> pin_to_input;
1423 auto select_pins = g->get_type()->get_pins([](
const GatePin* pin) {
return (pin->get_type() ==
PinType::select) && (pin->get_direction() ==
PinDirection::input); });
1425 std::vector<Gate*> preceding_inverters;
1426 for (
const auto& pin : g->get_type()->get_input_pins())
1428 const auto pred = g->get_predecessor(pin);
1429 const auto is_select = (std::find(select_pins.begin(), select_pins.end(), pin) != select_pins.end());
1430 if (!is_select || pred ==
nullptr || pred->get_gate() ==
nullptr || !pred->get_gate()->get_type()->has_property(
GateTypeProperty::c_inverter)
1431 || (pred->get_gate()->get_fan_in_endpoints().size() != 1))
1433 pin_to_input.insert({pin, g->get_fan_in_net(pin)});
1437 auto inv_gate = pred->get_gate();
1438 preceding_inverters.push_back(inv_gate);
1439 pin_to_input.insert({pin, inv_gate->get_fan_in_endpoints().front()->get_net()});
1440 mf.inverters.insert(pin);
1445 if (!preceding_inverters.empty())
1447 const Netlist* resynth_nl;
1449 auto subgraph = preceding_inverters;
1450 subgraph.push_back(g);
1453 if (
const auto it = resynth_cache.find(mf); it == resynth_cache.end())
1455 std::unordered_map<std::string, BooleanFunction> bfs;
1456 for (
const auto& ep : g->get_fan_out_endpoints())
1458 const auto bf_res = SubgraphNetlistDecorator(*nl).get_subgraph_function(subgraph, ep->get_net());
1459 if (bf_res.is_error())
1462 "unable to unify muxes select signals: failed to build boolean function for mux " + g->get_name() +
" with ID " + std::to_string(g->get_id())
1463 +
" at output " + ep->get_pin()->get_name());
1465 auto bf = bf_res.get();
1468 for (
const auto& [pin,
net] : pin_to_input)
1470 auto sub_res = bf.substitute(BooleanFunctionNetDecorator(*net).get_boolean_variable_name(),
BooleanFunction::Var(pin->get_name(), 1));
1471 if (sub_res.is_error())
1473 return ERR_APPEND(sub_res.get_error(),
"unable to unify muxes select signals: failed to substitute net_id variable with generic variable");
1478 bfs.insert({ep->get_pin()->get_name(), std::move(bf)});
1482 if (resynth_res.is_error())
1484 return ERR_APPEND(resynth_res.get_error(),
"unable to unify select signals of muxes: failed to resynthesize mux subgraph to netlist");
1486 auto unique_resynth_nl = resynth_res.get();
1487 resynth_nl = unique_resynth_nl.get();
1488 resynth_cache.insert({mf, std::move(unique_resynth_nl)});
1492 resynth_nl = it->second.get();
1495 std::unordered_map<Net*, std::vector<Net*>> global_io_mapping;
1498 for (
const auto& pin : resynth_nl->get_top_module()->get_input_pins())
1500 auto net_it = pin_to_input.find(g->get_type()->get_pin_by_name(pin->get_name()));
1501 if (net_it == pin_to_input.end())
1503 return ERR(
"unable to unify muxes select signals:: failed to locate net in destination netlist from global input " + pin->get_name() +
" in resynthesized netlist");
1505 global_io_mapping[pin->get_net()].push_back(net_it->second);
1507 for (
const auto& pin : resynth_nl->get_top_module()->get_output_pins())
1509 auto net = g->get_fan_out_net(pin->get_name());
1512 return ERR(
"unable to unify muxes select signals:: failed to locate net in destination netlist from global output " + pin->get_name() +
" in resynthesized netlist");
1514 global_io_mapping[pin->get_net()].push_back(
net);
1518 if (replace_res.is_error())
1520 return ERR(
"unable to unify muxes select signals: failed to replace mux subgraph with resynthesized netlist");
1524 std::vector<Gate*> to_delete;
1525 for (
const auto g : subgraph)
1527 bool has_no_outside_destinations =
true;
1528 bool has_only_outside_destinations =
true;
1529 for (
const auto& suc : g->get_successors())
1531 const auto it = std::find(subgraph.begin(), subgraph.end(), suc->get_gate());
1532 if (it == subgraph.end())
1534 has_no_outside_destinations =
false;
1537 if (it != subgraph.end())
1539 has_only_outside_destinations =
false;
1543 if (has_no_outside_destinations || has_only_outside_destinations)
1545 to_delete.push_back(g);
1549 for (
const auto& g : to_delete)
1551 if (!nl->delete_gate(g))
1553 return ERR(
"unable to unify muxes select signals: failed to delete gate " + g->get_name() +
" with ID " + std::to_string(g->get_id()) +
" in destination netlist");
1560 std::filesystem::remove_all(base_path);
1562 const i64 new_size = nl->get_gates().size();
1563 const i64 difference = std::abs(initial_size - new_size);
1565 return OK(
u32(difference));
1568 Result<u32> unify_select_signals(Netlist* nl)
1572 return ERR(
"netlist is a nullptr");
1575 u32 changed_connections = 0;
1578 std::map<std::pair<GateType*, std::set<Net*>>, std::vector<Gate*>> grouped_muxes;
1579 for (
const auto& g : nl->get_gates([](
const Gate* g) { return g->get_type()->has_property(GateTypeProperty::c_mux); }))
1581 std::set<Net*> select_signals;
1582 const auto select_pins = g->get_type()->get_pins([](
const GatePin* pin) {
return (pin->get_type() ==
PinType::select) && (pin->get_direction() ==
PinDirection::input); });
1583 for (
const auto& sp : select_pins)
1585 select_signals.insert(g->get_fan_in_net(sp));
1588 grouped_muxes[{g->get_type(), select_signals}].push_back(g);
1592 for (
const auto& [finger_print, mux_group] : grouped_muxes)
1594 const auto& [
type, select_signals_set] = finger_print;
1596 const auto output_pins =
type->get_pins([](
const GatePin* pin) {
return pin->get_direction() ==
PinDirection::output; });
1598 if (output_pins.size() != 1)
1601 "Cannot unify select signals for muxes of type {} since the type has {} output signals and we can only handle 1.",
1603 output_pins.size());
1608 std::map<std::map<GatePin*, Net*>, std::vector<Gate*>> select_map_to_muxes;
1609 for (
const auto& g : mux_group)
1611 std::map<GatePin*, Net*> select_map;
1612 for (
const auto& sp : select_pins)
1614 select_map.insert({sp, g->get_fan_in_net(sp)});
1617 select_map_to_muxes[select_map].push_back(g);
1620 if (select_map_to_muxes.size() == 1)
1625 const std::vector<Net*> select_signals = {select_signals_set.begin(), select_signals_set.end()};
1628 std::map<Gate*, std::map<GatePin*, Net*>> new_net_to_pin;
1631 for (
const auto& g : mux_group)
1633 for (
u32 select_index = 0; select_index < select_pins.size(); select_index++)
1635 auto select_pin = select_pins.at(select_index);
1636 auto select_signal = select_signals.at(select_index);
1637 new_net_to_pin[g][select_pin] = select_signal;
1642 auto type_bf =
type->get_boolean_function(output_pins.front());
1643 for (
u32 select_val = 0; select_val < (1 << select_signals.size()); select_val++)
1645 std::map<std::string, BooleanFunction> type_substitution;
1646 for (
u32 select_idx = 0; select_idx < select_pins.size(); select_idx++)
1648 auto select_pin = select_pins.at(select_idx);
1650 auto type_substitution_val = ((select_val >> select_idx) & 0x1) ?
BooleanFunction::Const(1, 1) : BooleanFunction::Const(0, 1);
1651 type_substitution.insert({select_pin->get_name(), type_substitution_val});
1654 auto type_substitution_res = type_bf.substitute(type_substitution);
1655 if (type_substitution_res.is_error())
1657 return ERR_APPEND(type_substitution_res.get_error(),
"cannot unify mux select signals: failed to substitute type Boolean function with select signal value mapping.");
1659 auto input = type_substitution_res.get().simplify_local();
1661 if (!
input.is_variable())
1663 return ERR(
"cannot unify mux select signals: substituted and simplified type Boolean function (" +
input.to_string() +
") is not a variable");
1666 const auto pin_name =
input.get_variable_name().get();
1667 auto pin =
type->get_pins([pin_name](
const auto& p) {
return p->get_name() == pin_name; }).front();
1669 for (
const auto& g : mux_group)
1671 auto gate_bf_res = g->get_boolean_function(output_pins.front(),
true,
true);
1672 if (gate_bf_res.is_error())
1675 "cannot unify mux select signals: failed to build Boolean function for gate " + g->get_name() +
" with ID " + std::to_string(g->get_id()));
1677 auto gate_bf = gate_bf_res.get();
1679 std::map<std::string, BooleanFunction> gate_substitution;
1681 for (
u32 select_idx = 0; select_idx < select_pins.size(); select_idx++)
1683 auto gate_substitution_val = ((select_val >> select_idx) & 0x1) ?
BooleanFunction::Const(1, 1) : BooleanFunction::Const(0, 1);
1684 gate_substitution.insert({BooleanFunctionNetDecorator(*(select_signals.at(select_idx))).get_boolean_variable_name(), gate_substitution_val});
1687 auto gate_substitution_res = gate_bf.substitute(gate_substitution);
1688 if (gate_substitution_res.is_error())
1690 return ERR_APPEND(gate_substitution_res.get_error(),
"cannot unify mux select signals: failed to substitute gate Boolean function with select signal value mapping.");
1692 auto input_net_var = gate_substitution_res.get().simplify_local();
1695 if (net_res.is_error())
1697 return ERR_APPEND(net_res.get_error(),
"cannot unify mux select signals: failed to extract net from substituted and simplified gate Boolean function");
1700 auto net = net_res.get();
1701 new_net_to_pin[g][pin] =
net;
1706 for (
auto& [g, pin_net] : new_net_to_pin)
1708 for (
const auto& [pin,
net] : pin_net)
1710 auto connected_net = g->get_fan_in_net(pin);
1711 if (
net == connected_net)
1716 connected_net->remove_destination(g, pin);
1717 net->add_destination(g, pin);
1719 changed_connections += 1;
1724 return OK(changed_connections);
1734 return ERR(
"netlist is a nullptr");
1737 if (mux_inv_gl ==
nullptr)
1739 return ERR(
"gate library is a nullptr");
1742 auto remove_res = remove_encasing_inverters(nl);
1743 if (remove_res.is_error())
1745 return ERR_APPEND(remove_res.get_error(),
"unable to apply manual mux optimizations: failed to remove encasing inverters");
1747 res_count += remove_res.get();
1749 auto unify_inverted_res = unify_inverted_select_signals(nl, mux_inv_gl);
1750 if (unify_inverted_res.is_error())
1752 return ERR_APPEND(unify_inverted_res.get_error(),
"unable to apply manual mux optimizations: failed to unify inverted select signals");
1754 res_count += unify_inverted_res.get();
1756 auto unify_res = unify_select_signals(nl);
1757 if (unify_res.is_error())
1759 return ERR_APPEND(unify_res.get_error(),
"unable to apply manual mux optimizations: failed to unify select signals");
1761 res_count += unify_res.get();
1763 return OK(res_count);
1770 return ERR(
"netlist is a nullptr");
1773 const GateScope scope(gates);
1778 u32 total_replaced_dst_count = 0;
1782 u32 replaced_dst_count = 0;
1783 std::vector<Gate*> to_delete;
1786 for (
const auto g : nl->
get_gates([&scope](
const auto g) {
1787 return scope.contains(g) && g->get_type()->has_property(GateTypeProperty::combinational) && !g->get_type()->has_property(GateTypeProperty::ground)
1788 && !g->get_type()->has_property(GateTypeProperty::power);
1791 bool has_global_output =
false;
1792 for (
const auto ep : g->get_fan_out_endpoints())
1794 if (ep->get_net()->is_global_output_net())
1796 has_global_output =
true;
1799 auto bf_res = g->get_boolean_function(ep->get_pin(),
true,
true);
1800 if (bf_res.is_error())
1803 "unable to propagate constants: failed to generate boolean function at gate " + g->get_name() +
" with ID " + std::to_string(g->get_id()) +
" for pin "
1804 + ep->get_pin()->get_name());
1806 auto bf = bf_res.get();
1808 if (sub_res.is_error())
1811 "unable to propagate constants: failed to substitue power and ground nets in boolean function of gate " + g->get_name() +
" with ID "
1812 + std::to_string(g->get_id()) +
" for pin " + ep->get_pin()->get_name());
1815 bf = bf.simplify_local();
1818 if (bf.is_constant())
1821 if (bf.has_constant_value(0))
1823 new_source = gnd_net;
1825 else if (bf.has_constant_value(1))
1827 new_source = vcc_net;
1834 if (new_source ==
nullptr)
1837 return ERR(
"unable to propagate constants: netlist is missing gnd or vcc net!");
1840 std::vector<std::pair<Gate*, GatePin*>> to_replace;
1841 for (
auto dst : ep->get_net()->get_destinations())
1843 to_replace.push_back({dst->get_gate(), dst->get_pin()});
1846 for (
const auto& [dst_g, dst_p] : to_replace)
1848 ep->get_net()->remove_destination(dst_g, dst_p);
1851 replaced_dst_count++;
1858 if (!has_global_output && g->get_successors().empty())
1860 to_delete.push_back(g);
1864 for (
auto g : to_delete)
1869 if (replaced_dst_count == 0)
1874 log_debug(
"netlist_preprocessing",
"replaced {} destinations this with power/ground nets this iteration", replaced_dst_count);
1875 total_replaced_dst_count += replaced_dst_count;
1878 log_info(
"netlist_preprocessing",
"replaced {} destinations with power/ground nets in total", total_replaced_dst_count);
1879 return OK(total_replaced_dst_count);
1886 return ERR(
"netlist is a nullptr");
1889 const GateScope scope(gates);
1891 std::set<Gate*> gates_to_delete;
1892 for (
auto* inv_gate : scope.gates(nl, [](
const Gate* g) { return g->get_type()->has_property(GateTypeProperty::c_inverter); }))
1894 if (gates_to_delete.find(inv_gate) != gates_to_delete.end())
1899 const auto& connection_endpoints = inv_gate->get_fan_in_endpoints();
1900 if (connection_endpoints.size() != 1)
1902 log_warning(
"netlist_preprocessing",
"could not handle gate '{}' with ID {} due to a fan-in size != 1", inv_gate->get_name(), inv_gate->get_id());
1906 auto* middle_fan_in_ep = connection_endpoints.front();
1907 auto* middle_net = middle_fan_in_ep->get_net();
1908 if (middle_net->get_sources().size() != 1)
1910 log_warning(
"netlist_preprocessing",
"could not handle gate '{}' with ID {} due to a number of predecessors != 1", inv_gate->get_name(), inv_gate->get_id());
1913 auto* pred_gate = middle_net->get_sources().front()->get_gate();
1916 if (!scope.contains(pred_gate))
1923 const auto& fan_in = pred_gate->get_fan_in_endpoints();
1924 if (fan_in.size() != 1)
1926 log_warning(
"netlist_preprocessing",
"could not handle gate '{}' with ID {} due to a fan-in size != 1", pred_gate->get_name(), pred_gate->get_id());
1929 if (pred_gate->get_fan_out_endpoints().size() != 1)
1931 log_warning(
"netlist_preprocessing",
"could not handle gate '{}' with ID {} due to a fan-out size != 1", pred_gate->get_name(), pred_gate->get_id());
1934 auto* in_net = fan_in.front()->get_net();
1936 const auto& fan_out = inv_gate->get_fan_out_endpoints();
1937 if (fan_out.size() != 1)
1939 log_warning(
"netlist_preprocessing",
"could not handle gate '{}' with ID {} due to a fan-out size != 1", inv_gate->get_name(), inv_gate->get_id());
1942 auto* out_net = fan_out.front()->get_net();
1944 for (
auto* dst_ep : out_net->get_destinations())
1946 auto* dst_pin = dst_ep->get_pin();
1947 auto* dst_gate = dst_ep->get_gate();
1949 out_net->remove_destination(dst_ep);
1950 in_net->add_destination(dst_gate, dst_pin);
1953 middle_net->remove_destination(middle_fan_in_ep);
1955 if (middle_net->get_num_of_destinations() == 0)
1958 gates_to_delete.insert(pred_gate);
1961 gates_to_delete.insert(inv_gate);
1965 u32 removed_ctr = 0;
1966 for (
auto* g : gates_to_delete)
1972 return OK(removed_ctr);
1977 std::string generate_hex_truth_table_string(
const std::vector<BooleanFunction::Value>& tt)
1979 std::string tt_str =
"";
1982 for (
u32 i = 0; i < tt.size(); i++)
1985 if (bit == BooleanFunction::Value::ONE)
1987 acc += (1 << (i % 4));
1992 std::stringstream stream;
1993 stream << std::hex << acc;
1995 tt_str = stream.str() + tt_str;
2009 const GateScope scope(gates);
2011 for (
auto g : scope.gates(nl, [](
const auto& g) { return g->get_type()->has_property(GateTypeProperty::c_lut); }))
2014 if (g->get_type()->get_output_pins().size() != 1)
2020 if (lc_simp ==
nullptr)
2026 if (g->get_fan_out_endpoints().empty())
2031 const auto out_ep = g->get_fan_out_endpoints().front();
2032 const GatePin* out_pin = out_ep->get_pin();
2034 auto res = lc_simp->get_init_string(g, out_pin);
2038 "unable to simplify lut init string for gate " + g->get_name() +
" with ID " + std::to_string(g->get_id()) +
": failed to get original INIT string");
2041 const auto original_init = res.get();
2044 if (g->get_boolean_functions().size() != 1)
2049 const auto bf_org = g->get_boolean_function(out_ep->get_pin());
2050 const auto org_vars = bf_org.get_variable_names();
2053 if (bf_replaced_res.is_error())
2055 return ERR_APPEND(bf_replaced_res.get_error(),
2056 "cannot simplify LUT inits: failed to replace power and ground pins for gate " + g->get_name() +
" with ID " + std::to_string(g->get_id()));
2058 const auto bf_replaced = bf_replaced_res.get();
2059 const auto bf_simplified = bf_replaced.simplify_local();
2061 const auto new_vars = bf_simplified.get_variable_names();
2063 if (org_vars.size() == new_vars.size())
2068 auto bf_extended = bf_simplified.clone();
2069 for (
const auto& in_pin : g->get_type()->get_input_pin_names())
2071 if (new_vars.find(in_pin) == new_vars.end())
2078 const auto tt = bf_extended.compute_truth_table().get();
2079 const auto new_init_string = generate_hex_truth_table_string(tt.front());
2084 lc_simp->set_init_string(g, out_pin, new_init_string).get();
2085 g->set_data(
"preprocessing_information",
"original_init",
"string", original_init);
2098 log_info(
"netlist_preprocessing",
"simplified {} LUT INIT strings inside of netlist with ID {}.", num_inits, nl->
get_id());
2099 return OK(num_inits);
2104 struct indexed_identifier
2106 indexed_identifier(
const std::string& p_identifier,
const u32 p_index,
const std::string& p_origin) :
identifier{p_identifier},
index{p_index},
origin{p_origin}
2116 const std::string hal_instance_index_pattern =
"__\\[(\\d+)\\]__";
2117 const std::string hal_instance_index_pattern_reverse =
"<HAL>(\\d+)<HAL>";
2119 std::string replace_hal_instance_index(
const std::string&
name)
2121 std::regex re(hal_instance_index_pattern);
2126 while (std::regex_search(
input, match, re))
2135 std::string reconstruct_hal_instance_index(
const std::string&
name)
2137 std::regex re(hal_instance_index_pattern_reverse);
2142 while (std::regex_search(input, match, re))
2151 const std::string net_index_pattern =
"\\((\\d+)\\)";
2152 const std::string gate_index_pattern =
"\\[(\\d+)\\]";
2155 std::optional<indexed_identifier> extract_index(
const std::string&
name,
const std::string& index_pattern,
const std::string&
origin)
2157 std::regex re(index_pattern);
2160 std::optional<std::string> last_match;
2161 std::optional<u32> last_index;
2165 while (std::regex_search(input, match, re))
2168 last_index = std::stoi(match[1]);
2169 last_match = match.str();
2170 input = match.suffix().str();
2173 if (!last_index.has_value())
2175 return std::nullopt;
2178 const auto found_match = last_match.value();
2179 auto identifier_name =
name;
2180 identifier_name = identifier_name.replace(
name.rfind(found_match), found_match.size(),
"");
2182 return std::optional<indexed_identifier>{{identifier_name, last_index.value(),
origin}};
2186 bool annotate_indexed_identifiers(Gate* gate,
const std::vector<indexed_identifier>& identifiers)
2188 std::string json_identifier_str =
2189 "[" +
utils::join(
", ", identifiers, [](
const auto& i) {
return std::string(
"[") +
'"' + i.identifier +
'"' +
", " + std::to_string(i.index) +
", " +
'"' + i.origin +
'"' +
"]"; })
2192 return gate->set_data(
"preprocessing_information",
"multi_bit_indexed_identifiers",
"string", json_identifier_str);
2196 std::vector<indexed_identifier> check_net_at_pin(
const PinType pin_type, Gate* gate)
2198 const auto typed_pins = gate->get_type()->get_pins([pin_type](
const auto p) {
return p->get_type() == pin_type; });
2200 std::vector<indexed_identifier> found_identfiers;
2202 for (
const auto& pin : typed_pins)
2204 const auto typed_net = (pin->get_direction() ==
PinDirection::output) ? gate->get_fan_out_net(pin) : gate->get_fan_in_net(pin);
2213 const auto net_name_index = extract_index(typed_net->get_name(), net_index_pattern,
"net_name");
2214 if (net_name_index.has_value())
2216 found_identfiers.push_back(net_name_index.value());
2220 if (!typed_net->has_data(
"parser_annotation",
"merged_nets"))
2225 const auto all_merged_nets_str = std::get<1>(typed_net->get_data(
"parser_annotation",
"merged_nets"));
2227 if (all_merged_nets_str.empty())
2233 rapidjson::Document doc;
2234 doc.Parse(all_merged_nets_str.c_str());
2236 for (
u32 i = 0; i < doc.GetArray().Size(); i++)
2238 const auto list = doc[i].GetArray();
2239 for (
u32 j = 0; j < list.Size(); j++)
2241 const auto merged_wire_name = list[j].GetString();
2243 const auto merged_wire_name_index = extract_index(merged_wire_name, net_index_pattern,
"net_name");
2244 if (merged_wire_name_index.has_value())
2246 found_identfiers.push_back(merged_wire_name_index.value());
2252 return found_identfiers;
2259 for (
auto&
ff : nl->
get_gates([](
const auto g) { return g->get_type()->has_property(GateTypeProperty::ff); }))
2261 std::vector<indexed_identifier> all_identifiers;
2264 const auto cleaned_gate_name = replace_hal_instance_index(
ff->get_name());
2265 const auto gate_name_index = extract_index(cleaned_gate_name, gate_index_pattern,
"gate_name");
2267 if (gate_name_index.has_value())
2269 auto found_identifier = gate_name_index.value();
2270 found_identifier.identifier = reconstruct_hal_instance_index(found_identifier.identifier);
2271 all_identifiers.push_back(found_identifier);
2277 for (
const auto& pt : relevant_pin_types)
2279 const auto found_identifiers = check_net_at_pin(pt,
ff);
2280 all_identifiers.insert(all_identifiers.end(), found_identifiers.begin(), found_identifiers.end());
2283 if (!all_identifiers.empty())
2288 annotate_indexed_identifiers(
ff, all_identifiers);
2296 std::map<std::string, std::map<u32, std::vector<ModulePin*>>> pg_name_to_indexed_pins;
2300 auto reconstruct = extract_index(pin->get_name(), net_index_pattern,
"");
2301 if (!reconstruct.has_value())
2306 auto [pg_name,
index, _] = reconstruct.value();
2308 pg_name_to_indexed_pins[pg_name][
index].push_back(pin);
2311 u32 reconstructed_counter = 0;
2312 for (
const auto& [pg_name, indexed_pins] : pg_name_to_indexed_pins)
2314 std::vector<ModulePin*> ordered_pins;
2316 bool valid_indices =
true;
2318 for (
const auto& [_index,
pins] : indexed_pins)
2320 if (
pins.size() > 1)
2322 valid_indices =
false;
2326 ordered_pins.push_back(
pins.front());
2337 return ERR_APPEND(res.get_error(),
"cannot reconstruct top module pin groups: failed to create pin group " + pg_name);
2340 reconstructed_counter++;
2343 return OK(reconstructed_counter);
2348 struct ComponentData
2356 TokenStream<std::string> tokenize(std::stringstream& ss)
2358 const std::string delimiters =
" ;-";
2359 std::string current_token;
2360 u32 line_number = 0;
2363 bool escaped =
false;
2365 std::vector<Token<std::string>> parsed_tokens;
2366 while (std::getline(ss, line))
2378 else if (escaped && std::isspace(c))
2384 if (((!std::isspace(c) && delimiters.find(c) == std::string::npos) || escaped))
2390 if (!current_token.empty())
2392 parsed_tokens.emplace_back(line_number, current_token);
2393 current_token.clear();
2396 if (!std::isspace(c))
2398 parsed_tokens.emplace_back(line_number, std::string(1, c));
2403 if (!current_token.empty())
2405 parsed_tokens.emplace_back(line_number, current_token);
2406 current_token.clear();
2410 return TokenStream(parsed_tokens, {}, {});
2413 Result<std::unordered_map<std::string, ComponentData>> parse_tokens(TokenStream<std::string>& ts)
2415 ts.consume_until(
"COMPONENTS");
2416 ts.consume(
"COMPONENTS");
2417 const auto component_count_str = ts.consume().string;
2420 u32 component_count;
2423 component_count = res.get();
2427 return ERR_APPEND(res.get_error(),
"could not parse tokens: failed to read component count from token" + component_count_str);
2430 std::cout <<
"Component count: " << component_count << std::endl;
2432 std::unordered_map<std::string, ComponentData> component_data;
2433 for (
u32 c_idx = 0; c_idx < component_count; c_idx++)
2436 ComponentData new_data_entry;
2438 new_data_entry.name = ts.consume().string;
2439 new_data_entry.type = ts.consume().string;
2441 ts.consume(
"SOURCE");
2443 ts.consume(
"TIMING");
2445 ts.consume(
"PLACED");
2446 ts.consume(
"FIXED");
2451 new_data_entry.x = res.get();
2455 return ERR_APPEND(res.get_error(),
"could not parse tokens: failed to read x coordinate from token");
2460 new_data_entry.y = res.get();
2464 return ERR_APPEND(res.get_error(),
"could not parse tokens: failed to read y coordinate from token");
2469 ts.consume_current_line();
2471 component_data.insert({new_data_entry.name, new_data_entry});
2474 return OK(component_data);
2480 std::stringstream ss;
2482 ifs.open(def_file.string(), std::ifstream::in);
2485 return ERR(
"could not parse DEF (Design Exchange Format) file '" + def_file.string() +
"' : unable to open file");
2490 auto ts = tokenize(ss);
2492 std::unordered_map<std::string, ComponentData> component_data;
2496 if (
auto res = parse_tokens(ts); res.is_error())
2498 return ERR_APPEND(res.get_error(),
"could not parse Design Exchange Format file '" + def_file.string() +
"': unable to parse tokens");
2502 component_data = res.get();
2507 if (e.line_number != (
u32)-1)
2509 return ERR(
"could not parse Design Exchange Format file '" + def_file.string() +
"': " + e.message +
" (line " + std::to_string(e.line_number) +
")");
2513 return ERR(
"could not parse Design Exchange Format file '" + def_file.string() +
"': " + e.message);
2517 std::unordered_map<std::string, Gate*> name_to_gate;
2520 name_to_gate.insert({g->get_name(), g});
2524 for (
const auto& [gate_name,
data] : component_data)
2526 if (
const auto& g_it = name_to_gate.find(gate_name); g_it != name_to_gate.end())
2529 g_it->second->set_location_x(
data.x);
2530 g_it->second->set_location_y(
data.y);
2536 log_info(
"netlist_preprocessing",
"reconstructed coordinates for {} / {} ({:.2}) gates", counter, nl->
get_gates().size(), (
double)counter / (
double)nl->
get_gates().size());
2543 std::vector<Module*> all_modules;
2544 for (
const auto& [gt_name, pin_groups] : concatenated_pin_groups)
2549 return ERR(
"unable to create multi bit gate module for gate type " + gt_name +
": failed to find gate type with that name in gate library " + nl->
get_gate_library()->
get_name());
2552 for (
const auto& g : nl->
get_gates([>](
const auto& g) { return g->get_type() == gt; }))
2554 auto m = nl->
create_module(
"module_" + g->get_name(), g->get_module(), {g});
2556 for (
const auto& [module_pg_name, gate_pg_names] : pin_groups)
2558 std::vector<ModulePin*> module_pins;
2559 for (
const auto& gate_pg_name : gate_pg_names)
2561 const auto& gate_pg = g->
get_type()->get_pin_group_by_name(gate_pg_name);
2563 if (gate_pg ==
nullptr)
2565 return ERR(
"unable to create multi-bit gate module for gate type " + gt_name +
" and pin group " + gate_pg_name +
": failed to find pin group with that name");
2568 std::vector<GatePin*> pin_list = gate_pg->get_pins();
2569 if (!gate_pg->is_ascending())
2571 std::reverse(pin_list.begin(), pin_list.end());
2574 for (
const auto& gate_pin : pin_list)
2576 const auto net = (gate_pin->get_direction() ==
PinDirection::output) ? g->get_fan_out_net(gate_pin) : g->get_fan_in_net(gate_pin);
2582 if (
net->is_gnd_net() ||
net->is_vcc_net())
2587 const auto module_pin = m->get_pin_by_net(
net);
2589 module_pins.push_back(module_pin);
2593 m->create_pin_group(module_pg_name, module_pins);
2594 u32 idx_counter = 0;
2595 for (
const auto& mp : module_pins)
2597 m->set_pin_name(mp, module_pg_name +
"_" + std::to_string(idx_counter));
2602 all_modules.push_back(m);
2606 return OK(all_modules);
2611 std::vector<Net*> created_nets;
2613 const GateScope scope(gates);
2615 for (
const auto& g : scope.gates(nl))
2617 for (
const auto& p : g->get_type()->get_output_pins())
2619 if (g->get_fan_out_net(p) ==
nullptr)
2622 new_net->
set_name(
"HAL_UNCONNECTED_" + std::to_string(new_net->get_id()));
2623 new_net->add_source(g, p);
2625 created_nets.push_back(new_net);
2630 return OK(created_nets);
2637 return ERR(
"netlist is a nullptr");
2640 if (inverter_type ==
nullptr)
2643 const auto inv_types =
2645 if (inv_types.empty())
2647 return ERR(
"gate library '" + gl->get_name() +
"' of netlist does not contain an inverter gate");
2649 inverter_type = inv_types.begin()->second;
2655 return ERR(
"inverter gate type '" + inverter_type->
get_name() +
"' of gate library '" + inverter_type->
get_gate_library()->
get_name() +
"' does not belong to gate library '"
2667 +
"' has an invalid number of input pins or output pins");
2676 const std::vector<Gate*>& gates = ffs.empty() ? nl->
get_gates() : ffs;
2678 for (
auto*
ff : gates)
2680 auto* ff_type =
ff->get_type();
2688 GatePin* neg_state_pin =
nullptr;
2690 for (
auto* o_pin : ff_type->get_output_pins())
2698 neg_state_pin = o_pin;
2702 if (neg_state_pin ==
nullptr)
2707 auto* neg_state_ep =
ff->get_fan_out_endpoint(neg_state_pin);
2708 if (neg_state_ep ==
nullptr)
2712 auto* neg_state_net = neg_state_ep->get_net();
2714 auto state_net =
ff->get_fan_out_net(state_pin);
2715 if (state_net ==
nullptr)
2717 state_net = nl->
create_net(
ff->get_name() +
"__STATE_NET__");
2721 auto* inv = nl->
create_gate(inverter_type,
ff->get_name() +
"__NEG_STATE_INVERT__");
2724 if (
auto* mod =
ff->get_module(); !mod->is_top_module())
2726 mod->assign_gate(inv);
2729 state_net->add_destination(inv, inv_in_pin);
2730 neg_state_net->remove_source(neg_state_ep);
2731 neg_state_net->add_source(inv, inv_out_pin);
const std::string & get_name() const
PinDirection get_direction() const
Result< BooleanFunction > substitute_power_ground_nets(const Netlist *nl) const
Result< BooleanFunction > substitute_power_ground_pins(const Gate *g) const
static Result< BooleanFunction > Eq(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static BooleanFunction Var(const std::string &name, u16 size=1)
Result< std::string > get_variable_name() const
std::set< std::string > get_variable_names() const
Value
represents the type of the node
BooleanFunction simplify_local() const
static BooleanFunction Const(const BooleanFunction::Value &value)
static Result< BooleanFunction > Not(BooleanFunction &&p0, u16 size)
static Result< BooleanFunction > And(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< Net * > get_net_from(const Netlist *netlist, const BooleanFunction &var)
std::string get_boolean_variable_name() const
GatePin * get_pin() const
BooleanFunction get_boolean_function(const std::string &name) const
GateType * get_type() const
std::vector< Endpoint * > get_successors(const std::function< bool(const GatePin *pin, Endpoint *ep)> &filter=nullptr) const
const std::string & get_name() const
Endpoint * get_predecessor(const std::string &pin_name) const
Endpoint * get_successor(const std::string &pin_name) const
std::unordered_map< std::string, GateType * > get_gate_types(const std::function< bool(const GateType *)> &filter=nullptr) const
GateType * get_gate_type_by_name(const std::string &name) const
std::string get_name() const
std::vector< std::string > get_input_pin_names() const
GateLibrary * get_gate_library() const
std::vector< GatePin * > get_output_pins() const
const std::string & get_name() const
bool has_property(GateTypeProperty property) const
std::vector< GatePin * > get_input_pins() const
const std::unordered_map< std::string, BooleanFunction > & get_boolean_functions() const
std::vector< GatePin * > get_pins(const std::function< bool(GatePin *)> &filter=nullptr) const
std::vector< ModulePin * > get_pins(const std::function< bool(ModulePin *)> &filter=nullptr) const
Result< PinGroup< ModulePin > * > create_pin_group(const u32 id, const std::string &name, const std::vector< ModulePin * > pins={}, PinDirection direction=PinDirection::none, PinType type=PinType::none, bool ascending=false, u32 start_index=0, bool delete_empty_groups=true, bool force_name=false)
std::string get_type() const
Endpoint * add_destination(Gate *gate, const std::string &pin_name)
bool remove_source(Gate *gate, const std::string &pin_name)
void set_name(const std::string &name)
Endpoint * add_source(Gate *gate, const std::string &pin_name)
const std::string & get_name() const
std::vector< Endpoint * > get_destinations(const std::function< bool(Endpoint *ep)> &filter=nullptr) const
bool remove_destination(Gate *gate, const std::string &pin_name)
Module * get_top_module() const
const std::vector< Gate * > & get_gates() const
bool delete_net(Net *net)
Net * create_net(const u32 net_id, const std::string &name)
const std::vector< Gate * > & get_gnd_gates() const
const std::vector< Gate * > & get_vcc_gates() const
bool delete_gate(Gate *gate)
Gate * create_gate(const u32 gate_id, GateType *gate_type, const std::string &name="", i32 x=-1, i32 y=-1)
const std::vector< Net * > & get_nets() const
const GateLibrary * get_gate_library() const
Module * create_module(const u32 module_id, const std::string &name, Module *parent, const std::vector< Gate * > &gates={})
Result< Net * > connect_nets(Net *master_net, Net *slave_net)
Result< BooleanFunction > get_subgraph_function(const std::vector< const Gate * > &subgraph_gates, const Net *subgraph_output) const
#define log_debug(channel,...)
#define log_info(channel,...)
#define log_warning(channel,...)
#define ERR_APPEND(prev_error, message)
bool save(std::filesystem::path file_path, GateLibrary *gate_lib, bool overwrite=false)
std::unique_ptr< GateLibrary > parse(std::filesystem::path file_path)
Result< std::monostate > parse_def_file(Netlist *nl, const std::filesystem::path &def_file)
Result< u32 > manual_mux_optimizations(Netlist *nl, GateLibrary *mux_inv_gl)
Result< u32 > propagate_constants(Netlist *nl, const std::vector< Gate * > &gates={})
Result< std::vector< Net * > > create_nets_at_unconnected_pins(Netlist *nl, const std::vector< Gate * > &gates={})
Result< u32 > remove_unconnected_gates(Netlist *nl, const std::vector< Gate * > &gates={})
Result< u32 > remove_redundant_loops(Netlist *nl)
Result< u32 > remove_redundant_logic_trees(Netlist *nl)
Result< u32 > remove_redundant_gates(Netlist *nl, const std::function< bool(const Gate *)> &filter=nullptr, const std::vector< Gate * > &gates={})
Result< u32 > reconstruct_top_module_pin_groups(Netlist *nl)
Result< u32 > simplify_lut_inits(Netlist *nl, const std::vector< Gate * > &gates={})
Result< u32 > remove_buffers(Netlist *nl, const std::vector< Gate * > &gates={})
Result< u32 > remove_unused_lut_inputs(Netlist *nl, const std::vector< Gate * > &gates={})
Result< u32 > remove_unconnected_looped(Netlist *nl)
Result< u32 > remove_unconnected_nets(Netlist *nl)
Result< u32 > reconstruct_indexed_ff_identifiers(Netlist *nl)
Result< u32 > remove_consecutive_inverters(Netlist *nl, const std::vector< Gate * > &gates={})
Result< std::vector< Module * > > create_multi_bit_gate_modules(Netlist *nl, const std::map< std::string, std::map< std::string, std::vector< std::string >>> &concatenated_pin_groups)
Result< u32 > unify_ff_outputs(Netlist *nl, const std::vector< Gate * > &ffs={}, GateType *inverter_type=nullptr)
Result< std::monostate > replace_subgraph_with_netlist(const std::vector< Gate * > &subgraph, const std::unordered_map< Net *, std::vector< Net * >> &global_io_mapping, const Netlist *src_nl, Netlist *dst_nl, const bool delete_subgraph_gates)
Result< std::unique_ptr< Netlist > > generate_resynth_netlist_for_boolean_functions(const std::unordered_map< std::string, BooleanFunction > &bfs, const std::filesystem::path &genlib_path, GateLibrary *target_gl, const bool optimize_area)
T replace(const T &str, const T &search, const T &replace)
Result< u64 > wrapped_stoull(const std::string &s, const u32 base=10)
Result< u32 > wrapped_stoul(const std::string &s, const u32 base=10)
std::string join(const std::string &joiner, const Iterator &begin, const Iterator &end, const Transform &transform)
Result< std::filesystem::path > get_unique_temp_directory(const std::string &prefix="", const u32 max_attempts=5)
Result< bool > compare_nets(const Netlist *netlist_a, const Netlist *netlist_b, const Net *net_a, const Net *net_b, const bool fail_on_unknown=true, const u32 solver_timeout=10)
Compare two nets from two different netlists.
std::vector< PinInformation > pins
std::set< GatePin * > inverters
This file contains functions to decompose or re-synthesize combinational parts of a gate-level netlis...