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