HAL  v4.5.0-254-g8f9f6a423
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
resynthesis.cpp
Go to the documentation of this file.
8 #include "hal_core/netlist/net.h"
12 #include "hal_core/utilities/log.h"
14 
15 #include <array>
16 #include <cstdlib> // std::getenv
17 #include <filesystem>
18 #include <fstream>
19 #include <string>
20 #include <string_view>
21 
22 namespace hal
23 {
24  namespace yosys
25  {
26  const std::string get_helper_gate_lib()
27  {
28  std::string yosys_gate_lib = "";
29  yosys_gate_lib += "// GND\n";
30  yosys_gate_lib += "module GND (G);\n";
31  yosys_gate_lib += "output G;\n";
32  yosys_gate_lib += "assign G = 1\'b0;\n";
33  yosys_gate_lib += "endmodule\n";
34  yosys_gate_lib += "\n";
35  yosys_gate_lib += "// VCC\n";
36  yosys_gate_lib += "module VCC (P);\n";
37  yosys_gate_lib += "output P;\n";
38  yosys_gate_lib += "assign P = 1\'b1;\n";
39  yosys_gate_lib += "endmodule\n";
40  yosys_gate_lib += "\n";
41  yosys_gate_lib += "// BUF\n";
42  yosys_gate_lib += "module HAL_BUF (A, O);\n";
43  yosys_gate_lib += "input A;\n";
44  yosys_gate_lib += "output O;\n";
45  yosys_gate_lib += "assign O = A;\n";
46  yosys_gate_lib += "endmodule\n";
47  yosys_gate_lib += "\n";
48  yosys_gate_lib += "// INV\n";
49  yosys_gate_lib += "module HAL_INV (A, O);\n";
50  yosys_gate_lib += "input A;\n";
51  yosys_gate_lib += "output O;\n";
52  yosys_gate_lib += "assign O = ~A;\n";
53  yosys_gate_lib += "endmodule\n";
54  yosys_gate_lib += "\n";
55  yosys_gate_lib += "// AND2\n";
56  yosys_gate_lib += "module HAL_AND2 (A, B, O);\n";
57  yosys_gate_lib += "input A, B;\n";
58  yosys_gate_lib += "output O;\n";
59  yosys_gate_lib += "assign O = A & B;\n";
60  yosys_gate_lib += "endmodule\n";
61  yosys_gate_lib += "\n";
62  yosys_gate_lib += "// AND3\n";
63  yosys_gate_lib += "module HAL_AND3 (A, B, C, O);\n";
64  yosys_gate_lib += "input A, B, C;\n";
65  yosys_gate_lib += "output O;\n";
66  yosys_gate_lib += "assign O = A & B & C;\n";
67  yosys_gate_lib += "endmodule\n";
68  yosys_gate_lib += "\n";
69  yosys_gate_lib += "// AND4\n";
70  yosys_gate_lib += "module HAL_AND4 (A, B, C, D, O);\n";
71  yosys_gate_lib += "input A, B, C, D;\n";
72  yosys_gate_lib += "output O;\n";
73  yosys_gate_lib += "assign O = A & B & C & D;\n";
74  yosys_gate_lib += "endmodule\n";
75  yosys_gate_lib += "\n";
76  yosys_gate_lib += "// OR2\n";
77  yosys_gate_lib += "module HAL_OR2 (A, B, O);\n";
78  yosys_gate_lib += "input A, B;\n";
79  yosys_gate_lib += "output O;\n";
80  yosys_gate_lib += "assign O = A | B;\n";
81  yosys_gate_lib += "endmodule\n";
82  yosys_gate_lib += "\n";
83  yosys_gate_lib += "// OR3\n";
84  yosys_gate_lib += "module HAL_OR3 (A, B, C, O);\n";
85  yosys_gate_lib += "input A, B, C;\n";
86  yosys_gate_lib += "output O;\n";
87  yosys_gate_lib += "assign O = A | B | C;\n";
88  yosys_gate_lib += "endmodule\n";
89  yosys_gate_lib += "\n";
90  yosys_gate_lib += "// OR4\n";
91  yosys_gate_lib += "module HAL_OR4 (A, B, C, D, O);\n";
92  yosys_gate_lib += "input A, B, C, D;\n";
93  yosys_gate_lib += "output O;\n";
94  yosys_gate_lib += "assign O = A | B | C | D;\n";
95  yosys_gate_lib += "endmodule\n";
96  yosys_gate_lib += "\n";
97  yosys_gate_lib += "// XOR2\n";
98  yosys_gate_lib += "module HAL_XOR2 (A, B, O);\n";
99  yosys_gate_lib += "input A, B;\n";
100  yosys_gate_lib += "output O;\n";
101  yosys_gate_lib += "assign O = A ^ B;\n";
102  yosys_gate_lib += "endmodule\n";
103  yosys_gate_lib += "\n";
104  yosys_gate_lib += "// XOR3\n";
105  yosys_gate_lib += "module HAL_XOR3 (A, B, C, O);\n";
106  yosys_gate_lib += "input A, B, C;\n";
107  yosys_gate_lib += "output O;\n";
108  yosys_gate_lib += "assign O = A ^ B ^ C;\n";
109  yosys_gate_lib += "endmodule\n";
110  yosys_gate_lib += "\n";
111  yosys_gate_lib += "// XOR4\n";
112  yosys_gate_lib += "module HAL_XOR4 (A, B, C, D, O);\n";
113  yosys_gate_lib += "input A, B, C, D;\n";
114  yosys_gate_lib += "output O;\n";
115  yosys_gate_lib += "assign O = A ^ B ^ C ^ D;\n";
116  yosys_gate_lib += "endmodule\n";
117  yosys_gate_lib += "\n";
118  yosys_gate_lib += "// XNOR2\n";
119  yosys_gate_lib += "module HAL_XNOR2 (A, B, O);\n";
120  yosys_gate_lib += "input A, B;\n";
121  yosys_gate_lib += "output O;\n";
122  yosys_gate_lib += "assign O = (! (A ^ B));\n";
123  yosys_gate_lib += "endmodule\n";
124  yosys_gate_lib += "\n";
125  yosys_gate_lib += "// XNOR3\n";
126  yosys_gate_lib += "module HAL_XNOR3 (A, B, C, O);\n";
127  yosys_gate_lib += "input A, B, C;\n";
128  yosys_gate_lib += "output O;\n";
129  yosys_gate_lib += "assign O =(! (A ^ (B ^ C)));\n";
130  yosys_gate_lib += "endmodule\n";
131  yosys_gate_lib += "\n";
132  yosys_gate_lib += "// XNOR4\n";
133  yosys_gate_lib += "module HAL_XNOR4 (A, B, C, D, O);\n";
134  yosys_gate_lib += "input A, B, C, D;\n";
135  yosys_gate_lib += "output O;\n";
136  yosys_gate_lib += "assign O = (! (A ^ (B ^ (C ^ D))));\n";
137  yosys_gate_lib += "endmodule\n";
138  yosys_gate_lib += "\n";
139  yosys_gate_lib += "module HAL_MUX (A, B, S, O);\n";
140  yosys_gate_lib += "input A, B, S;\n";
141  yosys_gate_lib += "output O;\n";
142  yosys_gate_lib += "assign O = ((A & S) | (B & (! S)));\n";
143  yosys_gate_lib += "endmodule\n";
144  yosys_gate_lib += "\n";
145  yosys_gate_lib += "module HAL_MUX3 (A, B, C, S1, S2, O);\n";
146  yosys_gate_lib += "input A, B, C, S1, S2;\n";
147  yosys_gate_lib += "output O;\n";
148  yosys_gate_lib += "assign O = ((A & S1) | (!S1 & ((B & S2) | (C & !S2))));\n";
149  yosys_gate_lib += "endmodule\n";
150  yosys_gate_lib += "\n";
151  yosys_gate_lib += "module HAL_MUX4 (A, B, C, D, S1, S2, O);\n";
152  yosys_gate_lib += "input A, B, C, D, S1, S2;\n";
153  yosys_gate_lib += "output O;\n";
154  yosys_gate_lib += "assign O = ((A & S1 & S2) | (B & S1 & !S2) | (C & !S1 & S2) | (D & !S1 & !S2));\n";
155  yosys_gate_lib += "endmodule\n";
156  yosys_gate_lib += "\n";
157  yosys_gate_lib += "module HAL_MUX5 (A, B, C, D, E, S1, S2, S3, O);\n";
158  yosys_gate_lib += "input A, B, C, D, E, S1, S2, S3;\n";
159  yosys_gate_lib += "output O;\n";
160  yosys_gate_lib += "assign O = ((~S1 & ~S2 & ~S3 & A) | (S1 & ~S2 & ~S3 & B) | (~S1 & S2 & ~S3 & C) | (~S1 & ~S2 & S3 & D) | (S1 & S2 & ~S3 & E));\n";
161  yosys_gate_lib += "endmodule\n";
162  yosys_gate_lib += "\n";
163  yosys_gate_lib += "module HAL_MUX6 (A, B, C, D, E, F, S1, S2, S3, O);\n";
164  yosys_gate_lib += "input A, B, C, D, E, F, S1, S2, S3;\n";
165  yosys_gate_lib += "output O;\n";
166  yosys_gate_lib += "assign O = ((~S1 & ~S2 & ~S3 & A) | (S1 & ~S2 & ~S3 & B) | (~S1 & S2 & ~S3 & C) | (~S1 & ~S2 & S3 & D) | (S1 & S2 & ~S3 & E) | (S1 & ~S2 & S3 & F));\n";
167  yosys_gate_lib += "endmodule\n";
168  yosys_gate_lib += "\n";
169  yosys_gate_lib += "module HAL_MUX7 (A, B, C, D, E, F, G, S1, S2, S3, O);\n";
170  yosys_gate_lib += "input A, B, C, D, E, F, G, S1, S2, S3;\n";
171  yosys_gate_lib += "output O;\n";
172  yosys_gate_lib +=
173  "assign O = ((~S1 & ~S2 & ~S3 & A) | (S1 & ~S2 & ~S3 & B) | (~S1 & S2 & ~S3 & C) | (~S1 & ~S2 & S3 & D) | (S1 & S2 & ~S3 & E) | (S1 & ~S2 & S3 & F) | (S1 & S2 & S3 & G));\n";
174  yosys_gate_lib += "endmodule\n";
175  yosys_gate_lib += "\n";
176  yosys_gate_lib += "module HAL_MUX8 (A, B, C, D, E, F, G, H, S1, S2, S3, O);\n";
177  yosys_gate_lib += "input A, B, C, D, E, F, G, H, S1, S2, S3;\n";
178  yosys_gate_lib += "output O;\n";
179  yosys_gate_lib +=
180  "assign O = ((~S1 & ~S2 & ~S3 & A) | (S1 & ~S2 & ~S3 & B) | (~S1 & S2 & ~S3 & C) | (~S1 & ~S2 & S3 & D) | (S1 & S2 & ~S3 & E) | (S1 & ~S2 & S3 & F) | (S1 & S2 & S3 & G) | "
181  "(H & S1 & S2 & S3));\n";
182  yosys_gate_lib += "endmodule\n";
183  yosys_gate_lib += "\n";
184 
185  return yosys_gate_lib;
186  }
187 
189  {
190  namespace fs = std::filesystem;
191 
192  /* 1. Well-known locations ─ quick exit for the common cases. */
193  static constexpr std::array<const char*, 4> kKnown = {"/usr/bin/yosys",
194  "/usr/local/bin/yosys",
195  "/opt/homebrew/bin/yosys", // Apple-silicon Homebrew
196  "/opt/yosys/yosys"};
197 
198  for (const char* p : kKnown)
199  {
200  if (fs::exists(p))
201  {
202  return OK(std::string{p});
203  }
204  }
205 
206  /* 2. Search every directory in $PATH. */
207  const char* raw = std::getenv("PATH");
208  if (raw == nullptr || *raw == '\0')
209  {
210  return ERR("could not query binary path: PATH is empty");
211  }
212 
213  std::string_view path{raw};
214  while (!path.empty())
215  {
216  std::size_t sep = path.find(':');
217  std::string_view dir = path.substr(0, sep);
218  if (!dir.empty())
219  {
220  fs::path candidate = fs::path(dir) / "yosys";
221  std::error_code ec; // avoids exceptions
222  if (fs::exists(candidate, ec) && !ec)
223  {
224  return OK(candidate.string());
225  }
226  }
227  if (sep == std::string_view::npos)
228  {
229  break;
230  }
231  path.remove_prefix(sep + 1); // skip the ':'
232  }
233 
234  return ERR("could not query binary path: yosys not found in PATH or default locations");
235  }
236 
237  } // namespace yosys
238 
239  namespace
240  {
241  std::string new_net_name(const Net* dst_net, const Net* new_net)
242  {
243  return new_net->get_name() + "_" + std::to_string(dst_net->get_id()) + "_NEW_NET";
244  }
245 
246  std::string new_gate_name(const Gate* dst_gate, const Gate* new_gate)
247  {
248  return new_gate->get_name() + "_" + std::to_string(dst_gate->get_id()) + "_NEW_GATE";
249  }
250 
251  Result<std::monostate> delete_subgraph(Netlist* nl, const std::vector<Gate*> subgraph)
252  {
253  // TODO currently only gates are deleted, not nets...
254  for (const auto& g : subgraph)
255  {
256  if (!nl->delete_gate(g))
257  {
258  return ERR("unable to delete subgraph: failed to delete gate '" + g->get_name() + "' with ID " + std::to_string(g->get_id()) + " in netlist with ID "
259  + std::to_string(nl->get_id()));
260  }
261  }
262 
263  return OK({});
264  }
265 
266  Result<std::monostate> replace_gate_with_netlist(Gate* g, const Netlist* src_nl, Netlist* dst_nl, const bool delete_gate = true)
267  {
268  std::unordered_map<Net*, std::vector<Net*>> global_io_mapping;
269 
270  for (const auto& g_i : src_nl->get_top_module()->get_input_pins())
271  {
272  const auto& pin_name = g_i->get_name();
273  const auto i_net = g->get_fan_in_net(pin_name);
274 
275  if (i_net == nullptr)
276  {
277  return ERR("unable to replace gate '" + g->get_name() + "' with ID " + std::to_string(g->get_id()) + " with netlist: failed to find net connected to gate pin '" + pin_name + "'");
278  }
279 
280  global_io_mapping[g_i->get_net()].push_back(i_net);
281  }
282 
283  for (const auto& g_o : src_nl->get_top_module()->get_output_pins())
284  {
285  const auto& pin_name = g_o->get_name();
286  const auto o_net = g->get_fan_out_net(pin_name);
287 
288  if (o_net == nullptr)
289  {
290  return ERR("unable to replace gate '" + g->get_name() + "' with ID " + std::to_string(g->get_id()) + " with netlist: failed to find net connected to gate pin '" + pin_name + "'");
291  }
292 
293  global_io_mapping[g_o->get_net()].push_back(o_net);
294  }
295 
296  return resynthesis::replace_subgraph_with_netlist({g}, global_io_mapping, src_nl, dst_nl, delete_gate);
297  }
298 
299  Result<std::tuple<GateType*, std::vector<GatePin*>, std::vector<GatePin*>>>
300  find_gate_type(const GateLibrary* gl, const std::set<GateTypeProperty>& properties, const u32 num_inputs, const u32 num_outputs)
301  {
302  const auto get_valid_input_pins = [](const GateType* gt) -> std::vector<GatePin*> {
303  return gt->get_pins([](const GatePin* gp) { return (gp->get_direction() == PinDirection::input) && (gp->get_type() != PinType::power) && (gp->get_type() != PinType::ground); });
304  };
305 
306  const auto get_valid_output_pins = [](const GateType* gt) -> std::vector<GatePin*> {
307  return gt->get_pins([](const GatePin* gp) { return (gp->get_direction() == PinDirection::output) && (gp->get_type() != PinType::power) && (gp->get_type() != PinType::ground); });
308  };
309 
310  // get types that match exactly with the properties and have the exact amount of input pins (excluding power pins)
311  const auto candidates = gl->get_gate_types([properties, num_inputs, get_valid_input_pins, num_outputs, get_valid_output_pins](const GateType* gt) {
312  return (gt->get_properties() == properties) && (get_valid_input_pins(gt).size() == num_inputs) && (get_valid_output_pins(gt).size() == num_outputs);
313  });
314 
315  if (candidates.empty())
316  {
317  return ERR("unable to find gate type matching the description");
318  }
319 
320  GateType* valid_gate_type = candidates.begin()->second;
321 
322  return OK({valid_gate_type, get_valid_input_pins(valid_gate_type), get_valid_output_pins(valid_gate_type)});
323  }
324 
325  // TODO change this to return a netlist. This would allow saving the decomposition of a specific gate type
326  Result<Net*> build_gate_tree_from_boolean_function(Netlist* nl, const BooleanFunction& bf, const std::map<std::string, Net*>& var_name_to_net, const Gate* org_gate = nullptr)
327  {
328  const auto create_gate_name = [](const Gate* new_gate, const Gate* original_gate) -> std::string {
329  const std::string new_name = (original_gate == nullptr) ? "new_gate_" : original_gate->get_name() + "_decomposed_";
330  return new_name + std::to_string(new_gate->get_id());
331  };
332 
333  const auto create_net_name = [](const Net* new_net, const Gate* original_gate) -> std::string {
334  const std::string new_name = (original_gate == nullptr) ? "new_net_" : original_gate->get_name() + "_decomposed_";
335  return new_name + std::to_string(new_net->get_id());
336  };
337 
338  if (bf.is_empty())
339  {
340  return ERR("cannot build gate tree for Boolean function: Boolean function is empty");
341  }
342 
343  if (bf.is_index())
344  {
345  return ERR("cannot build gate tree for Boolean function: Boolean function is of type index");
346  }
347 
348  if (bf.size() != 1)
349  {
350  return ERR("cannot build gate tree for Boolean function: Boolean function if of size " + std::to_string(bf.size()) + " but we only handle size 1");
351  }
352 
353  if (bf.is_constant())
354  {
355  if (bf.has_constant_value(0))
356  {
357  static Net* zero = nl->get_nets([](const Net* n) { return n->is_gnd_net(); }).front();
358  return OK(zero);
359  }
360 
361  if (bf.has_constant_value(1))
362  {
363  static Net* one = nl->get_nets([](const Net* n) { return n->is_vcc_net(); }).front();
364  return OK(one);
365  }
366  }
367 
368  if (bf.is_variable())
369  {
370  if (const auto it = var_name_to_net.find(bf.get_variable_name().get()); it == var_name_to_net.end())
371  {
372  return ERR("cannot build gate tree for Boolean function: found variable '" + bf.get_variable_name().get() + "' with no corresponding net provided");
373  }
374  else
375  {
376  return OK(it->second);
377  }
378  }
379 
380  if (!bf.get_top_level_node().is_operation())
381  {
382  return ERR("cannot build gate tree for Boolean function: cannot handle node type of top level node '" + bf.get_top_level_node().to_string() + "'");
383  }
384 
385  const auto operation = bf.get_top_level_node().type;
386  const auto parameters = bf.get_parameters();
387 
388  // TODO put this into a function that only searches for the gate types when they are actually needed
389  static const auto inv_type_res = find_gate_type(nl->get_gate_library(), {GateTypeProperty::combinational, GateTypeProperty::c_inverter}, 1, 1);
390  static const auto and_type_res = find_gate_type(nl->get_gate_library(), {GateTypeProperty::combinational, GateTypeProperty::c_and}, 2, 1);
391  static const auto or_type_res = find_gate_type(nl->get_gate_library(), {GateTypeProperty::combinational, GateTypeProperty::c_or}, 2, 1);
392  static const auto xor_type_res = find_gate_type(nl->get_gate_library(), {GateTypeProperty::combinational, GateTypeProperty::c_xor}, 2, 1);
393 
394  if (inv_type_res.is_error())
395  {
396  return ERR("cannot build gate tree for Boolean function: failed to find valid 'INVERT' gate type");
397  }
398 
399  if (and_type_res.is_error())
400  {
401  return ERR("cannot build gate tree for Boolean function: failed to find valid 'AND' gate type");
402  }
403 
404  if (or_type_res.is_error())
405  {
406  return ERR("cannot build gate tree for Boolean function: failed to find valid 'OR' gate type");
407  }
408 
409  if (xor_type_res.is_error())
410  {
411  return ERR("cannot build gate tree for Boolean function: failed to find valid 'XOR' gate type");
412  }
413 
414  const std::map<u16, std::tuple<GateType*, std::vector<GatePin*>, std::vector<GatePin*>>> node_type_to_gate_type = {
415  {BooleanFunction::NodeType::Not, inv_type_res.get()},
416  {BooleanFunction::NodeType::And, and_type_res.get()},
417  {BooleanFunction::NodeType::Or, or_type_res.get()},
418  {BooleanFunction::NodeType::Xor, xor_type_res.get()},
419  };
420 
421  std::vector<Net*> parameter_nets;
422  for (const auto& p : parameters)
423  {
424  const auto tree_res = build_gate_tree_from_boolean_function(nl, p, var_name_to_net, org_gate);
425  if (tree_res.is_error())
426  {
427  return ERR_APPEND(tree_res.get_error(), "cannot build gate tree for Boolean function: failed to do so for sub tree");
428  }
429  parameter_nets.push_back(tree_res.get());
430  }
431 
432  Gate* new_gate = nullptr;
433  Net* output_net = nl->create_net("__TEMP_NET_NAME__DECOMPOSED__");
434  output_net->set_name(create_net_name(output_net, org_gate));
435 
436  switch (operation)
437  {
442  auto [gt, in_pins, out_pins] = node_type_to_gate_type.at(operation);
443  new_gate = nl->create_gate(gt, "__TEMP_GATE_NAME__DECOMPOSED__");
444  for (u32 idx = 0; idx < parameter_nets.size(); idx++)
445  {
446  parameter_nets.at(idx)->add_destination(new_gate, in_pins.at(idx));
447  }
448  output_net->add_source(new_gate, out_pins.front());
449  break;
450  }
451  default:
452  break;
453  }
454 
455  if (new_gate == nullptr)
456  {
457  return ERR("cannot build gate tree for Boolean function: failed to create gate for operation '" + bf.get_top_level_node().to_string() + "'");
458  }
459 
460  new_gate->set_name(create_gate_name(new_gate, org_gate));
461 
462  if (org_gate != nullptr && !org_gate->get_module()->is_top_module())
463  {
464  org_gate->get_module()->assign_gate(new_gate);
465  }
466 
467  return OK(output_net);
468  }
469 
470  Result<std::unique_ptr<Netlist>> generate_decomposed_netlist_from_boolean_function(const std::vector<std::pair<std::string, BooleanFunction>>& bfs, const GateLibrary* gl)
471  {
472  auto nl = netlist_factory::create_netlist(gl);
473 
474  std::map<std::string, Net*> var_name_to_net;
475  for (const auto& [out_pin_name, bf] : bfs)
476  {
477  const auto bf_vars = bf.get_variable_names();
478  for (const auto& var : bf_vars)
479  {
480  if (var_name_to_net.find(var) != var_name_to_net.end())
481  {
482  continue;
483  }
484 
485  Net* new_net = nl->create_net(var);
486  if (!new_net)
487  {
488  return ERR("unable to generate decomposed netlist from Boolean function: failed to create net for boolean input var '" + var + "'");
489  }
490 
491  new_net->mark_global_input_net();
492  var_name_to_net.insert({var, new_net});
493  }
494 
495  auto new_out_net_res = build_gate_tree_from_boolean_function(nl.get(), bf, var_name_to_net, nullptr);
496  if (new_out_net_res.is_error())
497  {
498  return ERR_APPEND(new_out_net_res.get_error(), "unable to generate decomposed netlist from Boolean function: failed to build gate tree for Boolean function");
499  }
500 
501  Net* new_out_net = new_out_net_res.get();
502  new_out_net->mark_global_output_net();
503  new_out_net->set_name(out_pin_name);
504 
505  // rename top module pins to the var names.
506  // NOTE: this seems to be really depended on the order. Doing this earlier causes a crash. I did not fully understand what causes the top module pins to be created.
507 
508  Module* top_mod = nl->get_top_module();
509  for (const auto& [var, in_net] : var_name_to_net)
510  {
511  auto in_pin = top_mod->get_pin_by_net(in_net);
512  top_mod->set_pin_name(in_pin, var, true);
513  }
514  auto out_pin = top_mod->get_pin_by_net(new_out_net);
515  top_mod->set_pin_name(out_pin, out_pin_name, true);
516  }
517 
518  return OK(std::move(nl));
519  }
520 
521  std::string build_functional_verilog_module_from(const std::unordered_map<std::string, BooleanFunction>& bfs)
522  {
523  std::unordered_set<std::string> input_variable_names;
524 
525  for (const auto& [name, bf] : bfs)
526  {
527  for (const auto& var_name : bf.get_variable_names())
528  {
529  input_variable_names.insert(var_name);
530  }
531  }
532 
533  std::string verilog_str = "module top (";
534 
535  std::string var_str = "";
536  std::string io_str = "";
537  std::string function_str = "";
538 
539  for (const auto& input_var : input_variable_names)
540  {
541  var_str += (input_var + ", ");
542  io_str += ("input " + input_var + ";\n");
543  }
544 
545  for (const auto& [output_var, bf] : bfs)
546  {
547  var_str += (output_var + ", ");
548  io_str += ("output " + output_var + ";\n");
549  function_str += ("assign " + output_var + " = " + bf.to_string() + ";\n");
550  }
551 
552  var_str = var_str.substr(0, var_str.size() - 2);
553 
554  verilog_str += var_str;
555  verilog_str += ");\n";
556 
557  verilog_str += io_str;
558 
559  verilog_str += "\n";
560 
561  verilog_str += function_str;
562 
563  verilog_str += "\n";
564  verilog_str += "endmodule\n";
565  verilog_str += "\n";
566 
567  return verilog_str;
568  }
569 
570  Result<std::unique_ptr<Netlist>> generate_resynth_netlist_for_gate_level_subgraph(const Netlist* nl,
571  const std::vector<Gate*>& subgraph,
572  const std::filesystem::path& genlib_path,
573  GateLibrary* target_gl,
574  const bool optimize_area)
575  {
576  // TODO sanity check wether all gates in the subgraph have types that are in the genlib/target library
577  if (nl == nullptr)
578  {
579  return ERR("unable to re-synthesize gate-level subgraph: netlist is a 'nullptr'");
580  }
581 
582  if (target_gl == nullptr)
583  {
584  return ERR("unable to re-synthesize gate-level subgraph: gate library is a 'nullptr'");
585  }
586 
587  auto subgraph_nl_res = SubgraphNetlistDecorator(*nl).copy_subgraph_netlist(subgraph, true);
588  if (subgraph_nl_res.is_error())
589  {
590  return ERR_APPEND(subgraph_nl_res.get_error(), "unable to re-synthesize gate-level subgraph: failed to copy subgraph netlist");
591  }
592  const auto subgraph_nl = subgraph_nl_res.get();
593 
594  auto base_path_res = utils::get_unique_temp_directory("resynthesis_");
595  if (base_path_res.is_error())
596  {
597  return ERR_APPEND(base_path_res.get_error(), "unable to re-synthesize Boolean functions with yosys: failed to get unique temp directory");
598  }
599  const std::filesystem::path base_path = base_path_res.get();
600  const std::filesystem::path org_netlist_path = base_path / "org_netlist.v";
601  const std::filesystem::path resynthesized_netlist_path = base_path / "resynth_netlist.v";
602  const std::filesystem::path yosys_helper_lib_path = base_path / "yosys_helper_lib.v";
603 
604  std::filesystem::create_directory(base_path);
605 
606  if (!netlist_writer_manager::write(subgraph_nl.get(), org_netlist_path))
607  {
608  return ERR("unable to re-synthesize gate-level subgraph: failed to write netlist to file");
609  }
610 
611  // NOTE this is a way to get rid of the stupid timescale annotation that is added by the verilog writer (for the simulator!?) but cannot be parsed by yosys...
612  // Read the file into a vector of lines
613  std::vector<std::string> lines;
614  std::ifstream input_file(org_netlist_path);
615 
616  std::string line;
617  while (std::getline(input_file, line))
618  {
619  lines.push_back(line);
620  }
621  input_file.close();
622 
623  // Remove the first line from the vector
624  if (!lines.empty())
625  {
626  lines.erase(lines.begin());
627  }
628 
629  // Write the modified lines back to the file
630  std::ofstream output_file(org_netlist_path);
631  for (const auto& out_line : lines)
632  {
633  output_file << out_line << std::endl;
634  }
635  output_file.close();
636 
637  std::ofstream yosys_helper_lib_file(yosys_helper_lib_path);
638  yosys_helper_lib_file << yosys::get_helper_gate_lib();
639  yosys_helper_lib_file.close();
640 
641  auto yosys_query_res = yosys::query_binary_path();
642  if (yosys_query_res.is_error())
643  {
644  return ERR_APPEND(yosys_query_res.get_error(), "unable to re-synthesize Boolean functions with yosys: failed to find yosys path");
645  }
646 
647  const auto yosys_path = yosys_query_res.get();
648  const std::string command = yosys_path + " -q -p " + '"' + "read_verilog -sv " + org_netlist_path.string() + "; read_verilog " + yosys_helper_lib_path.string() + "; synth -flatten -top "
649  + subgraph_nl->get_design_name() + "; abc -genlib " + genlib_path.string() + "; " + "write_verilog " + resynthesized_netlist_path.string() + ";" + '"';
650 
651  // log_debug("netlist_preprocessing", "yosys command: {}", command);
652 
653  system(command.c_str());
654 
656  LogManager::get_instance()->deactivate_channel("netlist_parser");
657  auto resynth_nl = netlist_factory::load_netlist(resynthesized_netlist_path, target_gl);
658  if (resynth_nl == nullptr)
659  {
660  return ERR("unable to re-synthesize gate-level netlist with yosys: failed to load resynthesized netlist at " + resynthesized_netlist_path.string());
661  }
663  LogManager::get_instance()->activate_channel("netlist_parser");
664 
665  // delete the created directory and the contained files
666  std::filesystem::remove_all(base_path);
667 
668  return OK(std::move(resynth_nl));
669  }
670 
671  // // TODO move to the netlist traversal decorator, currently existing in the machine learning branch
672  // std::vector<Net*> get_outputs_of_subgraph(const std::vector<Gate*>& subgraph)
673  // {
674  // std::unordered_set<Gate*> subgraph_set = {subgraph.begin(), subgraph.end()};
675  // std::unordered_set<Net*> outputs;
676 
677  // for (const auto g : subgraph)
678  // {
679  // for (const auto ep : g->get_successors())
680  // {
681  // // check whether gate has a successor outside the subgraph
682  // if (subgraph_set.find(ep->get_gate()) == subgraph_set.end())
683  // {
684  // outputs.insert(ep->get_net());
685  // }
686  // }
687  // }
688 
689  // return {outputs.begin(), outputs.end()};
690  // }
691 
692  Result<std::unique_ptr<Netlist>> generate_resynth_netlist_for_gate(const Gate* g, GateLibrary* target_gl, const std::filesystem::path& genlib_path)
693  {
694  // build Boolean function for each output pin of the gate type
695  std::unordered_map<std::string, BooleanFunction> output_pin_name_to_bf;
696  for (const auto pin : g->get_type()->get_output_pins())
697  {
698  const auto bf_res = g->get_boolean_function(pin, true, false);
699  if (bf_res.is_error())
700  {
701  return ERR_APPEND(bf_res.get_error(),
702  "unable to re-synthesize LUT type '" + g->get_type()->get_name() + "' for gate instance '" + g->get_name() + "' with ID " + std::to_string(g->get_id())
703  + ": failed to build resolved Boolean function for pin '" + pin->get_name() + "'");
704  }
705 
706  const auto bf = bf_res.get();
707  output_pin_name_to_bf.insert({pin->get_name(), bf});
708  }
709 
710  auto resynth_res = resynthesis::generate_resynth_netlist_for_boolean_functions(output_pin_name_to_bf, genlib_path, target_gl, true);
711  if (resynth_res.is_error())
712  {
713  return ERR_APPEND(resynth_res.get_error(),
714  "unable to re-synthesize LUT type '" + g->get_type()->get_name() + "' for gate instance '" + g->get_name() + "' with ID " + std::to_string(g->get_id())
715  + ": failed to re-synthesize Boolean functions of gate");
716  }
717 
718  return OK(resynth_res.get());
719  }
720  } // namespace
721 
722  namespace resynthesis
723  {
724  Result<std::monostate> decompose_gate(Netlist* nl, Gate* g, const bool delete_gate)
725  {
726  // build Boolean function for each output pin of the gate
727 
728  // TODO use vector of pairs
729  std::vector<std::pair<std::string, BooleanFunction>> output_pin_name_to_bf;
730  for (const auto pin : g->get_type()->get_output_pins())
731  {
732  const auto bf_res = g->get_boolean_function(pin, true, false);
733  if (bf_res.is_error())
734  {
735  return ERR_APPEND(bf_res.get_error(),
736  "unable to decompose gate '" + g->get_name() + "' with ID " + std::to_string(g->get_id()) + ": failed to build resolved boolean function for pin '"
737  + pin->get_name() + "'");
738  }
739 
740  const auto bf = bf_res.get();
741  output_pin_name_to_bf.push_back({pin->get_name(), bf});
742  }
743 
744  auto resynth_res = generate_decomposed_netlist_from_boolean_function(output_pin_name_to_bf, nl->get_gate_library());
745  if (resynth_res.is_error())
746  {
747  return ERR_APPEND(resynth_res.get_error(), "unable to decompose gate '" + g->get_name() + "' with ID " + std::to_string(g->get_id()) + ": failed to generate decomposed netlist");
748  }
749  auto unique_resynth_nl = resynth_res.get();
750 
751  const auto replace_res = replace_gate_with_netlist(g, unique_resynth_nl.get(), nl, false);
752  if (replace_res.is_error())
753  {
754  return ERR_APPEND(replace_res.get_error(),
755  "unable to decompose gate '" + g->get_name() + "' with ID " + std::to_string(g->get_id()) + ": failed to replace gate with decomposed netlist");
756  }
757 
758  if (delete_gate)
759  {
760  if (!nl->delete_gate(g))
761  {
762  return ERR("unable to decompose gate '" + g->get_name() + "' with ID " + std::to_string(g->get_id()) + ": failed to delete original gate");
763  }
764  }
765 
766  return OK({});
767  }
768 
769  Result<u32> decompose_gates_of_type(Netlist* nl, const std::vector<const GateType*>& gate_types)
770  {
771  std::map<std::pair<const GateType*, std::vector<std::string>>, std::unique_ptr<Netlist>> gt_to_decomposed;
772 
773  u32 counter = 0;
774  for (const auto& gt : gate_types)
775  {
776  std::vector<Gate*> to_delete;
777  for (const auto& g : nl->get_gates([gt](const Gate* g) { return g->get_type() == gt; }))
778  {
779  const Netlist* resynth_nl = nullptr;
780  std::vector<std::string> init_data;
781 
782  if (gt->has_property(GateTypeProperty::c_lut))
783  {
784  const LUTComponent* lc = gt->get_component_as<LUTComponent>(
785  [](const GateTypeComponent* c) { return c->get_type() == GateTypeComponent::ComponentType::lut; });
786  if (lc == nullptr)
787  {
788  return ERR("unable to decompose gates of type: gate type '" + gt->get_name() + "' has no LUT component");
789  }
790 
791  // Collect unique INIT strings in sorted identifier order (preserves former get_init_data behaviour)
792  std::vector<std::string> ids;
793  for (const auto& [_, cfg] : lc->get_output_pin_configs())
794  {
795  if (std::find(ids.begin(), ids.end(), cfg.init_identifier) == ids.end())
796  ids.push_back(cfg.init_identifier);
797  }
798  std::sort(ids.begin(), ids.end());
799 
800  for (const auto& id : ids)
801  {
802  for (const auto& [pin_name, cfg] : lc->get_output_pin_configs())
803  {
804  if (cfg.init_identifier == id)
805  {
806  auto res = lc->get_init_string(g, pin_name);
807  if (res.is_error())
808  {
809  return ERR_APPEND(res.get_error(),
810  "unable to decompose gates of type: failed to get INIT string from gate '" + g->get_name() + "' with ID "
811  + std::to_string(g->get_id()));
812  }
813  init_data.push_back(res.get());
814  break;
815  }
816  }
817  }
818 
819  if (init_data.size() != 1)
820  {
821  return ERR("unable to decompose gates of type: got " + std::to_string(init_data.size()) + " INIT strings for gate '" + g->get_name() + "' with ID "
822  + std::to_string(g->get_id()));
823  }
824  }
825 
826  // get resynth netlist from cache or create it
827  if (const auto it = gt_to_decomposed.find({gt, init_data}); it != gt_to_decomposed.end())
828  {
829  resynth_nl = it->second.get();
830  }
831  else
832  {
833  // build Boolean function for each output pin of the gate type
834 
835  // TODO use vector of pairs
836  std::vector<std::pair<std::string, BooleanFunction>> output_pin_name_to_bf;
837  for (const auto pin : g->get_type()->get_output_pins())
838  {
839  const auto bf_res = g->get_boolean_function(pin, true, false);
840  if (bf_res.is_error())
841  {
842  return ERR_APPEND(bf_res.get_error(),
843  "unable to decompose gate type '" + g->get_type()->get_name() + "' for gate instance '" + g->get_name() + "' with ID " + std::to_string(g->get_id())
844  + ": failed to build resolved Boolean function for pin '" + pin->get_name() + "'");
845  }
846 
847  const auto bf = bf_res.get();
848  output_pin_name_to_bf.push_back({pin->get_name(), bf});
849  }
850 
851  auto resynth_res = generate_decomposed_netlist_from_boolean_function(output_pin_name_to_bf, nl->get_gate_library());
852  if (resynth_res.is_error())
853  {
854  return ERR_APPEND(resynth_res.get_error(), "unable to decompose gates of type: failed to generate decomposed netlist for gate type '" + gt->get_name() + "'");
855  }
856  auto unique_resynth_nl = resynth_res.get();
857  resynth_nl = unique_resynth_nl.get();
858 
859  gt_to_decomposed.insert({std::make_pair(gt, init_data), std::move(unique_resynth_nl)});
860  }
861 
862  const auto replace_res = replace_gate_with_netlist(g, resynth_nl, nl, false);
863  if (replace_res.is_error())
864  {
865  return ERR_APPEND(replace_res.get_error(),
866  "unable to decompose gates of type '" + gt->get_name() + "': failed to replace gate '" + g->get_name() + "' with ID " + std::to_string(g->get_id()));
867  }
868  to_delete.push_back(g);
869  }
870 
871  for (const auto& g : to_delete)
872  {
873  counter += 1;
874  if (!nl->delete_gate(g))
875  {
876  return ERR("unable to resynthesize gates of type '" + gt->get_name() + "': failed to delete gate '" + g->get_name() + "' with ID " + std::to_string(g->get_id()));
877  }
878  }
879  }
880 
881  return OK(counter);
882  }
883 
884  Result<std::monostate> resynthesize_gate(Netlist* nl, Gate* gate, GateLibrary* target_gl, const bool delete_gate)
885  {
886  if (nl == nullptr)
887  {
888  return ERR("could not re-synthesize gate, netlist is a 'nullptr'");
889  }
890 
891  if (gate == nullptr)
892  {
893  return ERR("could not re-synthesize gate, gate is a 'nullptr'");
894  }
895 
896  if (target_gl == nullptr)
897  {
898  return ERR("could not re-synthesize gate, target gate library is a 'nullptr'");
899  }
900 
901  auto base_path_res = utils::get_unique_temp_directory("resynthesis_");
902  if (base_path_res.is_error())
903  {
904  return ERR_APPEND(base_path_res.get_error(), "unable to re-synthesize Boolean functions with yosys: failed to get unique temp directory");
905  }
906  const auto base_path = base_path_res.get();
907  const auto genlib_path = base_path / "new_gate_library.genlib";
908  std::filesystem::create_directory(base_path);
909 
910  const auto gl_save_res = gate_library_manager::save(genlib_path, target_gl, true);
911  if (!gl_save_res)
912  {
913  return ERR("unable to re-synthesize gates of type: failed to save gate library '" + target_gl->get_name() + "' at location '" + genlib_path.string() + "'");
914  }
915 
916  auto resynth_res = generate_resynth_netlist_for_gate(gate, target_gl, genlib_path);
917  if (resynth_res.is_error())
918  {
919  return ERR_APPEND(resynth_res.get_error(),
920  "unable to re-synthesize gate '" + gate->get_name() + "' with ID " + std::to_string(gate->get_id()) + ": failed to generate re-synthesized netlist");
921  }
922  const auto resynth_nl = resynth_res.get();
923  const auto replace_res = replace_gate_with_netlist(gate, resynth_nl.get(), nl, false);
924  if (replace_res.is_error())
925  {
926  return ERR_APPEND(replace_res.get_error(),
927  "unable to re-synthesize gate '" + gate->get_name() + "' with ID " + std::to_string(gate->get_id()) + ": failed to replace gate with re-synthesized netlist");
928  }
929 
930  if (delete_gate)
931  {
932  if (!nl->delete_gate(gate))
933  {
934  return ERR("unable to decompose gate '" + gate->get_name() + "' with ID " + std::to_string(gate->get_id()) + ": failed to delete original gate.");
935  }
936  }
937 
938  return OK({});
939  }
940 
941  Result<u32> resynthesize_gates(Netlist* nl, const std::vector<Gate*>& gates, GateLibrary* target_gl)
942  {
943  auto base_path_res = utils::get_unique_temp_directory("resynthesis_");
944  if (base_path_res.is_error())
945  {
946  return ERR_APPEND(base_path_res.get_error(), "unable to re-synthesize Boolean functions with yosys: failed to get unique temp directory");
947  }
948  const auto base_path = base_path_res.get();
949  const auto genlib_path = base_path / "new_gate_library.genlib";
950  std::filesystem::create_directory(base_path);
951 
952  const auto gl_save_res = gate_library_manager::save(genlib_path, target_gl, true);
953  if (!gl_save_res)
954  {
955  return ERR("unable to re-synthesize gates of type: failed to save gate library '" + target_gl->get_name() + "' to location " + genlib_path.string());
956  }
957 
958  std::map<std::pair<const GateType*, std::vector<std::string>>, std::unique_ptr<Netlist>> gt_to_resynth;
959 
960  std::vector<Gate*> to_delete;
961  u32 counter = 0;
962  for (const auto& g : gates)
963  {
964  const auto& gt = g->get_type();
965 
966  Netlist* resynth_nl = nullptr;
967  std::vector<std::string> init_data = {};
968 
969  if (gt->has_property(GateTypeProperty::c_lut))
970  {
971  const LUTComponent* lc = gt->get_component_as<LUTComponent>(
972  [](const GateTypeComponent* c) { return c->get_type() == GateTypeComponent::ComponentType::lut; });
973  if (lc == nullptr)
974  {
975  return ERR("unable to re-synthesize gates of type: gate type '" + gt->get_name() + "' has no LUT component");
976  }
977 
978  // Collect unique INIT strings in sorted identifier order (preserves former get_init_data behaviour)
979  std::vector<std::string> ids;
980  for (const auto& [_, cfg] : lc->get_output_pin_configs())
981  {
982  if (std::find(ids.begin(), ids.end(), cfg.init_identifier) == ids.end())
983  ids.push_back(cfg.init_identifier);
984  }
985  std::sort(ids.begin(), ids.end());
986 
987  for (const auto& id : ids)
988  {
989  for (const auto& [pin_name, cfg] : lc->get_output_pin_configs())
990  {
991  if (cfg.init_identifier == id)
992  {
993  auto res = lc->get_init_string(g, pin_name);
994  if (res.is_error())
995  {
996  return ERR_APPEND(res.get_error(),
997  "unable to re-synthesize gates of type: failed to get INIT string from gate '" + g->get_name() + "' with ID "
998  + std::to_string(g->get_id()));
999  }
1000  init_data.push_back(res.get());
1001  break;
1002  }
1003  }
1004  }
1005 
1006  if (init_data.size() != 1)
1007  {
1008  return ERR("unable to re-synthesize gates of type: got " + std::to_string(init_data.size()) + " INIT strings for gate '" + g->get_name() + "' with ID "
1009  + std::to_string(g->get_id()));
1010  }
1011  }
1012 
1013  // get resynth netlist from cache or create it
1014  if (const auto it = gt_to_resynth.find({gt, init_data}); it != gt_to_resynth.end())
1015  {
1016  resynth_nl = it->second.get();
1017  }
1018  else
1019  {
1020  auto resynth_res = generate_resynth_netlist_for_gate(g, target_gl, genlib_path);
1021  if (resynth_res.is_error())
1022  {
1023  return ERR_APPEND(resynth_res.get_error(),
1024  "unable to re-synthesize gates of type: failed to re-synthesize gate '" + g->get_name() + "' with ID " + std::to_string(g->get_id()));
1025  }
1026  auto unique_resynth_nl = resynth_res.get();
1027  resynth_nl = unique_resynth_nl.get();
1028  gt_to_resynth.insert({std::make_pair(gt, init_data), std::move(unique_resynth_nl)});
1029  }
1030 
1031  const auto replace_res = replace_gate_with_netlist(g, resynth_nl, nl, false);
1032  if (replace_res.is_error())
1033  {
1034  return ERR_APPEND(replace_res.get_error(),
1035  "unable to re-synthesize gates of type '" + gt->get_name() + "': failed for gate '" + g->get_name() + "' with ID " + std::to_string(g->get_id()));
1036  }
1037  to_delete.push_back(g);
1038  }
1039 
1040  for (const auto& g : to_delete)
1041  {
1042  counter += 1;
1043  if (!nl->delete_gate(g))
1044  {
1045  return ERR("unable to re-synthesize gates of type '" + g->get_type()->get_name() + "': failed to delete gate '" + g->get_name() + "' with ID " + std::to_string(g->get_id()));
1046  }
1047  }
1048 
1049  // delete the created directory and the contained files
1050  std::filesystem::remove_all(base_path);
1051 
1052  return OK(counter);
1053  }
1054 
1055  Result<u32> resynthesize_gates_of_type(Netlist* nl, const std::vector<const GateType*>& gate_types, GateLibrary* target_gl)
1056  {
1057  const std::vector<Gate*> filtered_gates = nl->get_gates([gate_types](const auto& gate) {
1058  bool is_included = false;
1059  for (const auto& gt : gate_types)
1060  {
1061  if (gate->get_type() == gt)
1062  {
1063  is_included = true;
1064  break;
1065  }
1066  }
1067 
1068  return is_included;
1069  });
1070 
1071  return resynthesize_gates(nl, filtered_gates, target_gl);
1072  }
1073 
1074  Result<u32> resynthesize_subgraph(Netlist* nl, const std::vector<Gate*>& subgraph, GateLibrary* target_gl)
1075  {
1076  if (nl == nullptr)
1077  {
1078  return ERR("netlist is a 'nullptr'");
1079  }
1080 
1081  if (target_gl == nullptr)
1082  {
1083  return ERR("gate library is a 'nullptr'");
1084  }
1085 
1086  auto base_path_res = utils::get_unique_temp_directory("resynthesis_");
1087  if (base_path_res.is_error())
1088  {
1089  return ERR_APPEND(base_path_res.get_error(), "unable to re-synthesize Boolean functions with yosys: failed to get unique temp directory");
1090  }
1091  const std::filesystem::path base_path = base_path_res.get();
1092  const std::filesystem::path genlib_path = base_path / "new_gate_library.genlib";
1093  std::filesystem::create_directory(base_path);
1094 
1095  const auto gl_save_res = gate_library_manager::save(genlib_path, target_gl, true);
1096  if (!gl_save_res)
1097  {
1098  return ERR("unable to re-synthesize gates of type: failed to save gate library '" + target_gl->get_name() + "' to location " + genlib_path.string());
1099  }
1100 
1101  // auto resynth_res = resynthesize_functional_subgraph_with_yosys(nl, subgraph, genlib_path, target_gl, true);
1102  auto resynth_res = generate_resynth_netlist_for_gate_level_subgraph(nl, subgraph, genlib_path, target_gl, true);
1103  if (resynth_res.is_error())
1104  {
1105  return ERR_APPEND(resynth_res.get_error(), "unable to re-synthesize subgraphs of type: failed to re-synthesize subgraph to netlist");
1106  }
1107  auto resynth_nl = resynth_res.get();
1108 
1109  std::unordered_map<std::string, Net*> name_to_net;
1110  for (const auto n : nl->get_nets())
1111  {
1112  name_to_net.insert({n->get_name(), n});
1113  }
1114 
1115  std::unordered_map<Net*, std::vector<Net*>> global_io_mapping;
1116 
1117  // use top module pin names to find correponding nets in original netlist
1118  for (const auto& pin : resynth_nl->get_top_module()->get_input_pins())
1119  {
1120  auto net_it = name_to_net.find(pin->get_name());
1121  if (net_it == name_to_net.end())
1122  {
1123  return ERR("unable to re-synthesize subgraphs of type: failed to locate net in destination netlist from global input '" + pin->get_name() + "' in re-synthesized netlist");
1124  }
1125  global_io_mapping[pin->get_net()].push_back(net_it->second);
1126  }
1127  for (const auto& pin : resynth_nl->get_top_module()->get_output_pins())
1128  {
1129  auto net_it = name_to_net.find(pin->get_name());
1130  if (net_it == name_to_net.end())
1131  {
1132  return ERR("unable to re-synthesize subgraphs of type: failed to locate net in destination netlist from global output '" + pin->get_name() + "' in re-synthesized netlist");
1133  }
1134  global_io_mapping[pin->get_net()].push_back(net_it->second);
1135  }
1136 
1137  auto replace_res = replace_subgraph_with_netlist(subgraph, global_io_mapping, resynth_nl.get(), nl, false);
1138  if (replace_res.is_error())
1139  {
1140  return ERR_APPEND(replace_res.get_error(), "unable to re-synthesize subgraphs of type: failed to replace subgraph with re-synthesized netlist");
1141  }
1142 
1143  // delete subgraph gates
1144  auto delete_res = delete_subgraph(nl, subgraph);
1145  if (delete_res.is_error())
1146  {
1147  return ERR_APPEND(delete_res.get_error(), "unable to replace subgraph with netlist: failed to delete subgraph");
1148  }
1149 
1150  // delete the created directory and the contained files
1151  std::filesystem::remove_all(base_path);
1152 
1153  return OK(static_cast<unsigned int>(subgraph.size()));
1154  }
1155 
1156  Result<u32> resynthesize_subgraph_of_type(Netlist* nl, const std::vector<const GateType*>& gate_types, GateLibrary* target_gl)
1157  {
1158  std::vector<Gate*> subgraph;
1159  for (const auto& gt : gate_types)
1160  {
1161  for (const auto& g : nl->get_gates([gt](const Gate* g) { return g->get_type() == gt; }))
1162  {
1163  subgraph.push_back(g);
1164  }
1165  }
1166 
1167  return resynthesize_subgraph(nl, subgraph, target_gl);
1168  }
1169 
1170  // NOTE there are about a hundred more checks that we could do here
1171  Result<std::monostate> replace_subgraph_with_netlist(const std::vector<Gate*>& subgraph,
1172  const std::unordered_map<Net*, std::vector<Net*>>& global_io_mapping,
1173  const Netlist* src_nl,
1174  Netlist* dst_nl,
1175  const bool delete_subgraph_gates)
1176  {
1177  std::unordered_map<std::string, Gate*> gate_name_to_gate;
1178 
1179  const auto dst_gl = dst_nl->get_gate_library();
1180 
1181  // add all gates of the source netlist to the destination netlist
1182  for (const auto src_g : src_nl->get_gates())
1183  {
1184  const auto src_gt = src_g->get_type();
1185  const auto dst_gt = dst_gl->get_gate_type_by_name(src_gt->get_name());
1186  if (!dst_gt)
1187  {
1188  return ERR("unable to replace subgraph with netlist: gate library '" + dst_gl->get_name() + "' does not contain the required gate type " + src_gt->get_name());
1189  }
1190 
1191  auto new_gate = dst_nl->create_gate(dst_gt, "TEMP");
1192  const std::string new_name = new_gate_name(new_gate, src_g);
1193  new_gate->set_name(new_name);
1194 
1195  gate_name_to_gate.insert({src_g->get_name(), new_gate});
1196  }
1197 
1198  // connect all nets of the source netlist to the destination netlist
1199  for (const auto src_n : src_nl->get_nets())
1200  {
1201  Net* new_net = nullptr;
1202 
1203  // edge case for global inputs
1204  if (src_n->is_global_input_net())
1205  {
1206  if (const auto it = global_io_mapping.find(src_n); it != global_io_mapping.end())
1207  {
1208  const auto& net_connections = global_io_mapping.at(src_n);
1209  if (net_connections.size() != 1)
1210  {
1211  return ERR("unable to replace subgraph with netlist: found " + std::to_string(net_connections.size()) + " net connections to the global input " + src_n->get_name()
1212  + ", this would lead to multi-driven nets");
1213  }
1214  new_net = net_connections.front();
1215  }
1216  else
1217  {
1218  return ERR("unable to replace subgraph with netlist: failed to locate mapped net in destination netlist for global I/O net '" + src_n->get_name() + "' with ID "
1219  + std::to_string(src_n->get_id()));
1220  }
1221  }
1222  else if (src_n->is_global_output_net())
1223  {
1224  if (const auto it = global_io_mapping.find(src_n); it != global_io_mapping.end())
1225  {
1226  const auto& net_connections = global_io_mapping.at(src_n);
1227  new_net = net_connections.front();
1228 
1229  if (net_connections.size() != 1)
1230  {
1231  log_warning("resynthesis", "found multiple io connections for net '{}' with ID {}, this might lead to missing nets in the netlist", src_n->get_name(), src_n->get_id());
1232  // for (const auto& net : net_connections)
1233  // {
1234  // std::cout << net->get_id() << " - " << net->get_name() << std::endl;
1235  // }
1236 
1237  // if a single global output of the src netlist leads to multiple nets in the dst netlist, that means that the nets are functionally equivalent and we can connect/merge them.
1238  // however this can lead to nets disappearing from the dst netlist which might be unexpected behavior.
1239 
1240  for (u32 i = 1; i < net_connections.size(); i++)
1241  {
1242  const auto& res = NetlistModificationDecorator(*dst_nl).connect_nets(new_net, net_connections.at(i));
1243  if (res.is_error())
1244  {
1245  return ERR("unable to replace subgraph with netlist: failed to connect/merge all the net connections of net '" + src_n->get_name() + "' with ID "
1246  + std::to_string(src_n->get_id()));
1247  }
1248  }
1249  }
1250  else
1251  {
1252  new_net = net_connections.front();
1253  }
1254  }
1255  else
1256  {
1257  return ERR("unable to replace subgraph with netlist: failed to locate mapped net in destination netlist for global I/O net '" + src_n->get_name() + "' with ID "
1258  + std::to_string(src_n->get_id()));
1259  }
1260  }
1261  else if (src_n->is_gnd_net())
1262  {
1263  // set new net to an existing gnd net
1264  const auto gnd_gate = dst_nl->get_gnd_gates().front();
1265  const auto out_net = gnd_gate->get_fan_out_nets().front();
1266  new_net = out_net;
1267  }
1268  else if (src_n->is_vcc_net())
1269  {
1270  const auto vcc_gate = dst_nl->get_vcc_gates().front();
1271  const auto out_net = vcc_gate->get_fan_out_nets().front();
1272  new_net = out_net;
1273  }
1274  else
1275  {
1276  new_net = dst_nl->create_net("TEMP");
1277  const std::string new_name = new_net_name(new_net, src_n);
1278  new_net->set_name(new_name);
1279  }
1280 
1281  // connect net to sources
1282  for (const auto src_ep : src_n->get_sources())
1283  {
1284  const auto org_src_name = src_ep->get_gate()->get_name();
1285  const auto org_src_pin_name = src_ep->get_pin()->get_name();
1286  auto new_src_g = gate_name_to_gate.at(org_src_name);
1287  if (new_net->add_source(new_src_g, org_src_pin_name) == nullptr)
1288  {
1289  return ERR("unable to replace subgraph with netlist: failed to add gate '" + new_src_g->get_name() + "' with ID " + std::to_string(new_src_g->get_id()) + " at pin '"
1290  + org_src_pin_name + "' as new source to net '" + new_net->get_name() + "' with ID " + std::to_string(new_net->get_id()));
1291  }
1292  }
1293 
1294  // connect net to destinations
1295  for (const auto src_ep : src_n->get_destinations())
1296  {
1297  const auto org_dst_name = src_ep->get_gate()->get_name();
1298  const auto org_dst_pin_name = src_ep->get_pin()->get_name();
1299  auto new_dst_g = gate_name_to_gate.at(org_dst_name);
1300  if (!new_net->add_destination(new_dst_g, org_dst_pin_name))
1301  {
1302  return ERR("unable to replace subgraph with netlist: failed to add gate '" + new_dst_g->get_name() + "' with ID " + std::to_string(new_dst_g->get_id()) + " at pin '"
1303  + org_dst_pin_name + "' as new destination to net '" + new_net->get_name() + "' with ID " + std::to_string(new_net->get_id()));
1304  }
1305  }
1306  }
1307 
1308  // delete subgraph gates if flag is set
1309  if (delete_subgraph_gates)
1310  {
1311  auto delete_res = delete_subgraph(dst_nl, subgraph);
1312  if (delete_res.is_error())
1313  {
1314  return ERR_APPEND(delete_res.get_error(), "unable to replace subgraph with netlist: failed to delete subgraph");
1315  }
1316  }
1317 
1318  return OK({});
1319  }
1320 
1321  Result<std::unique_ptr<Netlist>> generate_resynth_netlist_for_boolean_functions(const std::unordered_map<std::string, BooleanFunction>& bfs,
1322  const std::filesystem::path& genlib_path,
1323  GateLibrary* target_gl,
1324  const bool optimize_area)
1325  {
1326  const auto verilog_module = build_functional_verilog_module_from(bfs);
1327 
1328  auto base_path_res = utils::get_unique_temp_directory("resynthesis_");
1329  if (base_path_res.is_error())
1330  {
1331  return ERR_APPEND(base_path_res.get_error(), "unable to resynthesize Boolean functions with yosys: failed to get unique temp directory");
1332  }
1333  const std::filesystem::path base_path = base_path_res.get();
1334  const std::filesystem::path functional_netlist_path = base_path / "func_netlist.v";
1335  const std::filesystem::path resynthesized_netlist_path = base_path / "resynth_netlist.v";
1336 
1337  std::filesystem::create_directory(base_path);
1338 
1339  std::ofstream out(functional_netlist_path);
1340  out << verilog_module;
1341  out.close();
1342 
1343  auto yosys_query_res = yosys::query_binary_path();
1344  if (yosys_query_res.is_error())
1345  {
1346  return ERR_APPEND(yosys_query_res.get_error(), "unable to resynthesize Boolean functions with yosys: failed to find yosys path");
1347  }
1348 
1349  const auto yosys_path = yosys_query_res.get();
1350  const std::string command = yosys_path + " -q -p " + "\"read -sv " + functional_netlist_path.string() + "; hierarchy -top top; proc; fsm; opt; memory; opt; techmap; opt; abc -genlib "
1351  + genlib_path.string() + "; " + "write_verilog " + resynthesized_netlist_path.string() + "; clean\"";
1352 
1353  // TODO check again the proper way to start a subprocess
1354  system(command.c_str());
1355 
1357  LogManager::get_instance()->deactivate_channel("netlist_parser");
1358  auto resynth_nl = netlist_factory::load_netlist(resynthesized_netlist_path, target_gl);
1359  if (resynth_nl == nullptr)
1360  {
1361  return ERR("unable to resynthesize Boolean functions with yosys: failed to load re-synthesized netlist at " + resynthesized_netlist_path.string());
1362  }
1364  LogManager::get_instance()->activate_channel("netlist_parser");
1365 
1366  // TODO check whether this is needed here or maybe move this somewhere else
1367  // yosys workaround for stupid net renaming
1368  for (const auto& pin : resynth_nl->get_top_module()->get_input_pins())
1369  {
1370  auto net = pin->get_net();
1371  net->set_name(pin->get_name());
1372  }
1373 
1374  // delete the created directory and the contained files
1375  std::filesystem::remove_all(base_path);
1376 
1377  return OK(std::move(resynth_nl));
1378  }
1379  } // namespace resynthesis
1380 
1381 } // namespace hal
Definition: gate.h:59
BooleanFunction get_boolean_function(const std::string &name) const
Definition: gate.cpp:246
GateType * get_type() const
Definition: gate.cpp:162
const std::string & get_name() const
Definition: gate.cpp:142
u32 get_id() const
Definition: gate.cpp:132
GateType * get_gate_type_by_name(const std::string &name) const
std::string get_name() const
T * get_component_as(const std::function< bool(const GateTypeComponent *)> &filter=nullptr)
std::vector< GatePin * > get_output_pins() const
Definition: gate_type.cpp:285
const std::string & get_name() const
Definition: gate_type.cpp:64
const std::unordered_map< std::string, LUTOutputConfig > & get_output_pin_configs() const
Result< std::string > get_init_string(const Gate *gate, const std::string &pin_name) const
void activate_channel(const std::string &channel_name)
Definition: log.cpp:178
void deactivate_channel(const std::string &channel_name)
Definition: log.cpp:191
static LogManager * get_instance(const std::filesystem::path &file_name="")
Definition: log.cpp:61
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
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
const std::vector< Gate * > & get_gates() const
Definition: netlist.cpp:206
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
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
Result< Net * > connect_nets(Net *master_net, Net *slave_net)
uint32_t u32
Definition: defines.h:41
#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< Netlist > create_netlist(const GateLibrary *gate_library)
Create a new empty netlist using the specified gate library.
std::unique_ptr< Netlist > load_netlist(const std::filesystem::path &netlist_file, const std::filesystem::path &gate_library_file=std::filesystem::path())
Create a netlist from the given file.
bool write(Netlist *netlist, const ProgramArguments &args)
Result< u32 > resynthesize_gates(Netlist *nl, const std::vector< Gate * > &gates, GateLibrary *target_gl)
Result< std::monostate > decompose_gate(Netlist *nl, Gate *gate, const bool delete_gate=true)
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::monostate > resynthesize_gate(Netlist *nl, Gate *gate, GateLibrary *target_gl, const bool delete_gate=true)
Result< u32 > decompose_gates_of_type(Netlist *nl, const std::vector< const GateType * > &gate_types)
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)
Result< u32 > resynthesize_subgraph_of_type(Netlist *nl, const std::vector< const GateType * > &gate_types, GateLibrary *target_gl)
Result< u32 > resynthesize_subgraph(Netlist *nl, const std::vector< Gate * > &subgraph, GateLibrary *target_gl)
Result< u32 > resynthesize_gates_of_type(Netlist *nl, const std::vector< const GateType * > &gate_types, GateLibrary *target_gl)
Result< std::filesystem::path > get_unique_temp_directory(const std::string &prefix="", const u32 max_attempts=5)
Definition: utils.cpp:276
Result< std::string > query_binary_path()
const std::string get_helper_gate_lib()
Definition: resynthesis.cpp:26
Definition: defines.h:45
std::error_code error_code
Definition: defines.h:46
Net * net
std::string name
This file contains various functions to create and load netlists.
This file contains functions to decompose or re-synthesize combinational parts of a gate-level netlis...