HAL
netlist_utils.cpp
Go to the documentation of this file.
2 
8 #include "hal_core/netlist/net.h"
10 #include "hal_core/utilities/log.h"
11 
12 #include <deque>
13 #include <unordered_set>
14 
15 namespace hal
16 {
17  namespace netlist_utils
18  {
19  namespace
20  {
21  class ShortestPathInternal
22  {
23  Gate* m_start_gate;
24  Gate* m_end_gate;
25  const std::unordered_set<Gate*>& m_end_gates;
26  bool m_forward;
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;
30 
31  bool heureka_single(Gate* test_gate) const
32  {
33  return (m_end_gate == test_gate);
34  }
35 
36  bool heureka_multiple(Gate* test_gate) const
37  {
38  return (m_end_gates.find(test_gate) != m_end_gates.end());
39  }
40 
41  std::unordered_set<Gate*> get_next_gates_forward(Gate* origin) const
42  {
43  std::unordered_set<Gate*> retval;
44  for (const Net* n : origin->get_fan_out_nets())
45  {
46  for (const Endpoint* ep : n->get_destinations())
47  {
48  retval.insert(ep->get_gate());
49  }
50  }
51  return retval;
52  }
53 
54  std::unordered_set<Gate*> get_next_gates_backward(Gate* origin) const
55  {
56  std::unordered_set<Gate*> retval;
57  for (const Net* n : origin->get_fan_in_nets())
58  {
59  for (const Endpoint* ep : n->get_sources())
60  {
61  retval.insert(ep->get_gate());
62  }
63  }
64  return retval;
65  }
66 
67  public:
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)
70  {
71  if (m_end_gates.size() == 1)
72  {
73  m_end_gate = *(m_end_gates.begin());
74  m_heureka = &ShortestPathInternal::heureka_single;
75  }
76  else
77  m_heureka = &ShortestPathInternal::heureka_multiple;
78 
79  if (forward)
80  m_get_next_gates = &ShortestPathInternal::get_next_gates_forward;
81  else
82  m_get_next_gates = &ShortestPathInternal::get_next_gates_backward;
83  }
84 
85  std::vector<Gate*> get_path() const
86  {
87  if (m_end_gates.empty())
88  {
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*>();
91  }
92  if ((this->*m_heureka)(m_start_gate))
93  {
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*>();
96  }
97 
98  std::vector<Gate*> v0;
99  std::vector<Gate*> v1;
100  v0.push_back(m_start_gate);
101  std::unordered_map<Gate*, Gate*> originMap;
102 
103  while (!v0.empty())
104  {
105  for (Gate* g0 : v0)
106  {
107  for (Gate* g1 : (this->*m_get_next_gates)(g0))
108  {
109  if (originMap.find(g1) != originMap.end())
110  continue; // already routed to
111  v1.push_back(g1);
112  originMap[g1] = g0;
113 
114  if ((this->*m_heureka)(g1))
115  {
116  // heureka! Path found
117  std::vector<Gate*> retval;
118  Gate* g = g1;
119  while (g != m_start_gate)
120  {
121  retval.push_back(g);
122  auto it = originMap.find(g);
123  assert(it != originMap.end());
124  g = it->second;
125  }
126  retval.push_back(m_start_gate);
127  if (m_forward)
128  std::reverse(retval.begin(),retval.end());
129  return retval;
130  }
131  }
132  }
133  v0 = v1;
134  v1.clear();
135  }
136 
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*>();
139  }
140  };
141 
142  } // namespace
143 
144  Result<BooleanFunction> get_subgraph_function(const Net* net, const std::vector<const Gate*>& subgraph_gates, std::map<std::pair<u32, const GatePin*>, BooleanFunction>& cache)
145  {
146  if (net == nullptr)
147  {
148  return ERR("could not get subgraph function: net is a 'nullptr'");
149  }
150 
151  if (auto res = SubgraphNetlistDecorator(*net->get_netlist()).get_subgraph_function(subgraph_gates, net, cache); res.is_ok())
152  {
153  return res;
154  }
155  else
156  {
157  return ERR(res.get_error());
158  }
159  }
160 
161  Result<BooleanFunction> get_subgraph_function(const Net* net, const std::vector<const Gate*>& subgraph_gates)
162  {
163  std::map<std::pair<u32, const GatePin*>, BooleanFunction> cache;
164  if (auto res = get_subgraph_function(net, subgraph_gates, cache); res.is_error())
165  {
166  return ERR(res.get_error());
167  }
168  else
169  {
170  return res;
171  }
172  }
173 
174  std::unique_ptr<Netlist> copy_netlist(const Netlist* nl)
175  {
176  if (auto res = nl->copy(); res.is_error())
177  {
178  log_error("netlist_utils", "error encountered while copying netlist:\n{}", res.get_error().get());
179  return nullptr;
180  }
181  else
182  {
183  return res.get();
184  }
185  }
186 
187  std::pair<std::map<u32, Gate*>, std::vector<std::vector<int>>> get_ff_dependency_matrix(const Netlist* nl)
188  {
189  std::map<u32, Gate*> matrix_id_to_gate;
190  std::map<Gate*, u32> gate_to_matrix_id;
191  std::vector<std::vector<int>> matrix;
192 
193  u32 matrix_gates = 0;
194  for (const auto& gate : nl->get_gates())
195  {
196  if (!gate->get_type()->has_property(GateTypeProperty::ff))
197  {
198  continue;
199  }
200  gate_to_matrix_id[gate] = matrix_gates;
201  matrix_id_to_gate[matrix_gates] = gate;
202  matrix_gates++;
203  }
204 
205  for (const auto& [id, gate] : matrix_id_to_gate)
206  {
207  std::vector<int> line_of_matrix;
208 
209  std::set<u32> gates_to_add;
210  for (const auto& pred_gate : netlist_utils::get_next_sequential_gates(gate, false))
211  {
212  gates_to_add.insert(gate_to_matrix_id[pred_gate]);
213  }
214 
215  for (u32 i = 0; i < matrix_gates; i++)
216  {
217  if (gates_to_add.find(i) != gates_to_add.end())
218  {
219  line_of_matrix.push_back(1);
220  }
221  else
222  {
223  line_of_matrix.push_back(0);
224  }
225  }
226  matrix.push_back(line_of_matrix);
227  }
228 
229  return std::make_pair(matrix_id_to_gate, matrix);
230  }
231 
232  std::unique_ptr<Netlist> get_partial_netlist(const Netlist* nl, const std::vector<const Gate*>& subgraph_gates)
233  {
234  if (auto res = SubgraphNetlistDecorator(*nl).copy_subgraph_netlist(subgraph_gates); res.is_ok())
235  {
236  return res.get();
237  }
238  else
239  {
240  log_error("netlist_utils", "error encountered while copying subgraph netlist:\n{}", res.get_error().get());
241  return nullptr;
242  }
243  }
244 
245  std::vector<Gate*> get_next_gates(const Gate* gate, bool get_successors, int depth, const std::function<bool(const Gate*)>& filter)
246  {
247  std::vector<Gate*> retval;
248  std::unordered_map<u32, std::vector<Gate*>> cache;
249  std::vector<const Gate*> v0;
250  v0.push_back(gate);
251  std::unordered_set<const Gate*> gats_handled;
252  std::unordered_set<const Net*> nets_handled;
253  gats_handled.insert(gate);
254 
255  for (int round = 0; !depth || round < depth; round++)
256  {
257  std::vector<const Gate*> v1;
258  for (const Gate* g0 : v0)
259  {
260  for (const Net* n : get_successors ? g0->get_fan_out_nets() : g0->get_fan_in_nets())
261  {
262  if (nets_handled.find(n) != nets_handled.end())
263  {
264  continue;
265  }
266  nets_handled.insert(n);
267 
268  for (const Endpoint* ep : get_successors ? n->get_destinations() : n->get_sources())
269  {
270  Gate* g1 = ep->get_gate();
271  if (gats_handled.find(g1) != gats_handled.end())
272  {
273  continue; // already handled
274  }
275  gats_handled.insert(g1);
276  if (!filter || filter(g1))
277  {
278  v1.push_back(g1);
279  retval.push_back(g1);
280  }
281  }
282  }
283  }
284  if (v1.empty())
285  {
286  break;
287  }
288  v0 = v1;
289  }
290  return retval;
291  }
292 
293  std::vector<Gate*> get_next_gates(const Net* net, bool get_successors, int depth, const std::function<bool(const Gate*)>& filter)
294  {
295  std::vector<Gate*> retval;
296  std::unordered_map<u32, std::vector<Gate*>> cache;
297  std::vector<const Gate*> v0;
298  std::unordered_set<const Gate*> gates_handled;
299  std::unordered_set<const Net*> nets_handled;
300  for (const Endpoint* ep : (get_successors ? net->get_destinations() : net->get_sources()))
301  {
302  Gate* g = ep->get_gate();
303  if (!filter || filter(g))
304  {
305  v0.push_back(g);
306  gates_handled.insert(g);
307  nets_handled.insert(net);
308  retval.push_back(g);
309  }
310  }
311 
312  for (int round = 1; depth == 0 || round < depth; round++)
313  {
314  std::vector<const Gate*> v1;
315  for (const Gate* g0 : v0)
316  {
317  for (const Net* n : get_successors ? g0->get_fan_out_nets() : g0->get_fan_in_nets())
318  {
319  if (nets_handled.find(n) != nets_handled.end())
320  {
321  continue;
322  }
323  nets_handled.insert(n);
324 
325  for (const Endpoint* ep : get_successors ? n->get_destinations() : n->get_sources())
326  {
327  Gate* g1 = ep->get_gate();
328  if (gates_handled.find(g1) != gates_handled.end())
329  {
330  continue; // already handled
331  }
332  gates_handled.insert(g1);
333  if (!filter || filter(g1))
334  {
335  v1.push_back(g1);
336  retval.push_back(g1);
337  }
338  }
339  }
340  }
341  if (v1.empty())
342  {
343  break;
344  }
345  v0 = v1;
346  }
347  return retval;
348  }
349 
350  std::vector<Gate*> get_shortest_path(Gate* start_gate, Module* end_module, bool forward_direction)
351  {
352  std::unordered_set<Gate*> end_gates;
353  for (Gate* g : end_module->get_gates(nullptr, true))
354  {
355  end_gates.insert(g);
356  }
357  ShortestPathInternal spi(start_gate, end_gates, forward_direction);
358  return spi.get_path();
359  }
360 
361  std::vector<Gate*> get_shortest_path(Gate* start_gate, Gate* end_gate, bool search_both_directions)
362  {
363  std::unordered_set<Gate*> end_gates_forward;
364  end_gates_forward.insert(end_gate);
365  ShortestPathInternal spi_forward(start_gate, end_gates_forward, true);
366  std::vector<Gate*> path_forward = spi_forward.get_path();
367  if (!search_both_directions)
368  return path_forward;
369  std::unordered_set<Gate*> start_gates_reverse;
370  start_gates_reverse.insert(start_gate);
371  ShortestPathInternal spi_reverse(end_gate, start_gates_reverse, false);
372  std::vector<Gate*> path_reverse = spi_reverse.get_path();
373  return (path_reverse.size() < path_forward.size()) ? path_reverse : path_forward;
374  }
375 
376  namespace
377  {
378  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)
379  {
380  if (auto it = cache.find(start_net->get_id()); it != cache.end())
381  {
382  return it->second;
383  }
384 
385  if (seen.find(start_net->get_id()) != seen.end())
386  {
387  return {};
388  }
389 
390  seen.insert(start_net->get_id());
391 
392  std::vector<Gate*> found_ffs;
393 
394  for (auto endpoint : forward ? start_net->get_destinations() : start_net->get_sources())
395  {
396  auto next_gate = endpoint->get_gate();
397 
398  if (next_gate->get_type()->has_property(GateTypeProperty::ff))
399  {
400  found_ffs.push_back(next_gate);
401  }
402  else
403  {
404  for (auto n : forward ? next_gate->get_fan_out_nets() : next_gate->get_fan_in_nets())
405  {
406  auto next_gates = get_next_sequential_gates_internal(n, forward, seen, cache);
407  found_ffs.insert(found_ffs.end(), next_gates.begin(), next_gates.end());
408  }
409  }
410  }
411 
412  std::sort(found_ffs.begin(), found_ffs.end());
413  found_ffs.erase(std::unique(found_ffs.begin(), found_ffs.end()), found_ffs.end());
414 
415  cache.emplace(start_net->get_id(), found_ffs);
416  return found_ffs;
417  }
418  } // namespace
419 
420  std::vector<Gate*> get_next_sequential_gates(const Gate* gate, bool get_successors, std::unordered_map<u32, std::vector<Gate*>>& cache)
421  {
422  std::vector<Gate*> found_ffs;
423  for (const auto& n : get_successors ? gate->get_fan_out_nets() : gate->get_fan_in_nets())
424  {
425  auto suc = get_next_sequential_gates(n, get_successors, cache);
426  found_ffs.insert(found_ffs.end(), suc.begin(), suc.end());
427  }
428 
429  std::sort(found_ffs.begin(), found_ffs.end());
430  found_ffs.erase(std::unique(found_ffs.begin(), found_ffs.end()), found_ffs.end());
431 
432  return found_ffs;
433  }
434 
435  std::vector<Gate*> get_next_sequential_gates(const Net* net, bool get_successors, std::unordered_map<u32, std::vector<Gate*>>& cache)
436  {
437  std::unordered_set<u32> seen;
438  return get_next_sequential_gates_internal(net, get_successors, seen, cache);
439  }
440 
441  std::vector<Gate*> get_next_sequential_gates(const Gate* gate, bool get_successors)
442  {
443  std::unordered_map<u32, std::vector<Gate*>> cache;
444  return get_next_sequential_gates(gate, get_successors, cache);
445  }
446 
447  std::vector<Gate*> get_next_sequential_gates(const Net* net, bool get_successors)
448  {
449  std::unordered_map<u32, std::vector<Gate*>> cache;
450  return get_next_sequential_gates(net, get_successors, cache);
451  }
452 
453  namespace
454  {
455  std::vector<Gate*>
456  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)
457  {
458  if (auto it = cache.find(start_net->get_id()); it != cache.end())
459  {
460  return it->second;
461  }
462 
463  if (seen.find(start_net->get_id()) != seen.end())
464  {
465  return {};
466  }
467 
468  seen.insert(start_net->get_id());
469 
470  std::vector<Gate*> found_combinational;
471 
472  for (auto endpoint : forward ? start_net->get_destinations() : start_net->get_sources())
473  {
474  auto next_gate = endpoint->get_gate();
475 
476  bool stop = false;
477  for (GateTypeProperty property : next_gate->get_type()->get_properties())
478  {
479  if (stop_types.find(property) != stop_types.end())
480  {
481  stop = true;
482  }
483  }
484 
485  if (stop == false)
486  {
487  found_combinational.push_back(next_gate);
488 
489  for (auto n : forward ? next_gate->get_fan_out_nets() : next_gate->get_fan_in_nets())
490  {
491  auto next_gates = get_path_internal(n, forward, stop_types, seen, cache);
492  found_combinational.insert(found_combinational.end(), next_gates.begin(), next_gates.end());
493  }
494  }
495  }
496 
497  std::sort(found_combinational.begin(), found_combinational.end());
498  found_combinational.erase(std::unique(found_combinational.begin(), found_combinational.end()), found_combinational.end());
499 
500  cache.emplace(start_net->get_id(), found_combinational);
501  return found_combinational;
502  }
503  } // namespace
504 
505  std::vector<Gate*> get_path(const Gate* gate, bool get_successors, std::set<GateTypeProperty> stop_properties, std::unordered_map<u32, std::vector<Gate*>>& cache)
506  {
507  std::vector<Gate*> found_combinational;
508  for (const auto& n : get_successors ? gate->get_fan_out_nets() : gate->get_fan_in_nets())
509  {
510  auto suc = get_path(n, get_successors, stop_properties, cache);
511  found_combinational.insert(found_combinational.end(), suc.begin(), suc.end());
512  }
513 
514  std::sort(found_combinational.begin(), found_combinational.end());
515  found_combinational.erase(std::unique(found_combinational.begin(), found_combinational.end()), found_combinational.end());
516 
517  return found_combinational;
518  }
519 
520  std::vector<Gate*> get_path(const Net* net, bool get_successors, std::set<GateTypeProperty> stop_properties, std::unordered_map<u32, std::vector<Gate*>>& cache)
521  {
522  std::unordered_set<u32> seen;
523  return get_path_internal(net, get_successors, stop_properties, seen, cache);
524  }
525 
526  std::vector<Gate*> get_path(const Gate* gate, bool get_successors, std::set<GateTypeProperty> stop_properties)
527  {
528  std::unordered_map<u32, std::vector<Gate*>> cache;
529  return get_path(gate, get_successors, stop_properties, cache);
530  }
531 
532  std::vector<Gate*> get_path(const Net* net, bool get_successors, std::set<GateTypeProperty> stop_properties)
533  {
534  std::unordered_map<u32, std::vector<Gate*>> cache;
535  return get_path(net, get_successors, stop_properties, cache);
536  }
537 
538  std::vector<Net*> get_nets_at_pins(Gate* gate, std::vector<GatePin*> pins)
539  {
540  std::vector<Net*> nets;
541 
542  for (const auto& pin : pins)
543  {
544  if (pin == nullptr)
545  {
546  log_warning("netlist_utils", "'nullptr' given as pin.");
547  continue;
548  }
549 
550  PinDirection direction = pin->get_direction();
552  {
553  if (auto net = gate->get_fan_in_net(pin); net != nullptr)
554  {
555  nets.push_back(net);
556  }
557  else
558  {
559  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());
560  }
561  }
562  else if (direction == PinDirection::output)
563  {
564  if (auto net = gate->get_fan_out_net(pin); net != nullptr)
565  {
566  nets.push_back(net);
567  }
568  else
569  {
570  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());
571  }
572  }
573  }
574 
575  return nets;
576  }
577 
578  Result<u32> remove_buffers(Netlist* netlist, bool analyze_inputs)
579  {
580  u32 num_gates = 0;
581 
582  for (const auto& gate : netlist->get_gates())
583  {
584  std::vector<Endpoint*> fan_out = gate->get_fan_out_endpoints();
585 
586  GateType* gt = gate->get_type();
588  {
589  // continue if of invalid base type
590  continue;
591  }
592 
593  if (fan_out.size() != 1)
594  {
595  // continue if more than one fan-out net
596  continue;
597  }
598 
599  std::unordered_map<std::string, BooleanFunction> functions = gate->get_boolean_functions();
600  if (functions.size() != 1)
601  {
602  // continue if more than one Boolean function (tri-state?)
603  continue;
604  }
605 
606  Endpoint* out_endpoint = *(fan_out.begin());
607  if (out_endpoint->get_pin()->get_name() != (functions.begin())->first)
608  {
609  // continue if Boolean function name does not match output pin
610  continue;
611  }
612 
613  std::vector<Endpoint*> fan_in = gate->get_fan_in_endpoints();
614  BooleanFunction func = functions.begin()->second;
615 
616  if (analyze_inputs)
617  {
618  for (Endpoint* ep : fan_in)
619  {
620  auto sources = ep->get_net()->get_sources();
621  if (sources.size() != 1)
622  {
623  break;
624  }
625 
626  if (sources.front()->get_gate()->is_gnd_gate())
627  {
628  if (auto substitution = func.substitute(ep->get_pin()->get_name(), BooleanFunction::Const(0, 1)); substitution.is_ok())
629  {
630  func = substitution.get();
631  }
632  }
633  else if (sources.front()->get_gate()->is_vcc_gate())
634  {
635  if (auto substitution = func.substitute(ep->get_pin()->get_name(), BooleanFunction::Const(1, 1)); substitution.is_ok())
636  {
637  func = substitution.get();
638  }
639  }
640  }
641 
642  func = func.simplify();
643  }
644 
645  std::string func_str = func.to_string();
646  std::vector<std::string> in_pins = gt->get_input_pin_names();
647  if (std::find(in_pins.begin(), in_pins.end(), func_str) != in_pins.end())
648  {
649  Net* out_net = out_endpoint->get_net();
650 
651  // check all input endpoints and ...
652  for (Endpoint* in_endpoint : fan_in)
653  {
654  Net* in_net = in_endpoint->get_net();
655 
656  if (in_endpoint->get_pin()->get_name() == func_str)
657  {
658  // reconnect outputs if the input is passed through the buffer
659  for (Endpoint* dst : out_net->get_destinations())
660  {
661  Gate* dst_gate = dst->get_gate();
662  GatePin* dst_pin = dst->get_pin();
663  if (!out_net->remove_destination(dst))
664  {
665  return ERR("could not completely remove buffers from netlist with ID " + std::to_string(netlist->get_id()) + ": failed to remove destination from output net '"
666  + out_net->get_name() + "' with ID " + std::to_string(out_net->get_id()) + " of buffer gate '" + gate->get_name() + "' with ID "
667  + std::to_string(gate->get_id()));
668  }
669  if (!in_net->add_destination(dst_gate, dst_pin))
670  {
671  return ERR("could not completely remove buffers from netlist with ID " + std::to_string(netlist->get_id()) + ": failed to add destination to input net '"
672  + in_net->get_name() + "' with ID " + std::to_string(in_net->get_id()) + " of buffer gate '" + gate->get_name() + "' with ID "
673  + std::to_string(gate->get_id()));
674  }
675  }
676  }
677  else
678  {
679  // remove the input endpoint otherwise
680  if (!in_net->remove_destination(gate, in_endpoint->get_pin()))
681  {
682  return ERR("could not completely remove buffers from netlist with ID " + std::to_string(netlist->get_id()) + ": failed to remove destination from input net '"
683  + in_net->get_name() + "' with ID " + std::to_string(in_net->get_id()) + " of buffer gate '" + gate->get_name() + "' with ID "
684  + std::to_string(gate->get_id()));
685  }
686  }
687  }
688 
689  // delete output net and buffer gate
690  netlist->delete_net(out_net);
691  netlist->delete_gate(gate);
692  num_gates++;
693  }
694  else if (func_str == "0" || func_str == "1")
695  {
696  Net* out_net = out_endpoint->get_net();
697 
698  const std::vector<Gate*>& gnd_gates = netlist->get_gnd_gates();
699  const std::vector<Gate*>& vcc_gates = netlist->get_vcc_gates();
700  if (gnd_gates.empty() || vcc_gates.empty())
701  {
702  continue;
703  }
704  Net* gnd_net = gnd_gates.front()->get_fan_out_nets().front();
705  Net* vcc_net = vcc_gates.front()->get_fan_out_nets().front();
706 
707  for (Endpoint* in_endpoint : fan_in)
708  {
709  Net* in_net = in_endpoint->get_net();
710 
711  // remove the input endpoint otherwise
712  if (!in_net->remove_destination(gate, in_endpoint->get_pin()))
713  {
714  return ERR("could not completely remove buffers from netlist with ID " + std::to_string(netlist->get_id()) + ": failed to remove destination from input net '"
715  + 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()));
716  }
717  }
718  if (func_str == "0")
719  {
720  for (Endpoint* dst : out_net->get_destinations())
721  {
722  Gate* dst_gate = dst->get_gate();
723  GatePin* dst_pin = dst->get_pin();
724  if (!out_net->remove_destination(dst))
725  {
726  return ERR("could not completely remove buffers from netlist with ID " + std::to_string(netlist->get_id()) + ": failed to remove destination from output net '"
727  + out_net->get_name() + "' with ID " + std::to_string(out_net->get_id()) + " of buffer gate '" + gate->get_name() + "' with ID "
728  + std::to_string(gate->get_id()));
729  }
730  if (!gnd_net->add_destination(dst_gate, dst_pin))
731  {
732  return ERR("could not completely remove buffers from netlist with ID " + std::to_string(netlist->get_id()) + ": failed to add destination to GND net '"
733  + gnd_net->get_name() + "' with ID " + std::to_string(gnd_net->get_id()));
734  }
735  }
736  }
737  else if (func_str == "1")
738  {
739  for (Endpoint* dst : out_net->get_destinations())
740  {
741  Gate* dst_gate = dst->get_gate();
742  GatePin* dst_pin = dst->get_pin();
743  if (!out_net->remove_destination(dst))
744  {
745  return ERR("could not completely remove buffers from netlist with ID " + std::to_string(netlist->get_id()) + ": failed to remove destination from output net '"
746  + out_net->get_name() + "' with ID " + std::to_string(out_net->get_id()) + " of buffer gate '" + gate->get_name() + "' with ID "
747  + std::to_string(gate->get_id()));
748  }
749  if (!vcc_net->add_destination(dst_gate, dst_pin))
750  {
751  return ERR("could not completely remove buffers from netlist with ID " + std::to_string(netlist->get_id()) + ": failed to add destination to VCC net '"
752  + gnd_net->get_name() + "' with ID " + std::to_string(gnd_net->get_id()));
753  }
754  }
755  }
756 
757  // delete output net and buffer gate
758  netlist->delete_net(out_net);
759  netlist->delete_gate(gate);
760  num_gates++;
761  }
762  }
763 
764  return OK(num_gates);
765  }
766 
768  {
769  u32 num_eps = 0;
770 
771  // net connected to GND
772  const std::vector<Gate*>& gnd_gates = netlist->get_gnd_gates();
773  if (gnd_gates.empty())
774  {
775  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");
776  }
777  Net* gnd_net = gnd_gates.front()->get_fan_out_nets().front();
778 
779  // iterate all LUT gates
780  for (const auto& gate : netlist->get_gates([](const Gate* g) { return g->get_type()->has_property(GateTypeProperty::c_lut); }))
781  {
782  std::vector<Endpoint*> fan_in = gate->get_fan_in_endpoints();
783  std::unordered_map<std::string, BooleanFunction> functions = gate->get_boolean_functions();
784 
785  // skip if more than one function
786  if (functions.size() != 1)
787  {
788  continue;
789  }
790 
791  auto active_pins = functions.begin()->second.get_variable_names();
792 
793  // if there are more fan-in nets than there are active pins, we need to get rid of some nets
794  if (fan_in.size() > active_pins.size())
795  {
796  for (const auto& ep : fan_in)
797  {
798  if (std::find(active_pins.begin(), active_pins.end(), ep->get_pin()->get_name()) == active_pins.end())
799  {
800  num_eps++;
801  GatePin* pin = ep->get_pin();
802  if (!ep->get_net()->remove_destination(gate, pin))
803  {
804  return ERR("could not completely remove unused LUT endpoints from netlist with ID " + std::to_string(netlist->get_id())
805  + ": failed to remove inactive endpoint from gate '" + gate->get_name() + "' with ID " + std::to_string(gate->get_id()));
806  }
807  if (!gnd_net->add_destination(gate, pin))
808  {
809  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 '"
810  + gate->get_name() + "' with ID " + std::to_string(gate->get_id()) + " to GND net");
811  }
812  }
813  }
814  }
815  }
816 
817  return OK(num_eps);
818  }
819 
820  std::vector<Net*> get_common_inputs(const std::vector<Gate*>& gates, u32 threshold)
821  {
822  // if threshold = 0, a net is only considered to be common if it is an input to all gates
823  if (threshold == 0)
824  {
825  threshold = gates.size();
826  }
827 
828  // count input net occurences
829  std::map<Net*, u32> net_count;
830  for (Gate* g : gates)
831  {
832  for (Endpoint* pred : g->get_predecessors())
833  {
834  if (pred->get_gate()->is_gnd_gate() || pred->get_gate()->is_vcc_gate())
835  {
836  continue;
837  }
838 
839  Net* pred_net = pred->get_net();
840  if (const auto it = net_count.find(pred_net); it != net_count.end())
841  {
842  it->second++;
843  }
844  else
845  {
846  net_count[pred_net] = 1;
847  }
848  }
849  }
850 
851  // consider every net that is input to at least half the gates to be a common input
852  std::vector<Net*> common_inputs;
853  for (const auto& [n, cnt] : net_count)
854  {
855  if (cnt >= threshold)
856  {
857  common_inputs.push_back(n);
858  }
859  }
860 
861  return common_inputs;
862  }
863 
864  Result<std::monostate> replace_gate(Gate* gate, GateType* target_type, std::map<GatePin*, GatePin*> pin_map)
865  {
866  if (auto res = NetlistModificationDecorator(*(gate->get_netlist())).replace_gate(gate, target_type, pin_map); res.is_ok())
867  {
868  return OK({});
869  }
870  else
871  {
872  return ERR(res.get_error());
873  }
874  }
875 
877  get_gate_chain(Gate* start_gate, const std::vector<const GatePin*>& input_pins, const std::vector<const GatePin*>& output_pins, const std::function<bool(const Gate*)>& filter)
878  {
879  if (start_gate == nullptr)
880  {
881  return ERR("could not detect gate chain at start gate: start gate is a 'nullptr'");
882  }
883 
884  // check filter on start gate
885  if (filter && !filter(start_gate))
886  {
887  return ERR("could not detect gate chain at start gate '" + start_gate->get_name() + "' with ID " + std::to_string(start_gate->get_id())
888  + ": filter evaluates to 'false' for start gate");
889  }
890 
891  std::deque<Gate*> gate_chain = {start_gate};
892  std::unordered_set<Gate*> visited_gates = {start_gate};
893  const GateType* target_type = start_gate->get_type();
894  bool found_next_gate;
895 
896  // move forward
897  const Gate* current_gate = start_gate;
898  do
899  {
900  found_next_gate = false;
901 
902  // check all eligible successors of current gate
903  std::vector<Endpoint*> successors = current_gate->get_successors([input_pins, output_pins, target_type, filter](const GatePin* ep_pin, Endpoint* ep) {
904  if (ep->get_gate()->get_type() == target_type)
905  {
906  if (output_pins.empty() || std::find(output_pins.begin(), output_pins.end(), ep_pin) != output_pins.end())
907  {
908  if (input_pins.empty() || std::find(input_pins.begin(), input_pins.end(), ep->get_pin()) != input_pins.end())
909  {
910  if (!filter || filter(ep->get_gate()))
911  {
912  return true;
913  }
914  }
915  }
916  }
917  return false;
918  });
919 
920  if (successors.size() > 1)
921  {
922  log_debug("netlist_utils",
923  "detected more than one valid successor gate for gate '{}' with ID {} in netlist with ID {}.",
924  current_gate->get_name(),
925  current_gate->get_id(),
926  current_gate->get_netlist()->get_id());
927  break;
928  }
929  else if (!successors.empty())
930  {
931  Gate* suc_gate = successors.at(0)->get_gate();
932 
933  if (visited_gates.find(suc_gate) != visited_gates.end())
934  {
935  log_debug("netlist_utils", "detected a loop at gate with ID {}.", suc_gate->get_id());
936  break;
937  }
938 
939  gate_chain.push_back(suc_gate);
940  visited_gates.insert(suc_gate);
941  current_gate = suc_gate;
942  found_next_gate = true;
943  }
944  } while (found_next_gate);
945 
946  // move backwards
947  current_gate = start_gate;
948  do
949  {
950  found_next_gate = false;
951 
952  // check all eligable predecessors of current gate
953  std::vector<Endpoint*> predecessors = current_gate->get_predecessors([input_pins, output_pins, target_type, filter](const GatePin* ep_pin, Endpoint* ep) {
954  if (ep->get_gate()->get_type() == target_type)
955  {
956  if (input_pins.empty() || std::find(input_pins.begin(), input_pins.end(), ep_pin) != input_pins.end())
957  {
958  if (output_pins.empty() || std::find(output_pins.begin(), output_pins.end(), ep->get_pin()) != output_pins.end())
959  {
960  if (!filter || filter(ep->get_gate()))
961  {
962  return true;
963  }
964  }
965  }
966  }
967  return false;
968  });
969 
970  if (predecessors.size() > 1)
971  {
972  log_debug("netlist_utils",
973  "detected more than one valid predecessor gate for gate '{}' with ID {} in netlist with ID {}.",
974  current_gate->get_name(),
975  current_gate->get_id(),
976  current_gate->get_netlist()->get_id());
977  break;
978  }
979  else if (!predecessors.empty())
980  {
981  Gate* pred_gate = predecessors.at(0)->get_gate();
982 
983  if (visited_gates.find(pred_gate) != visited_gates.end())
984  {
985  log_debug("netlist_utils", "detected a loop at gate with ID {}.", pred_gate->get_id());
986  break;
987  }
988 
989  gate_chain.push_front(pred_gate);
990  visited_gates.insert(pred_gate);
991  current_gate = pred_gate;
992  found_next_gate = true;
993  log_debug("netlist_utils", "found predecessor gate with ID {}.", pred_gate->get_id());
994  }
995  } while (found_next_gate);
996 
997  return OK(std::vector<Gate*>(gate_chain.begin(), gate_chain.end()));
998  }
999 
1001  const std::vector<GateType*>& chain_types,
1002  const std::map<GateType*, std::vector<const GatePin*>>& input_pins,
1003  const std::map<GateType*, std::vector<const GatePin*>>& output_pins,
1004  const std::function<bool(const Gate*)>& filter)
1005  {
1006  if (start_gate == nullptr)
1007  {
1008  return ERR("could not detect gate chain at start gate: start gate is a 'nullptr'");
1009  }
1010  if (chain_types.size() < 2)
1011  {
1012  return ERR("could not detect gate chain at start gate: 'chain_types' comprises less than two target gate types");
1013  }
1014  if (start_gate->get_type() != chain_types.at(0))
1015  {
1016  return ERR("could not detect gate chain at start gate '" + start_gate->get_name() + "' with ID " + std::to_string(start_gate->get_id()) + ": start gate is not of type '"
1017  + chain_types.front()->get_name() + "'");
1018  }
1019  if (filter && !filter(start_gate))
1020  {
1021  return ERR("could not detect gate chain at start gate '" + start_gate->get_name() + "' with ID " + std::to_string(start_gate->get_id())
1022  + ": filter evaluates to 'false' for start gate");
1023  }
1024 
1025  std::deque<Gate*> gate_chain = {start_gate};
1026  std::unordered_set<Gate*> visited_gates;
1027 
1028  u32 last_index = 0;
1029  u32 current_index = (last_index + 1) % chain_types.size();
1030 
1031  // move forward
1032  bool found_next_gate;
1033  const Gate* current_gate = start_gate;
1034  do
1035  {
1036  found_next_gate = false;
1037 
1038  // check all successors of current gate
1039  GateType* target_type = chain_types.at(current_index);
1040  const std::vector<const GatePin*>& inputs = input_pins.at(target_type);
1041  const std::vector<const GatePin*>& outputs = output_pins.at(chain_types.at(last_index));
1042  std::vector<Endpoint*> successors = current_gate->get_successors([target_type, inputs, outputs, filter](const GatePin* ep_pin, Endpoint* ep) {
1043  if (ep->get_gate()->get_type() == target_type)
1044  {
1045  if (outputs.empty() || std::find(outputs.begin(), outputs.end(), ep_pin) != outputs.end())
1046  {
1047  if (inputs.empty() || std::find(inputs.begin(), inputs.end(), ep->get_pin()) != inputs.end())
1048  {
1049  if (!filter || filter(ep->get_gate()))
1050  {
1051  return true;
1052  }
1053  }
1054  }
1055  }
1056  return false;
1057  });
1058 
1059  if (successors.size() > 1)
1060  {
1061  log_debug("netlist_utils",
1062  "detected more than one valid successor gate for gate '{}' with ID {} in netlist with ID {}.",
1063  current_gate->get_name(),
1064  current_gate->get_id(),
1065  current_gate->get_netlist()->get_id());
1066  break;
1067  }
1068  else if (!successors.empty())
1069  {
1070  Gate* suc_gate = successors.at(0)->get_gate();
1071 
1072  if (visited_gates.find(suc_gate) != visited_gates.end())
1073  {
1074  log_debug("netlist_utils", "detected a loop at gate with ID {}.", suc_gate->get_id());
1075  break;
1076  }
1077 
1078  gate_chain.push_back(suc_gate);
1079  visited_gates.insert(suc_gate);
1080  current_gate = suc_gate;
1081  last_index = current_index;
1082  current_index = (current_index + 1) % chain_types.size();
1083  found_next_gate = true;
1084  }
1085  } while (found_next_gate);
1086 
1087  // remove partial sequences at the end of the chain
1088  while (current_index != 0)
1089  {
1090  gate_chain.pop_back();
1091  current_index--;
1092  }
1093 
1094  current_gate = start_gate;
1095  last_index = 0;
1096  current_index = chain_types.size() - 1;
1097 
1098  // move backwards
1099  do
1100  {
1101  found_next_gate = false;
1102 
1103  // check all predecessors of current gate
1104  GateType* target_type = chain_types.at(current_index);
1105  const std::vector<const GatePin*>& inputs = input_pins.at(chain_types.at(last_index));
1106  const std::vector<const GatePin*>& outputs = output_pins.at(target_type);
1107  std::vector<Endpoint*> predecessors = current_gate->get_predecessors([target_type, inputs, outputs, filter](const GatePin* ep_pin, Endpoint* ep) {
1108  if (ep->get_gate()->get_type() == target_type)
1109  {
1110  if (inputs.empty() || std::find(inputs.begin(), inputs.end(), ep_pin) != inputs.end())
1111  {
1112  if (outputs.empty() || std::find(outputs.begin(), outputs.end(), ep->get_pin()) != outputs.end())
1113  {
1114  if (!filter || filter(ep->get_gate()))
1115  {
1116  return true;
1117  }
1118  }
1119  }
1120  }
1121  return false;
1122  });
1123 
1124  if (predecessors.size() > 1)
1125  {
1126  log_debug("netlist_utils",
1127  "detected more than one valid predecessor gate for gate '{}' with ID {} in netlist with ID {}.",
1128  current_gate->get_name(),
1129  current_gate->get_id(),
1130  current_gate->get_netlist()->get_id());
1131  break;
1132  }
1133  else if (!predecessors.empty())
1134  {
1135  Gate* pred_gate = predecessors.at(0)->get_gate();
1136 
1137  if (visited_gates.find(pred_gate) != visited_gates.end())
1138  {
1139  log_debug("netlist_utils", "detected a loop at gate with ID {}.", pred_gate->get_id());
1140  break;
1141  }
1142 
1143  gate_chain.push_front(pred_gate);
1144  visited_gates.insert(pred_gate);
1145  current_gate = pred_gate;
1146  last_index = current_index;
1147  current_index = (current_index == 0) ? chain_types.size() - 1 : current_index - 1;
1148  found_next_gate = true;
1149  }
1150  } while (found_next_gate);
1151 
1152  // remove partial sequences at the beginning of the chain
1153  while (last_index != 0)
1154  {
1155  gate_chain.pop_front();
1156  last_index--;
1157  }
1158 
1159  return OK(std::vector<Gate*>(gate_chain.begin(), gate_chain.end()));
1160  }
1161  } // namespace netlist_utils
1162 } // namespace hal
const std::string & get_name() const
Definition: base_pin.h:108
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
Net * get_net() const
Definition: endpoint.cpp:33
GatePin * get_pin() const
Definition: endpoint.cpp:28
Gate * get_gate() const
Definition: endpoint.cpp:23
Definition: gate.h:58
Net * get_fan_in_net(const std::string &pin_name) const
Definition: gate.cpp:617
const std::vector< Net * > & get_fan_in_nets() const
Definition: gate.cpp:591
const std::vector< Endpoint * > & get_fan_out_endpoints() const
Definition: gate.cpp:797
GateType * get_type() const
Definition: gate.cpp:125
std::vector< Endpoint * > get_predecessors(const std::function< bool(const GatePin *pin, Endpoint *ep)> &filter=nullptr) const
Definition: gate.cpp:886
Net * get_fan_out_net(const std::string &pin_name) const
Definition: gate.cpp:761
std::vector< Endpoint * > get_successors(const std::function< bool(const GatePin *pin, Endpoint *ep)> &filter=nullptr) const
Definition: gate.cpp:966
const std::string & get_name() const
Definition: gate.cpp:105
const std::vector< Net * > & get_fan_out_nets() const
Definition: gate.cpp:735
const std::vector< Endpoint * > & get_fan_in_endpoints() const
Definition: gate.cpp:653
Netlist * get_netlist() const
Definition: gate.cpp:100
std::unordered_map< std::string, BooleanFunction > get_boolean_functions(bool only_custom_functions=false) const
Definition: gate.cpp:262
u32 get_id() const
Definition: gate.cpp:95
std::vector< std::string > get_input_pin_names() const
Definition: gate_type.cpp:277
bool has_property(GateTypeProperty property) const
Definition: gate_type.cpp:101
const std::vector< Gate * > & get_gates() const
Definition: module.cpp:391
Definition: net.h:58
u32 get_id() const
Definition: net.cpp:88
Endpoint * add_destination(Gate *gate, const std::string &pin_name)
Definition: net.cpp:288
const std::string & get_name() const
Definition: net.cpp:98
std::vector< Endpoint * > get_destinations(const std::function< bool(Endpoint *ep)> &filter=nullptr) const
Definition: net.cpp:426
bool remove_destination(Gate *gate, const std::string &pin_name)
Definition: net.cpp:319
std::vector< Endpoint * > get_sources(const std::function< bool(Endpoint *ep)> &filter=nullptr) const
Definition: net.cpp:264
const std::vector< Gate * > & get_gates() const
Definition: netlist.cpp:204
u32 get_id() const
Definition: netlist.cpp:75
Result< std::unique_ptr< Netlist > > copy() const
Definition: netlist.cpp:142
Result< Gate * > replace_gate(Gate *gate, GateType *target_type, const std::map< GatePin *, GatePin * > &pin_map)
Result< std::unique_ptr< Netlist > > copy_subgraph_netlist(const std::vector< const Gate * > &subgraph_gates, const bool all_global_io=false) const
Result< BooleanFunction > get_subgraph_function(const std::vector< const Gate * > &subgraph_gates, const Net *subgraph_output, std::map< std::pair< u32, const GatePin * >, BooleanFunction > &cache) const
#define log_error(channel,...)
Definition: log.h:78
#define log_debug(channel,...)
Definition: log.h:74
#define log_warning(channel,...)
Definition: log.h:76
#define ERR(message)
Definition: result.h:53
#define OK(...)
Definition: result.h:49
std::vector< Net * > get_common_inputs(const std::vector< Gate * > &gates, u32 threshold)
std::unique_ptr< Netlist > get_partial_netlist(const Netlist *nl, const std::vector< const Gate * > &subgraph_gates)
std::vector< Gate * > get_next_gates(const Gate *gate, bool get_successors, int depth, const std::function< bool(const Gate *)> &filter)
Result< std::vector< Gate * > > get_gate_chain(Gate *start_gate, const std::vector< const GatePin * > &input_pins, const std::vector< const GatePin * > &output_pins, const std::function< bool(const Gate *)> &filter)
Result< std::vector< Gate * > > get_complex_gate_chain(Gate *start_gate, const std::vector< GateType * > &chain_types, const std::map< GateType *, std::vector< const GatePin * >> &input_pins, const std::map< GateType *, std::vector< const GatePin * >> &output_pins, const std::function< bool(const Gate *)> &filter)
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::unique_ptr< Netlist > copy_netlist(const Netlist *nl)
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)
Result< u32 > remove_unused_lut_endpoints(Netlist *netlist)
Result< BooleanFunction > get_subgraph_function(const Net *net, const std::vector< const Gate * > &subgraph_gates, std::map< std::pair< u32, const GatePin * >, BooleanFunction > &cache)
std::vector< Gate * > get_shortest_path(Gate *start_gate, Module *end_module, bool forward_direction)
std::vector< Gate * > get_next_sequential_gates(const Gate *gate, bool get_successors, std::unordered_map< u32, std::vector< Gate * >> &cache)
std::pair< std::map< u32, Gate * >, std::vector< std::vector< int > > > get_ff_dependency_matrix(const Netlist *nl)
Result< u32 > remove_buffers(Netlist *netlist, bool analyze_inputs)
PinDirection
Definition: pin_direction.h:36
n
Definition: test.py:6
quint32 u32
std::vector< PinInformation > pins
Net * net
PinDirection direction
This file contains various functions to create and load netlists.