HAL  v4.5.0-254-g8f9f6a423
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
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  UNUSED(cache);
147  return get_subgraph_function(net, subgraph_gates);
148  }
149 
150  Result<BooleanFunction> get_subgraph_function(const Net* net, const std::vector<const Gate*>& subgraph_gates)
151  {
152  if (net == nullptr)
153  {
154  return ERR("could not get subgraph function: net is a 'nullptr'");
155  }
156 
157  if (auto res = SubgraphNetlistDecorator(*net->get_netlist()).get_subgraph_function(subgraph_gates, net); res.is_ok())
158  {
159  return res;
160  }
161  else
162  {
163  return ERR(res.get_error());
164  }
165  }
166 
167  std::unique_ptr<Netlist> copy_netlist(const Netlist* nl)
168  {
169  if (auto res = nl->copy(); res.is_error())
170  {
171  log_error("netlist_utils", "error encountered while copying netlist:\n{}", res.get_error().get());
172  return nullptr;
173  }
174  else
175  {
176  return res.get();
177  }
178  }
179 
180  std::pair<std::map<u32, Gate*>, std::vector<std::vector<int>>> get_ff_dependency_matrix(const Netlist* nl)
181  {
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;
185 
186  u32 matrix_gates = 0;
187  for (const auto& gate : nl->get_gates())
188  {
189  if (!gate->get_type()->has_property(GateTypeProperty::ff))
190  {
191  continue;
192  }
193  gate_to_matrix_id[gate] = matrix_gates;
194  matrix_id_to_gate[matrix_gates] = gate;
195  matrix_gates++;
196  }
197 
198  for (const auto& [id, gate] : matrix_id_to_gate)
199  {
200  std::vector<int> line_of_matrix;
201 
202  std::set<u32> gates_to_add;
203  for (const auto& pred_gate : netlist_utils::get_next_sequential_gates(gate, false))
204  {
205  gates_to_add.insert(gate_to_matrix_id[pred_gate]);
206  }
207 
208  for (u32 i = 0; i < matrix_gates; i++)
209  {
210  if (gates_to_add.find(i) != gates_to_add.end())
211  {
212  line_of_matrix.push_back(1);
213  }
214  else
215  {
216  line_of_matrix.push_back(0);
217  }
218  }
219  matrix.push_back(line_of_matrix);
220  }
221 
222  return std::make_pair(matrix_id_to_gate, matrix);
223  }
224 
225  std::unique_ptr<Netlist> get_partial_netlist(const Netlist* nl, const std::vector<const Gate*>& subgraph_gates)
226  {
227  if (auto res = SubgraphNetlistDecorator(*nl).copy_subgraph_netlist(subgraph_gates); res.is_ok())
228  {
229  return res.get();
230  }
231  else
232  {
233  log_error("netlist_utils", "error encountered while copying subgraph netlist:\n{}", res.get_error().get());
234  return nullptr;
235  }
236  }
237 
238  std::vector<Gate*> get_next_gates(const Gate* gate, bool get_successors, int depth, const std::function<bool(const Gate*)>& filter)
239  {
240  std::vector<Gate*> retval;
241  std::unordered_map<u32, std::vector<Gate*>> cache;
242  std::vector<const Gate*> v0;
243  v0.push_back(gate);
244  std::unordered_set<const Gate*> gats_handled;
245  std::unordered_set<const Net*> nets_handled;
246  gats_handled.insert(gate);
247 
248  for (int round = 0; !depth || round < depth; round++)
249  {
250  std::vector<const Gate*> v1;
251  for (const Gate* g0 : v0)
252  {
253  for (const Net* n : get_successors ? g0->get_fan_out_nets() : g0->get_fan_in_nets())
254  {
255  if (nets_handled.find(n) != nets_handled.end())
256  {
257  continue;
258  }
259  nets_handled.insert(n);
260 
261  for (const Endpoint* ep : get_successors ? n->get_destinations() : n->get_sources())
262  {
263  Gate* g1 = ep->get_gate();
264  if (gats_handled.find(g1) != gats_handled.end())
265  {
266  continue; // already handled
267  }
268  gats_handled.insert(g1);
269  if (!filter || filter(g1))
270  {
271  v1.push_back(g1);
272  retval.push_back(g1);
273  }
274  }
275  }
276  }
277  if (v1.empty())
278  {
279  break;
280  }
281  v0 = v1;
282  }
283  return retval;
284  }
285 
286  std::vector<Gate*> get_next_gates(const Net* net, bool get_successors, int depth, const std::function<bool(const Gate*)>& filter)
287  {
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()))
294  {
295  Gate* g = ep->get_gate();
296  if (!filter || filter(g))
297  {
298  v0.push_back(g);
299  gates_handled.insert(g);
300  nets_handled.insert(net);
301  retval.push_back(g);
302  }
303  }
304 
305  for (int round = 1; depth == 0 || round < depth; round++)
306  {
307  std::vector<const Gate*> v1;
308  for (const Gate* g0 : v0)
309  {
310  for (const Net* n : get_successors ? g0->get_fan_out_nets() : g0->get_fan_in_nets())
311  {
312  if (nets_handled.find(n) != nets_handled.end())
313  {
314  continue;
315  }
316  nets_handled.insert(n);
317 
318  for (const Endpoint* ep : get_successors ? n->get_destinations() : n->get_sources())
319  {
320  Gate* g1 = ep->get_gate();
321  if (gates_handled.find(g1) != gates_handled.end())
322  {
323  continue; // already handled
324  }
325  gates_handled.insert(g1);
326  if (!filter || filter(g1))
327  {
328  v1.push_back(g1);
329  retval.push_back(g1);
330  }
331  }
332  }
333  }
334  if (v1.empty())
335  {
336  break;
337  }
338  v0 = v1;
339  }
340  return retval;
341  }
342 
343  std::vector<Gate*> get_shortest_path(Gate* start_gate, Module* end_module, bool forward_direction)
344  {
345  std::unordered_set<Gate*> end_gates;
346  for (Gate* g : end_module->get_gates(nullptr, true))
347  {
348  end_gates.insert(g);
349  }
350  ShortestPathInternal spi(start_gate, end_gates, forward_direction);
351  return spi.get_path();
352  }
353 
354  std::vector<std::vector<Gate*> > get_shortest_path(Module* start_module, Module* end_module)
355  {
356  std::unordered_set<Gate*> start_gates;
357  for (Gate* g : start_module->get_gates(nullptr, true))
358  {
359  start_gates.insert(g);
360  }
361 
362  int shortest_length = -1;
363  std::vector<std::vector<Gate*> > retval;
364  for (Gate* end_gate : end_module->get_gates(nullptr,true))
365  {
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();
369  if (!len) continue;
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);
374  }
375 
376  auto it = retval.begin();
377  while (it != retval.end())
378  {
379  if (it->size() > shortest_length)
380  it = retval.erase(it);
381  else
382  ++it;
383  }
384  return retval;
385  }
386 
387  std::vector<Gate*> get_shortest_path(Gate* start_gate, Gate* end_gate, bool search_both_directions)
388  {
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)
394  return path_forward;
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;
400  }
401 
402  namespace
403  {
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)
405  {
406  if (auto it = cache.find(start_net->get_id()); it != cache.end())
407  {
408  return it->second;
409  }
410 
411  if (seen.find(start_net->get_id()) != seen.end())
412  {
413  return {};
414  }
415 
416  seen.insert(start_net->get_id());
417 
418  std::vector<Gate*> found_ffs;
419 
420  for (auto endpoint : forward ? start_net->get_destinations() : start_net->get_sources())
421  {
422  auto next_gate = endpoint->get_gate();
423 
424  if (next_gate->get_type()->has_property(GateTypeProperty::ff))
425  {
426  found_ffs.push_back(next_gate);
427  }
428  else
429  {
430  for (auto n : forward ? next_gate->get_fan_out_nets() : next_gate->get_fan_in_nets())
431  {
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());
434  }
435  }
436  }
437 
438  std::sort(found_ffs.begin(), found_ffs.end());
439  found_ffs.erase(std::unique(found_ffs.begin(), found_ffs.end()), found_ffs.end());
440 
441  cache.emplace(start_net->get_id(), found_ffs);
442  return found_ffs;
443  }
444  } // namespace
445 
446  std::vector<Gate*> get_next_sequential_gates(const Gate* gate, bool get_successors, std::unordered_map<u32, std::vector<Gate*>>& cache)
447  {
448  std::vector<Gate*> found_ffs;
449  for (const auto& n : get_successors ? gate->get_fan_out_nets() : gate->get_fan_in_nets())
450  {
451  auto suc = get_next_sequential_gates(n, get_successors, cache);
452  found_ffs.insert(found_ffs.end(), suc.begin(), suc.end());
453  }
454 
455  std::sort(found_ffs.begin(), found_ffs.end());
456  found_ffs.erase(std::unique(found_ffs.begin(), found_ffs.end()), found_ffs.end());
457 
458  return found_ffs;
459  }
460 
461  std::vector<Gate*> get_next_sequential_gates(const Net* net, bool get_successors, std::unordered_map<u32, std::vector<Gate*>>& cache)
462  {
463  std::unordered_set<u32> seen;
464  return get_next_sequential_gates_internal(net, get_successors, seen, cache);
465  }
466 
467  std::vector<Gate*> get_next_sequential_gates(const Gate* gate, bool get_successors)
468  {
469  std::unordered_map<u32, std::vector<Gate*>> cache;
470  return get_next_sequential_gates(gate, get_successors, cache);
471  }
472 
473  std::vector<Gate*> get_next_sequential_gates(const Net* net, bool get_successors)
474  {
475  std::unordered_map<u32, std::vector<Gate*>> cache;
476  return get_next_sequential_gates(net, get_successors, cache);
477  }
478 
479  namespace
480  {
481  std::vector<Gate*>
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)
483  {
484  if (auto it = cache.find(start_net->get_id()); it != cache.end())
485  {
486  return it->second;
487  }
488 
489  if (seen.find(start_net->get_id()) != seen.end())
490  {
491  return {};
492  }
493 
494  seen.insert(start_net->get_id());
495 
496  std::vector<Gate*> found_combinational;
497 
498  for (auto endpoint : forward ? start_net->get_destinations() : start_net->get_sources())
499  {
500  auto next_gate = endpoint->get_gate();
501 
502  bool stop = false;
503  for (GateTypeProperty property : next_gate->get_type()->get_properties())
504  {
505  if (stop_types.find(property) != stop_types.end())
506  {
507  stop = true;
508  }
509  }
510 
511  if (stop == false)
512  {
513  found_combinational.push_back(next_gate);
514 
515  for (auto n : forward ? next_gate->get_fan_out_nets() : next_gate->get_fan_in_nets())
516  {
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());
519  }
520  }
521  }
522 
523  std::sort(found_combinational.begin(), found_combinational.end());
524  found_combinational.erase(std::unique(found_combinational.begin(), found_combinational.end()), found_combinational.end());
525 
526  cache.emplace(start_net->get_id(), found_combinational);
527  return found_combinational;
528  }
529  } // namespace
530 
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)
532  {
533  std::vector<Gate*> found_combinational;
534  for (const auto& n : get_successors ? gate->get_fan_out_nets() : gate->get_fan_in_nets())
535  {
536  auto suc = get_path(n, get_successors, stop_properties, cache);
537  found_combinational.insert(found_combinational.end(), suc.begin(), suc.end());
538  }
539 
540  std::sort(found_combinational.begin(), found_combinational.end());
541  found_combinational.erase(std::unique(found_combinational.begin(), found_combinational.end()), found_combinational.end());
542 
543  return found_combinational;
544  }
545 
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)
547  {
548  std::unordered_set<u32> seen;
549  return get_path_internal(net, get_successors, stop_properties, seen, cache);
550  }
551 
552  std::vector<Gate*> get_path(const Gate* gate, bool get_successors, std::set<GateTypeProperty> stop_properties)
553  {
554  std::unordered_map<u32, std::vector<Gate*>> cache;
555  return get_path(gate, get_successors, stop_properties, cache);
556  }
557 
558  std::vector<Gate*> get_path(const Net* net, bool get_successors, std::set<GateTypeProperty> stop_properties)
559  {
560  std::unordered_map<u32, std::vector<Gate*>> cache;
561  return get_path(net, get_successors, stop_properties, cache);
562  }
563 
564  std::vector<Net*> get_nets_at_pins(Gate* gate, std::vector<GatePin*> pins)
565  {
566  std::vector<Net*> nets;
567 
568  for (const auto& pin : pins)
569  {
570  if (pin == nullptr)
571  {
572  log_warning("netlist_utils", "'nullptr' given as pin.");
573  continue;
574  }
575 
576  PinDirection direction = pin->get_direction();
578  {
579  if (auto net = gate->get_fan_in_net(pin); net != nullptr)
580  {
581  nets.push_back(net);
582  }
583  else
584  {
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());
586  }
587  }
588  else if (direction == PinDirection::output)
589  {
590  if (auto net = gate->get_fan_out_net(pin); net != nullptr)
591  {
592  nets.push_back(net);
593  }
594  else
595  {
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());
597  }
598  }
599  }
600 
601  return nets;
602  }
603 
604  Result<u32> remove_buffers(Netlist* netlist, bool analyze_inputs)
605  {
606  u32 num_gates = 0;
607 
608  for (const auto& gate : netlist->get_gates())
609  {
610  std::vector<Endpoint*> fan_out = gate->get_fan_out_endpoints();
611 
612  GateType* gt = gate->get_type();
614  {
615  // continue if of invalid base type
616  continue;
617  }
618 
619  if (fan_out.size() != 1)
620  {
621  // continue if more than one fan-out net
622  continue;
623  }
624 
625  std::unordered_map<std::string, BooleanFunction> functions = gate->get_boolean_functions();
626  if (functions.size() != 1)
627  {
628  // continue if more than one Boolean function (tri-state?)
629  continue;
630  }
631 
632  Endpoint* out_endpoint = *(fan_out.begin());
633  if (out_endpoint->get_pin()->get_name() != (functions.begin())->first)
634  {
635  // continue if Boolean function name does not match output pin
636  continue;
637  }
638 
639  std::vector<Endpoint*> fan_in = gate->get_fan_in_endpoints();
640  BooleanFunction func = functions.begin()->second;
641 
642  if (analyze_inputs)
643  {
644  for (Endpoint* ep : fan_in)
645  {
646  auto sources = ep->get_net()->get_sources();
647  if (sources.size() != 1)
648  {
649  break;
650  }
651 
652  if (sources.front()->get_gate()->is_gnd_gate())
653  {
654  if (auto substitution = func.substitute(ep->get_pin()->get_name(), BooleanFunction::Const(0, 1)); substitution.is_ok())
655  {
656  func = substitution.get();
657  }
658  }
659  else if (sources.front()->get_gate()->is_vcc_gate())
660  {
661  if (auto substitution = func.substitute(ep->get_pin()->get_name(), BooleanFunction::Const(1, 1)); substitution.is_ok())
662  {
663  func = substitution.get();
664  }
665  }
666  }
667 
668  func = func.simplify();
669  }
670 
671  std::string func_str = func.to_string();
672  std::vector<std::string> in_pins = gt->get_input_pin_names();
673  if (std::find(in_pins.begin(), in_pins.end(), func_str) != in_pins.end())
674  {
675  Net* out_net = out_endpoint->get_net();
676 
677  // check all input endpoints and ...
678  for (Endpoint* in_endpoint : fan_in)
679  {
680  Net* in_net = in_endpoint->get_net();
681 
682  if (in_endpoint->get_pin()->get_name() == func_str)
683  {
684  // reconnect outputs if the input is passed through the buffer
685  for (Endpoint* dst : out_net->get_destinations())
686  {
687  Gate* dst_gate = dst->get_gate();
688  GatePin* dst_pin = dst->get_pin();
689  if (!out_net->remove_destination(dst))
690  {
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()));
694  }
695  if (!in_net->add_destination(dst_gate, dst_pin))
696  {
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()));
700  }
701  }
702  }
703  else
704  {
705  // remove the input endpoint otherwise
706  if (!in_net->remove_destination(gate, in_endpoint->get_pin()))
707  {
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()));
711  }
712  }
713  }
714 
715  // delete output net and buffer gate
716  netlist->delete_net(out_net);
717  netlist->delete_gate(gate);
718  num_gates++;
719  }
720  else if (func_str == "0" || func_str == "1")
721  {
722  Net* out_net = out_endpoint->get_net();
723 
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())
727  {
728  continue;
729  }
730  Net* gnd_net = gnd_gates.front()->get_fan_out_nets().front();
731  Net* vcc_net = vcc_gates.front()->get_fan_out_nets().front();
732 
733  for (Endpoint* in_endpoint : fan_in)
734  {
735  Net* in_net = in_endpoint->get_net();
736 
737  // remove the input endpoint otherwise
738  if (!in_net->remove_destination(gate, in_endpoint->get_pin()))
739  {
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()));
742  }
743  }
744  if (func_str == "0")
745  {
746  for (Endpoint* dst : out_net->get_destinations())
747  {
748  Gate* dst_gate = dst->get_gate();
749  GatePin* dst_pin = dst->get_pin();
750  if (!out_net->remove_destination(dst))
751  {
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()));
755  }
756  if (!gnd_net->add_destination(dst_gate, dst_pin))
757  {
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()));
760  }
761  }
762  }
763  else if (func_str == "1")
764  {
765  for (Endpoint* dst : out_net->get_destinations())
766  {
767  Gate* dst_gate = dst->get_gate();
768  GatePin* dst_pin = dst->get_pin();
769  if (!out_net->remove_destination(dst))
770  {
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()));
774  }
775  if (!vcc_net->add_destination(dst_gate, dst_pin))
776  {
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()));
779  }
780  }
781  }
782 
783  // delete output net and buffer gate
784  netlist->delete_net(out_net);
785  netlist->delete_gate(gate);
786  num_gates++;
787  }
788  }
789 
790  return OK(num_gates);
791  }
792 
794  {
795  u32 num_eps = 0;
796 
797  // net connected to GND
798  const std::vector<Gate*>& gnd_gates = netlist->get_gnd_gates();
799  if (gnd_gates.empty())
800  {
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");
802  }
803  Net* gnd_net = gnd_gates.front()->get_fan_out_nets().front();
804 
805  // iterate all LUT gates
806  for (const auto& gate : netlist->get_gates([](const Gate* g) { return g->get_type()->has_property(GateTypeProperty::c_lut); }))
807  {
808  std::vector<Endpoint*> fan_in = gate->get_fan_in_endpoints();
809  std::unordered_map<std::string, BooleanFunction> functions = gate->get_boolean_functions();
810 
811  // skip if more than one function
812  if (functions.size() != 1)
813  {
814  continue;
815  }
816 
817  auto active_pins = functions.begin()->second.get_variable_names();
818 
819  // if there are more fan-in nets than there are active pins, we need to get rid of some nets
820  if (fan_in.size() > active_pins.size())
821  {
822  for (const auto& ep : fan_in)
823  {
824  if (std::find(active_pins.begin(), active_pins.end(), ep->get_pin()->get_name()) == active_pins.end())
825  {
826  num_eps++;
827  GatePin* pin = ep->get_pin();
828  if (!ep->get_net()->remove_destination(gate, pin))
829  {
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()));
832  }
833  if (!gnd_net->add_destination(gate, pin))
834  {
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");
837  }
838  }
839  }
840  }
841  }
842 
843  return OK(num_eps);
844  }
845 
846  std::vector<Net*> get_common_inputs(const std::vector<Gate*>& gates, u32 threshold)
847  {
848  // if threshold = 0, a net is only considered to be common if it is an input to all gates
849  if (threshold == 0)
850  {
851  threshold = gates.size();
852  }
853 
854  // count input net occurences
855  std::map<Net*, u32> net_count;
856  for (Gate* g : gates)
857  {
858  for (Endpoint* pred : g->get_predecessors())
859  {
860  if (pred->get_gate()->is_gnd_gate() || pred->get_gate()->is_vcc_gate())
861  {
862  continue;
863  }
864 
865  Net* pred_net = pred->get_net();
866  if (const auto it = net_count.find(pred_net); it != net_count.end())
867  {
868  it->second++;
869  }
870  else
871  {
872  net_count[pred_net] = 1;
873  }
874  }
875  }
876 
877  // consider every net that is input to at least half the gates to be a common input
878  std::vector<Net*> common_inputs;
879  for (const auto& [n, cnt] : net_count)
880  {
881  if (cnt >= threshold)
882  {
883  common_inputs.push_back(n);
884  }
885  }
886 
887  return common_inputs;
888  }
889 
890  Result<std::monostate> replace_gate(Gate* gate, GateType* target_type, std::map<GatePin*, GatePin*> pin_map)
891  {
892  if (auto res = NetlistModificationDecorator(*(gate->get_netlist())).replace_gate(gate, target_type, pin_map); res.is_ok())
893  {
894  return OK({});
895  }
896  else
897  {
898  return ERR(res.get_error());
899  }
900  }
901 
902 
903  } // namespace netlist_utils
904 } // namespace hal
const std::string & get_name() const
Definition: base_pin.h:110
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
Definition: gate.h:59
Net * get_fan_in_net(const std::string &pin_name) const
Definition: gate.cpp:852
const std::vector< Net * > & get_fan_in_nets() const
Definition: gate.cpp:826
const std::vector< Endpoint * > & get_fan_out_endpoints() const
Definition: gate.cpp:1032
GateType * get_type() const
Definition: gate.cpp:162
Net * get_fan_out_net(const std::string &pin_name) const
Definition: gate.cpp:996
const std::string & get_name() const
Definition: gate.cpp:142
const std::vector< Net * > & get_fan_out_nets() const
Definition: gate.cpp:970
const std::vector< Endpoint * > & get_fan_in_endpoints() const
Definition: gate.cpp:888
Netlist * get_netlist() const
Definition: gate.cpp:137
std::unordered_map< std::string, BooleanFunction > get_boolean_functions(bool only_custom_functions=false) const
Definition: gate.cpp:451
u32 get_id() const
Definition: gate.cpp:132
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:400
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:300
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:450
bool remove_destination(Gate *gate, const std::string &pin_name)
Definition: net.cpp:343
std::vector< Endpoint * > get_sources(const std::function< bool(Endpoint *ep)> &filter=nullptr) const
Definition: net.cpp:276
const std::vector< Gate * > & get_gates() const
Definition: netlist.cpp:206
bool delete_net(Net *net)
Definition: netlist.cpp:345
const std::vector< Gate * > & get_gnd_gates() const
Definition: netlist.cpp:311
const std::vector< Gate * > & get_vcc_gates() const
Definition: netlist.cpp:306
bool delete_gate(Gate *gate)
Definition: netlist.cpp:185
u32 get_id() const
Definition: netlist.cpp:77
Result< std::unique_ptr< Netlist > > copy() const
Definition: netlist.cpp:144
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
uint32_t u32
Definition: defines.h:41
#define UNUSED(expr)
Definition: defines.h:49
#define log_error(channel,...)
Definition: log.h:78
#define log_warning(channel,...)
Definition: log.h:76
#define ERR(message)
Definition: result.h:60
#define OK(...)
Definition: result.h:56
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)
Definition: defines.h:45
PinDirection
Definition: pin_direction.h:36
std::vector< PinInformation > pins
Net * net
PinDirection direction
This file contains various functions to create and load netlists.
std::string origin