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<std::vector<Gate*> > get_shortest_path(Module* start_module, Module* end_module)
362  {
363  std::unordered_set<Gate*> start_gates;
364  for (Gate* g : start_module->get_gates(nullptr, true))
365  {
366  start_gates.insert(g);
367  }
368 
369  int shortest_length = -1;
370  std::vector<std::vector<Gate*> > retval;
371  for (Gate* end_gate : end_module->get_gates(nullptr,true))
372  {
373  ShortestPathInternal spi_reverse(end_gate, start_gates, false);
374  std::vector<Gate*> path_reverse = spi_reverse.get_path();
375  int len = path_reverse.size();
376  if (!len) continue;
377  if (shortest_length < 0) shortest_length = len;
378  if (len > shortest_length) continue;
379  if (len < shortest_length) shortest_length = len;
380  retval.push_back(path_reverse);
381  }
382 
383  auto it = retval.begin();
384  while (it != retval.end())
385  {
386  if (it->size() > shortest_length)
387  it = retval.erase(it);
388  else
389  ++it;
390  }
391  return retval;
392  }
393 
394  std::vector<Gate*> get_shortest_path(Gate* start_gate, Gate* end_gate, bool search_both_directions)
395  {
396  std::unordered_set<Gate*> end_gates_forward;
397  end_gates_forward.insert(end_gate);
398  ShortestPathInternal spi_forward(start_gate, end_gates_forward, true);
399  std::vector<Gate*> path_forward = spi_forward.get_path();
400  if (!search_both_directions)
401  return path_forward;
402  std::unordered_set<Gate*> start_gates_reverse;
403  start_gates_reverse.insert(start_gate);
404  ShortestPathInternal spi_reverse(end_gate, start_gates_reverse, false);
405  std::vector<Gate*> path_reverse = spi_reverse.get_path();
406  return (path_reverse.size() < path_forward.size()) ? path_reverse : path_forward;
407  }
408 
409  namespace
410  {
411  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)
412  {
413  if (auto it = cache.find(start_net->get_id()); it != cache.end())
414  {
415  return it->second;
416  }
417 
418  if (seen.find(start_net->get_id()) != seen.end())
419  {
420  return {};
421  }
422 
423  seen.insert(start_net->get_id());
424 
425  std::vector<Gate*> found_ffs;
426 
427  for (auto endpoint : forward ? start_net->get_destinations() : start_net->get_sources())
428  {
429  auto next_gate = endpoint->get_gate();
430 
431  if (next_gate->get_type()->has_property(GateTypeProperty::ff))
432  {
433  found_ffs.push_back(next_gate);
434  }
435  else
436  {
437  for (auto n : forward ? next_gate->get_fan_out_nets() : next_gate->get_fan_in_nets())
438  {
439  auto next_gates = get_next_sequential_gates_internal(n, forward, seen, cache);
440  found_ffs.insert(found_ffs.end(), next_gates.begin(), next_gates.end());
441  }
442  }
443  }
444 
445  std::sort(found_ffs.begin(), found_ffs.end());
446  found_ffs.erase(std::unique(found_ffs.begin(), found_ffs.end()), found_ffs.end());
447 
448  cache.emplace(start_net->get_id(), found_ffs);
449  return found_ffs;
450  }
451  } // namespace
452 
453  std::vector<Gate*> get_next_sequential_gates(const Gate* gate, bool get_successors, std::unordered_map<u32, std::vector<Gate*>>& cache)
454  {
455  std::vector<Gate*> found_ffs;
456  for (const auto& n : get_successors ? gate->get_fan_out_nets() : gate->get_fan_in_nets())
457  {
458  auto suc = get_next_sequential_gates(n, get_successors, cache);
459  found_ffs.insert(found_ffs.end(), suc.begin(), suc.end());
460  }
461 
462  std::sort(found_ffs.begin(), found_ffs.end());
463  found_ffs.erase(std::unique(found_ffs.begin(), found_ffs.end()), found_ffs.end());
464 
465  return found_ffs;
466  }
467 
468  std::vector<Gate*> get_next_sequential_gates(const Net* net, bool get_successors, std::unordered_map<u32, std::vector<Gate*>>& cache)
469  {
470  std::unordered_set<u32> seen;
471  return get_next_sequential_gates_internal(net, get_successors, seen, cache);
472  }
473 
474  std::vector<Gate*> get_next_sequential_gates(const Gate* gate, bool get_successors)
475  {
476  std::unordered_map<u32, std::vector<Gate*>> cache;
477  return get_next_sequential_gates(gate, get_successors, cache);
478  }
479 
480  std::vector<Gate*> get_next_sequential_gates(const Net* net, bool get_successors)
481  {
482  std::unordered_map<u32, std::vector<Gate*>> cache;
483  return get_next_sequential_gates(net, get_successors, cache);
484  }
485 
486  namespace
487  {
488  std::vector<Gate*>
489  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)
490  {
491  if (auto it = cache.find(start_net->get_id()); it != cache.end())
492  {
493  return it->second;
494  }
495 
496  if (seen.find(start_net->get_id()) != seen.end())
497  {
498  return {};
499  }
500 
501  seen.insert(start_net->get_id());
502 
503  std::vector<Gate*> found_combinational;
504 
505  for (auto endpoint : forward ? start_net->get_destinations() : start_net->get_sources())
506  {
507  auto next_gate = endpoint->get_gate();
508 
509  bool stop = false;
510  for (GateTypeProperty property : next_gate->get_type()->get_properties())
511  {
512  if (stop_types.find(property) != stop_types.end())
513  {
514  stop = true;
515  }
516  }
517 
518  if (stop == false)
519  {
520  found_combinational.push_back(next_gate);
521 
522  for (auto n : forward ? next_gate->get_fan_out_nets() : next_gate->get_fan_in_nets())
523  {
524  auto next_gates = get_path_internal(n, forward, stop_types, seen, cache);
525  found_combinational.insert(found_combinational.end(), next_gates.begin(), next_gates.end());
526  }
527  }
528  }
529 
530  std::sort(found_combinational.begin(), found_combinational.end());
531  found_combinational.erase(std::unique(found_combinational.begin(), found_combinational.end()), found_combinational.end());
532 
533  cache.emplace(start_net->get_id(), found_combinational);
534  return found_combinational;
535  }
536  } // namespace
537 
538  std::vector<Gate*> get_path(const Gate* gate, bool get_successors, std::set<GateTypeProperty> stop_properties, std::unordered_map<u32, std::vector<Gate*>>& cache)
539  {
540  std::vector<Gate*> found_combinational;
541  for (const auto& n : get_successors ? gate->get_fan_out_nets() : gate->get_fan_in_nets())
542  {
543  auto suc = get_path(n, get_successors, stop_properties, cache);
544  found_combinational.insert(found_combinational.end(), suc.begin(), suc.end());
545  }
546 
547  std::sort(found_combinational.begin(), found_combinational.end());
548  found_combinational.erase(std::unique(found_combinational.begin(), found_combinational.end()), found_combinational.end());
549 
550  return found_combinational;
551  }
552 
553  std::vector<Gate*> get_path(const Net* net, bool get_successors, std::set<GateTypeProperty> stop_properties, std::unordered_map<u32, std::vector<Gate*>>& cache)
554  {
555  std::unordered_set<u32> seen;
556  return get_path_internal(net, get_successors, stop_properties, seen, cache);
557  }
558 
559  std::vector<Gate*> get_path(const Gate* gate, bool get_successors, std::set<GateTypeProperty> stop_properties)
560  {
561  std::unordered_map<u32, std::vector<Gate*>> cache;
562  return get_path(gate, get_successors, stop_properties, cache);
563  }
564 
565  std::vector<Gate*> get_path(const Net* net, bool get_successors, std::set<GateTypeProperty> stop_properties)
566  {
567  std::unordered_map<u32, std::vector<Gate*>> cache;
568  return get_path(net, get_successors, stop_properties, cache);
569  }
570 
571  std::vector<Net*> get_nets_at_pins(Gate* gate, std::vector<GatePin*> pins)
572  {
573  std::vector<Net*> nets;
574 
575  for (const auto& pin : pins)
576  {
577  if (pin == nullptr)
578  {
579  log_warning("netlist_utils", "'nullptr' given as pin.");
580  continue;
581  }
582 
583  PinDirection direction = pin->get_direction();
585  {
586  if (auto net = gate->get_fan_in_net(pin); net != nullptr)
587  {
588  nets.push_back(net);
589  }
590  else
591  {
592  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());
593  }
594  }
595  else if (direction == PinDirection::output)
596  {
597  if (auto net = gate->get_fan_out_net(pin); net != nullptr)
598  {
599  nets.push_back(net);
600  }
601  else
602  {
603  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());
604  }
605  }
606  }
607 
608  return nets;
609  }
610 
611  Result<u32> remove_buffers(Netlist* netlist, bool analyze_inputs)
612  {
613  u32 num_gates = 0;
614 
615  for (const auto& gate : netlist->get_gates())
616  {
617  std::vector<Endpoint*> fan_out = gate->get_fan_out_endpoints();
618 
619  GateType* gt = gate->get_type();
621  {
622  // continue if of invalid base type
623  continue;
624  }
625 
626  if (fan_out.size() != 1)
627  {
628  // continue if more than one fan-out net
629  continue;
630  }
631 
632  std::unordered_map<std::string, BooleanFunction> functions = gate->get_boolean_functions();
633  if (functions.size() != 1)
634  {
635  // continue if more than one Boolean function (tri-state?)
636  continue;
637  }
638 
639  Endpoint* out_endpoint = *(fan_out.begin());
640  if (out_endpoint->get_pin()->get_name() != (functions.begin())->first)
641  {
642  // continue if Boolean function name does not match output pin
643  continue;
644  }
645 
646  std::vector<Endpoint*> fan_in = gate->get_fan_in_endpoints();
647  BooleanFunction func = functions.begin()->second;
648 
649  if (analyze_inputs)
650  {
651  for (Endpoint* ep : fan_in)
652  {
653  auto sources = ep->get_net()->get_sources();
654  if (sources.size() != 1)
655  {
656  break;
657  }
658 
659  if (sources.front()->get_gate()->is_gnd_gate())
660  {
661  if (auto substitution = func.substitute(ep->get_pin()->get_name(), BooleanFunction::Const(0, 1)); substitution.is_ok())
662  {
663  func = substitution.get();
664  }
665  }
666  else if (sources.front()->get_gate()->is_vcc_gate())
667  {
668  if (auto substitution = func.substitute(ep->get_pin()->get_name(), BooleanFunction::Const(1, 1)); substitution.is_ok())
669  {
670  func = substitution.get();
671  }
672  }
673  }
674 
675  func = func.simplify();
676  }
677 
678  std::string func_str = func.to_string();
679  std::vector<std::string> in_pins = gt->get_input_pin_names();
680  if (std::find(in_pins.begin(), in_pins.end(), func_str) != in_pins.end())
681  {
682  Net* out_net = out_endpoint->get_net();
683 
684  // check all input endpoints and ...
685  for (Endpoint* in_endpoint : fan_in)
686  {
687  Net* in_net = in_endpoint->get_net();
688 
689  if (in_endpoint->get_pin()->get_name() == func_str)
690  {
691  // reconnect outputs if the input is passed through the buffer
692  for (Endpoint* dst : out_net->get_destinations())
693  {
694  Gate* dst_gate = dst->get_gate();
695  GatePin* dst_pin = dst->get_pin();
696  if (!out_net->remove_destination(dst))
697  {
698  return ERR("could not completely remove buffers from netlist with ID " + std::to_string(netlist->get_id()) + ": failed to remove destination from output net '"
699  + out_net->get_name() + "' with ID " + std::to_string(out_net->get_id()) + " of buffer gate '" + gate->get_name() + "' with ID "
700  + std::to_string(gate->get_id()));
701  }
702  if (!in_net->add_destination(dst_gate, dst_pin))
703  {
704  return ERR("could not completely remove buffers from netlist with ID " + std::to_string(netlist->get_id()) + ": failed to add destination to input net '"
705  + in_net->get_name() + "' with ID " + std::to_string(in_net->get_id()) + " of buffer gate '" + gate->get_name() + "' with ID "
706  + std::to_string(gate->get_id()));
707  }
708  }
709  }
710  else
711  {
712  // remove the input endpoint otherwise
713  if (!in_net->remove_destination(gate, in_endpoint->get_pin()))
714  {
715  return ERR("could not completely remove buffers from netlist with ID " + std::to_string(netlist->get_id()) + ": failed to remove destination from input net '"
716  + in_net->get_name() + "' with ID " + std::to_string(in_net->get_id()) + " of buffer gate '" + gate->get_name() + "' with ID "
717  + std::to_string(gate->get_id()));
718  }
719  }
720  }
721 
722  // delete output net and buffer gate
723  netlist->delete_net(out_net);
724  netlist->delete_gate(gate);
725  num_gates++;
726  }
727  else if (func_str == "0" || func_str == "1")
728  {
729  Net* out_net = out_endpoint->get_net();
730 
731  const std::vector<Gate*>& gnd_gates = netlist->get_gnd_gates();
732  const std::vector<Gate*>& vcc_gates = netlist->get_vcc_gates();
733  if (gnd_gates.empty() || vcc_gates.empty())
734  {
735  continue;
736  }
737  Net* gnd_net = gnd_gates.front()->get_fan_out_nets().front();
738  Net* vcc_net = vcc_gates.front()->get_fan_out_nets().front();
739 
740  for (Endpoint* in_endpoint : fan_in)
741  {
742  Net* in_net = in_endpoint->get_net();
743 
744  // remove the input endpoint otherwise
745  if (!in_net->remove_destination(gate, in_endpoint->get_pin()))
746  {
747  return ERR("could not completely remove buffers from netlist with ID " + std::to_string(netlist->get_id()) + ": failed to remove destination from input net '"
748  + 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()));
749  }
750  }
751  if (func_str == "0")
752  {
753  for (Endpoint* dst : out_net->get_destinations())
754  {
755  Gate* dst_gate = dst->get_gate();
756  GatePin* dst_pin = dst->get_pin();
757  if (!out_net->remove_destination(dst))
758  {
759  return ERR("could not completely remove buffers from netlist with ID " + std::to_string(netlist->get_id()) + ": failed to remove destination from output net '"
760  + out_net->get_name() + "' with ID " + std::to_string(out_net->get_id()) + " of buffer gate '" + gate->get_name() + "' with ID "
761  + std::to_string(gate->get_id()));
762  }
763  if (!gnd_net->add_destination(dst_gate, dst_pin))
764  {
765  return ERR("could not completely remove buffers from netlist with ID " + std::to_string(netlist->get_id()) + ": failed to add destination to GND net '"
766  + gnd_net->get_name() + "' with ID " + std::to_string(gnd_net->get_id()));
767  }
768  }
769  }
770  else if (func_str == "1")
771  {
772  for (Endpoint* dst : out_net->get_destinations())
773  {
774  Gate* dst_gate = dst->get_gate();
775  GatePin* dst_pin = dst->get_pin();
776  if (!out_net->remove_destination(dst))
777  {
778  return ERR("could not completely remove buffers from netlist with ID " + std::to_string(netlist->get_id()) + ": failed to remove destination from output net '"
779  + out_net->get_name() + "' with ID " + std::to_string(out_net->get_id()) + " of buffer gate '" + gate->get_name() + "' with ID "
780  + std::to_string(gate->get_id()));
781  }
782  if (!vcc_net->add_destination(dst_gate, dst_pin))
783  {
784  return ERR("could not completely remove buffers from netlist with ID " + std::to_string(netlist->get_id()) + ": failed to add destination to VCC net '"
785  + gnd_net->get_name() + "' with ID " + std::to_string(gnd_net->get_id()));
786  }
787  }
788  }
789 
790  // delete output net and buffer gate
791  netlist->delete_net(out_net);
792  netlist->delete_gate(gate);
793  num_gates++;
794  }
795  }
796 
797  return OK(num_gates);
798  }
799 
801  {
802  u32 num_eps = 0;
803 
804  // net connected to GND
805  const std::vector<Gate*>& gnd_gates = netlist->get_gnd_gates();
806  if (gnd_gates.empty())
807  {
808  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");
809  }
810  Net* gnd_net = gnd_gates.front()->get_fan_out_nets().front();
811 
812  // iterate all LUT gates
813  for (const auto& gate : netlist->get_gates([](const Gate* g) { return g->get_type()->has_property(GateTypeProperty::c_lut); }))
814  {
815  std::vector<Endpoint*> fan_in = gate->get_fan_in_endpoints();
816  std::unordered_map<std::string, BooleanFunction> functions = gate->get_boolean_functions();
817 
818  // skip if more than one function
819  if (functions.size() != 1)
820  {
821  continue;
822  }
823 
824  auto active_pins = functions.begin()->second.get_variable_names();
825 
826  // if there are more fan-in nets than there are active pins, we need to get rid of some nets
827  if (fan_in.size() > active_pins.size())
828  {
829  for (const auto& ep : fan_in)
830  {
831  if (std::find(active_pins.begin(), active_pins.end(), ep->get_pin()->get_name()) == active_pins.end())
832  {
833  num_eps++;
834  GatePin* pin = ep->get_pin();
835  if (!ep->get_net()->remove_destination(gate, pin))
836  {
837  return ERR("could not completely remove unused LUT endpoints from netlist with ID " + std::to_string(netlist->get_id())
838  + ": failed to remove inactive endpoint from gate '" + gate->get_name() + "' with ID " + std::to_string(gate->get_id()));
839  }
840  if (!gnd_net->add_destination(gate, pin))
841  {
842  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 '"
843  + gate->get_name() + "' with ID " + std::to_string(gate->get_id()) + " to GND net");
844  }
845  }
846  }
847  }
848  }
849 
850  return OK(num_eps);
851  }
852 
853  std::vector<Net*> get_common_inputs(const std::vector<Gate*>& gates, u32 threshold)
854  {
855  // if threshold = 0, a net is only considered to be common if it is an input to all gates
856  if (threshold == 0)
857  {
858  threshold = gates.size();
859  }
860 
861  // count input net occurences
862  std::map<Net*, u32> net_count;
863  for (Gate* g : gates)
864  {
865  for (Endpoint* pred : g->get_predecessors())
866  {
867  if (pred->get_gate()->is_gnd_gate() || pred->get_gate()->is_vcc_gate())
868  {
869  continue;
870  }
871 
872  Net* pred_net = pred->get_net();
873  if (const auto it = net_count.find(pred_net); it != net_count.end())
874  {
875  it->second++;
876  }
877  else
878  {
879  net_count[pred_net] = 1;
880  }
881  }
882  }
883 
884  // consider every net that is input to at least half the gates to be a common input
885  std::vector<Net*> common_inputs;
886  for (const auto& [n, cnt] : net_count)
887  {
888  if (cnt >= threshold)
889  {
890  common_inputs.push_back(n);
891  }
892  }
893 
894  return common_inputs;
895  }
896 
897  Result<std::monostate> replace_gate(Gate* gate, GateType* target_type, std::map<GatePin*, GatePin*> pin_map)
898  {
899  if (auto res = NetlistModificationDecorator(*(gate->get_netlist())).replace_gate(gate, target_type, pin_map); res.is_ok())
900  {
901  return OK({});
902  }
903  else
904  {
905  return ERR(res.get_error());
906  }
907  }
908 
910  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)
911  {
912  if (start_gate == nullptr)
913  {
914  return ERR("could not detect gate chain at start gate: start gate is a 'nullptr'");
915  }
916 
917  // check filter on start gate
918  if (filter && !filter(start_gate))
919  {
920  return ERR("could not detect gate chain at start gate '" + start_gate->get_name() + "' with ID " + std::to_string(start_gate->get_id())
921  + ": filter evaluates to 'false' for start gate");
922  }
923 
924  std::deque<Gate*> gate_chain = {start_gate};
925  std::unordered_set<Gate*> visited_gates = {start_gate};
926  const GateType* target_type = start_gate->get_type();
927  bool found_next_gate;
928 
929  // move forward
930  const Gate* current_gate = start_gate;
931  do
932  {
933  found_next_gate = false;
934 
935  // check all eligible successors of current gate
936  std::vector<Endpoint*> successors = current_gate->get_successors([input_pins, output_pins, target_type, filter](const GatePin* ep_pin, Endpoint* ep) {
937  if (ep->get_gate()->get_type() == target_type)
938  {
939  if (output_pins.empty() || std::find(output_pins.begin(), output_pins.end(), ep_pin) != output_pins.end())
940  {
941  if (input_pins.empty() || std::find(input_pins.begin(), input_pins.end(), ep->get_pin()) != input_pins.end())
942  {
943  if (!filter || filter(ep->get_gate()))
944  {
945  return true;
946  }
947  }
948  }
949  }
950  return false;
951  });
952 
953  if (successors.size() > 1)
954  {
955  log_debug("netlist_utils",
956  "detected more than one valid successor gate for gate '{}' with ID {} in netlist with ID {}.",
957  current_gate->get_name(),
958  current_gate->get_id(),
959  current_gate->get_netlist()->get_id());
960  break;
961  }
962  else if (!successors.empty())
963  {
964  Gate* suc_gate = successors.at(0)->get_gate();
965 
966  if (visited_gates.find(suc_gate) != visited_gates.end())
967  {
968  log_debug("netlist_utils", "detected a loop at gate with ID {}.", suc_gate->get_id());
969  break;
970  }
971 
972  gate_chain.push_back(suc_gate);
973  visited_gates.insert(suc_gate);
974  current_gate = suc_gate;
975  found_next_gate = true;
976  }
977  } while (found_next_gate);
978 
979  // move backwards
980  current_gate = start_gate;
981  do
982  {
983  found_next_gate = false;
984 
985  // check all eligable predecessors of current gate
986  std::vector<Endpoint*> predecessors = current_gate->get_predecessors([input_pins, output_pins, target_type, filter](const GatePin* ep_pin, Endpoint* ep) {
987  if (ep->get_gate()->get_type() == target_type)
988  {
989  if (input_pins.empty() || std::find(input_pins.begin(), input_pins.end(), ep_pin) != input_pins.end())
990  {
991  if (output_pins.empty() || std::find(output_pins.begin(), output_pins.end(), ep->get_pin()) != output_pins.end())
992  {
993  if (!filter || filter(ep->get_gate()))
994  {
995  return true;
996  }
997  }
998  }
999  }
1000  return false;
1001  });
1002 
1003  if (predecessors.size() > 1)
1004  {
1005  log_debug("netlist_utils",
1006  "detected more than one valid predecessor gate for gate '{}' with ID {} in netlist with ID {}.",
1007  current_gate->get_name(),
1008  current_gate->get_id(),
1009  current_gate->get_netlist()->get_id());
1010  break;
1011  }
1012  else if (!predecessors.empty())
1013  {
1014  Gate* pred_gate = predecessors.at(0)->get_gate();
1015 
1016  if (visited_gates.find(pred_gate) != visited_gates.end())
1017  {
1018  log_debug("netlist_utils", "detected a loop at gate with ID {}.", pred_gate->get_id());
1019  break;
1020  }
1021 
1022  gate_chain.push_front(pred_gate);
1023  visited_gates.insert(pred_gate);
1024  current_gate = pred_gate;
1025  found_next_gate = true;
1026  log_debug("netlist_utils", "found predecessor gate with ID {}.", pred_gate->get_id());
1027  }
1028  } while (found_next_gate);
1029 
1030  return OK(std::vector<Gate*>(gate_chain.begin(), gate_chain.end()));
1031  }
1032 
1034  const std::vector<GateType*>& chain_types,
1035  const std::map<GateType*, std::vector<const GatePin*>>& input_pins,
1036  const std::map<GateType*, std::vector<const GatePin*>>& output_pins,
1037  const std::function<bool(const Gate*)>& filter)
1038  {
1039  if (start_gate == nullptr)
1040  {
1041  return ERR("could not detect gate chain at start gate: start gate is a 'nullptr'");
1042  }
1043  if (chain_types.size() < 2)
1044  {
1045  return ERR("could not detect gate chain at start gate: 'chain_types' comprises less than two target gate types");
1046  }
1047  if (start_gate->get_type() != chain_types.at(0))
1048  {
1049  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 '"
1050  + chain_types.front()->get_name() + "'");
1051  }
1052  if (filter && !filter(start_gate))
1053  {
1054  return ERR("could not detect gate chain at start gate '" + start_gate->get_name() + "' with ID " + std::to_string(start_gate->get_id())
1055  + ": filter evaluates to 'false' for start gate");
1056  }
1057 
1058  std::deque<Gate*> gate_chain = {start_gate};
1059  std::unordered_set<Gate*> visited_gates;
1060 
1061  u32 last_index = 0;
1062  u32 current_index = (last_index + 1) % chain_types.size();
1063 
1064  // move forward
1065  bool found_next_gate;
1066  const Gate* current_gate = start_gate;
1067  do
1068  {
1069  found_next_gate = false;
1070 
1071  // check all successors of current gate
1072  GateType* target_type = chain_types.at(current_index);
1073  const std::vector<const GatePin*>& inputs = input_pins.at(target_type);
1074  const std::vector<const GatePin*>& outputs = output_pins.at(chain_types.at(last_index));
1075  std::vector<Endpoint*> successors = current_gate->get_successors([target_type, inputs, outputs, filter](const GatePin* ep_pin, Endpoint* ep) {
1076  if (ep->get_gate()->get_type() == target_type)
1077  {
1078  if (outputs.empty() || std::find(outputs.begin(), outputs.end(), ep_pin) != outputs.end())
1079  {
1080  if (inputs.empty() || std::find(inputs.begin(), inputs.end(), ep->get_pin()) != inputs.end())
1081  {
1082  if (!filter || filter(ep->get_gate()))
1083  {
1084  return true;
1085  }
1086  }
1087  }
1088  }
1089  return false;
1090  });
1091 
1092  if (successors.size() > 1)
1093  {
1094  log_debug("netlist_utils",
1095  "detected more than one valid successor gate for gate '{}' with ID {} in netlist with ID {}.",
1096  current_gate->get_name(),
1097  current_gate->get_id(),
1098  current_gate->get_netlist()->get_id());
1099  break;
1100  }
1101  else if (!successors.empty())
1102  {
1103  Gate* suc_gate = successors.at(0)->get_gate();
1104 
1105  if (visited_gates.find(suc_gate) != visited_gates.end())
1106  {
1107  log_debug("netlist_utils", "detected a loop at gate with ID {}.", suc_gate->get_id());
1108  break;
1109  }
1110 
1111  gate_chain.push_back(suc_gate);
1112  visited_gates.insert(suc_gate);
1113  current_gate = suc_gate;
1114  last_index = current_index;
1115  current_index = (current_index + 1) % chain_types.size();
1116  found_next_gate = true;
1117  }
1118  } while (found_next_gate);
1119 
1120  // remove partial sequences at the end of the chain
1121  while (current_index != 0)
1122  {
1123  gate_chain.pop_back();
1124  current_index--;
1125  }
1126 
1127  current_gate = start_gate;
1128  last_index = 0;
1129  current_index = chain_types.size() - 1;
1130 
1131  // move backwards
1132  do
1133  {
1134  found_next_gate = false;
1135 
1136  // check all predecessors of current gate
1137  GateType* target_type = chain_types.at(current_index);
1138  const std::vector<const GatePin*>& inputs = input_pins.at(chain_types.at(last_index));
1139  const std::vector<const GatePin*>& outputs = output_pins.at(target_type);
1140  std::vector<Endpoint*> predecessors = current_gate->get_predecessors([target_type, inputs, outputs, filter](const GatePin* ep_pin, Endpoint* ep) {
1141  if (ep->get_gate()->get_type() == target_type)
1142  {
1143  if (inputs.empty() || std::find(inputs.begin(), inputs.end(), ep_pin) != inputs.end())
1144  {
1145  if (outputs.empty() || std::find(outputs.begin(), outputs.end(), ep->get_pin()) != outputs.end())
1146  {
1147  if (!filter || filter(ep->get_gate()))
1148  {
1149  return true;
1150  }
1151  }
1152  }
1153  }
1154  return false;
1155  });
1156 
1157  if (predecessors.size() > 1)
1158  {
1159  log_debug("netlist_utils",
1160  "detected more than one valid predecessor gate for gate '{}' with ID {} in netlist with ID {}.",
1161  current_gate->get_name(),
1162  current_gate->get_id(),
1163  current_gate->get_netlist()->get_id());
1164  break;
1165  }
1166  else if (!predecessors.empty())
1167  {
1168  Gate* pred_gate = predecessors.at(0)->get_gate();
1169 
1170  if (visited_gates.find(pred_gate) != visited_gates.end())
1171  {
1172  log_debug("netlist_utils", "detected a loop at gate with ID {}.", pred_gate->get_id());
1173  break;
1174  }
1175 
1176  gate_chain.push_front(pred_gate);
1177  visited_gates.insert(pred_gate);
1178  current_gate = pred_gate;
1179  last_index = current_index;
1180  current_index = (current_index == 0) ? chain_types.size() - 1 : current_index - 1;
1181  found_next_gate = true;
1182  }
1183  } while (found_next_gate);
1184 
1185  // remove partial sequences at the beginning of the chain
1186  while (last_index != 0)
1187  {
1188  gate_chain.pop_front();
1189  last_index--;
1190  }
1191 
1192  return OK(std::vector<Gate*>(gate_chain.begin(), gate_chain.end()));
1193  }
1194  } // namespace netlist_utils
1195 } // 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:393
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.