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