13 #include <unordered_set>
17 namespace netlist_utils
21 class ShortestPathInternal
25 const std::unordered_set<Gate*>& m_end_gates;
27 std::unordered_map<Gate*, Gate*> m_origin_map;
28 bool (ShortestPathInternal::*m_heureka) (
Gate*)
const;
29 std::unordered_set<Gate*> (ShortestPathInternal::*m_get_next_gates) (
Gate*)
const;
31 bool heureka_single(Gate* test_gate)
const
33 return (m_end_gate == test_gate);
36 bool heureka_multiple(Gate* test_gate)
const
38 return (m_end_gates.find(test_gate) != m_end_gates.end());
41 std::unordered_set<Gate*> get_next_gates_forward(Gate*
origin)
const
43 std::unordered_set<Gate*> retval;
44 for (
const Net* n :
origin->get_fan_out_nets())
46 for (
const Endpoint* ep : n->get_destinations())
48 retval.insert(ep->get_gate());
54 std::unordered_set<Gate*> get_next_gates_backward(Gate*
origin)
const
56 std::unordered_set<Gate*> retval;
57 for (
const Net* n :
origin->get_fan_in_nets())
59 for (
const Endpoint* ep : n->get_sources())
61 retval.insert(ep->get_gate());
68 ShortestPathInternal(Gate* start_gate,
const std::unordered_set<Gate*>& end_gates,
bool forward=
true)
69 : m_start_gate(start_gate), m_end_gate(nullptr), m_end_gates(end_gates), m_forward(
forward)
71 if (m_end_gates.size() == 1)
73 m_end_gate = *(m_end_gates.begin());
74 m_heureka = &ShortestPathInternal::heureka_single;
77 m_heureka = &ShortestPathInternal::heureka_multiple;
80 m_get_next_gates = &ShortestPathInternal::get_next_gates_forward;
82 m_get_next_gates = &ShortestPathInternal::get_next_gates_backward;
87 if (m_end_gates.empty())
89 log_warning(
"netlist_utils",
"Cannot find shortest path from start gate ID={}, no target given.", m_start_gate->get_id());
90 return std::vector<Gate*>();
92 if ((this->*m_heureka)(m_start_gate))
94 log_warning(
"netlist_utils",
"Cannot find shortest path since start gate ID={} and target are the same.", m_start_gate->get_id());
95 return std::vector<Gate*>();
98 std::vector<Gate*> v0;
99 std::vector<Gate*> v1;
100 v0.push_back(m_start_gate);
101 std::unordered_map<Gate*, Gate*> originMap;
107 for (Gate* g1 : (this->*m_get_next_gates)(g0))
109 if (originMap.find(g1) != originMap.end())
114 if ((this->*m_heureka)(g1))
117 std::vector<Gate*> retval;
119 while (g != m_start_gate)
122 auto it = originMap.find(g);
123 assert(it != originMap.end());
126 retval.push_back(m_start_gate);
128 std::reverse(retval.begin(),retval.end());
137 log_warning(
"netlist_utils",
"It looks like there is no path from start gate ID={} to selected {} target(s).", m_start_gate->get_id(), m_end_gates.size());
138 return std::vector<Gate*>();
154 return ERR(
"could not get subgraph function: net is a 'nullptr'");
163 return ERR(res.get_error());
169 if (
auto res = nl->
copy(); res.is_error())
171 log_error(
"netlist_utils",
"error encountered while copying netlist:\n{}", res.get_error().get());
182 std::map<u32, Gate*> matrix_id_to_gate;
183 std::map<Gate*, u32> gate_to_matrix_id;
184 std::vector<std::vector<int>> matrix;
186 u32 matrix_gates = 0;
193 gate_to_matrix_id[gate] = matrix_gates;
194 matrix_id_to_gate[matrix_gates] = gate;
198 for (
const auto& [
id, gate] : matrix_id_to_gate)
200 std::vector<int> line_of_matrix;
202 std::set<u32> gates_to_add;
205 gates_to_add.insert(gate_to_matrix_id[pred_gate]);
208 for (
u32 i = 0; i < matrix_gates; i++)
210 if (gates_to_add.find(i) != gates_to_add.end())
212 line_of_matrix.push_back(1);
216 line_of_matrix.push_back(0);
219 matrix.push_back(line_of_matrix);
222 return std::make_pair(matrix_id_to_gate, matrix);
233 log_error(
"netlist_utils",
"error encountered while copying subgraph netlist:\n{}", res.get_error().get());
238 std::vector<Gate*>
get_next_gates(
const Gate* gate,
bool get_successors,
int depth,
const std::function<
bool(
const Gate*)>& filter)
240 std::vector<Gate*> retval;
241 std::unordered_map<u32, std::vector<Gate*>> cache;
242 std::vector<const Gate*> v0;
244 std::unordered_set<const Gate*> gats_handled;
245 std::unordered_set<const Net*> nets_handled;
246 gats_handled.insert(gate);
248 for (
int round = 0; !depth || round < depth; round++)
250 std::vector<const Gate*> v1;
251 for (
const Gate* g0 : v0)
253 for (
const Net* n : get_successors ? g0->get_fan_out_nets() : g0->get_fan_in_nets())
255 if (nets_handled.find(n) != nets_handled.end())
259 nets_handled.insert(n);
261 for (
const Endpoint* ep : get_successors ? n->get_destinations() : n->get_sources())
263 Gate* g1 = ep->get_gate();
264 if (gats_handled.find(g1) != gats_handled.end())
268 gats_handled.insert(g1);
269 if (!filter || filter(g1))
272 retval.push_back(g1);
288 std::vector<Gate*> retval;
289 std::unordered_map<u32, std::vector<Gate*>> cache;
290 std::vector<const Gate*> v0;
291 std::unordered_set<const Gate*> gates_handled;
292 std::unordered_set<const Net*> nets_handled;
293 for (
const Endpoint* ep : (get_successors ?
net->get_destinations() :
net->get_sources()))
295 Gate* g = ep->get_gate();
296 if (!filter || filter(g))
299 gates_handled.insert(g);
300 nets_handled.insert(
net);
305 for (
int round = 1; depth == 0 || round < depth; round++)
307 std::vector<const Gate*> v1;
308 for (
const Gate* g0 : v0)
310 for (
const Net* n : get_successors ? g0->get_fan_out_nets() : g0->get_fan_in_nets())
312 if (nets_handled.find(n) != nets_handled.end())
316 nets_handled.insert(n);
318 for (
const Endpoint* ep : get_successors ? n->get_destinations() : n->get_sources())
320 Gate* g1 = ep->get_gate();
321 if (gates_handled.find(g1) != gates_handled.end())
325 gates_handled.insert(g1);
326 if (!filter || filter(g1))
329 retval.push_back(g1);
345 std::unordered_set<Gate*> end_gates;
350 ShortestPathInternal spi(start_gate, end_gates, forward_direction);
351 return spi.get_path();
356 std::unordered_set<Gate*> start_gates;
359 start_gates.insert(g);
362 int shortest_length = -1;
363 std::vector<std::vector<Gate*> > retval;
366 ShortestPathInternal spi_reverse(end_gate, start_gates,
false);
367 std::vector<Gate*> path_reverse = spi_reverse.get_path();
368 int len = path_reverse.size();
370 if (shortest_length < 0) shortest_length = len;
371 if (len > shortest_length)
continue;
372 if (len < shortest_length) shortest_length = len;
373 retval.push_back(path_reverse);
376 auto it = retval.begin();
377 while (it != retval.end())
379 if (it->size() > shortest_length)
380 it = retval.erase(it);
389 std::unordered_set<Gate*> end_gates_forward;
390 end_gates_forward.insert(end_gate);
391 ShortestPathInternal spi_forward(start_gate, end_gates_forward,
true);
392 std::vector<Gate*> path_forward = spi_forward.get_path();
393 if (!search_both_directions)
395 std::unordered_set<Gate*> start_gates_reverse;
396 start_gates_reverse.insert(start_gate);
397 ShortestPathInternal spi_reverse(end_gate, start_gates_reverse,
false);
398 std::vector<Gate*> path_reverse = spi_reverse.get_path();
399 return (path_reverse.size() < path_forward.size()) ? path_reverse : path_forward;
404 std::vector<Gate*> get_next_sequential_gates_internal(
const Net* start_net,
bool forward, std::unordered_set<u32>& seen, std::unordered_map<
u32, std::vector<Gate*>>& cache)
406 if (
auto it = cache.find(start_net->
get_id()); it != cache.end())
411 if (seen.find(start_net->
get_id()) != seen.end())
416 seen.insert(start_net->
get_id());
418 std::vector<Gate*> found_ffs;
422 auto next_gate = endpoint->get_gate();
426 found_ffs.push_back(next_gate);
430 for (
auto n : forward ? next_gate->get_fan_out_nets() : next_gate->get_fan_in_nets())
432 auto next_gates = get_next_sequential_gates_internal(n, forward, seen, cache);
433 found_ffs.insert(found_ffs.end(), next_gates.begin(), next_gates.end());
438 std::sort(found_ffs.begin(), found_ffs.end());
439 found_ffs.erase(std::unique(found_ffs.begin(), found_ffs.end()), found_ffs.end());
441 cache.emplace(start_net->
get_id(), found_ffs);
448 std::vector<Gate*> found_ffs;
452 found_ffs.insert(found_ffs.end(), suc.begin(), suc.end());
455 std::sort(found_ffs.begin(), found_ffs.end());
456 found_ffs.erase(std::unique(found_ffs.begin(), found_ffs.end()), found_ffs.end());
463 std::unordered_set<u32> seen;
464 return get_next_sequential_gates_internal(
net, get_successors, seen, cache);
469 std::unordered_map<u32, std::vector<Gate*>> cache;
475 std::unordered_map<u32, std::vector<Gate*>> cache;
482 get_path_internal(
const Net* start_net,
bool forward, std::set<GateTypeProperty> stop_types, std::unordered_set<u32>& seen, std::unordered_map<
u32, std::vector<Gate*>>& cache)
484 if (
auto it = cache.find(start_net->
get_id()); it != cache.end())
489 if (seen.find(start_net->
get_id()) != seen.end())
494 seen.insert(start_net->
get_id());
496 std::vector<Gate*> found_combinational;
500 auto next_gate = endpoint->get_gate();
505 if (stop_types.find(property) != stop_types.end())
513 found_combinational.push_back(next_gate);
515 for (
auto n : forward ? next_gate->get_fan_out_nets() : next_gate->get_fan_in_nets())
517 auto next_gates = get_path_internal(n, forward, stop_types, seen, cache);
518 found_combinational.insert(found_combinational.end(), next_gates.begin(), next_gates.end());
523 std::sort(found_combinational.begin(), found_combinational.end());
524 found_combinational.erase(std::unique(found_combinational.begin(), found_combinational.end()), found_combinational.end());
526 cache.emplace(start_net->
get_id(), found_combinational);
527 return found_combinational;
531 std::vector<Gate*>
get_path(
const Gate* gate,
bool get_successors, std::set<GateTypeProperty> stop_properties, std::unordered_map<
u32, std::vector<Gate*>>& cache)
533 std::vector<Gate*> found_combinational;
536 auto suc =
get_path(n, get_successors, stop_properties, cache);
537 found_combinational.insert(found_combinational.end(), suc.begin(), suc.end());
540 std::sort(found_combinational.begin(), found_combinational.end());
541 found_combinational.erase(std::unique(found_combinational.begin(), found_combinational.end()), found_combinational.end());
543 return found_combinational;
546 std::vector<Gate*>
get_path(
const Net*
net,
bool get_successors, std::set<GateTypeProperty> stop_properties, std::unordered_map<
u32, std::vector<Gate*>>& cache)
548 std::unordered_set<u32> seen;
549 return get_path_internal(
net, get_successors, stop_properties, seen, cache);
552 std::vector<Gate*>
get_path(
const Gate* gate,
bool get_successors, std::set<GateTypeProperty> stop_properties)
554 std::unordered_map<u32, std::vector<Gate*>> cache;
555 return get_path(gate, get_successors, stop_properties, cache);
558 std::vector<Gate*>
get_path(
const Net*
net,
bool get_successors, std::set<GateTypeProperty> stop_properties)
560 std::unordered_map<u32, std::vector<Gate*>> cache;
561 return get_path(
net, get_successors, stop_properties, cache);
566 std::vector<Net*> nets;
568 for (
const auto& pin :
pins)
572 log_warning(
"netlist_utils",
"'nullptr' given as pin.");
585 log_warning(
"netlist_utils",
"could not retrieve fan-in net for pin '{}' of gate '{}' with ID {}.", pin->get_name(), gate->
get_name(), gate->
get_id());
596 log_warning(
"netlist_utils",
"could not retrieve fan-out net for pin '{}' of gate '{}' with ID {}.", pin->get_name(), gate->
get_name(), gate->
get_id());
608 for (
const auto& gate : netlist->
get_gates())
619 if (fan_out.size() != 1)
626 if (functions.size() != 1)
632 Endpoint* out_endpoint = *(fan_out.begin());
646 auto sources = ep->get_net()->get_sources();
647 if (sources.size() != 1)
652 if (sources.front()->get_gate()->is_gnd_gate())
656 func = substitution.get();
659 else if (sources.front()->get_gate()->is_vcc_gate())
663 func = substitution.get();
673 if (std::find(in_pins.begin(), in_pins.end(), func_str) != in_pins.end())
678 for (
Endpoint* in_endpoint : fan_in)
680 Net* in_net = in_endpoint->get_net();
682 if (in_endpoint->get_pin()->get_name() == func_str)
687 Gate* dst_gate = dst->get_gate();
688 GatePin* dst_pin = dst->get_pin();
691 return ERR(
"could not completely remove buffers from netlist with ID " + std::to_string(netlist->
get_id()) +
": failed to remove destination from output net '"
692 + out_net->
get_name() +
"' with ID " + std::to_string(out_net->
get_id()) +
" of buffer gate '" + gate->
get_name() +
"' with ID "
693 + std::to_string(gate->
get_id()));
697 return ERR(
"could not completely remove buffers from netlist with ID " + std::to_string(netlist->
get_id()) +
": failed to add destination to input net '"
698 + in_net->
get_name() +
"' with ID " + std::to_string(in_net->
get_id()) +
" of buffer gate '" + gate->
get_name() +
"' with ID "
699 + std::to_string(gate->
get_id()));
708 return ERR(
"could not completely remove buffers from netlist with ID " + std::to_string(netlist->
get_id()) +
": failed to remove destination from input net '"
709 + in_net->
get_name() +
"' with ID " + std::to_string(in_net->
get_id()) +
" of buffer gate '" + gate->
get_name() +
"' with ID "
710 + std::to_string(gate->
get_id()));
720 else if (func_str ==
"0" || func_str ==
"1")
724 const std::vector<Gate*>& gnd_gates = netlist->
get_gnd_gates();
725 const std::vector<Gate*>& vcc_gates = netlist->
get_vcc_gates();
726 if (gnd_gates.empty() || vcc_gates.empty())
730 Net* gnd_net = gnd_gates.front()->get_fan_out_nets().front();
731 Net* vcc_net = vcc_gates.front()->get_fan_out_nets().front();
733 for (
Endpoint* in_endpoint : fan_in)
735 Net* in_net = in_endpoint->get_net();
740 return ERR(
"could not completely remove buffers from netlist with ID " + std::to_string(netlist->
get_id()) +
": failed to remove destination from input net '"
741 + in_net->
get_name() +
"' with ID " + std::to_string(in_net->
get_id()) +
" of buffer gate '" + gate->
get_name() +
"' with ID " + std::to_string(gate->
get_id()));
748 Gate* dst_gate = dst->get_gate();
749 GatePin* dst_pin = dst->get_pin();
752 return ERR(
"could not completely remove buffers from netlist with ID " + std::to_string(netlist->
get_id()) +
": failed to remove destination from output net '"
753 + out_net->
get_name() +
"' with ID " + std::to_string(out_net->
get_id()) +
" of buffer gate '" + gate->
get_name() +
"' with ID "
754 + std::to_string(gate->
get_id()));
758 return ERR(
"could not completely remove buffers from netlist with ID " + std::to_string(netlist->
get_id()) +
": failed to add destination to GND net '"
759 + gnd_net->
get_name() +
"' with ID " + std::to_string(gnd_net->
get_id()));
763 else if (func_str ==
"1")
767 Gate* dst_gate = dst->get_gate();
768 GatePin* dst_pin = dst->get_pin();
771 return ERR(
"could not completely remove buffers from netlist with ID " + std::to_string(netlist->
get_id()) +
": failed to remove destination from output net '"
772 + out_net->
get_name() +
"' with ID " + std::to_string(out_net->
get_id()) +
" of buffer gate '" + gate->
get_name() +
"' with ID "
773 + std::to_string(gate->
get_id()));
777 return ERR(
"could not completely remove buffers from netlist with ID " + std::to_string(netlist->
get_id()) +
": failed to add destination to VCC net '"
778 + gnd_net->
get_name() +
"' with ID " + std::to_string(gnd_net->
get_id()));
790 return OK(num_gates);
798 const std::vector<Gate*>& gnd_gates = netlist->
get_gnd_gates();
799 if (gnd_gates.empty())
801 return ERR(
"could not completely remove unused LUT endpoints from netlist with ID " + std::to_string(netlist->
get_id()) +
": no GND net available within netlist");
803 Net* gnd_net = gnd_gates.front()->get_fan_out_nets().front();
806 for (
const auto& gate : netlist->
get_gates([](
const Gate* g) { return g->get_type()->has_property(GateTypeProperty::c_lut); }))
812 if (functions.size() != 1)
817 auto active_pins = functions.begin()->second.get_variable_names();
820 if (fan_in.size() > active_pins.size())
822 for (
const auto& ep : fan_in)
824 if (std::find(active_pins.begin(), active_pins.end(), ep->get_pin()->get_name()) == active_pins.end())
828 if (!ep->get_net()->remove_destination(gate, pin))
830 return ERR(
"could not completely remove unused LUT endpoints from netlist with ID " + std::to_string(netlist->
get_id())
831 +
": failed to remove inactive endpoint from gate '" + gate->
get_name() +
"' with ID " + std::to_string(gate->
get_id()));
835 return ERR(
"could not completely remove unused LUT endpoints from netlist with ID " + std::to_string(netlist->
get_id()) +
": failed to connect inactive input of gate '"
836 + gate->
get_name() +
"' with ID " + std::to_string(gate->
get_id()) +
" to GND net");
851 threshold = gates.size();
855 std::map<Net*, u32> net_count;
856 for (
Gate* g : gates)
858 for (
Endpoint* pred : g->get_predecessors())
860 if (pred->get_gate()->is_gnd_gate() || pred->get_gate()->is_vcc_gate())
865 Net* pred_net = pred->get_net();
866 if (
const auto it = net_count.find(pred_net); it != net_count.end())
872 net_count[pred_net] = 1;
878 std::vector<Net*> common_inputs;
879 for (
const auto& [n, cnt] : net_count)
881 if (cnt >= threshold)
883 common_inputs.push_back(n);
887 return common_inputs;
898 return ERR(res.get_error());
const std::string & get_name() const
BooleanFunction simplify() const
static std::string to_string(Value value)
static BooleanFunction Const(const BooleanFunction::Value &value)
BooleanFunction substitute(const std::string &old_variable_name, const std::string &new_variable_name) const
GatePin * get_pin() const
Net * get_fan_in_net(const std::string &pin_name) const
const std::vector< Net * > & get_fan_in_nets() const
const std::vector< Endpoint * > & get_fan_out_endpoints() const
GateType * get_type() const
Net * get_fan_out_net(const std::string &pin_name) const
const std::string & get_name() const
const std::vector< Net * > & get_fan_out_nets() const
const std::vector< Endpoint * > & get_fan_in_endpoints() const
Netlist * get_netlist() const
std::unordered_map< std::string, BooleanFunction > get_boolean_functions(bool only_custom_functions=false) const
std::vector< std::string > get_input_pin_names() const
bool has_property(GateTypeProperty property) const
const std::vector< Gate * > & get_gates() const
Endpoint * add_destination(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)
std::vector< Endpoint * > get_sources(const std::function< bool(Endpoint *ep)> &filter=nullptr) const
const std::vector< Gate * > & get_gates() const
bool delete_net(Net *net)
const std::vector< Gate * > & get_gnd_gates() const
const std::vector< Gate * > & get_vcc_gates() const
bool delete_gate(Gate *gate)
Result< std::unique_ptr< Netlist > > copy() const
Result< Gate * > replace_gate(Gate *gate, GateType *target_type, const std::map< GatePin *, GatePin * > &pin_map)
Result< BooleanFunction > get_subgraph_function(const std::vector< const Gate * > &subgraph_gates, const Net *subgraph_output) const
Result< std::unique_ptr< Netlist > > copy_subgraph_netlist(const std::vector< const Gate * > &subgraph_gates, const bool all_global_io=false) const
#define log_error(channel,...)
#define log_warning(channel,...)
Result< u32 > remove_unused_lut_endpoints(Netlist *netlist)
std::vector< Gate * > get_path(const Gate *gate, bool get_successors, std::set< GateTypeProperty > stop_properties, std::unordered_map< u32, std::vector< Gate * >> &cache)
std::vector< Gate * > get_next_gates(const Gate *gate, bool get_successors, int depth=0, const std::function< bool(const Gate *)> &filter=nullptr)
Result< BooleanFunction > get_subgraph_function(const Net *net, const std::vector< const Gate * > &subgraph_gates, std::map< std::pair< u32, const GatePin * >, BooleanFunction > &cache)
Result< u32 > remove_buffers(Netlist *netlist, bool analyze_inputs=false)
std::unique_ptr< Netlist > copy_netlist(const Netlist *nl)
std::vector< Gate * > get_next_sequential_gates(const Gate *gate, bool get_successors, std::unordered_map< u32, std::vector< Gate * >> &cache)
std::vector< Gate * > get_shortest_path(Gate *start_gate, Gate *end_gate, bool search_both_directions=false)
Result< std::monostate > replace_gate(Gate *gate, GateType *target_type, std::map< GatePin *, GatePin * > pin_map)
std::vector< Net * > get_nets_at_pins(Gate *gate, std::vector< GatePin * > pins)
std::vector< Net * > get_common_inputs(const std::vector< Gate * > &gates, u32 threshold=0)
std::pair< std::map< u32, Gate * >, std::vector< std::vector< int > > > get_ff_dependency_matrix(const Netlist *nl)
std::unique_ptr< Netlist > get_partial_netlist(const Netlist *nl, const std::vector< const Gate * > &subgraph_gates)
std::vector< PinInformation > pins
This file contains various functions to create and load netlists.