HAL  v4.5.0-133-g64838ea8d
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
netlist_preprocessing.cpp
Go to the documentation of this file.
2 
11 #include "hal_core/netlist/net.h"
14 #include "nlohmann/json.hpp"
15 #include "rapidjson/document.h"
18 
19 #include <algorithm>
20 #include <fstream>
21 #include <queue>
22 #include <regex>
23 
24 namespace hal
25 {
26  namespace netlist_preprocessing
27  {
28  namespace
29  {
34  struct GateScope
35  {
36  GateScope(const std::vector<Gate*>& gates) : m_all(gates.empty())
37  {
38  // duplicates are dropped, but the caller's order is preserved so that results stay reproducible
39  for (auto* g : gates)
40  {
41  if (m_lookup.insert(g).second)
42  {
43  m_gates.push_back(g);
44  }
45  }
46  }
47 
48  bool contains(const Gate* g) const
49  {
50  return m_all || m_lookup.find(g) != m_lookup.end();
51  }
52 
57  std::vector<Gate*> gates(const Netlist* nl, const std::function<bool(const Gate*)>& type_filter = nullptr) const
58  {
59  if (m_all)
60  {
61  return type_filter ? nl->get_gates(type_filter) : nl->get_gates();
62  }
63 
64  std::vector<Gate*> res;
65  for (auto* g : m_gates)
66  {
67  if (!type_filter || type_filter(g))
68  {
69  res.push_back(g);
70  }
71  }
72  return res;
73  }
74 
75  private:
76  bool m_all;
77  std::vector<Gate*> m_gates;
78  std::unordered_set<const Gate*> m_lookup;
79  };
80  } // namespace
81 
82  Result<u32> remove_unused_lut_inputs(Netlist* nl, const std::vector<Gate*>& gates)
83  {
84  u32 num_eps = 0;
85 
86  // get net connected to GND
87  const std::vector<Gate*>& gnd_gates = nl->get_gnd_gates();
88  if (gnd_gates.empty())
89  {
90  return ERR("could not remove unused LUT endpoints from netlist with ID " + std::to_string(nl->get_id()) + ": no GND net available within netlist");
91  }
92  Net* gnd_net = gnd_gates.front()->get_fan_out_nets().front();
93 
94  const GateScope scope(gates);
95 
96  // iterate all LUT gates
97  for (const auto& gate : scope.gates(nl, [](const Gate* g) { return g->get_type()->has_property(GateTypeProperty::c_lut); }))
98  {
99  std::vector<Endpoint*> fan_in = gate->get_fan_in_endpoints();
100  std::unordered_map<std::string, BooleanFunction> functions = gate->get_boolean_functions();
101 
102  // skip if more than one function
103  if (functions.size() != 1)
104  {
105  continue;
106  }
107 
108  // only pins used as variables in Boolean function are considered active
109  auto active_pins = functions.begin()->second.get_variable_names();
110 
111  // if there are more fan-in nets than there are active pins, remove those that are not used within the Boolean function and reconnect to GND
112  if (fan_in.size() > active_pins.size())
113  {
114  for (const auto& ep : fan_in)
115  {
116  if (ep->get_net()->is_gnd_net() || ep->get_net()->is_vcc_net())
117  {
118  continue;
119  }
120 
121  if (std::find(active_pins.begin(), active_pins.end(), ep->get_pin()->get_name()) == active_pins.end())
122  {
123  GatePin* pin = ep->get_pin();
124  if (!ep->get_net()->remove_destination(gate, pin))
125  {
126  log_warning(
127  "netlist_preprocessing", "failed to remove unused input from LUT gate '{}' with ID {} from netlist with ID {}.", gate->get_name(), gate->get_id(), nl->get_id());
128  continue;
129  }
130  if (!gnd_net->add_destination(gate, pin))
131  {
132  log_warning("netlist_preprocessing",
133  "failed to reconnect unused input of LUT gate '{}' with ID {} to GND in netlist with ID {}.",
134  gate->get_name(),
135  gate->get_id(),
136  nl->get_id());
137  continue;
138  }
139  num_eps++;
140  }
141  }
142  }
143  }
144 
145  log_info("netlist_preprocessing", "removed {} unused LUT endpoints from netlist with ID {}.", num_eps, nl->get_id());
146  return OK(num_eps);
147  }
148 
149  // TODO make this check every pin of a gate and check whether the generated boolean function (with replaced gnd and vcc nets) is just a variable.
150  // Afterwards just connect input net to buffer destination. Do this for all pins and delete gate if it has no more successors and not global outputs
151  Result<u32> remove_buffers(Netlist* nl, const std::vector<Gate*>& gates)
152  {
153  u32 num_gates = 0;
154 
155  std::queue<Gate*> gates_to_be_deleted;
156 
157  const GateScope scope(gates);
158 
159  for (const auto& gate : scope.gates(nl))
160  {
161  std::vector<Endpoint*> fan_out = gate->get_fan_out_endpoints();
162 
163  GateType* gt = gate->get_type();
164 
165  // continue if of invalid base type
167  {
168  continue;
169  }
170 
171  // continue if more than one fan-out net
172  if (fan_out.size() != 1)
173  {
174  continue;
175  }
176 
177  // continue if more than one Boolean function
178  std::unordered_map<std::string, BooleanFunction> functions = gate->get_boolean_functions();
179  if (functions.size() != 1)
180  {
181  continue;
182  }
183 
184  // continue if Boolean function name does not match output pin
185  Endpoint* out_endpoint = *(fan_out.begin());
186  if (out_endpoint->get_pin()->get_name() != (functions.begin())->first)
187  {
188  continue;
189  }
190 
191  std::vector<Endpoint*> fan_in = gate->get_fan_in_endpoints();
192  BooleanFunction func = functions.begin()->second;
193 
194  // simplify Boolean function for constant 0 or 1 inputs (takes care of, e.g., an AND2 connected to an input and logic 1)
195  const auto substitute_res = BooleanFunctionDecorator(func).substitute_power_ground_pins(gate);
196  if (substitute_res.is_error())
197  {
198  return ERR_APPEND(substitute_res.get_error(),
199  "Cannot replace buffers: failed to substitute pins with constants at gate " + gate->get_name() + " with ID " + std::to_string(gate->get_id()));
200  }
201 
202  func = substitute_res.get().simplify_local();
203 
204  bool failed = false;
205  std::vector<std::string> in_pins = gt->get_input_pin_names();
206  if (func.is_variable() && std::find(in_pins.begin(), in_pins.end(), func.get_variable_name().get()) != in_pins.end())
207  {
208  Net* out_net = out_endpoint->get_net();
209 
210  // check all input endpoints and ...
211  for (Endpoint* in_endpoint : fan_in)
212  {
213  Net* in_net = in_endpoint->get_net();
214  if (in_endpoint->get_pin()->get_name() == func.get_variable_name().get())
215  {
216  // const auto merge_res = netlist_utils::merge_nets(nl, in_net, out_net, true);
217  const auto merge_res = NetlistModificationDecorator(*nl).connect_nets(out_net, in_net);
218  if (merge_res.is_error())
219  {
220  log_warning("netlist_preprocessing", "{}", merge_res.get_error().get());
221  failed = true;
222  }
223  }
224  else
225  {
226  // completely remove the input endpoint otherwise
227  if (!in_net->remove_destination(in_endpoint))
228  {
229  log_warning("netlist_preprocessing",
230  "failed to remove destination from input net '{}' with ID {} of buffer gate '{}' with ID {} from netlist with ID {}.",
231  in_net->get_name(),
232  in_net->get_id(),
233  gate->get_name(),
234  gate->get_id(),
235  nl->get_id());
236  failed = true;
237  }
238  }
239 
240  if (failed)
241  {
242  break;
243  }
244  }
245 
246  if (!failed)
247  {
248  gates_to_be_deleted.push(gate);
249  }
250  }
251  // TODO this functionality is not a buffer and is covered by propagate_constants
252  /*
253  else if (func.is_constant() && (func.has_constant_value(0) || func.has_constant_value(1)))
254  {
255  auto* out_net = out_endpoint->get_net();
256 
257  const auto& gnd_gates = nl->get_gnd_gates();
258  const auto& vcc_gates = nl->get_vcc_gates();
259  if (gnd_gates.empty() || vcc_gates.empty())
260  {
261  continue;
262  }
263  auto* gnd_net = gnd_gates.front()->get_fan_out_nets().front();
264  auto* vcc_net = vcc_gates.front()->get_fan_out_nets().front();
265 
266  for (auto* in_endpoint : fan_in)
267  {
268  auto* in_net = in_endpoint->get_net();
269 
270  // remove the input endpoint otherwise
271  if (!in_net->remove_destination(gate, in_endpoint->get_pin()))
272  {
273  log_warning("netlist_preprocessing",
274  "failed to remove destination from input net '{}' with ID {} of buffer gate '{}' with ID {} from netlist with ID {}.",
275  in_net->get_name(),
276  in_net->get_id(),
277  gate->get_name(),
278  gate->get_id(),
279  nl->get_id());
280  failed = true;
281  break;
282  }
283  }
284  if (!failed && func.has_constant_value(0))
285  {
286  for (auto* dst : out_net->get_destinations())
287  {
288  auto* dst_gate = dst->get_gate();
289  auto* dst_pin = dst->get_pin();
290  if (!out_net->remove_destination(dst))
291  {
292  log_warning("netlist_preprocessing",
293  "failed to remove destination from output net '{}' with ID {} of buffer gate '{}' with ID {} from netlist with ID {}.",
294  out_net->get_name(),
295  out_net->get_id(),
296  gate->get_name(),
297  gate->get_id(),
298  nl->get_id());
299  failed = true;
300  break;
301  }
302  if (!gnd_net->add_destination(dst_gate, dst_pin))
303  {
304  log_warning("netlist_preprocessing",
305  "failed to add buffer gate '{}' with ID {} as destination to GND net '{}' with ID {} in netlist with ID {}.",
306  gnd_net->get_name(),
307  gnd_net->get_id(),
308  gate->get_name(),
309  gate->get_id(),
310  nl->get_id());
311  failed = true;
312  break;
313  }
314  }
315  }
316  else if (!failed && func.has_constant_value(1))
317  {
318  for (Endpoint* dst : out_net->get_destinations())
319  {
320  Gate* dst_gate = dst->get_gate();
321  GatePin* dst_pin = dst->get_pin();
322  if (!out_net->remove_destination(dst))
323  {
324  log_warning("netlist_preprocessing",
325  "failed to remove destination from output net '{}' with ID {} of buffer gate '{}' with ID {} from netlist with ID {}.",
326  out_net->get_name(),
327  out_net->get_id(),
328  gate->get_name(),
329  gate->get_id(),
330  nl->get_id());
331  failed = true;
332  break;
333  }
334  if (!vcc_net->add_destination(dst_gate, dst_pin))
335  {
336  log_warning("netlist_preprocessing",
337  "failed to add buffer gate '{}' with ID {} as destination to VCC net '{}' with ID {} in netlist with ID {}.",
338  vcc_net->get_name(),
339  vcc_net->get_id(),
340  gate->get_name(),
341  gate->get_id(),
342  nl->get_id());
343  failed = true;
344  break;
345  }
346  }
347  }
348 
349  // delete output net and buffer gate
350  if (!failed && !nl->delete_net(out_net))
351  {
352  log_warning("netlist_preprocessing",
353  "failed to remove output net '{}' with ID {} of buffer gate '{}' with ID {} from netlist with ID {}.",
354  out_net->get_name(),
355  out_net->get_id(),
356  gate->get_name(),
357  gate->get_id(),
358  nl->get_id());
359  continue;
360  }
361  if (!failed)
362  {
363  gates_to_be_deleted.push(gate);
364  }
365  }
366  */
367  }
368 
369  log_debug("netlist_preprocessing", "removing {} buffer gates...", gates_to_be_deleted.size());
370 
371  while (!gates_to_be_deleted.empty())
372  {
373  Gate* gate = gates_to_be_deleted.front();
374  gates_to_be_deleted.pop();
375  if (!nl->delete_gate(gate))
376  {
377  log_warning("netlist_preprocessing", "failed to remove buffer gate '{}' with ID {} from netlist with ID {}.", gate->get_name(), gate->get_id(), nl->get_id());
378  continue;
379  }
380  num_gates++;
381  }
382 
383  log_info("netlist_preprocessing", "removed {} buffer gates from netlist with ID {}.", num_gates, nl->get_id());
384  return OK(num_gates);
385  }
386 
387  namespace
388  {
389  std::unordered_map<Gate*, std::vector<std::string>> restore_ff_replacements(const Netlist* nl)
390  {
391  std::unordered_map<Gate*, std::vector<std::string>> replacements;
392 
393  for (auto& g : nl->get_gates())
394  {
395  if (g->has_data("preprocessing_information", "replaced_gates"))
396  {
397  const auto& [_, s] = g->get_data("preprocessing_information", "replaced_gates");
398  std::vector<std::string> replaced_gate_names = nlohmann::json::parse(s);
399  replacements.insert({g, replaced_gate_names});
400  }
401  }
402 
403  return replacements;
404  }
405 
406  void update_ff_replacements(std::unordered_map<Gate*, std::vector<std::string>>& replacements)
407  {
408  for (auto& [g, r] : replacements)
409  {
410  const nlohmann::json j = r;
411  const std::string s = j.dump();
412 
413  g->set_data("preprocessing_information", "replaced_gates", "string", s);
414  }
415 
416  return;
417  }
418 
419  void annotate_ff_survivor(std::unordered_map<Gate*, std::vector<std::string>>& replacements, Gate* survivor, Gate* to_be_replaced)
420  {
421  auto& it_s = replacements[survivor];
422 
423  if (const auto& it = replacements.find(to_be_replaced); it != replacements.end())
424  {
425  for (const auto& s : it->second)
426  {
427  it_s.push_back(s);
428  }
429  replacements.erase(it);
430  }
431 
432  it_s.push_back(to_be_replaced->get_name());
433 
434  return;
435  }
436  } // namespace
437 
438  Result<u32> remove_redundant_gates(Netlist* nl, const std::function<bool(const Gate*)>& filter, const std::vector<Gate*>& gates)
439  {
440  // NOTE: the scope restricts which gates may be deleted, not which gates are compared. The gate that is
441  // kept in place of a duplicate is allowed to lie outside of it, so the candidate pool below stays global.
442  const GateScope scope(gates);
443 
444  auto config = hal::SMT::QueryConfig();
445 
446 #ifdef BITWUZLA_LIBRARY
447  auto s_type = hal::SMT::SolverType::Bitwuzla;
448  auto s_call = hal::SMT::SolverCall::Library;
449  config = config.with_solver(s_type).with_call(s_call);
450 #endif
451  struct GateFingerprint
452  {
453  const GateType* type;
454  std::map<GatePin*, Net*> ordered_fan_in = {};
455  std::set<Net*> unordered_fan_in = {};
456  u8 truth_table_hw = 0;
457  std::vector<std::string> init_data = {};
458 
459  bool operator<(const GateFingerprint& other) const
460  {
461  return std::tie(type, ordered_fan_in, unordered_fan_in, truth_table_hw, init_data)
462  < std::tie(other.type, other.ordered_fan_in, other.unordered_fan_in, other.truth_table_hw, other.init_data);
463  }
464  };
465 
466  static std::vector<u8> hw_map = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
467 
468  u32 num_gates = 0;
469  bool progress;
470 
471  std::vector<Gate*> target_gates;
472  if (filter)
473  {
474  target_gates = nl->get_gates([filter](const Gate* g) {
475  const auto& type = g->get_type();
476  return (type->has_property(GateTypeProperty::combinational) || type->has_property(GateTypeProperty::ff)) && filter(g);
477  });
478  }
479  else
480  {
481  target_gates = nl->get_gates([](const Gate* g) {
482  const auto& type = g->get_type();
483  return type->has_property(GateTypeProperty::combinational) || type->has_property(GateTypeProperty::ff);
484  });
485  }
486 
487  auto ff_replacements = restore_ff_replacements(nl);
488 
489  do
490  {
491  std::map<GateFingerprint, std::vector<Gate*>> fingerprinted_gates;
492 
493  progress = false;
494 
495  for (auto* gate : target_gates)
496  {
497  GateFingerprint fingerprint;
498  fingerprint.type = gate->get_type();
499  if (fingerprint.type->has_property(GateTypeProperty::combinational))
500  {
501  const auto& fan_in_nets = gate->get_fan_in_nets();
502  fingerprint.unordered_fan_in.insert(fan_in_nets.cbegin(), fan_in_nets.cend());
503  if (fingerprint.type->has_property(GateTypeProperty::c_lut))
504  {
505  if (const auto res = gate->get_init_data(); res.is_ok())
506  {
507  const auto& init_str = res.get().front();
508  for (const auto c : init_str)
509  {
510  u8 tmp = std::toupper(c) - 0x30;
511  if (tmp > 9)
512  {
513  tmp -= 0x7;
514  }
515  fingerprint.truth_table_hw += hw_map.at(tmp);
516  }
517  }
518  }
519  }
520  else if (fingerprint.type->has_property(GateTypeProperty::ff))
521  {
522  for (const auto& ep : gate->get_fan_in_endpoints())
523  {
524  fingerprint.ordered_fan_in[ep->get_pin()] = ep->get_net();
525  }
526 
527  // Two flip-flops of the same type driven by the same nets can still differ in the value they
528  // start out at, which the fan-in does not show. The fingerprint decides on its own here, as
529  // there is no equivalence check behind it as there is for combinational gates, so the initial
530  // value has to be part of it rather than folded into a hash of it.
531  if (const auto res = gate->get_init_data(); res.is_ok())
532  {
533  fingerprint.init_data = res.get();
534  }
535  }
536 
537  fingerprinted_gates[fingerprint].push_back(gate);
538  }
539 
540  std::vector<std::vector<Gate*>> duplicate_gates;
541  for (const auto& [fingerprint, gates] : fingerprinted_gates)
542  {
543  if (gates.size() == 1)
544  {
545  continue;
546  }
547 
548  // no gate of this group may be deleted, so skip the equivalence checks altogether
549  if (std::none_of(gates.begin(), gates.end(), [&scope](const Gate* g) { return scope.contains(g); }))
550  {
551  continue;
552  }
553 
554  if (fingerprint.type->has_property(GateTypeProperty::combinational))
555  {
556  std::set<const Gate*> visited;
557  for (size_t i = 0; i < gates.size(); i++)
558  {
559  Gate* master_gate = gates.at(i);
560 
561  if (visited.find(master_gate) != visited.cend())
562  {
563  continue;
564  }
565 
566  std::vector<Gate*> current_duplicates = {master_gate};
567 
568  for (size_t j = i + 1; j < gates.size(); j++)
569  {
570  Gate* current_gate = gates.at(j);
571  bool equal = true;
572  for (const auto* pin : fingerprint.type->get_output_pins())
573  {
574  const auto solver_res =
575  master_gate->get_resolved_boolean_function(pin)
576  .map<BooleanFunction>([pin, current_gate](BooleanFunction&& bf_master) {
577  return current_gate->get_resolved_boolean_function(pin).map<BooleanFunction>([bf_master = std::move(bf_master)](BooleanFunction&& bf_current) mutable {
578  return BooleanFunction::Eq(std::move(bf_master), std::move(bf_current), 1);
579  });
580  })
581  .map<BooleanFunction>([](auto&& bf_eq) -> Result<BooleanFunction> { return BooleanFunction::Not(std::move(bf_eq), 1); })
582  .map<SMT::SolverResult>([&config](auto&& bf_not) -> Result<SMT::SolverResult> { return SMT::Solver({SMT::Constraint(std::move(bf_not))}).query(config); });
583 
584  if (solver_res.is_error() || !solver_res.get().is_unsat())
585  {
586  equal = false;
587  }
588  }
589 
590  if (equal)
591  {
592  current_duplicates.push_back(current_gate);
593  visited.insert(current_gate);
594  }
595  }
596 
597  if (current_duplicates.size() > 1)
598  {
599  duplicate_gates.push_back(current_duplicates);
600  }
601  }
602  }
603  else if (fingerprint.type->has_property(GateTypeProperty::ff))
604  {
605  duplicate_gates.push_back(std::move(gates));
606  }
607  }
608 
609  std::set<Gate*> affected_gates;
610  for (auto& current_duplicates : duplicate_gates)
611  {
612  std::sort(current_duplicates.begin(), current_duplicates.end(), [](const auto& g1, const auto& g2) { return g1->get_name().length() < g2->get_name().length(); });
613 
614  // a gate outside of the scope must never be deleted, so move such gates to the front to make one
615  // of them the survivor. Without a scope this is a no-op and the shortest name survives as before.
616  std::stable_partition(current_duplicates.begin(), current_duplicates.end(), [&scope](const Gate* g) { return !scope.contains(g); });
617 
618  auto* survivor_gate = current_duplicates.front();
619  std::map<GatePin*, Net*> out_pins_to_nets;
620  for (auto* ep : survivor_gate->get_fan_out_endpoints())
621  {
622  Net* out_net = ep->get_net();
623  out_pins_to_nets[ep->get_pin()] = out_net;
624  for (const auto* dst : out_net->get_destinations())
625  {
626  auto* dst_gate = dst->get_gate();
627  auto* dst_type = dst_gate->get_type();
628  if (dst_type->has_property(GateTypeProperty::combinational) || dst_type->has_property(GateTypeProperty::ff))
629  {
630  affected_gates.insert(dst_gate);
631  }
632  }
633  }
634 
635  for (u32 k = 1; k < current_duplicates.size(); k++)
636  {
637  auto* current_gate = current_duplicates.at(k);
638 
639  // a group can hold more than one gate outside of the scope, none of which may be deleted
640  if (!scope.contains(current_gate))
641  {
642  continue;
643  }
644 
645  for (auto* ep : current_gate->get_fan_out_endpoints())
646  {
647  auto* ep_net = ep->get_net();
648  auto* ep_pin = ep->get_pin();
649 
650  if (auto it = out_pins_to_nets.find(ep_pin); it != out_pins_to_nets.cend())
651  {
652  // survivor already has net connected to this output -> add destination to survivor's net
653  for (auto* dst : ep_net->get_destinations())
654  {
655  auto* dst_gate = dst->get_gate();
656  auto* dst_pin = dst->get_pin();
657  dst->get_net()->remove_destination(dst);
658  it->second->add_destination(dst_gate, dst_pin);
659 
660  auto* dst_type = dst_gate->get_type();
661  if (dst_type->has_property(GateTypeProperty::combinational) || dst_type->has_property(GateTypeProperty::ff))
662  {
663  affected_gates.insert(dst_gate);
664  }
665  }
666  if (!nl->delete_net(ep_net))
667  {
668  log_warning("netlist_preprocessing", "could not delete net '{}' with ID {} from netlist with ID {}.", ep_net->get_name(), ep_net->get_id(), nl->get_id());
669  }
670  }
671  else
672  {
673  // survivor does not feature net on this output pin -> connect this net to survivor
674  ep_net->add_source(survivor_gate, ep_pin);
675  out_pins_to_nets[ep_pin] = ep_net;
676  for (auto* dst : ep_net->get_destinations())
677  {
678  auto* dst_gate = dst->get_gate();
679  auto* dst_type = dst_gate->get_type();
680  if (dst_type->has_property(GateTypeProperty::combinational) || dst_type->has_property(GateTypeProperty::ff))
681  {
682  affected_gates.insert(dst_gate);
683  }
684  }
685  }
686  }
687 
688  annotate_ff_survivor(ff_replacements, survivor_gate, current_gate);
689 
690  affected_gates.erase(current_gate);
691  if (!nl->delete_gate(current_gate))
692  {
693  log_warning("netlist_preprocessing", "could not delete gate '{}' with ID {} from netlist with ID {}.", current_gate->get_name(), current_gate->get_id(), nl->get_id());
694  }
695  else
696  {
697  progress = true;
698  num_gates++;
699  }
700  }
701  }
702  target_gates = std::vector<Gate*>(affected_gates.cbegin(), affected_gates.cend());
703  } while (progress);
704 
705  update_ff_replacements(ff_replacements);
706 
707  log_info("netlist_preprocessing", "removed {} redundant gates from netlist with ID {}.", num_gates, nl->get_id());
708  return OK(num_gates);
709  }
710 
712  {
713  struct LoopFingerprint
714  {
715  std::map<const GateType*, u32> types;
716  std::set<std::string> external_variable_names;
717  std::set<const Net*> ff_control_nets;
718 
719  bool operator<(const LoopFingerprint& other) const
720  {
721  return (other.types < types) || (other.types == types && other.external_variable_names < external_variable_names)
722  || (other.types == types && other.external_variable_names == external_variable_names && other.ff_control_nets < ff_control_nets);
723  }
724  };
725 
726  auto config = hal::SMT::QueryConfig();
727 
728 #ifdef BITWUZLA_LIBRARY
729  auto s_type = hal::SMT::SolverType::Bitwuzla;
730  auto s_call = hal::SMT::SolverCall::Library;
731  config = config.with_solver(s_type).with_call(s_call);
732 #endif
733 
734  u32 num_gates = 0;
735 
736  auto ff_replacements = restore_ff_replacements(nl);
737 
738  static const std::set<PinType> ff_control_pin_types = {PinType::clock, PinType::enable, PinType::reset, PinType::set};
739 
740  // detect combinational loops that begin and end at the same FF
741  // for some FFs, multiple combinational lops may exist; such loops wil be merged into a single one
742  std::unordered_map<Gate*, std::unordered_set<Gate*>> loops_by_start_gate;
743  for (auto* start_ff : nl->get_gates([](const Gate* g) { return g->get_type()->has_property(GateTypeProperty::ff); }))
744  {
745  std::vector<Gate*> stack = {start_ff};
746  std::vector<Gate*> previous_gates;
747  std::unordered_set<Gate*> visited_gates;
748  std::unordered_set<Gate*> cache;
749 
750  while (!stack.empty())
751  {
752  auto* current_gate = stack.back();
753 
754  if (!previous_gates.empty() && current_gate == previous_gates.back())
755  {
756  stack.pop_back();
757  previous_gates.pop_back();
758  continue;
759  }
760 
761  visited_gates.insert(current_gate);
762 
763  bool added = false;
764  for (const auto* suc_ep : current_gate->get_successors())
765  {
766  if (ff_control_pin_types.find(suc_ep->get_pin()->get_type()) != ff_control_pin_types.end())
767  {
768  continue;
769  }
770 
771  auto* suc_gate = suc_ep->get_gate();
772  if (suc_gate == start_ff || cache.find(suc_gate) != cache.end())
773  {
774  loops_by_start_gate[start_ff].insert(current_gate);
775  cache.insert(current_gate);
776  for (auto it = ++(previous_gates.begin()); it != previous_gates.end(); it++)
777  {
778  cache.insert(*it);
779  loops_by_start_gate[start_ff].insert(*it);
780  }
781  }
782  else if (suc_gate->get_type()->has_property(GateTypeProperty::combinational))
783  {
784  if (visited_gates.find(suc_gate) == visited_gates.end())
785  {
786  stack.push_back(suc_gate);
787  added = true;
788  }
789  }
790  }
791 
792  if (added)
793  {
794  previous_gates.push_back(current_gate);
795  }
796  else
797  {
798  stack.pop_back();
799  }
800  }
801  }
802 
803  std::map<LoopFingerprint, std::vector<std::pair<std::vector<Gate*>, BooleanFunction>>> fingerprinted_loops;
804  for (const auto& [start_ff, comb_gates] : loops_by_start_gate)
805  {
806  LoopFingerprint fingerprint;
807 
808  // do not consider loop of more than 30 gates
809  if (comb_gates.size() > 30)
810  {
811  continue;
812  }
813 
814  // collect FF control and data nets
815  std::vector<const Endpoint*> data_in;
816  for (const auto* ep : start_ff->get_fan_in_endpoints())
817  {
818  auto pin_type = ep->get_pin()->get_type();
819  if (ff_control_pin_types.find(pin_type) != ff_control_pin_types.end())
820  {
821  fingerprint.ff_control_nets.insert(ep->get_net());
822  }
823  else if (pin_type == PinType::data)
824  {
825  data_in.push_back(ep);
826  }
827  }
828 
829  if (data_in.size() != 1)
830  {
831  continue;
832  }
833 
834  // collect gate types
835  fingerprint.types[start_ff->get_type()] = 1;
836  for (const auto* g : comb_gates)
837  {
838  const auto* gt = g->get_type();
839  if (const auto type_it = fingerprint.types.find(gt); type_it == fingerprint.types.end())
840  {
841  fingerprint.types[gt] = 0;
842  }
843  fingerprint.types[gt]++;
844  }
845 
846  std::vector<const Gate*> comb_gates_vec(comb_gates.cbegin(), comb_gates.cend());
847  if (auto function_res = SubgraphNetlistDecorator(*nl).get_subgraph_function(comb_gates_vec, data_in.front()->get_net()); function_res.is_ok())
848  {
849  // get Boolean function variable names
850  BooleanFunction function = function_res.get();
851  fingerprint.external_variable_names = function.get_variable_names();
852 
853  // replace FF output net identifier from function variables (otherwise varies depending on FF, preventing later SMT check)
854  for (const auto* ep : start_ff->get_fan_out_endpoints())
855  {
856  if (const auto it = fingerprint.external_variable_names.find(BooleanFunctionNetDecorator(*(ep->get_net())).get_boolean_variable_name());
857  it != fingerprint.external_variable_names.end())
858  {
859  function = function.substitute(*it, ep->get_pin()->get_name());
860  fingerprint.external_variable_names.erase(it);
861  }
862  }
863 
864  std::vector<Gate*> loop_gates = {start_ff};
865  loop_gates.insert(loop_gates.end(), comb_gates.begin(), comb_gates.end());
866  fingerprinted_loops[fingerprint].push_back(std::make_pair(loop_gates, std::move(function)));
867  }
868  }
869 
870  std::vector<std::vector<std::vector<Gate*>>> duplicate_loops;
871  for (const auto& [_, loops] : fingerprinted_loops)
872  {
873  if (loops.size() == 1)
874  {
875  continue;
876  }
877 
878  std::set<u32> visited;
879  for (u32 i = 0; i < loops.size(); i++)
880  {
881  if (visited.find(i) != visited.cend())
882  {
883  continue;
884  }
885 
886  const auto& master_loop = loops.at(i);
887 
888  std::vector<std::vector<Gate*>> current_duplicates = {std::get<0>(master_loop)};
889 
890  for (size_t j = i + 1; j < loops.size(); j++)
891  {
892  const auto& current_loop = loops.at(j);
893  const auto solver_res =
894  BooleanFunction::Eq(std::get<1>(master_loop).clone(), std::get<1>(current_loop).clone(), 1)
895  .map<BooleanFunction>([](auto&& bf_eq) -> Result<BooleanFunction> { return BooleanFunction::Not(std::move(bf_eq), 1); })
896  .map<SMT::SolverResult>([&config](auto&& bf_not) -> Result<SMT::SolverResult> { return SMT::Solver({SMT::Constraint(std::move(bf_not))}).query(config); });
897 
898  if (solver_res.is_ok() && solver_res.get().is_unsat())
899  {
900  current_duplicates.push_back(std::get<0>(current_loop));
901  visited.insert(j);
902  }
903  }
904 
905  if (current_duplicates.size() > 1)
906  {
907  duplicate_loops.push_back(std::move(current_duplicates));
908  }
909  }
910  }
911 
912  for (const auto& current_duplicates : duplicate_loops)
913  {
914  // TODO the "replace" logic where the output of the survivor ff is connected to new sources and the old gates are deleted is a duplicate of the above functionality
915  const auto& survivor_loop = current_duplicates.front();
916  auto* survivor_ff = survivor_loop.front();
917 
918  std::map<GatePin*, Net*> out_pins_to_nets;
919  for (auto* ep : survivor_ff->get_fan_out_endpoints())
920  {
921  Net* out_net = ep->get_net();
922  out_pins_to_nets[ep->get_pin()] = out_net;
923  }
924 
925  for (u32 i = 1; i < current_duplicates.size(); i++)
926  {
927  auto* current_ff = current_duplicates.at(i).front();
928  for (auto* ep : current_ff->get_fan_out_endpoints())
929  {
930  auto* ep_net = ep->get_net();
931  auto* ep_pin = ep->get_pin();
932 
933  if (auto it = out_pins_to_nets.find(ep_pin); it != out_pins_to_nets.cend())
934  {
935  // survivor already has net connected to this output -> add destination to survivor's net
936  for (auto* dst : ep_net->get_destinations())
937  {
938  auto* dst_gate = dst->get_gate();
939  auto* dst_pin = dst->get_pin();
940  dst->get_net()->remove_destination(dst);
941  it->second->add_destination(dst_gate, dst_pin);
942  }
943  if (!nl->delete_net(ep_net))
944  {
945  log_warning("netlist_preprocessing", "could not delete net '{}' with ID {} from netlist with ID {}.", ep_net->get_name(), ep_net->get_id(), nl->get_id());
946  }
947  }
948  else
949  {
950  // survivor does not feature net on this output pin -> connect this net to survivor
951  ep_net->add_source(survivor_ff, ep_pin);
952  out_pins_to_nets[ep_pin] = ep_net;
953  }
954  }
955 
956  annotate_ff_survivor(ff_replacements, survivor_ff, current_ff);
957 
958  if (!nl->delete_gate(current_ff))
959  {
960  log_warning("netlist_preprocessing", "could not delete gate '{}' with ID {} from netlist with ID {}.", current_ff->get_name(), current_ff->get_id(), nl->get_id());
961  }
962  else
963  {
964  num_gates++;
965  }
966  }
967  }
968 
969  update_ff_replacements(ff_replacements);
970 
971  log_info("netlist_preprocessing", "removed {} redundant loops from netlist with ID {}.", num_gates, nl->get_id());
972  return OK(num_gates);
973  }
974 
976  {
977  struct TreeFingerprint
978  {
979  std::set<const Net*> external_inputs;
980  // std::set<std::string> external_inputs;
981 
982  bool operator<(const TreeFingerprint& other) const
983  {
984  return (other.external_inputs < external_inputs);
985  }
986  };
987 
988  const std::vector<Gate*> all_comb_gates_vec = nl->get_gates([](const auto& g) { return g->get_type()->has_property(GateTypeProperty::combinational); });
989  // const std::unordered_set<Gate*> all_comb_gates_set = {all_comb_gates_vec.begin(), all_comb_gates_vec.end()};
990 
991  std::map<TreeFingerprint, std::set<Net*>> fingerprint_to_nets;
992  for (const auto& g : all_comb_gates_vec)
993  {
994  for (const auto& out_ep : g->get_fan_out_endpoints())
995  {
996  // const auto non_comb_destinations = out_ep->get_net()->get_destinations([](const auto& in_ep){ return !in_ep->get_gate()->get_type()->has_property(GateTypeProperty::combinational);});
997  // if (!non_comb_destinations.empty())
998  {
999  const auto& out_net = out_ep->get_net();
1000  auto inputs_res = SubgraphNetlistDecorator(*nl).get_subgraph_function_inputs(all_comb_gates_vec, out_net);
1001  if (inputs_res.is_error())
1002  {
1003  return ERR_APPEND(inputs_res.get_error(),
1004  "Unable to remove redundant logic trees: failed to gather inputs for net " + out_net->get_name() + " with ID " + std::to_string(out_net->get_id()));
1005  }
1006  TreeFingerprint tf;
1007  tf.external_inputs = inputs_res.get();
1008  // tf.external_inputs = SubgraphNetlistDecorator(*nl).get_subgraph_function(all_comb_gates_vec, out_net).get().simplify().get_variable_names();
1009 
1010  fingerprint_to_nets[tf].insert(out_net);
1011  }
1012  }
1013  }
1014 
1015  std::vector<std::vector<Net*>> equality_classes;
1016 
1017  for (const auto& [_fingerprint, nets] : fingerprint_to_nets)
1018  {
1019  // TODO remove
1020  // std::cout << "Fingerprint(" << _fingerprint.external_inputs.size() << "): " << std::endl;
1021  // for (const auto& n : _fingerprint.external_inputs)
1022  // {
1023  // std::cout << "\t" << n << std::endl;
1024  // }
1025  // std::cout << "Checking nets: " << std::endl;
1026  // for (const auto& n : nets)
1027  // {
1028  // std::cout << "\t" << n->get_name() << std::endl;
1029  // }
1030 
1031  std::vector<Net*> current_candidate_nets = {nets.begin(), nets.end()};
1032  std::vector<Net*> next_candidate_nets;
1033 
1034  while (!current_candidate_nets.empty())
1035  {
1036  const auto n = current_candidate_nets.back();
1037  current_candidate_nets.pop_back();
1038 
1039  std::vector<Net*> new_equality_class = {n};
1040 
1041  for (const auto& m : current_candidate_nets)
1042  {
1043  auto comp_res = z3_utils::compare_nets(nl, nl, n, m);
1044  if (comp_res.is_error())
1045  {
1046  return ERR_APPEND(comp_res.get_error(),
1047  "Unable to remove redundant logic trees: failed to compare net " + n->get_name() + " with ID " + std::to_string(n->get_id()) + " with net "
1048  + m->get_name() + " with ID " + std::to_string(m->get_id()));
1049  }
1050  const auto are_equal = comp_res.get();
1051 
1052  if (are_equal)
1053  {
1054  new_equality_class.push_back(m);
1055  }
1056  else
1057  {
1058  next_candidate_nets.push_back(m);
1059  }
1060  }
1061 
1062  equality_classes.push_back(new_equality_class);
1063  current_candidate_nets = next_candidate_nets;
1064  next_candidate_nets.clear();
1065  }
1066  }
1067 
1068  u32 counter = 0;
1069  for (const auto& eq_class : equality_classes)
1070  {
1071  // TODO remove
1072  // std::cout << "Equal nets: " << std::endl;
1073  // for (const auto& n : eq_class)
1074  // {
1075  // std::cout << n->get_name() << std::endl;
1076  // }
1077 
1078  auto survivor_net = eq_class.front();
1079 
1080  for (u32 i = 1; i < eq_class.size(); i++)
1081  {
1082  auto victim_net = eq_class.at(i);
1083  for (const auto& dst : victim_net->get_destinations())
1084  {
1085  auto dst_gate = dst->get_gate();
1086  auto dst_pin = dst->get_pin();
1087 
1088  if (!victim_net->remove_destination(dst))
1089  {
1090  return ERR("Unable to remove redundant logic trees: failed to remove destination of net " + victim_net->get_name() + " with ID " + std::to_string(victim_net->get_id())
1091  + " at gate " + dst_gate->get_name() + " with ID " + std::to_string(dst_gate->get_id()) + " and pin " + dst_pin->get_name());
1092  }
1093  if (!survivor_net->add_destination(dst_gate, dst_pin))
1094  {
1095  return ERR("Unable to remove redundant logic trees: failed to add destination to net " + survivor_net->get_name() + " with ID " + std::to_string(survivor_net->get_id())
1096  + " at gate " + dst_gate->get_name() + " with ID " + std::to_string(dst_gate->get_id()) + " and pin " + dst_pin->get_name());
1097  }
1098 
1099  counter += 1;
1100  }
1101  }
1102  }
1103 
1104  auto clean_up_res = remove_unconnected_looped(nl);
1105  if (clean_up_res.is_error())
1106  {
1107  return ERR_APPEND(clean_up_res.get_error(), "Unable to remove redundant logic trees: failed to clean up dangling trees");
1108  }
1109 
1110  return OK(clean_up_res.get() + counter);
1111  }
1112 
1113  Result<u32> remove_unconnected_gates(Netlist* nl, const std::vector<Gate*>& gates)
1114  {
1115  u32 num_gates = 0;
1116  const GateScope scope(gates);
1117 
1118  // gates outside of the scope are never deleted, so the candidates can only shrink from here on
1119  std::vector<Gate*> candidates = scope.gates(nl);
1120 
1121  std::vector<Gate*> to_delete;
1122  do
1123  {
1124  to_delete.clear();
1125 
1126  for (const auto& g : candidates)
1127  {
1128  bool is_unconnected = true;
1129  for (const auto& on : g->get_fan_out_nets())
1130  {
1131  if (!on->get_destinations().empty() || on->is_global_output_net())
1132  {
1133  is_unconnected = false;
1134  }
1135  }
1136 
1137  if (is_unconnected)
1138  {
1139  to_delete.push_back(g);
1140  }
1141  }
1142 
1143  for (const auto& g : to_delete)
1144  {
1145  if (!nl->delete_gate(g))
1146  {
1147  log_warning("netlist_preprocessing", "could not delete gate '{}' with ID {} from netlist with ID {}.", g->get_name(), g->get_id(), nl->get_id());
1148  }
1149  else
1150  {
1151  num_gates++;
1152  }
1153  }
1154 
1155  // drop every gate that was handled so that the next round neither dereferences a deleted gate nor
1156  // retries one that could not be deleted
1157  if (!to_delete.empty())
1158  {
1159  const std::unordered_set<Gate*> handled(to_delete.begin(), to_delete.end());
1160  candidates.erase(std::remove_if(candidates.begin(), candidates.end(), [&handled](Gate* g) { return handled.find(g) != handled.end(); }), candidates.end());
1161  }
1162  } while (!to_delete.empty());
1163 
1164  log_info("netlist_preprocessing", "removed {} unconnected gates from netlist with ID {}.", num_gates, nl->get_id());
1165  return OK(num_gates);
1166  }
1167 
1169  {
1170  u32 num_nets = 0;
1171 
1172  std::vector<Net*> to_delete;
1173 
1174  for (const auto& n : nl->get_nets())
1175  {
1176  if (!n->is_global_input_net() && n->get_sources().empty() && !n->is_global_output_net() && n->get_destinations().empty())
1177  {
1178  to_delete.push_back(n);
1179  }
1180  }
1181 
1182  for (const auto& n : to_delete)
1183  {
1184  if (!nl->delete_net(n))
1185  {
1186  log_warning("netlist_preprocessing", "could not delete net '{}' with ID {} from netlist with ID {}.", n->get_name(), n->get_id(), nl->get_id());
1187  }
1188  else
1189  {
1190  num_nets++;
1191  }
1192  }
1193 
1194  log_info("netlist_preprocessing", "removed {} unconnected nets from netlist with ID {}.", num_nets, nl->get_id());
1195  return OK(num_nets);
1196  }
1197 
1199  {
1200  u32 total_removed = 0;
1201 
1202  while (true)
1203  {
1204  auto gate_res = remove_unconnected_gates(nl);
1205  if (gate_res.is_error())
1206  {
1207  return ERR_APPEND(gate_res.get_error(), "unable to execute clean up loop: failed to remove unconnected gates");
1208  }
1209 
1210  auto net_res = remove_unconnected_nets(nl);
1211  if (net_res.is_error())
1212  {
1213  return ERR_APPEND(net_res.get_error(), "unable to execute clean up loop: failed to remove unconnected nets");
1214  }
1215 
1216  const u32 removed = gate_res.get() + net_res.get();
1217  total_removed += removed;
1218  if (!removed)
1219  {
1220  break;
1221  }
1222  }
1223 
1224  return OK(total_removed);
1225  }
1226 
1227  namespace
1228  {
1229  Result<u32> remove_encasing_inverters(Netlist* nl)
1230  {
1231  // check whether all inputs and output are inverted -> remove all inverters
1232 
1233  // TODO: this only considers HAL muxes, but i do not see a reason why. There is no resynthesis happening here
1234  std::vector<Gate*> muxes = nl->get_gates([](const Gate* g) { return (g->get_type()->get_name().find("HAL_MUX") != std::string::npos); });
1235 
1236  u32 delete_count = 0;
1237  std::vector<Gate*> delete_gate_q;
1238 
1239  for (const auto& g : muxes)
1240  {
1241  if (g->get_successors().size() > 1)
1242  {
1243  continue;
1244  }
1245 
1246  auto data_pins = g->get_type()->get_pins([](const GatePin* pin) { return (pin->get_type() == PinType::data) && (pin->get_direction() == PinDirection::input); });
1247  auto out_pins = g->get_type()->get_pins([](const GatePin* pin) { return (pin->get_direction() == PinDirection::output); });
1248 
1249  if (data_pins.size() < 2)
1250  {
1251  continue;
1252  }
1253 
1254  if (out_pins.size() != 1)
1255  {
1256  continue;
1257  }
1258 
1259  bool preceded_by_inv = true;
1260  for (const auto& pin : data_pins)
1261  {
1262  const auto pred = g->get_predecessor(pin);
1263  if (pred == nullptr || pred->get_gate() == nullptr || !pred->get_gate()->get_type()->has_property(GateTypeProperty::c_inverter))
1264  {
1265  preceded_by_inv = false;
1266  break;
1267  }
1268  }
1269 
1270  if (!preceded_by_inv)
1271  {
1272  continue;
1273  }
1274 
1275  bool succeded_by_inv = true;
1276  for (const auto& pin : out_pins)
1277  {
1278  const auto suc = g->get_successor(pin);
1279  if (suc == nullptr || suc->get_gate() == nullptr || !suc->get_gate()->get_type()->has_property(GateTypeProperty::c_inverter))
1280  {
1281  succeded_by_inv = false;
1282  break;
1283  }
1284  }
1285 
1286  if (!succeded_by_inv)
1287  {
1288  continue;
1289  }
1290 
1291  // delete all connections from and to inverters (and inverter gates if they do not share any other connection)
1292  for (const auto& pin : data_pins)
1293  {
1294  const auto pred = g->get_predecessor(pin);
1295 
1296  // disconnect inverter output from mux
1297  pred->get_net()->remove_destination(g, pin);
1298 
1299  // connect inverter input net to mux
1300  auto in_net = pred->get_gate()->get_fan_in_nets().front();
1301  in_net->add_destination(g, pin);
1302 
1303  // delete inverter gate if it does not have any successors
1304  if (pred->get_gate()->get_successors().empty())
1305  {
1306  delete_gate_q.push_back(pred->get_gate());
1307  }
1308  }
1309 
1310  for (const auto& pin : out_pins)
1311  {
1312  const auto suc = g->get_successor(pin);
1313 
1314  // disconnect inverter input from mux
1315  suc->get_net()->remove_source(g, pin);
1316 
1317  // connect inverter output net to mux
1318  auto in_net = suc->get_gate()->get_fan_out_nets().front();
1319  in_net->add_source(g, pin);
1320 
1321  // delete inverter gate if it does not have any predecessors
1322  if (suc->get_gate()->get_predecessors().empty())
1323  {
1324  delete_gate_q.push_back(suc->get_gate());
1325  }
1326  }
1327  }
1328 
1329  for (auto g : delete_gate_q)
1330  {
1331  nl->delete_gate(g);
1332  delete_count++;
1333  }
1334 
1335  log_info("netlist_preprocessing", "removed {} encasing inverters", delete_count);
1336 
1337  return OK(delete_count);
1338  }
1339 
1340  struct MuxFingerprint
1341  {
1342  GateType* type;
1343  std::set<GatePin*> inverters;
1344 
1345  bool operator<(const MuxFingerprint& other) const
1346  {
1347  return (other.type < type) || (other.type == type && other.inverters < inverters);
1348  }
1349  };
1350 
1351  Result<u32> unify_inverted_select_signals(Netlist* nl, GateLibrary* mux_inv_gl)
1352  {
1353  if (nl == nullptr)
1354  {
1355  return ERR("netlist is a nullptr");
1356  }
1357 
1358  if (mux_inv_gl == nullptr)
1359  {
1360  return ERR("gate library is a nullptr");
1361  }
1362 
1363  auto base_path_res = utils::get_unique_temp_directory("resynthesis_");
1364  if (base_path_res.is_error())
1365  {
1366  return ERR_APPEND(base_path_res.get_error(), "unable to resynthesize boolean functions with yosys: failed to get unique temp directory");
1367  }
1368  const std::filesystem::path base_path = base_path_res.get();
1369  const std::filesystem::path genlib_path = base_path / "mux_inv.genlib";
1370  std::filesystem::create_directory(base_path);
1371 
1372  const auto gl_save_res = gate_library_manager::save(genlib_path, mux_inv_gl, true);
1373  if (!gl_save_res)
1374  {
1375  return ERR("unable to unify muxe select signals: failed to save gate library " + mux_inv_gl->get_name() + " to location " + genlib_path.string());
1376  }
1377 
1378  const i64 initial_size = nl->get_gates().size();
1379 
1380  // resynthesize all muxes where any select signal is preceded by an inverter hoping to unify the structure with regards to other muxes conntected to the same select signal
1381 
1382  // TODO: as long as resynthezising the subgraph this can only consider HAL muxes
1383  std::vector<Gate*> muxes = nl->get_gates([](const Gate* g) { return (g->get_type()->get_name().find("HAL_MUX") != std::string::npos); });
1384 
1385  std::map<MuxFingerprint, std::unique_ptr<Netlist>> resynth_cache;
1386 
1387  for (const auto& g : muxes)
1388  {
1389  // MUX fingerprint for caching resynthesis results
1390  MuxFingerprint mf;
1391  mf.type = g->get_type();
1392 
1393  // mapping from MUX select pins to either the input net of the preceding inverter or the net directly connected to the select pin
1394  std::map<GatePin*, Net*> pin_to_input;
1395 
1396  auto select_pins = g->get_type()->get_pins([](const GatePin* pin) { return (pin->get_type() == PinType::select) && (pin->get_direction() == PinDirection::input); });
1397 
1398  std::vector<Gate*> preceding_inverters;
1399  for (const auto& pin : g->get_type()->get_input_pins())
1400  {
1401  const auto pred = g->get_predecessor(pin);
1402  const auto is_select = (std::find(select_pins.begin(), select_pins.end(), pin) != select_pins.end());
1403  if (!is_select || pred == nullptr || pred->get_gate() == nullptr || !pred->get_gate()->get_type()->has_property(GateTypeProperty::c_inverter)
1404  || (pred->get_gate()->get_fan_in_endpoints().size() != 1))
1405  {
1406  pin_to_input.insert({pin, g->get_fan_in_net(pin)});
1407  }
1408  else
1409  {
1410  auto inv_gate = pred->get_gate();
1411  preceding_inverters.push_back(inv_gate);
1412  pin_to_input.insert({pin, inv_gate->get_fan_in_endpoints().front()->get_net()});
1413  mf.inverters.insert(pin);
1414  }
1415  }
1416 
1417  // if there is at least one inverter in front of the mux gate we build a subgraph containing all inverters and the mux gate and resynthesize
1418  if (!preceding_inverters.empty())
1419  {
1420  const Netlist* resynth_nl;
1421 
1422  auto subgraph = preceding_inverters;
1423  subgraph.push_back(g);
1424 
1425  // try to use cached resynth netlist
1426  if (const auto it = resynth_cache.find(mf); it == resynth_cache.end())
1427  {
1428  std::unordered_map<std::string, BooleanFunction> bfs;
1429  for (const auto& ep : g->get_fan_out_endpoints())
1430  {
1431  const auto bf_res = SubgraphNetlistDecorator(*nl).get_subgraph_function(subgraph, ep->get_net());
1432  if (bf_res.is_error())
1433  {
1434  return ERR_APPEND(bf_res.get_error(),
1435  "unable to unify muxes select signals: failed to build boolean function for mux " + g->get_name() + " with ID " + std::to_string(g->get_id())
1436  + " at output " + ep->get_pin()->get_name());
1437  }
1438  auto bf = bf_res.get();
1439 
1440  // replace all net id vars with generic vaiables refering to their connectivity to the mux
1441  for (const auto& [pin, net] : pin_to_input)
1442  {
1443  auto sub_res = bf.substitute(BooleanFunctionNetDecorator(*net).get_boolean_variable_name(), BooleanFunction::Var(pin->get_name(), 1));
1444  if (sub_res.is_error())
1445  {
1446  return ERR_APPEND(sub_res.get_error(), "unable to unify muxes select signals: failed to substitute net_id variable with generic variable");
1447  }
1448  bf = sub_res.get();
1449  }
1450 
1451  bfs.insert({ep->get_pin()->get_name(), std::move(bf)});
1452  }
1453 
1454  auto resynth_res = resynthesis::generate_resynth_netlist_for_boolean_functions(bfs, genlib_path, mux_inv_gl, true);
1455  if (resynth_res.is_error())
1456  {
1457  return ERR_APPEND(resynth_res.get_error(), "unable to unify select signals of muxes: failed to resynthesize mux subgraph to netlist");
1458  }
1459  auto unique_resynth_nl = resynth_res.get();
1460  resynth_nl = unique_resynth_nl.get();
1461  resynth_cache.insert({mf, std::move(unique_resynth_nl)});
1462  }
1463  else
1464  {
1465  resynth_nl = it->second.get();
1466  }
1467 
1468  std::unordered_map<Net*, std::vector<Net*>> global_io_mapping;
1469 
1470  // use top module pin names to find correponding nets in original netlist
1471  for (const auto& pin : resynth_nl->get_top_module()->get_input_pins())
1472  {
1473  auto net_it = pin_to_input.find(g->get_type()->get_pin_by_name(pin->get_name()));
1474  if (net_it == pin_to_input.end())
1475  {
1476  return ERR("unable to unify muxes select signals:: failed to locate net in destination netlist from global input " + pin->get_name() + " in resynthesized netlist");
1477  }
1478  global_io_mapping[pin->get_net()].push_back(net_it->second);
1479  }
1480  for (const auto& pin : resynth_nl->get_top_module()->get_output_pins())
1481  {
1482  auto net = g->get_fan_out_net(pin->get_name());
1483  if (net == nullptr)
1484  {
1485  return ERR("unable to unify muxes select signals:: failed to locate net in destination netlist from global output " + pin->get_name() + " in resynthesized netlist");
1486  }
1487  global_io_mapping[pin->get_net()].push_back(net);
1488  }
1489 
1490  auto replace_res = resynthesis::replace_subgraph_with_netlist(subgraph, global_io_mapping, resynth_nl, nl, false);
1491  if (replace_res.is_error())
1492  {
1493  return ERR("unable to unify muxes select signals: failed to replace mux subgraph with resynthesized netlist");
1494  }
1495 
1496  // delete old subgraph gates that only fed into the mux
1497  std::vector<Gate*> to_delete;
1498  for (const auto g : subgraph)
1499  {
1500  bool has_no_outside_destinations = true;
1501  bool has_only_outside_destinations = true;
1502  for (const auto& suc : g->get_successors())
1503  {
1504  const auto it = std::find(subgraph.begin(), subgraph.end(), suc->get_gate());
1505  if (it == subgraph.end())
1506  {
1507  has_no_outside_destinations = false;
1508  }
1509 
1510  if (it != subgraph.end())
1511  {
1512  has_only_outside_destinations = false;
1513  }
1514  }
1515 
1516  if (has_no_outside_destinations || has_only_outside_destinations)
1517  {
1518  to_delete.push_back(g);
1519  }
1520  }
1521 
1522  for (const auto& g : to_delete)
1523  {
1524  if (!nl->delete_gate(g))
1525  {
1526  return ERR("unable to unify muxes select signals: failed to delete gate " + g->get_name() + " with ID " + std::to_string(g->get_id()) + " in destination netlist");
1527  }
1528  }
1529  }
1530  }
1531 
1532  // delete the created directory and the contained files
1533  std::filesystem::remove_all(base_path);
1534 
1535  const i64 new_size = nl->get_gates().size();
1536  const i64 difference = std::abs(initial_size - new_size);
1537 
1538  return OK(u32(difference));
1539  }
1540 
1541  Result<u32> unify_select_signals(Netlist* nl)
1542  {
1543  if (nl == nullptr)
1544  {
1545  return ERR("netlist is a nullptr");
1546  }
1547 
1548  u32 changed_connections = 0;
1549 
1550  // sort into groups of same type and identical select signals
1551  std::map<std::pair<GateType*, std::set<Net*>>, std::vector<Gate*>> grouped_muxes;
1552  for (const auto& g : nl->get_gates([](const Gate* g) { return g->get_type()->has_property(GateTypeProperty::c_mux); }))
1553  {
1554  std::set<Net*> select_signals;
1555  const auto select_pins = g->get_type()->get_pins([](const GatePin* pin) { return (pin->get_type() == PinType::select) && (pin->get_direction() == PinDirection::input); });
1556  for (const auto& sp : select_pins)
1557  {
1558  select_signals.insert(g->get_fan_in_net(sp));
1559  }
1560 
1561  grouped_muxes[{g->get_type(), select_signals}].push_back(g);
1562  }
1563 
1564  // unify select signals for each group
1565  for (const auto& [finger_print, mux_group] : grouped_muxes)
1566  {
1567  const auto& [type, select_signals_set] = finger_print;
1568  const auto select_pins = type->get_pins([](const GatePin* pin) { return (pin->get_type() == PinType::select) && (pin->get_direction() == PinDirection::input); });
1569  const auto output_pins = type->get_pins([](const GatePin* pin) { return pin->get_direction() == PinDirection::output; });
1570 
1571  if (output_pins.size() != 1)
1572  {
1573  log_warning("netlist_preprocessing",
1574  "Cannot unify select signals for muxes of type {} since the type has {} output signals and we can only handle 1.",
1575  type->get_name(),
1576  output_pins.size());
1577  continue;
1578  }
1579 
1580  // check whether there is one mapping from select signals to select pins
1581  std::map<std::map<GatePin*, Net*>, std::vector<Gate*>> select_map_to_muxes;
1582  for (const auto& g : mux_group)
1583  {
1584  std::map<GatePin*, Net*> select_map;
1585  for (const auto& sp : select_pins)
1586  {
1587  select_map.insert({sp, g->get_fan_in_net(sp)});
1588  }
1589 
1590  select_map_to_muxes[select_map].push_back(g);
1591  }
1592 
1593  if (select_map_to_muxes.size() == 1)
1594  {
1595  continue;
1596  }
1597 
1598  const std::vector<Net*> select_signals = {select_signals_set.begin(), select_signals_set.end()};
1599 
1600  // collect a new mapping from net to gate pin for each mux gate
1601  std::map<Gate*, std::map<GatePin*, Net*>> new_net_to_pin;
1602 
1603  // add newly ordered select signals to pin/net mapping
1604  for (const auto& g : mux_group)
1605  {
1606  for (u32 select_index = 0; select_index < select_pins.size(); select_index++)
1607  {
1608  auto select_pin = select_pins.at(select_index);
1609  auto select_signal = select_signals.at(select_index);
1610  new_net_to_pin[g][select_pin] = select_signal;
1611  }
1612  }
1613 
1614  // determine new pin/net connection for each "data" signal
1615  auto type_bf = type->get_boolean_function(output_pins.front());
1616  for (u32 select_val = 0; select_val < (1 << select_signals.size()); select_val++)
1617  {
1618  std::map<std::string, BooleanFunction> type_substitution;
1619  for (u32 select_idx = 0; select_idx < select_pins.size(); select_idx++)
1620  {
1621  auto select_pin = select_pins.at(select_idx);
1622 
1623  auto type_substitution_val = ((select_val >> select_idx) & 0x1) ? BooleanFunction::Const(1, 1) : BooleanFunction::Const(0, 1);
1624  type_substitution.insert({select_pin->get_name(), type_substitution_val});
1625  }
1626 
1627  auto type_substitution_res = type_bf.substitute(type_substitution);
1628  if (type_substitution_res.is_error())
1629  {
1630  return ERR_APPEND(type_substitution_res.get_error(), "cannot unify mux select signals: failed to substitute type Boolean function with select signal value mapping.");
1631  }
1632  auto input = type_substitution_res.get().simplify_local();
1633 
1634  if (!input.is_variable())
1635  {
1636  return ERR("cannot unify mux select signals: substituted and simplified type Boolean function (" + input.to_string() + ") is not a variable");
1637  }
1638 
1639  const auto pin_name = input.get_variable_name().get();
1640  auto pin = type->get_pins([pin_name](const auto& p) { return p->get_name() == pin_name; }).front();
1641 
1642  for (const auto& g : mux_group)
1643  {
1644  auto gate_bf_res = g->get_resolved_boolean_function(output_pins.front(), false);
1645  if (gate_bf_res.is_error())
1646  {
1647  return ERR_APPEND(gate_bf_res.get_error(),
1648  "cannot unify mux select signals: failed to build Boolean function for gate " + g->get_name() + " with ID " + std::to_string(g->get_id()));
1649  }
1650  auto gate_bf = gate_bf_res.get();
1651 
1652  std::map<std::string, BooleanFunction> gate_substitution;
1653 
1654  for (u32 select_idx = 0; select_idx < select_pins.size(); select_idx++)
1655  {
1656  auto gate_substitution_val = ((select_val >> select_idx) & 0x1) ? BooleanFunction::Const(1, 1) : BooleanFunction::Const(0, 1);
1657  gate_substitution.insert({BooleanFunctionNetDecorator(*(select_signals.at(select_idx))).get_boolean_variable_name(), gate_substitution_val});
1658  }
1659 
1660  auto gate_substitution_res = gate_bf.substitute(gate_substitution);
1661  if (gate_substitution_res.is_error())
1662  {
1663  return ERR_APPEND(gate_substitution_res.get_error(), "cannot unify mux select signals: failed to substitute gate Boolean function with select signal value mapping.");
1664  }
1665  auto input_net_var = gate_substitution_res.get().simplify_local();
1666  auto net_res = BooleanFunctionNetDecorator::get_net_from(nl, input_net_var);
1667 
1668  if (net_res.is_error())
1669  {
1670  return ERR_APPEND(net_res.get_error(), "cannot unify mux select signals: failed to extract net from substituted and simplified gate Boolean function");
1671  }
1672 
1673  auto net = net_res.get();
1674  new_net_to_pin[g][pin] = net;
1675  }
1676  }
1677 
1678  // apply new pin/net mapping to all gates
1679  for (auto& [g, pin_net] : new_net_to_pin)
1680  {
1681  for (const auto& [pin, net] : pin_net)
1682  {
1683  auto connected_net = g->get_fan_in_net(pin);
1684  if (net == connected_net)
1685  {
1686  continue;
1687  }
1688 
1689  connected_net->remove_destination(g, pin);
1690  net->add_destination(g, pin);
1691 
1692  changed_connections += 1;
1693  }
1694  }
1695  }
1696 
1697  return OK(changed_connections);
1698  }
1699  } // namespace
1700 
1702  {
1703  u32 res_count = 0;
1704 
1705  if (nl == nullptr)
1706  {
1707  return ERR("netlist is a nullptr");
1708  }
1709 
1710  if (mux_inv_gl == nullptr)
1711  {
1712  return ERR("gate library is a nullptr");
1713  }
1714 
1715  auto remove_res = remove_encasing_inverters(nl);
1716  if (remove_res.is_error())
1717  {
1718  return ERR_APPEND(remove_res.get_error(), "unable to apply manual mux optimizations: failed to remove encasing inverters");
1719  }
1720  res_count += remove_res.get();
1721 
1722  auto unify_inverted_res = unify_inverted_select_signals(nl, mux_inv_gl);
1723  if (unify_inverted_res.is_error())
1724  {
1725  return ERR_APPEND(unify_inverted_res.get_error(), "unable to apply manual mux optimizations: failed to unify inverted select signals");
1726  }
1727  res_count += unify_inverted_res.get();
1728 
1729  auto unify_res = unify_select_signals(nl);
1730  if (unify_res.is_error())
1731  {
1732  return ERR_APPEND(unify_res.get_error(), "unable to apply manual mux optimizations: failed to unify select signals");
1733  }
1734  res_count += unify_res.get();
1735 
1736  return OK(res_count);
1737  }
1738 
1739  Result<u32> propagate_constants(Netlist* nl, const std::vector<Gate*>& gates)
1740  {
1741  if (nl == nullptr)
1742  {
1743  return ERR("netlist is a nullptr");
1744  }
1745 
1746  const GateScope scope(gates);
1747 
1748  Net* gnd_net = nl->get_gnd_gates().empty() ? nullptr : nl->get_gnd_gates().front()->get_fan_out_nets().front();
1749  Net* vcc_net = nl->get_vcc_gates().empty() ? nullptr : nl->get_vcc_gates().front()->get_fan_out_nets().front();
1750 
1751  u32 total_replaced_dst_count = 0;
1752 
1753  while (true)
1754  {
1755  u32 replaced_dst_count = 0;
1756  std::vector<Gate*> to_delete;
1757  // re-queried every round so that gates deleted in a previous round are never revisited, the scope
1758  // keeps the propagation from cascading into gates the caller did not select
1759  for (const auto g : nl->get_gates([&scope](const auto g) {
1760  return scope.contains(g) && g->get_type()->has_property(GateTypeProperty::combinational) && !g->get_type()->has_property(GateTypeProperty::ground)
1761  && !g->get_type()->has_property(GateTypeProperty::power);
1762  }))
1763  {
1764  bool has_global_output = false;
1765  for (const auto ep : g->get_fan_out_endpoints())
1766  {
1767  if (ep->get_net()->is_global_output_net())
1768  {
1769  has_global_output = true;
1770  }
1771 
1772  auto bf_res = g->get_resolved_boolean_function(ep->get_pin(), false);
1773  if (bf_res.is_error())
1774  {
1775  return ERR_APPEND(bf_res.get_error(),
1776  "unable to propagate constants: failed to generate boolean function at gate " + g->get_name() + " with ID " + std::to_string(g->get_id()) + " for pin "
1777  + ep->get_pin()->get_name());
1778  }
1779  auto bf = bf_res.get();
1781  if (sub_res.is_error())
1782  {
1783  return ERR_APPEND(bf_res.get_error(),
1784  "unable to propagate constants: failed to substitue power and ground nets in boolean function of gate " + g->get_name() + " with ID "
1785  + std::to_string(g->get_id()) + " for pin " + ep->get_pin()->get_name());
1786  }
1787  bf = sub_res.get();
1788  bf = bf.simplify_local();
1789 
1790  // if boolean function of output pin can be simplified to a constant connect all its successors to gnd/vcc instead
1791  if (bf.is_constant())
1792  {
1793  Net* new_source;
1794  if (bf.has_constant_value(0))
1795  {
1796  new_source = gnd_net;
1797  }
1798  else if (bf.has_constant_value(1))
1799  {
1800  new_source = vcc_net;
1801  }
1802  else
1803  {
1804  continue;
1805  }
1806 
1807  if (new_source == nullptr)
1808  {
1809  // log_error("netlist_preprocessing", "failed to replace bf {} with constant net because netlist is missing GND gate or VCC gate");
1810  return ERR("unable to propagate constants: netlist is missing gnd or vcc net!");
1811  }
1812 
1813  std::vector<std::pair<Gate*, GatePin*>> to_replace;
1814  for (auto dst : ep->get_net()->get_destinations())
1815  {
1816  to_replace.push_back({dst->get_gate(), dst->get_pin()});
1817  }
1818 
1819  for (const auto& [dst_g, dst_p] : to_replace)
1820  {
1821  ep->get_net()->remove_destination(dst_g, dst_p);
1822  new_source->add_destination(dst_g, dst_p);
1823 
1824  replaced_dst_count++;
1825  }
1826 
1827  nl->delete_net(ep->get_net());
1828  }
1829  }
1830 
1831  if (!has_global_output && g->get_successors().empty())
1832  {
1833  to_delete.push_back(g);
1834  }
1835  }
1836 
1837  for (auto g : to_delete)
1838  {
1839  nl->delete_gate(g);
1840  }
1841 
1842  if (replaced_dst_count == 0)
1843  {
1844  break;
1845  }
1846 
1847  log_debug("netlist_preprocessing", "replaced {} destinations this with power/ground nets this iteration", replaced_dst_count);
1848  total_replaced_dst_count += replaced_dst_count;
1849  }
1850 
1851  log_info("netlist_preprocessing", "replaced {} destinations with power/ground nets in total", total_replaced_dst_count);
1852  return OK(total_replaced_dst_count);
1853  }
1854 
1855  Result<u32> remove_consecutive_inverters(Netlist* nl, const std::vector<Gate*>& gates)
1856  {
1857  if (nl == nullptr)
1858  {
1859  return ERR("netlist is a nullptr");
1860  }
1861 
1862  const GateScope scope(gates);
1863 
1864  std::set<Gate*> gates_to_delete;
1865  for (auto* inv_gate : scope.gates(nl, [](const Gate* g) { return g->get_type()->has_property(GateTypeProperty::c_inverter); }))
1866  {
1867  if (gates_to_delete.find(inv_gate) != gates_to_delete.end())
1868  {
1869  continue;
1870  }
1871 
1872  const auto& connection_endpoints = inv_gate->get_fan_in_endpoints();
1873  if (connection_endpoints.size() != 1)
1874  {
1875  log_warning("netlist_preprocessing", "could not handle gate '{}' with ID {} due to a fan-in size != 1", inv_gate->get_name(), inv_gate->get_id());
1876  continue;
1877  }
1878 
1879  auto* middle_fan_in_ep = connection_endpoints.front();
1880  auto* middle_net = middle_fan_in_ep->get_net();
1881  if (middle_net->get_sources().size() != 1)
1882  {
1883  log_warning("netlist_preprocessing", "could not handle gate '{}' with ID {} due to a number of predecessors != 1", inv_gate->get_name(), inv_gate->get_id());
1884  continue;
1885  }
1886  auto* pred_gate = middle_net->get_sources().front()->get_gate();
1887 
1888  // both inverters of the pair have to be in scope, even if only the second one ends up being deleted
1889  if (!scope.contains(pred_gate))
1890  {
1891  continue;
1892  }
1893 
1894  if (pred_gate->get_type()->has_property(GateTypeProperty::c_inverter))
1895  {
1896  const auto& fan_in = pred_gate->get_fan_in_endpoints();
1897  if (fan_in.size() != 1)
1898  {
1899  log_warning("netlist_preprocessing", "could not handle gate '{}' with ID {} due to a fan-in size != 1", pred_gate->get_name(), pred_gate->get_id());
1900  continue;
1901  }
1902  if (pred_gate->get_fan_out_endpoints().size() != 1)
1903  {
1904  log_warning("netlist_preprocessing", "could not handle gate '{}' with ID {} due to a fan-out size != 1", pred_gate->get_name(), pred_gate->get_id());
1905  continue;
1906  }
1907  auto* in_net = fan_in.front()->get_net();
1908 
1909  const auto& fan_out = inv_gate->get_fan_out_endpoints();
1910  if (fan_out.size() != 1)
1911  {
1912  log_warning("netlist_preprocessing", "could not handle gate '{}' with ID {} due to a fan-out size != 1", inv_gate->get_name(), inv_gate->get_id());
1913  continue;
1914  }
1915  auto* out_net = fan_out.front()->get_net();
1916 
1917  for (auto* dst_ep : out_net->get_destinations())
1918  {
1919  auto* dst_pin = dst_ep->get_pin();
1920  auto* dst_gate = dst_ep->get_gate();
1921 
1922  out_net->remove_destination(dst_ep);
1923  in_net->add_destination(dst_gate, dst_pin);
1924  }
1925 
1926  middle_net->remove_destination(middle_fan_in_ep);
1927 
1928  if (middle_net->get_num_of_destinations() == 0)
1929  {
1930  nl->delete_net(middle_net);
1931  gates_to_delete.insert(pred_gate);
1932  }
1933 
1934  gates_to_delete.insert(inv_gate);
1935  }
1936  }
1937 
1938  u32 removed_ctr = 0;
1939  for (auto* g : gates_to_delete)
1940  {
1941  nl->delete_gate(g);
1942  removed_ctr++;
1943  }
1944 
1945  return OK(removed_ctr);
1946  }
1947 
1948  namespace
1949  {
1950  std::string generate_hex_truth_table_string(const std::vector<BooleanFunction::Value>& tt)
1951  {
1952  std::string tt_str = "";
1953 
1954  u32 acc = 0;
1955  for (u32 i = 0; i < tt.size(); i++)
1956  {
1957  const BooleanFunction::Value bit = tt.at(i);
1958  if (bit == BooleanFunction::Value::ONE)
1959  {
1960  acc += (1 << (i % 4));
1961  }
1962 
1963  if ((i % 4) == 3)
1964  {
1965  std::stringstream stream;
1966  stream << std::hex << acc;
1967 
1968  tt_str = stream.str() + tt_str;
1969 
1970  acc = 0;
1971  }
1972  }
1973 
1974  return tt_str;
1975  }
1976  } // namespace
1977 
1978  Result<u32> simplify_lut_inits(Netlist* nl, const std::vector<Gate*>& gates)
1979  {
1980  u32 num_inits = 0;
1981 
1982  const GateScope scope(gates);
1983 
1984  for (auto g : scope.gates(nl, [](const auto& g) { return g->get_type()->has_property(GateTypeProperty::c_lut); }))
1985  {
1986  auto res = g->get_init_data();
1987  if (res.is_error())
1988  {
1989  return ERR_APPEND(res.get_error(),
1990  "unable to simplify lut init string for gate " + g->get_name() + " with ID " + std::to_string(g->get_id()) + ": failed to get original INIT string");
1991  }
1992 
1993  const auto original_inits = res.get();
1994 
1995  if (original_inits.size() != 1)
1996  {
1997  return ERR("unable to simplify lut init string for gate " + g->get_name() + " with ID " + std::to_string(g->get_id()) + ": found " + std::to_string(original_inits.size())
1998  + " init data strings but expected exactly 1.");
1999  }
2000 
2001  const auto original_init = original_inits.front();
2002 
2003  // skip if the gate type has more than one fan out endpoints
2004  if (g->get_type()->get_output_pins().size() != 1)
2005  {
2006  continue;
2007  }
2008 
2009  // skip if the output pin is not connected, there is nothing to simplify then
2010  if (g->get_fan_out_endpoints().empty())
2011  {
2012  continue;
2013  }
2014 
2015  const auto out_ep = g->get_fan_out_endpoints().front();
2016 
2017  // skip if the gate has more than one boolean function
2018  if (g->get_boolean_functions().size() != 1)
2019  {
2020  continue;
2021  }
2022 
2023  const auto bf_org = g->get_boolean_function(out_ep->get_pin());
2024  const auto org_vars = bf_org.get_variable_names();
2025 
2026  const auto bf_replaced_res = BooleanFunctionDecorator(bf_org).substitute_power_ground_pins(g);
2027  if (bf_replaced_res.is_error())
2028  {
2029  return ERR_APPEND(bf_replaced_res.get_error(),
2030  "cannot simplify LUT inits: failed to replace power and ground pins for gate " + g->get_name() + " with ID " + std::to_string(g->get_id()));
2031  }
2032  const auto bf_replaced = bf_replaced_res.get();
2033  const auto bf_simplified = bf_replaced.simplify_local();
2034 
2035  const auto new_vars = bf_simplified.get_variable_names();
2036 
2037  if (org_vars.size() == new_vars.size())
2038  {
2039  continue;
2040  }
2041 
2042  auto bf_extended = bf_simplified.clone();
2043  for (const auto& in_pin : g->get_type()->get_input_pin_names())
2044  {
2045  if (new_vars.find(in_pin) == new_vars.end())
2046  {
2047  auto bf_filler = BooleanFunction::Var(in_pin) | (~BooleanFunction::Var(in_pin));
2048  bf_extended = BooleanFunction::And(std::move(bf_extended), std::move(bf_filler), 1).get();
2049  }
2050  }
2051 
2052  const auto tt = bf_extended.compute_truth_table().get();
2053  const auto new_init_string = generate_hex_truth_table_string(tt.front());
2054 
2055  // std::cout << "Org Init: " << g->get_init_data().get().front() << std::endl;
2056  // std::cout << "New Init: " << new_init_string << std::endl;
2057 
2058  g->set_init_data({new_init_string}).get();
2059  g->set_data("preprocessing_information", "original_init", "string", original_init);
2060 
2061  // const auto bf_test = g->get_boolean_function(out_ep->get_pin());
2062 
2063  // std::cout << "Org: " << bf_org << std::endl;
2064  // std::cout << "Rep: " << bf_replaced << std::endl;
2065  // std::cout << "Simp: " << bf_simplified << std::endl;
2066  // std::cout << "Test: " << bf_test << std::endl;
2067  // std::cout << "Ext: " << bf_extended << std::endl;
2068 
2069  num_inits++;
2070  }
2071 
2072  log_info("netlist_preprocessing", "simplified {} LUT INIT strings inside of netlist with ID {}.", num_inits, nl->get_id());
2073  return OK(num_inits);
2074  }
2075 
2076  namespace
2077  {
2078  struct indexed_identifier
2079  {
2080  indexed_identifier(const std::string& p_identifier, const u32 p_index, const std::string& p_origin) : identifier{p_identifier}, index{p_index}, origin{p_origin}
2081  {
2082  }
2083 
2084  std::string identifier;
2086  std::string origin;
2087  };
2088 
2089  // TODO when the verilog parser changes are merged into the master this will no longer be needed
2090  const std::string hal_instance_index_pattern = "__\\[(\\d+)\\]__";
2091  const std::string hal_instance_index_pattern_reverse = "<HAL>(\\d+)<HAL>";
2092 
2093  std::string replace_hal_instance_index(const std::string& name)
2094  {
2095  std::regex re(hal_instance_index_pattern);
2096 
2097  std::string input = name;
2098  std::string index;
2099  std::smatch match;
2100  while (std::regex_search(input, match, re))
2101  {
2102  index = match[1];
2103  input = utils::replace(input, match.str(), "<HAL>" + index + "<HAL>");
2104  }
2105 
2106  return input;
2107  }
2108 
2109  std::string reconstruct_hal_instance_index(const std::string& name)
2110  {
2111  std::regex re(hal_instance_index_pattern_reverse);
2112 
2113  std::string input = name;
2114  std::string index;
2115  std::smatch match;
2116  while (std::regex_search(input, match, re))
2117  {
2118  index = match[1];
2119  input = utils::replace(input, match.str(), "__[" + index + "]__");
2120  }
2121 
2122  return input;
2123  }
2124 
2125  const std::string net_index_pattern = "\\((\\d+)\\)";
2126  const std::string gate_index_pattern = "\\[(\\d+)\\]";
2127 
2128  // Extracts an index from a string by taking the last integer enclosed by parentheses
2129  std::optional<indexed_identifier> extract_index(const std::string& name, const std::string& index_pattern, const std::string& origin)
2130  {
2131  std::regex re(index_pattern);
2132 
2133  std::string input = name;
2134  std::optional<std::string> last_match;
2135  std::optional<u32> last_index;
2136 
2137  // Search for last match within string
2138  std::smatch match;
2139  while (std::regex_search(input, match, re))
2140  {
2141  // Capture integer and update input string to search from after the match
2142  last_index = std::stoi(match[1]);
2143  last_match = match.str();
2144  input = match.suffix().str();
2145  }
2146 
2147  if (!last_index.has_value())
2148  {
2149  return std::nullopt;
2150  }
2151 
2152  const auto found_match = last_match.value();
2153  auto identifier_name = name;
2154  identifier_name = identifier_name.replace(name.rfind(found_match), found_match.size(), "");
2155 
2156  return std::optional<indexed_identifier>{{identifier_name, last_index.value(), origin}};
2157  }
2158 
2159  // annotate all found identifiers to a gate
2160  bool annotate_indexed_identifiers(Gate* gate, const std::vector<indexed_identifier>& identifiers)
2161  {
2162  std::string json_identifier_str =
2163  "[" + utils::join(", ", identifiers, [](const auto& i) { return std::string("[") + '"' + i.identifier + '"' + ", " + std::to_string(i.index) + ", " + '"' + i.origin + '"' + "]"; })
2164  + "]";
2165 
2166  return gate->set_data("preprocessing_information", "multi_bit_indexed_identifiers", "string", json_identifier_str);
2167  }
2168 
2169  // search for a net that connects to the gate at a pin of a specific type and tries to reconstruct an indexed identifier from its name or form a name of its merged wires
2170  std::vector<indexed_identifier> check_net_at_pin(const PinType pin_type, Gate* gate)
2171  {
2172  const auto typed_pins = gate->get_type()->get_pins([pin_type](const auto p) { return p->get_type() == pin_type; });
2173 
2174  std::vector<indexed_identifier> found_identfiers;
2175 
2176  for (const auto& pin : typed_pins)
2177  {
2178  const auto typed_net = (pin->get_direction() == PinDirection::output) ? gate->get_fan_out_net(pin) : gate->get_fan_in_net(pin);
2179 
2180  // 0) make sure pin is connected to net
2181  if (! typed_net)
2182  {
2183  continue;
2184  }
2185 
2186  // 1) search the net name itself
2187  const auto net_name_index = extract_index(typed_net->get_name(), net_index_pattern, "net_name");
2188  if (net_name_index.has_value())
2189  {
2190  found_identfiers.push_back(net_name_index.value());
2191  }
2192 
2193  // 2) search all the names of the wires that where merged into this net
2194  if (!typed_net->has_data("parser_annotation", "merged_nets"))
2195  {
2196  continue;
2197  }
2198 
2199  const auto all_merged_nets_str = std::get<1>(typed_net->get_data("parser_annotation", "merged_nets"));
2200 
2201  if (all_merged_nets_str.empty())
2202  {
2203  continue;
2204  }
2205 
2206  // parse json list of merged net names
2207  rapidjson::Document doc;
2208  doc.Parse(all_merged_nets_str.c_str());
2209 
2210  for (u32 i = 0; i < doc.GetArray().Size(); i++)
2211  {
2212  const auto list = doc[i].GetArray();
2213  for (u32 j = 0; j < list.Size(); j++)
2214  {
2215  const auto merged_wire_name = list[j].GetString();
2216 
2217  const auto merged_wire_name_index = extract_index(merged_wire_name, net_index_pattern, "net_name");
2218  if (merged_wire_name_index.has_value())
2219  {
2220  found_identfiers.push_back(merged_wire_name_index.value());
2221  }
2222  }
2223  }
2224  }
2225 
2226  return found_identfiers;
2227  }
2228  } // namespace
2229 
2231  {
2232  u32 counter = 0;
2233  for (auto& ff : nl->get_gates([](const auto g) { return g->get_type()->has_property(GateTypeProperty::ff); }))
2234  {
2235  std::vector<indexed_identifier> all_identifiers;
2236 
2237  // 1) Check whether the ff gate already has an index annotated in its gate name
2238  const auto cleaned_gate_name = replace_hal_instance_index(ff->get_name());
2239  const auto gate_name_index = extract_index(cleaned_gate_name, gate_index_pattern, "gate_name");
2240 
2241  if (gate_name_index.has_value())
2242  {
2243  auto found_identifier = gate_name_index.value();
2244  found_identifier.identifier = reconstruct_hal_instance_index(found_identifier.identifier);
2245  all_identifiers.push_back(found_identifier);
2246  }
2247 
2248  static const std::vector<PinType> relevant_pin_types = {PinType::state, PinType::neg_state, PinType::data};
2249 
2250  // 2) Check all relevant pin_types
2251  for (const auto& pt : relevant_pin_types)
2252  {
2253  const auto found_identifiers = check_net_at_pin(pt, ff);
2254  all_identifiers.insert(all_identifiers.end(), found_identifiers.begin(), found_identifiers.end());
2255  }
2256 
2257  if (!all_identifiers.empty())
2258  {
2259  counter++;
2260  }
2261 
2262  annotate_indexed_identifiers(ff, all_identifiers);
2263  }
2264 
2265  return OK(counter);
2266  }
2267 
2269  {
2270  std::map<std::string, std::map<u32, std::vector<ModulePin*>>> pg_name_to_indexed_pins;
2271 
2272  for (const auto& pin : nl->get_top_module()->get_pins())
2273  {
2274  auto reconstruct = extract_index(pin->get_name(), net_index_pattern, "");
2275  if (!reconstruct.has_value())
2276  {
2277  continue;
2278  }
2279 
2280  auto [pg_name, index, _] = reconstruct.value();
2281 
2282  pg_name_to_indexed_pins[pg_name][index].push_back(pin);
2283  }
2284 
2285  u32 reconstructed_counter = 0;
2286  for (const auto& [pg_name, indexed_pins] : pg_name_to_indexed_pins)
2287  {
2288  std::vector<ModulePin*> ordered_pins;
2289 
2290  bool valid_indices = true;
2291  // NOTE: since the map already orders the indices from low to high, if we iterate over it we also get the pins in the right order
2292  for (const auto& [_index, pins] : indexed_pins)
2293  {
2294  if (pins.size() > 1)
2295  {
2296  valid_indices = false;
2297  break;
2298  }
2299 
2300  ordered_pins.push_back(pins.front());
2301  }
2302 
2303  if (!valid_indices)
2304  {
2305  continue;
2306  }
2307 
2308  auto res = nl->get_top_module()->create_pin_group(pg_name, ordered_pins);
2309  if (res.is_error())
2310  {
2311  return ERR_APPEND(res.get_error(), "cannot reconstruct top module pin groups: failed to create pin group " + pg_name);
2312  }
2313 
2314  reconstructed_counter++;
2315  }
2316 
2317  return OK(reconstructed_counter);
2318  }
2319 
2320  namespace
2321  {
2322  struct ComponentData
2323  {
2324  std::string name;
2325  std::string type;
2328  };
2329 
2330  TokenStream<std::string> tokenize(std::stringstream& ss)
2331  {
2332  const std::string delimiters = " ;-";
2333  std::string current_token;
2334  u32 line_number = 0;
2335 
2336  std::string line;
2337  bool escaped = false;
2338 
2339  std::vector<Token<std::string>> parsed_tokens;
2340  while (std::getline(ss, line))
2341  {
2342  line_number++;
2343 
2344  for (char c : line)
2345  {
2346  // deal with escaping and strings
2347  if (c == '\\')
2348  {
2349  escaped = true;
2350  continue;
2351  }
2352  else if (escaped && std::isspace(c))
2353  {
2354  escaped = false;
2355  continue;
2356  }
2357 
2358  if (((!std::isspace(c) && delimiters.find(c) == std::string::npos) || escaped))
2359  {
2360  current_token += c;
2361  }
2362  else
2363  {
2364  if (!current_token.empty())
2365  {
2366  parsed_tokens.emplace_back(line_number, current_token);
2367  current_token.clear();
2368  }
2369 
2370  if (!std::isspace(c))
2371  {
2372  parsed_tokens.emplace_back(line_number, std::string(1, c));
2373  }
2374  }
2375  }
2376 
2377  if (!current_token.empty())
2378  {
2379  parsed_tokens.emplace_back(line_number, current_token);
2380  current_token.clear();
2381  }
2382  }
2383 
2384  return TokenStream(parsed_tokens, {}, {});
2385  }
2386 
2387  Result<std::unordered_map<std::string, ComponentData>> parse_tokens(TokenStream<std::string>& ts)
2388  {
2389  ts.consume_until("COMPONENTS");
2390  ts.consume("COMPONENTS");
2391  const auto component_count_str = ts.consume().string;
2392  ts.consume(";");
2393 
2394  u32 component_count;
2395  if (const auto res = utils::wrapped_stoul(component_count_str); res.is_ok())
2396  {
2397  component_count = res.get();
2398  }
2399  else
2400  {
2401  return ERR_APPEND(res.get_error(), "could not parse tokens: failed to read component count from token" + component_count_str);
2402  }
2403 
2404  std::cout << "Component count: " << component_count << std::endl;
2405 
2406  std::unordered_map<std::string, ComponentData> component_data;
2407  for (u32 c_idx = 0; c_idx < component_count; c_idx++)
2408  {
2409  // parse a line
2410  ComponentData new_data_entry;
2411  ts.consume("-");
2412  new_data_entry.name = ts.consume().string;
2413  new_data_entry.type = ts.consume().string;
2414  ts.consume("+");
2415  ts.consume("SOURCE");
2416  ts.consume("DIST");
2417  ts.consume("TIMING");
2418  ts.consume("+");
2419  ts.consume("PLACED");
2420  ts.consume("FIXED");
2421  ts.consume("(");
2422 
2423  if (const auto res = utils::wrapped_stoull(ts.consume().string); res.is_ok())
2424  {
2425  new_data_entry.x = res.get();
2426  }
2427  else
2428  {
2429  return ERR_APPEND(res.get_error(), "could not parse tokens: failed to read x coordinate from token");
2430  }
2431 
2432  if (const auto res = utils::wrapped_stoull(ts.consume().string); res.is_ok())
2433  {
2434  new_data_entry.y = res.get();
2435  }
2436  else
2437  {
2438  return ERR_APPEND(res.get_error(), "could not parse tokens: failed to read y coordinate from token");
2439  }
2440 
2441  ts.consume(")");
2442 
2443  ts.consume_current_line();
2444 
2445  component_data.insert({new_data_entry.name, new_data_entry});
2446  }
2447 
2448  return OK(component_data);
2449  }
2450  } // namespace
2451 
2452  Result<std::monostate> parse_def_file(Netlist* nl, const std::filesystem::path& def_file)
2453  {
2454  std::stringstream ss;
2455  std::ifstream ifs;
2456  ifs.open(def_file.string(), std::ifstream::in);
2457  if (!ifs.is_open())
2458  {
2459  return ERR("could not parse DEF (Design Exchange Format) file '" + def_file.string() + "' : unable to open file");
2460  }
2461  ss << ifs.rdbuf();
2462  ifs.close();
2463 
2464  auto ts = tokenize(ss);
2465 
2466  std::unordered_map<std::string, ComponentData> component_data;
2467  // parse tokens
2468  try
2469  {
2470  if (auto res = parse_tokens(ts); res.is_error())
2471  {
2472  return ERR_APPEND(res.get_error(), "could not parse Design Exchange Format file '" + def_file.string() + "': unable to parse tokens");
2473  }
2474  else
2475  {
2476  component_data = res.get();
2477  }
2478  }
2480  {
2481  if (e.line_number != (u32)-1)
2482  {
2483  return ERR("could not parse Design Exchange Format file '" + def_file.string() + "': " + e.message + " (line " + std::to_string(e.line_number) + ")");
2484  }
2485  else
2486  {
2487  return ERR("could not parse Design Exchange Format file '" + def_file.string() + "': " + e.message);
2488  }
2489  }
2490 
2491  std::unordered_map<std::string, Gate*> name_to_gate;
2492  for (auto g : nl->get_gates())
2493  {
2494  name_to_gate.insert({g->get_name(), g});
2495  }
2496 
2497  u32 counter = 0;
2498  for (const auto& [gate_name, data] : component_data)
2499  {
2500  if (const auto& g_it = name_to_gate.find(gate_name); g_it != name_to_gate.end())
2501  {
2502  // TODO figure out whereever we are saving coordinates now...
2503  g_it->second->set_location_x(data.x);
2504  g_it->second->set_location_y(data.y);
2505 
2506  counter++;
2507  }
2508  }
2509 
2510  log_info("netlist_preprocessing", "reconstructed coordinates for {} / {} ({:.2}) gates", counter, nl->get_gates().size(), (double)counter / (double)nl->get_gates().size());
2511 
2512  return OK({});
2513  }
2514 
2515  Result<std::vector<Module*>> create_multi_bit_gate_modules(Netlist* nl, const std::map<std::string, std::map<std::string, std::vector<std::string>>>& concatenated_pin_groups)
2516  {
2517  std::vector<Module*> all_modules;
2518  for (const auto& [gt_name, pin_groups] : concatenated_pin_groups)
2519  {
2520  const auto& gt = nl->get_gate_library()->get_gate_type_by_name(gt_name);
2521  if (gt == nullptr)
2522  {
2523  return ERR("unable to create multi bit gate module for gate type " + gt_name + ": failed to find gate type with that name in gate library " + nl->get_gate_library()->get_name());
2524  }
2525 
2526  for (const auto& g : nl->get_gates([&gt](const auto& g) { return g->get_type() == gt; }))
2527  {
2528  auto m = nl->create_module("module_" + g->get_name(), g->get_module(), {g});
2529 
2530  for (const auto& [module_pg_name, gate_pg_names] : pin_groups)
2531  {
2532  std::vector<ModulePin*> module_pins;
2533  for (const auto& gate_pg_name : gate_pg_names)
2534  {
2535  const auto& gate_pg = g->get_type()->get_pin_group_by_name(gate_pg_name);
2536 
2537  if (gate_pg == nullptr)
2538  {
2539  return ERR("unable to create multi-bit gate module for gate type " + gt_name + " and pin group " + gate_pg_name + ": failed to find pin group with that name");
2540  }
2541 
2542  std::vector<GatePin*> pin_list = gate_pg->get_pins();
2543  if (!gate_pg->is_ascending())
2544  {
2545  std::reverse(pin_list.begin(), pin_list.end());
2546  }
2547 
2548  for (const auto& gate_pin : pin_list)
2549  {
2550  const auto net = (gate_pin->get_direction() == PinDirection::output) ? g->get_fan_out_net(gate_pin) : g->get_fan_in_net(gate_pin);
2551  if (net == nullptr)
2552  {
2553  continue;
2554  }
2555 
2556  if (net->is_gnd_net() || net->is_vcc_net())
2557  {
2558  continue;
2559  }
2560 
2561  const auto module_pin = m->get_pin_by_net(net);
2562 
2563  module_pins.push_back(module_pin);
2564  }
2565  }
2566 
2567  m->create_pin_group(module_pg_name, module_pins);
2568  u32 idx_counter = 0;
2569  for (const auto& mp : module_pins)
2570  {
2571  m->set_pin_name(mp, module_pg_name + "_" + std::to_string(idx_counter));
2572  idx_counter++;
2573  }
2574  }
2575 
2576  all_modules.push_back(m);
2577  }
2578  }
2579 
2580  return OK(all_modules);
2581  }
2582 
2584  {
2585  std::vector<Net*> created_nets;
2586 
2587  const GateScope scope(gates);
2588 
2589  for (const auto& g : scope.gates(nl))
2590  {
2591  for (const auto& p : g->get_type()->get_output_pins())
2592  {
2593  if (g->get_fan_out_net(p) == nullptr)
2594  {
2595  auto new_net = nl->create_net("TEMP");
2596  new_net->set_name("HAL_UNCONNECTED_" + std::to_string(new_net->get_id()));
2597  new_net->add_source(g, p);
2598 
2599  created_nets.push_back(new_net);
2600  }
2601  }
2602  }
2603 
2604  return OK(created_nets);
2605  }
2606 
2607  Result<u32> unify_ff_outputs(Netlist* nl, const std::vector<Gate*>& ffs, GateType* inverter_type)
2608  {
2609  if (nl == nullptr)
2610  {
2611  return ERR("netlist is a nullptr");
2612  }
2613 
2614  if (inverter_type == nullptr)
2615  {
2616  const auto* gl = nl->get_gate_library();
2617  const auto inv_types =
2618  gl->get_gate_types([](const GateType* gt) { return gt->has_property(GateTypeProperty::c_inverter) && gt->get_input_pins().size() == 1 && gt->get_output_pins().size() == 1; });
2619  if (inv_types.empty())
2620  {
2621  return ERR("gate library '" + gl->get_name() + "' of netlist does not contain an inverter gate");
2622  }
2623  inverter_type = inv_types.begin()->second;
2624  }
2625  else
2626  {
2627  if (inverter_type->get_gate_library() != nl->get_gate_library())
2628  {
2629  return ERR("inverter gate type '" + inverter_type->get_name() + "' of gate library '" + inverter_type->get_gate_library()->get_name() + "' does not belong to gate library '"
2630  + nl->get_gate_library()->get_name() + "' of provided netlist");
2631  }
2632 
2633  if (!inverter_type->has_property(GateTypeProperty::c_inverter))
2634  {
2635  return ERR("gate type '" + inverter_type->get_name() + "' of gate library '" + inverter_type->get_gate_library()->get_name() + "' is not an inverter gate type");
2636  }
2637 
2638  if (inverter_type->get_input_pins().size() != 1 || inverter_type->get_output_pins().size() != 1)
2639  {
2640  return ERR("inverter gate type '" + inverter_type->get_name() + "' of gate library '" + inverter_type->get_gate_library()->get_name()
2641  + "' has an invalid number of input pins or output pins");
2642  }
2643  }
2644 
2645  auto inv_in_pin = inverter_type->get_input_pins().front();
2646  auto inv_out_pin = inverter_type->get_output_pins().front();
2647 
2648  u32 ctr = 0;
2649 
2650  const std::vector<Gate*>& gates = ffs.empty() ? nl->get_gates() : ffs;
2651 
2652  for (auto* ff : gates)
2653  {
2654  auto* ff_type = ff->get_type();
2655 
2656  if (!ff_type->has_property(GateTypeProperty::ff))
2657  {
2658  continue;
2659  }
2660 
2661  GatePin* state_pin = nullptr;
2662  GatePin* neg_state_pin = nullptr;
2663 
2664  for (auto* o_pin : ff_type->get_output_pins())
2665  {
2666  if (o_pin->get_type() == PinType::state)
2667  {
2668  state_pin = o_pin;
2669  }
2670  else if (o_pin->get_type() == PinType::neg_state)
2671  {
2672  neg_state_pin = o_pin;
2673  }
2674  }
2675 
2676  if (neg_state_pin == nullptr)
2677  {
2678  continue;
2679  }
2680 
2681  auto* neg_state_ep = ff->get_fan_out_endpoint(neg_state_pin);
2682  if (neg_state_ep == nullptr)
2683  {
2684  continue;
2685  }
2686  auto* neg_state_net = neg_state_ep->get_net();
2687 
2688  auto state_net = ff->get_fan_out_net(state_pin);
2689  if (state_net == nullptr)
2690  {
2691  state_net = nl->create_net(ff->get_name() + "__STATE_NET__");
2692  state_net->add_source(ff, state_pin);
2693  }
2694 
2695  auto* inv = nl->create_gate(inverter_type, ff->get_name() + "__NEG_STATE_INVERT__");
2696 
2697  // keep the new inverter within the module of the flip-flop it belongs to instead of the top module
2698  if (auto* mod = ff->get_module(); !mod->is_top_module())
2699  {
2700  mod->assign_gate(inv);
2701  }
2702 
2703  state_net->add_destination(inv, inv_in_pin);
2704  neg_state_net->remove_source(neg_state_ep);
2705  neg_state_net->add_source(inv, inv_out_pin);
2706  ctr++;
2707  }
2708 
2709  return OK(ctr);
2710  }
2711  } // namespace netlist_preprocessing
2712 } // namespace hal
const std::string & get_name() const
Definition: base_pin.h:110
Result< BooleanFunction > substitute_power_ground_nets(const Netlist *nl) const
Result< BooleanFunction > substitute_power_ground_pins(const Gate *g) const
static Result< BooleanFunction > Eq(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static BooleanFunction Var(const std::string &name, u16 size=1)
Result< std::string > get_variable_name() const
std::set< std::string > get_variable_names() const
Value
represents the type of the node
BooleanFunction simplify_local() const
static BooleanFunction Const(const BooleanFunction::Value &value)
static Result< BooleanFunction > Not(BooleanFunction &&p0, u16 size)
static Result< BooleanFunction > And(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< Net * > get_net_from(const Netlist *netlist, const BooleanFunction &var)
Net * get_net() const
Definition: endpoint.cpp:33
GatePin * get_pin() const
Definition: endpoint.cpp:28
Definition: gate.h:58
GateType * get_type() const
Definition: gate.cpp:125
Result< BooleanFunction > get_resolved_boolean_function(const GatePin *pin, const bool use_net_variables=false) const
Definition: gate.cpp:287
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
Endpoint * get_predecessor(const std::string &pin_name) const
Definition: gate.cpp:938
Endpoint * get_successor(const std::string &pin_name) const
Definition: gate.cpp:1018
u32 get_id() const
Definition: gate.cpp:95
std::unordered_map< std::string, GateType * > get_gate_types(const std::function< bool(const GateType *)> &filter=nullptr) const
GateType * get_gate_type_by_name(const std::string &name) const
std::string get_name() const
std::vector< std::string > get_input_pin_names() const
Definition: gate_type.cpp:277
GateLibrary * get_gate_library() const
Definition: gate_type.cpp:106
std::vector< GatePin * > get_output_pins() const
Definition: gate_type.cpp:285
const std::string & get_name() const
Definition: gate_type.cpp:64
bool has_property(GateTypeProperty property) const
Definition: gate_type.cpp:101
std::vector< GatePin * > get_input_pins() const
Definition: gate_type.cpp:269
const std::unordered_map< std::string, BooleanFunction > & get_boolean_functions() const
Definition: gate_type.cpp:746
std::vector< GatePin * > get_pins(const std::function< bool(GatePin *)> &filter=nullptr) const
Definition: gate_type.cpp:210
std::vector< ModulePin * > get_pins(const std::function< bool(ModulePin *)> &filter=nullptr) const
Definition: module.cpp:880
Result< PinGroup< ModulePin > * > create_pin_group(const u32 id, const std::string &name, const std::vector< ModulePin * > pins={}, PinDirection direction=PinDirection::none, PinType type=PinType::none, bool ascending=false, u32 start_index=0, bool delete_empty_groups=true, bool force_name=false)
Definition: module.cpp:1260
std::string get_type() const
Definition: module.cpp:107
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
bool remove_source(Gate *gate, const std::string &pin_name)
Definition: net.cpp:169
void set_name(const std::string &name)
Definition: net.cpp:103
Endpoint * add_source(Gate *gate, const std::string &pin_name)
Definition: net.cpp:127
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
Module * get_top_module() const
Definition: netlist.cpp:610
const std::vector< Gate * > & get_gates() const
Definition: netlist.cpp:206
bool delete_net(Net *net)
Definition: netlist.cpp:345
Net * create_net(const u32 net_id, const std::string &name)
Definition: netlist.cpp:335
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
Gate * create_gate(const u32 gate_id, GateType *gate_type, const std::string &name="", i32 x=-1, i32 y=-1)
Definition: netlist.cpp:175
const std::vector< Net * > & get_nets() const
Definition: netlist.cpp:366
const GateLibrary * get_gate_library() const
Definition: netlist.cpp:134
Module * create_module(const u32 module_id, const std::string &name, Module *parent, const std::vector< Gate * > &gates={})
Definition: netlist.cpp:589
Result< Net * > connect_nets(Net *master_net, Net *slave_net)
Result< std::set< const Net * > > get_subgraph_function_inputs(const std::vector< const Gate * > &subgraph_gates, const Net *subgraph_output) 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
uint64_t u64
Definition: defines.h:42
uint32_t u32
Definition: defines.h:41
int64_t i64
Definition: defines.h:37
uint8_t u8
Definition: defines.h:39
#define log_debug(channel,...)
Definition: log.h:74
#define log_info(channel,...)
Definition: log.h:70
#define log_warning(channel,...)
Definition: log.h:76
#define ERR(message)
Definition: result.h:60
#define OK(...)
Definition: result.h:56
#define ERR_APPEND(prev_error, message)
Definition: result.h:64
bool save(std::filesystem::path file_path, GateLibrary *gate_lib, bool overwrite=false)
std::unique_ptr< GateLibrary > parse(std::filesystem::path file_path)
Result< std::monostate > parse_def_file(Netlist *nl, const std::filesystem::path &def_file)
Result< u32 > manual_mux_optimizations(Netlist *nl, GateLibrary *mux_inv_gl)
Result< u32 > propagate_constants(Netlist *nl, const std::vector< Gate * > &gates={})
Result< std::vector< Net * > > create_nets_at_unconnected_pins(Netlist *nl, const std::vector< Gate * > &gates={})
Result< u32 > remove_unconnected_gates(Netlist *nl, const std::vector< Gate * > &gates={})
Result< u32 > remove_redundant_loops(Netlist *nl)
Result< u32 > remove_redundant_logic_trees(Netlist *nl)
Result< u32 > remove_redundant_gates(Netlist *nl, const std::function< bool(const Gate *)> &filter=nullptr, const std::vector< Gate * > &gates={})
Result< u32 > reconstruct_top_module_pin_groups(Netlist *nl)
Result< u32 > simplify_lut_inits(Netlist *nl, const std::vector< Gate * > &gates={})
Result< u32 > remove_buffers(Netlist *nl, const std::vector< Gate * > &gates={})
Result< u32 > remove_unused_lut_inputs(Netlist *nl, const std::vector< Gate * > &gates={})
Result< u32 > remove_unconnected_looped(Netlist *nl)
Result< u32 > remove_unconnected_nets(Netlist *nl)
Result< u32 > reconstruct_indexed_ff_identifiers(Netlist *nl)
Result< u32 > remove_consecutive_inverters(Netlist *nl, const std::vector< Gate * > &gates={})
Result< std::vector< Module * > > create_multi_bit_gate_modules(Netlist *nl, const std::map< std::string, std::map< std::string, std::vector< std::string >>> &concatenated_pin_groups)
Result< u32 > unify_ff_outputs(Netlist *nl, const std::vector< Gate * > &ffs={}, GateType *inverter_type=nullptr)
Result< std::monostate > replace_subgraph_with_netlist(const std::vector< Gate * > &subgraph, const std::unordered_map< Net *, std::vector< Net * >> &global_io_mapping, const Netlist *src_nl, Netlist *dst_nl, const bool delete_subgraph_gates)
Result< std::unique_ptr< Netlist > > generate_resynth_netlist_for_boolean_functions(const std::unordered_map< std::string, BooleanFunction > &bfs, const std::filesystem::path &genlib_path, GateLibrary *target_gl, const bool optimize_area)
T replace(const T &str, const T &search, const T &replace)
Definition: utils.h:428
Result< u64 > wrapped_stoull(const std::string &s, const u32 base=10)
Definition: utils.cpp:696
Result< u32 > wrapped_stoul(const std::string &s, const u32 base=10)
Definition: utils.cpp:714
std::string join(const std::string &joiner, const Iterator &begin, const Iterator &end, const Transform &transform)
Definition: utils.h:458
Result< std::filesystem::path > get_unique_temp_directory(const std::string &prefix="", const u32 max_attempts=5)
Definition: utils.cpp:276
Result< bool > compare_nets(const Netlist *netlist_a, const Netlist *netlist_b, const Net *net_a, const Net *net_b, const bool fail_on_unknown=true, const u32 solver_timeout=10)
Compare two nets from two different netlists.
Definition: defines.h:45
PinType
Definition: pin_type.h:36
std::vector< PinInformation > pins
Net * net
std::string identifier
GateType * type
std::string origin
std::string name
std::set< GatePin * > inverters
This file contains functions to decompose or re-synthesize combinational parts of a gate-level netlis...