20 #include <string_view>
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";
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";
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";
185 return yosys_gate_lib;
190 namespace fs = std::filesystem;
193 static constexpr std::array<const char*, 4> kKnown = {
"/usr/bin/yosys",
194 "/usr/local/bin/yosys",
195 "/opt/homebrew/bin/yosys",
198 for (
const char* p : kKnown)
202 return OK(std::string{p});
207 const char* raw = std::getenv(
"PATH");
208 if (raw ==
nullptr || *raw ==
'\0')
210 return ERR(
"could not query binary path: PATH is empty");
213 std::string_view path{raw};
214 while (!path.empty())
216 std::size_t sep = path.find(
':');
217 std::string_view dir = path.substr(0, sep);
220 fs::path candidate = fs::path(dir) /
"yosys";
222 if (fs::exists(candidate, ec) && !ec)
224 return OK(candidate.string());
227 if (sep == std::string_view::npos)
231 path.remove_prefix(sep + 1);
234 return ERR(
"could not query binary path: yosys not found in PATH or default locations");
241 std::string new_net_name(
const Net* dst_net,
const Net* new_net)
243 return new_net->get_name() +
"_" + std::to_string(dst_net->get_id()) +
"_NEW_NET";
246 std::string new_gate_name(
const Gate* dst_gate,
const Gate* new_gate)
248 return new_gate->get_name() +
"_" + std::to_string(dst_gate->get_id()) +
"_NEW_GATE";
251 Result<std::monostate> delete_subgraph(Netlist* nl,
const std::vector<Gate*> subgraph)
254 for (
const auto& g : subgraph)
256 if (!nl->delete_gate(g))
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()));
266 Result<std::monostate> replace_gate_with_netlist(Gate* g,
const Netlist* src_nl, Netlist* dst_nl,
const bool delete_gate =
true)
268 std::unordered_map<Net*, std::vector<Net*>> global_io_mapping;
270 for (
const auto& g_i : src_nl->get_top_module()->get_input_pins())
272 const auto& pin_name = g_i->get_name();
273 const auto i_net = g->get_fan_in_net(pin_name);
275 if (i_net ==
nullptr)
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 +
"'");
280 global_io_mapping[g_i->get_net()].push_back(i_net);
283 for (
const auto& g_o : src_nl->get_top_module()->get_output_pins())
285 const auto& pin_name = g_o->get_name();
286 const auto o_net = g->get_fan_out_net(pin_name);
288 if (o_net ==
nullptr)
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 +
"'");
293 global_io_mapping[g_o->get_net()].push_back(o_net);
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)
302 const auto get_valid_input_pins = [](
const GateType* gt) -> std::vector<GatePin*> {
306 const auto get_valid_output_pins = [](
const GateType* gt) -> std::vector<GatePin*> {
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);
315 if (candidates.empty())
317 return ERR(
"unable to find gate type matching the description");
320 GateType* valid_gate_type = candidates.begin()->second;
322 return OK({valid_gate_type, get_valid_input_pins(valid_gate_type), get_valid_output_pins(valid_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)
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());
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());
340 return ERR(
"cannot build gate tree for Boolean function: Boolean function is empty");
345 return ERR(
"cannot build gate tree for Boolean function: Boolean function is of type index");
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");
353 if (bf.is_constant())
355 if (bf.has_constant_value(0))
357 static Net* zero = nl->get_nets([](
const Net* n) {
return n->is_gnd_net(); }).front();
361 if (bf.has_constant_value(1))
363 static Net* one = nl->get_nets([](
const Net* n) {
return n->is_vcc_net(); }).front();
368 if (bf.is_variable())
370 if (
const auto it = var_name_to_net.find(bf.get_variable_name().get()); it == var_name_to_net.end())
372 return ERR(
"cannot build gate tree for Boolean function: found variable '" + bf.get_variable_name().get() +
"' with no corresponding net provided");
376 return OK(it->second);
380 if (!bf.get_top_level_node().is_operation())
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() +
"'");
385 const auto operation = bf.get_top_level_node().type;
386 const auto parameters = bf.get_parameters();
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);
394 if (inv_type_res.is_error())
396 return ERR(
"cannot build gate tree for Boolean function: failed to find valid 'INVERT' gate type");
399 if (and_type_res.is_error())
401 return ERR(
"cannot build gate tree for Boolean function: failed to find valid 'AND' gate type");
404 if (or_type_res.is_error())
406 return ERR(
"cannot build gate tree for Boolean function: failed to find valid 'OR' gate type");
409 if (xor_type_res.is_error())
411 return ERR(
"cannot build gate tree for Boolean function: failed to find valid 'XOR' gate type");
414 const std::map<u16, std::tuple<GateType*, std::vector<GatePin*>, std::vector<GatePin*>>> node_type_to_gate_type = {
421 std::vector<Net*> parameter_nets;
422 for (
const auto& p : parameters)
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())
427 return ERR_APPEND(tree_res.get_error(),
"cannot build gate tree for Boolean function: failed to do so for sub tree");
429 parameter_nets.push_back(tree_res.get());
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));
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++)
446 parameter_nets.at(idx)->add_destination(new_gate, in_pins.at(idx));
448 output_net->add_source(new_gate, out_pins.front());
455 if (new_gate ==
nullptr)
457 return ERR(
"cannot build gate tree for Boolean function: failed to create gate for operation '" + bf.get_top_level_node().to_string() +
"'");
460 new_gate->set_name(create_gate_name(new_gate, org_gate));
462 if (org_gate !=
nullptr && !org_gate->get_module()->is_top_module())
464 org_gate->get_module()->assign_gate(new_gate);
467 return OK(output_net);
470 Result<std::unique_ptr<Netlist>> generate_decomposed_netlist_from_boolean_function(
const std::vector<std::pair<std::string, BooleanFunction>>& bfs,
const GateLibrary* gl)
474 std::map<std::string, Net*> var_name_to_net;
475 for (
const auto& [out_pin_name, bf] : bfs)
477 const auto bf_vars = bf.get_variable_names();
478 for (
const auto& var : bf_vars)
480 if (var_name_to_net.find(var) != var_name_to_net.end())
485 Net* new_net = nl->create_net(var);
488 return ERR(
"unable to generate decomposed netlist from Boolean function: failed to create net for boolean input var '" + var +
"'");
491 new_net->mark_global_input_net();
492 var_name_to_net.insert({var, new_net});
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())
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");
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);
508 Module* top_mod = nl->get_top_module();
509 for (
const auto& [var, in_net] : var_name_to_net)
511 auto in_pin = top_mod->get_pin_by_net(in_net);
512 top_mod->set_pin_name(in_pin, var,
true);
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);
518 return OK(std::move(nl));
521 std::string build_functional_verilog_module_from(
const std::unordered_map<std::string, BooleanFunction>& bfs)
523 std::unordered_set<std::string> input_variable_names;
525 for (
const auto& [
name, bf] : bfs)
527 for (
const auto& var_name : bf.get_variable_names())
529 input_variable_names.insert(var_name);
533 std::string verilog_str =
"module top (";
535 std::string var_str =
"";
536 std::string io_str =
"";
537 std::string function_str =
"";
539 for (
const auto& input_var : input_variable_names)
541 var_str += (input_var +
", ");
542 io_str += (
"input " + input_var +
";\n");
545 for (
const auto& [output_var, bf] : bfs)
547 var_str += (output_var +
", ");
548 io_str += (
"output " + output_var +
";\n");
549 function_str += (
"assign " + output_var +
" = " + bf.to_string() +
";\n");
552 var_str = var_str.substr(0, var_str.size() - 2);
554 verilog_str += var_str;
555 verilog_str +=
");\n";
557 verilog_str += io_str;
561 verilog_str += function_str;
564 verilog_str +=
"endmodule\n";
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)
579 return ERR(
"unable to re-synthesize gate-level subgraph: netlist is a 'nullptr'");
582 if (target_gl ==
nullptr)
584 return ERR(
"unable to re-synthesize gate-level subgraph: gate library is a 'nullptr'");
587 auto subgraph_nl_res = SubgraphNetlistDecorator(*nl).copy_subgraph_netlist(subgraph,
true);
588 if (subgraph_nl_res.is_error())
590 return ERR_APPEND(subgraph_nl_res.get_error(),
"unable to re-synthesize gate-level subgraph: failed to copy subgraph netlist");
592 const auto subgraph_nl = subgraph_nl_res.get();
595 if (base_path_res.is_error())
597 return ERR_APPEND(base_path_res.get_error(),
"unable to re-synthesize Boolean functions with yosys: failed to get unique temp directory");
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";
604 std::filesystem::create_directory(base_path);
608 return ERR(
"unable to re-synthesize gate-level subgraph: failed to write netlist to file");
613 std::vector<std::string> lines;
614 std::ifstream input_file(org_netlist_path);
617 while (std::getline(input_file, line))
619 lines.push_back(line);
626 lines.erase(lines.begin());
630 std::ofstream output_file(org_netlist_path);
631 for (
const auto& out_line : lines)
633 output_file << out_line << std::endl;
637 std::ofstream yosys_helper_lib_file(yosys_helper_lib_path);
639 yosys_helper_lib_file.close();
642 if (yosys_query_res.is_error())
644 return ERR_APPEND(yosys_query_res.get_error(),
"unable to re-synthesize Boolean functions with yosys: failed to find yosys path");
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() +
";" +
'"';
653 system(command.c_str());
658 if (resynth_nl ==
nullptr)
660 return ERR(
"unable to re-synthesize gate-level netlist with yosys: failed to load resynthesized netlist at " + resynthesized_netlist_path.string());
666 std::filesystem::remove_all(base_path);
668 return OK(std::move(resynth_nl));
692 Result<std::unique_ptr<Netlist>> generate_resynth_netlist_for_gate(
const Gate* g, GateLibrary* target_gl,
const std::filesystem::path& genlib_path)
695 std::unordered_map<std::string, BooleanFunction> output_pin_name_to_bf;
696 for (
const auto pin : g->get_type()->get_output_pins())
698 const auto bf_res = g->get_boolean_function(pin,
true,
false);
699 if (bf_res.is_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() +
"'");
706 const auto bf = bf_res.get();
707 output_pin_name_to_bf.insert({pin->get_name(), bf});
711 if (resynth_res.is_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");
718 return OK(resynth_res.get());
722 namespace resynthesis
729 std::vector<std::pair<std::string, BooleanFunction>> output_pin_name_to_bf;
733 if (bf_res.is_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() +
"'");
740 const auto bf = bf_res.get();
741 output_pin_name_to_bf.push_back({pin->get_name(), bf});
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())
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");
749 auto unique_resynth_nl = resynth_res.get();
751 const auto replace_res = replace_gate_with_netlist(g, unique_resynth_nl.get(), nl,
false);
752 if (replace_res.is_error())
755 "unable to decompose gate '" + g->
get_name() +
"' with ID " + std::to_string(g->
get_id()) +
": failed to replace gate with decomposed netlist");
762 return ERR(
"unable to decompose gate '" + g->
get_name() +
"' with ID " + std::to_string(g->
get_id()) +
": failed to delete original gate");
771 std::map<std::pair<const GateType*, std::vector<std::string>>, std::unique_ptr<Netlist>> gt_to_decomposed;
774 for (
const auto& gt : gate_types)
776 std::vector<Gate*> to_delete;
777 for (
const auto& g : nl->
get_gates([gt](
const Gate* g) { return g->get_type() == gt; }))
779 const Netlist* resynth_nl =
nullptr;
780 std::vector<std::string> init_data;
788 return ERR(
"unable to decompose gates of type: gate type '" + gt->get_name() +
"' has no LUT component");
792 std::vector<std::string> ids;
795 if (std::find(ids.begin(), ids.end(), cfg.init_identifier) == ids.end())
796 ids.push_back(cfg.init_identifier);
798 std::sort(ids.begin(), ids.end());
800 for (
const auto&
id : ids)
804 if (cfg.init_identifier ==
id)
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()));
813 init_data.push_back(res.get());
819 if (init_data.size() != 1)
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()));
827 if (
const auto it = gt_to_decomposed.find({gt, init_data}); it != gt_to_decomposed.end())
829 resynth_nl = it->second.get();
836 std::vector<std::pair<std::string, BooleanFunction>> output_pin_name_to_bf;
840 if (bf_res.is_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() +
"'");
847 const auto bf = bf_res.get();
848 output_pin_name_to_bf.push_back({pin->get_name(), bf});
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())
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() +
"'");
856 auto unique_resynth_nl = resynth_res.get();
857 resynth_nl = unique_resynth_nl.get();
859 gt_to_decomposed.insert({std::make_pair(gt, init_data), std::move(unique_resynth_nl)});
862 const auto replace_res = replace_gate_with_netlist(g, resynth_nl, nl,
false);
863 if (replace_res.is_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()));
868 to_delete.push_back(g);
871 for (
const auto& g : to_delete)
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()));
888 return ERR(
"could not re-synthesize gate, netlist is a 'nullptr'");
893 return ERR(
"could not re-synthesize gate, gate is a 'nullptr'");
896 if (target_gl ==
nullptr)
898 return ERR(
"could not re-synthesize gate, target gate library is a 'nullptr'");
902 if (base_path_res.is_error())
904 return ERR_APPEND(base_path_res.get_error(),
"unable to re-synthesize Boolean functions with yosys: failed to get unique temp directory");
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);
913 return ERR(
"unable to re-synthesize gates of type: failed to save gate library '" + target_gl->
get_name() +
"' at location '" + genlib_path.string() +
"'");
916 auto resynth_res = generate_resynth_netlist_for_gate(gate, target_gl, genlib_path);
917 if (resynth_res.is_error())
920 "unable to re-synthesize gate '" + gate->
get_name() +
"' with ID " + std::to_string(gate->
get_id()) +
": failed to generate re-synthesized netlist");
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())
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");
934 return ERR(
"unable to decompose gate '" + gate->
get_name() +
"' with ID " + std::to_string(gate->
get_id()) +
": failed to delete original gate.");
944 if (base_path_res.is_error())
946 return ERR_APPEND(base_path_res.get_error(),
"unable to re-synthesize Boolean functions with yosys: failed to get unique temp directory");
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);
955 return ERR(
"unable to re-synthesize gates of type: failed to save gate library '" + target_gl->
get_name() +
"' to location " + genlib_path.string());
958 std::map<std::pair<const GateType*, std::vector<std::string>>, std::unique_ptr<Netlist>> gt_to_resynth;
960 std::vector<Gate*> to_delete;
962 for (
const auto& g : gates)
964 const auto& gt = g->get_type();
967 std::vector<std::string> init_data = {};
975 return ERR(
"unable to re-synthesize gates of type: gate type '" + gt->get_name() +
"' has no LUT component");
979 std::vector<std::string> ids;
982 if (std::find(ids.begin(), ids.end(), cfg.init_identifier) == ids.end())
983 ids.push_back(cfg.init_identifier);
985 std::sort(ids.begin(), ids.end());
987 for (
const auto&
id : ids)
991 if (cfg.init_identifier ==
id)
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()));
1000 init_data.push_back(res.get());
1006 if (init_data.size() != 1)
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()));
1014 if (
const auto it = gt_to_resynth.find({gt, init_data}); it != gt_to_resynth.end())
1016 resynth_nl = it->second.get();
1020 auto resynth_res = generate_resynth_netlist_for_gate(g, target_gl, genlib_path);
1021 if (resynth_res.is_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()));
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)});
1031 const auto replace_res = replace_gate_with_netlist(g, resynth_nl, nl,
false);
1032 if (replace_res.is_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()));
1037 to_delete.push_back(g);
1040 for (
const auto& g : to_delete)
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()));
1050 std::filesystem::remove_all(base_path);
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)
1061 if (gate->get_type() == gt)
1078 return ERR(
"netlist is a 'nullptr'");
1081 if (target_gl ==
nullptr)
1083 return ERR(
"gate library is a 'nullptr'");
1087 if (base_path_res.is_error())
1089 return ERR_APPEND(base_path_res.get_error(),
"unable to re-synthesize Boolean functions with yosys: failed to get unique temp directory");
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);
1098 return ERR(
"unable to re-synthesize gates of type: failed to save gate library '" + target_gl->
get_name() +
"' to location " + genlib_path.string());
1102 auto resynth_res = generate_resynth_netlist_for_gate_level_subgraph(nl, subgraph, genlib_path, target_gl,
true);
1103 if (resynth_res.is_error())
1105 return ERR_APPEND(resynth_res.get_error(),
"unable to re-synthesize subgraphs of type: failed to re-synthesize subgraph to netlist");
1107 auto resynth_nl = resynth_res.get();
1109 std::unordered_map<std::string, Net*> name_to_net;
1110 for (
const auto n : nl->
get_nets())
1112 name_to_net.insert({n->get_name(), n});
1115 std::unordered_map<Net*, std::vector<Net*>> global_io_mapping;
1118 for (
const auto& pin : resynth_nl->get_top_module()->get_input_pins())
1120 auto net_it = name_to_net.find(pin->get_name());
1121 if (net_it == name_to_net.end())
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");
1125 global_io_mapping[pin->get_net()].push_back(net_it->second);
1127 for (
const auto& pin : resynth_nl->get_top_module()->get_output_pins())
1129 auto net_it = name_to_net.find(pin->get_name());
1130 if (net_it == name_to_net.end())
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");
1134 global_io_mapping[pin->get_net()].push_back(net_it->second);
1138 if (replace_res.is_error())
1140 return ERR_APPEND(replace_res.get_error(),
"unable to re-synthesize subgraphs of type: failed to replace subgraph with re-synthesized netlist");
1144 auto delete_res = delete_subgraph(nl, subgraph);
1145 if (delete_res.is_error())
1147 return ERR_APPEND(delete_res.get_error(),
"unable to replace subgraph with netlist: failed to delete subgraph");
1151 std::filesystem::remove_all(base_path);
1153 return OK(
static_cast<unsigned int>(subgraph.size()));
1158 std::vector<Gate*> subgraph;
1159 for (
const auto& gt : gate_types)
1161 for (
const auto& g : nl->
get_gates([gt](
const Gate* g) { return g->get_type() == gt; }))
1163 subgraph.push_back(g);
1172 const std::unordered_map<
Net*, std::vector<Net*>>& global_io_mapping,
1175 const bool delete_subgraph_gates)
1177 std::unordered_map<std::string, Gate*> gate_name_to_gate;
1182 for (
const auto src_g : src_nl->
get_gates())
1184 const auto src_gt = src_g->get_type();
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());
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);
1195 gate_name_to_gate.insert({src_g->get_name(), new_gate});
1199 for (
const auto src_n : src_nl->
get_nets())
1201 Net* new_net =
nullptr;
1204 if (src_n->is_global_input_net())
1206 if (
const auto it = global_io_mapping.find(src_n); it != global_io_mapping.end())
1208 const auto& net_connections = global_io_mapping.at(src_n);
1209 if (net_connections.size() != 1)
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");
1214 new_net = net_connections.front();
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()));
1222 else if (src_n->is_global_output_net())
1224 if (
const auto it = global_io_mapping.find(src_n); it != global_io_mapping.end())
1226 const auto& net_connections = global_io_mapping.at(src_n);
1227 new_net = net_connections.front();
1229 if (net_connections.size() != 1)
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());
1240 for (
u32 i = 1; i < net_connections.size(); i++)
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()));
1252 new_net = net_connections.front();
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()));
1261 else if (src_n->is_gnd_net())
1265 const auto out_net = gnd_gate->get_fan_out_nets().front();
1268 else if (src_n->is_vcc_net())
1271 const auto out_net = vcc_gate->get_fan_out_nets().front();
1277 const std::string new_name = new_net_name(new_net, src_n);
1282 for (
const auto src_ep : src_n->get_sources())
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)
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()));
1295 for (
const auto src_ep : src_n->get_destinations())
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);
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()));
1309 if (delete_subgraph_gates)
1311 auto delete_res = delete_subgraph(dst_nl, subgraph);
1312 if (delete_res.is_error())
1314 return ERR_APPEND(delete_res.get_error(),
"unable to replace subgraph with netlist: failed to delete subgraph");
1322 const std::filesystem::path& genlib_path,
1324 const bool optimize_area)
1326 const auto verilog_module = build_functional_verilog_module_from(bfs);
1329 if (base_path_res.is_error())
1331 return ERR_APPEND(base_path_res.get_error(),
"unable to resynthesize Boolean functions with yosys: failed to get unique temp directory");
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";
1337 std::filesystem::create_directory(base_path);
1339 std::ofstream out(functional_netlist_path);
1340 out << verilog_module;
1344 if (yosys_query_res.is_error())
1346 return ERR_APPEND(yosys_query_res.get_error(),
"unable to resynthesize Boolean functions with yosys: failed to find yosys path");
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\"";
1354 system(command.c_str());
1359 if (resynth_nl ==
nullptr)
1361 return ERR(
"unable to resynthesize Boolean functions with yosys: failed to load re-synthesized netlist at " + resynthesized_netlist_path.string());
1368 for (
const auto& pin : resynth_nl->get_top_module()->get_input_pins())
1370 auto net = pin->get_net();
1371 net->set_name(pin->get_name());
1375 std::filesystem::remove_all(base_path);
1377 return OK(std::move(resynth_nl));
BooleanFunction get_boolean_function(const std::string &name) const
GateType * get_type() const
const std::string & get_name() const
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
const std::string & get_name() const
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)
void deactivate_channel(const std::string &channel_name)
static LogManager * get_instance(const std::filesystem::path &file_name="")
Endpoint * add_destination(Gate *gate, const std::string &pin_name)
void set_name(const std::string &name)
Endpoint * add_source(Gate *gate, const std::string &pin_name)
const std::string & get_name() const
const std::vector< Gate * > & get_gates() const
Net * create_net(const u32 net_id, const std::string &name)
const std::vector< Gate * > & get_gnd_gates() const
const std::vector< Gate * > & get_vcc_gates() const
bool delete_gate(Gate *gate)
Gate * create_gate(const u32 gate_id, GateType *gate_type, const std::string &name="", i32 x=-1, i32 y=-1)
const std::vector< Net * > & get_nets() const
const GateLibrary * get_gate_library() const
Result< Net * > connect_nets(Net *master_net, Net *slave_net)
#define log_warning(channel,...)
#define ERR_APPEND(prev_error, message)
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)
Result< std::string > query_binary_path()
const std::string get_helper_gate_lib()
std::error_code error_code
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...