19 #include <string_view>
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";
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";
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";
184 return yosys_gate_lib;
189 namespace fs = std::filesystem;
192 static constexpr std::array<const char*, 4> kKnown = {
"/usr/bin/yosys",
193 "/usr/local/bin/yosys",
194 "/opt/homebrew/bin/yosys",
197 for (
const char* p : kKnown)
201 return OK(std::string{p});
206 const char* raw = std::getenv(
"PATH");
207 if (raw ==
nullptr || *raw ==
'\0')
209 return ERR(
"could not query binary path: PATH is empty");
212 std::string_view path{raw};
213 while (!path.empty())
215 std::size_t sep = path.find(
':');
216 std::string_view dir = path.substr(0, sep);
219 fs::path candidate = fs::path(dir) /
"yosys";
221 if (fs::exists(candidate, ec) && !ec)
223 return OK(candidate.string());
226 if (sep == std::string_view::npos)
230 path.remove_prefix(sep + 1);
233 return ERR(
"could not query binary path: yosys not found in PATH or default locations");
240 std::string new_net_name(
const Net* dst_net,
const Net* new_net)
242 return new_net->get_name() +
"_" + std::to_string(dst_net->get_id()) +
"_NEW_NET";
245 std::string new_gate_name(
const Gate* dst_gate,
const Gate* new_gate)
247 return new_gate->get_name() +
"_" + std::to_string(dst_gate->get_id()) +
"_NEW_GATE";
250 Result<std::monostate> delete_subgraph(Netlist* nl,
const std::vector<Gate*> subgraph)
253 for (
const auto& g : subgraph)
255 if (!nl->delete_gate(g))
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()));
265 Result<std::monostate> replace_gate_with_netlist(Gate* g,
const Netlist* src_nl, Netlist* dst_nl,
const bool delete_gate =
true)
267 std::unordered_map<Net*, std::vector<Net*>> global_io_mapping;
269 for (
const auto& g_i : src_nl->get_top_module()->get_input_pins())
271 const auto& pin_name = g_i->get_name();
272 const auto i_net = g->get_fan_in_net(pin_name);
274 if (i_net ==
nullptr)
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 +
"'");
279 global_io_mapping[g_i->get_net()].push_back(i_net);
282 for (
const auto& g_o : src_nl->get_top_module()->get_output_pins())
284 const auto& pin_name = g_o->get_name();
285 const auto o_net = g->get_fan_out_net(pin_name);
287 if (o_net ==
nullptr)
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 +
"'");
292 global_io_mapping[g_o->get_net()].push_back(o_net);
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)
301 const auto get_valid_input_pins = [](
const GateType* gt) -> std::vector<GatePin*> {
305 const auto get_valid_output_pins = [](
const GateType* gt) -> std::vector<GatePin*> {
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);
314 if (candidates.empty())
316 return ERR(
"unable to find gate type matching the description");
319 GateType* valid_gate_type = candidates.begin()->second;
321 return OK({valid_gate_type, get_valid_input_pins(valid_gate_type), get_valid_output_pins(valid_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)
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());
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());
339 return ERR(
"cannot build gate tree for Boolean function: Boolean function is empty");
344 return ERR(
"cannot build gate tree for Boolean function: Boolean function is of type index");
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");
352 if (bf.is_constant())
354 if (bf.has_constant_value(0))
356 static Net* zero = nl->get_nets([](
const Net* n) {
return n->is_gnd_net(); }).front();
360 if (bf.has_constant_value(1))
362 static Net* one = nl->get_nets([](
const Net* n) {
return n->is_vcc_net(); }).front();
367 if (bf.is_variable())
369 if (
const auto it = var_name_to_net.find(bf.get_variable_name().get()); it == var_name_to_net.end())
371 return ERR(
"cannot build gate tree for Boolean function: found variable '" + bf.get_variable_name().get() +
"' with no corresponding net provided");
375 return OK(it->second);
379 if (!bf.get_top_level_node().is_operation())
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() +
"'");
384 const auto operation = bf.get_top_level_node().type;
385 const auto parameters = bf.get_parameters();
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);
393 if (inv_type_res.is_error())
395 return ERR(
"cannot build gate tree for Boolean function: failed to find valid 'INVERT' gate type");
398 if (and_type_res.is_error())
400 return ERR(
"cannot build gate tree for Boolean function: failed to find valid 'AND' gate type");
403 if (or_type_res.is_error())
405 return ERR(
"cannot build gate tree for Boolean function: failed to find valid 'OR' gate type");
408 if (xor_type_res.is_error())
410 return ERR(
"cannot build gate tree for Boolean function: failed to find valid 'XOR' gate type");
413 const std::map<u16, std::tuple<GateType*, std::vector<GatePin*>, std::vector<GatePin*>>> node_type_to_gate_type = {
420 std::vector<Net*> parameter_nets;
421 for (
const auto& p : parameters)
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())
426 return ERR_APPEND(tree_res.get_error(),
"cannot build gate tree for Boolean function: failed to do so for sub tree");
428 parameter_nets.push_back(tree_res.get());
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));
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++)
445 parameter_nets.at(idx)->add_destination(new_gate, in_pins.at(idx));
447 output_net->add_source(new_gate, out_pins.front());
454 if (new_gate ==
nullptr)
456 return ERR(
"cannot build gate tree for Boolean function: failed to create gate for operation '" + bf.get_top_level_node().to_string() +
"'");
459 new_gate->set_name(create_gate_name(new_gate, org_gate));
461 if (org_gate !=
nullptr && !org_gate->get_module()->is_top_module())
463 org_gate->get_module()->assign_gate(new_gate);
466 return OK(output_net);
469 Result<std::unique_ptr<Netlist>> generate_decomposed_netlist_from_boolean_function(
const std::vector<std::pair<std::string, BooleanFunction>>& bfs,
const GateLibrary* gl)
473 std::map<std::string, Net*> var_name_to_net;
474 for (
const auto& [out_pin_name, bf] : bfs)
476 const auto bf_vars = bf.get_variable_names();
477 for (
const auto& var : bf_vars)
479 if (var_name_to_net.find(var) != var_name_to_net.end())
484 Net* new_net = nl->create_net(var);
487 return ERR(
"unable to generate decomposed netlist from Boolean function: failed to create net for boolean input var '" + var +
"'");
490 new_net->mark_global_input_net();
491 var_name_to_net.insert({var, new_net});
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())
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");
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);
507 Module* top_mod = nl->get_top_module();
508 for (
const auto& [var, in_net] : var_name_to_net)
510 auto in_pin = top_mod->get_pin_by_net(in_net);
511 top_mod->set_pin_name(in_pin, var,
true);
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);
517 return OK(std::move(nl));
520 std::string build_functional_verilog_module_from(
const std::unordered_map<std::string, BooleanFunction>& bfs)
522 std::unordered_set<std::string> input_variable_names;
524 for (
const auto& [
name, bf] : bfs)
526 for (
const auto& var_name : bf.get_variable_names())
528 input_variable_names.insert(var_name);
532 std::string verilog_str =
"module top (";
534 std::string var_str =
"";
535 std::string io_str =
"";
536 std::string function_str =
"";
538 for (
const auto& input_var : input_variable_names)
540 var_str += (input_var +
", ");
541 io_str += (
"input " + input_var +
";\n");
544 for (
const auto& [output_var, bf] : bfs)
546 var_str += (output_var +
", ");
547 io_str += (
"output " + output_var +
";\n");
548 function_str += (
"assign " + output_var +
" = " + bf.to_string() +
";\n");
551 var_str = var_str.substr(0, var_str.size() - 2);
553 verilog_str += var_str;
554 verilog_str +=
");\n";
556 verilog_str += io_str;
560 verilog_str += function_str;
563 verilog_str +=
"endmodule\n";
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)
578 return ERR(
"unable to re-synthesize gate-level subgraph: netlist is a 'nullptr'");
581 if (target_gl ==
nullptr)
583 return ERR(
"unable to re-synthesize gate-level subgraph: gate library is a 'nullptr'");
586 auto subgraph_nl_res = SubgraphNetlistDecorator(*nl).copy_subgraph_netlist(subgraph,
true);
587 if (subgraph_nl_res.is_error())
589 return ERR_APPEND(subgraph_nl_res.get_error(),
"unable to re-synthesize gate-level subgraph: failed to copy subgraph netlist");
591 const auto subgraph_nl = subgraph_nl_res.get();
594 if (base_path_res.is_error())
596 return ERR_APPEND(base_path_res.get_error(),
"unable to re-synthesize Boolean functions with yosys: failed to get unique temp directory");
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";
603 std::filesystem::create_directory(base_path);
607 return ERR(
"unable to re-synthesize gate-level subgraph: failed to write netlist to file");
612 std::vector<std::string> lines;
613 std::ifstream input_file(org_netlist_path);
616 while (std::getline(input_file, line))
618 lines.push_back(line);
625 lines.erase(lines.begin());
629 std::ofstream output_file(org_netlist_path);
630 for (
const auto& out_line : lines)
632 output_file << out_line << std::endl;
636 std::ofstream yosys_helper_lib_file(yosys_helper_lib_path);
638 yosys_helper_lib_file.close();
641 if (yosys_query_res.is_error())
643 return ERR_APPEND(yosys_query_res.get_error(),
"unable to re-synthesize Boolean functions with yosys: failed to find yosys path");
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() +
";" +
'"';
652 system(command.c_str());
657 if (resynth_nl ==
nullptr)
659 return ERR(
"unable to re-synthesize gate-level netlist with yosys: failed to load resynthesized netlist at " + resynthesized_netlist_path.string());
665 std::filesystem::remove_all(base_path);
667 return OK(std::move(resynth_nl));
691 Result<std::unique_ptr<Netlist>> generate_resynth_netlist_for_gate(
const Gate* g, GateLibrary* target_gl,
const std::filesystem::path& genlib_path)
694 std::unordered_map<std::string, BooleanFunction> output_pin_name_to_bf;
695 for (
const auto pin : g->get_type()->get_output_pins())
697 const auto bf_res = g->get_resolved_boolean_function(pin,
true);
698 if (bf_res.is_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() +
"'");
705 const auto bf = bf_res.get();
706 output_pin_name_to_bf.insert({pin->get_name(), bf});
710 if (resynth_res.is_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");
717 return OK(resynth_res.get());
721 namespace resynthesis
728 std::vector<std::pair<std::string, BooleanFunction>> output_pin_name_to_bf;
732 if (bf_res.is_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() +
"'");
739 const auto bf = bf_res.get();
740 output_pin_name_to_bf.push_back({pin->get_name(), bf});
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())
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");
748 auto unique_resynth_nl = resynth_res.get();
750 const auto replace_res = replace_gate_with_netlist(g, unique_resynth_nl.get(), nl,
false);
751 if (replace_res.is_error())
754 "unable to decompose gate '" + g->
get_name() +
"' with ID " + std::to_string(g->
get_id()) +
": failed to replace gate with decomposed netlist");
761 return ERR(
"unable to decompose gate '" + g->
get_name() +
"' with ID " + std::to_string(g->
get_id()) +
": failed to delete original gate");
770 std::map<std::pair<const GateType*, std::vector<std::string>>, std::unique_ptr<Netlist>> gt_to_decomposed;
773 for (
const auto& gt : gate_types)
775 std::vector<Gate*> to_delete;
776 for (
const auto& g : nl->
get_gates([gt](
const Gate* g) { return g->get_type() == gt; }))
778 const Netlist* resynth_nl =
nullptr;
779 std::vector<std::string> init_data;
784 if (init_res.is_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()));
789 const auto init_vec = init_res.get();
790 if (init_vec.size() != 1)
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()));
796 init_data = init_vec;
800 if (
const auto it = gt_to_decomposed.find({gt, init_data}); it != gt_to_decomposed.end())
802 resynth_nl = it->second.get();
809 std::vector<std::pair<std::string, BooleanFunction>> output_pin_name_to_bf;
813 if (bf_res.is_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() +
"'");
820 const auto bf = bf_res.get();
821 output_pin_name_to_bf.push_back({pin->get_name(), bf});
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())
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() +
"'");
829 auto unique_resynth_nl = resynth_res.get();
830 resynth_nl = unique_resynth_nl.get();
832 gt_to_decomposed.insert({std::make_pair(gt, init_data), std::move(unique_resynth_nl)});
835 const auto replace_res = replace_gate_with_netlist(g, resynth_nl, nl,
false);
836 if (replace_res.is_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()));
841 to_delete.push_back(g);
844 for (
const auto& g : to_delete)
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()));
861 return ERR(
"could not re-synthesize gate, netlist is a 'nullptr'");
866 return ERR(
"could not re-synthesize gate, gate is a 'nullptr'");
869 if (target_gl ==
nullptr)
871 return ERR(
"could not re-synthesize gate, target gate library is a 'nullptr'");
875 if (base_path_res.is_error())
877 return ERR_APPEND(base_path_res.get_error(),
"unable to re-synthesize Boolean functions with yosys: failed to get unique temp directory");
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);
886 return ERR(
"unable to re-synthesize gates of type: failed to save gate library '" + target_gl->
get_name() +
"' at location '" + genlib_path.string() +
"'");
889 auto resynth_res = generate_resynth_netlist_for_gate(gate, target_gl, genlib_path);
890 if (resynth_res.is_error())
893 "unable to re-synthesize gate '" + gate->
get_name() +
"' with ID " + std::to_string(gate->
get_id()) +
": failed to generate re-synthesized netlist");
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())
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");
907 return ERR(
"unable to decompose gate '" + gate->
get_name() +
"' with ID " + std::to_string(gate->
get_id()) +
": failed to delete original gate.");
917 if (base_path_res.is_error())
919 return ERR_APPEND(base_path_res.get_error(),
"unable to re-synthesize Boolean functions with yosys: failed to get unique temp directory");
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);
928 return ERR(
"unable to re-synthesize gates of type: failed to save gate library '" + target_gl->
get_name() +
"' to location " + genlib_path.string());
931 std::map<std::pair<const GateType*, std::vector<std::string>>, std::unique_ptr<Netlist>> gt_to_resynth;
933 std::vector<Gate*> to_delete;
935 for (
const auto& g : gates)
937 const auto& gt = g->get_type();
940 std::vector<std::string> init_data = {};
944 const auto init_res = g->get_init_data();
945 if (init_res.is_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()));
950 const auto init_vec = init_res.get();
951 if (init_vec.size() != 1)
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()));
957 init_data = init_vec;
961 if (
const auto it = gt_to_resynth.find({gt, init_data}); it != gt_to_resynth.end())
963 resynth_nl = it->second.get();
967 auto resynth_res = generate_resynth_netlist_for_gate(g, target_gl, genlib_path);
968 if (resynth_res.is_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()));
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)});
978 const auto replace_res = replace_gate_with_netlist(g, resynth_nl, nl,
false);
979 if (replace_res.is_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()));
984 to_delete.push_back(g);
987 for (
const auto& g : to_delete)
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()));
997 std::filesystem::remove_all(base_path);
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)
1008 if (gate->get_type() == gt)
1025 return ERR(
"netlist is a 'nullptr'");
1028 if (target_gl ==
nullptr)
1030 return ERR(
"gate library is a 'nullptr'");
1034 if (base_path_res.is_error())
1036 return ERR_APPEND(base_path_res.get_error(),
"unable to re-synthesize Boolean functions with yosys: failed to get unique temp directory");
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);
1045 return ERR(
"unable to re-synthesize gates of type: failed to save gate library '" + target_gl->
get_name() +
"' to location " + genlib_path.string());
1049 auto resynth_res = generate_resynth_netlist_for_gate_level_subgraph(nl, subgraph, genlib_path, target_gl,
true);
1050 if (resynth_res.is_error())
1052 return ERR_APPEND(resynth_res.get_error(),
"unable to re-synthesize subgraphs of type: failed to re-synthesize subgraph to netlist");
1054 auto resynth_nl = resynth_res.get();
1056 std::unordered_map<std::string, Net*> name_to_net;
1057 for (
const auto n : nl->
get_nets())
1059 name_to_net.insert({n->get_name(), n});
1062 std::unordered_map<Net*, std::vector<Net*>> global_io_mapping;
1065 for (
const auto& pin : resynth_nl->get_top_module()->get_input_pins())
1067 auto net_it = name_to_net.find(pin->get_name());
1068 if (net_it == name_to_net.end())
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");
1072 global_io_mapping[pin->get_net()].push_back(net_it->second);
1074 for (
const auto& pin : resynth_nl->get_top_module()->get_output_pins())
1076 auto net_it = name_to_net.find(pin->get_name());
1077 if (net_it == name_to_net.end())
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");
1081 global_io_mapping[pin->get_net()].push_back(net_it->second);
1085 if (replace_res.is_error())
1087 return ERR_APPEND(replace_res.get_error(),
"unable to re-synthesize subgraphs of type: failed to replace subgraph with re-synthesized netlist");
1091 auto delete_res = delete_subgraph(nl, subgraph);
1092 if (delete_res.is_error())
1094 return ERR_APPEND(delete_res.get_error(),
"unable to replace subgraph with netlist: failed to delete subgraph");
1098 std::filesystem::remove_all(base_path);
1100 return OK(
static_cast<unsigned int>(subgraph.size()));
1105 std::vector<Gate*> subgraph;
1106 for (
const auto& gt : gate_types)
1108 for (
const auto& g : nl->
get_gates([gt](
const Gate* g) { return g->get_type() == gt; }))
1110 subgraph.push_back(g);
1119 const std::unordered_map<
Net*, std::vector<Net*>>& global_io_mapping,
1122 const bool delete_subgraph_gates)
1124 std::unordered_map<std::string, Gate*> gate_name_to_gate;
1129 for (
const auto src_g : src_nl->
get_gates())
1131 const auto src_gt = src_g->get_type();
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());
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);
1142 gate_name_to_gate.insert({src_g->get_name(), new_gate});
1146 for (
const auto src_n : src_nl->
get_nets())
1148 Net* new_net =
nullptr;
1151 if (src_n->is_global_input_net())
1153 if (
const auto it = global_io_mapping.find(src_n); it != global_io_mapping.end())
1155 const auto& net_connections = global_io_mapping.at(src_n);
1156 if (net_connections.size() != 1)
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");
1161 new_net = net_connections.front();
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()));
1169 else if (src_n->is_global_output_net())
1171 if (
const auto it = global_io_mapping.find(src_n); it != global_io_mapping.end())
1173 const auto& net_connections = global_io_mapping.at(src_n);
1174 new_net = net_connections.front();
1176 if (net_connections.size() != 1)
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());
1187 for (
u32 i = 1; i < net_connections.size(); i++)
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()));
1199 new_net = net_connections.front();
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()));
1208 else if (src_n->is_gnd_net())
1212 const auto out_net = gnd_gate->get_fan_out_nets().front();
1215 else if (src_n->is_vcc_net())
1218 const auto out_net = vcc_gate->get_fan_out_nets().front();
1224 const std::string new_name = new_net_name(new_net, src_n);
1229 for (
const auto src_ep : src_n->get_sources())
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)
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()));
1242 for (
const auto src_ep : src_n->get_destinations())
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);
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()));
1256 if (delete_subgraph_gates)
1258 auto delete_res = delete_subgraph(dst_nl, subgraph);
1259 if (delete_res.is_error())
1261 return ERR_APPEND(delete_res.get_error(),
"unable to replace subgraph with netlist: failed to delete subgraph");
1269 const std::filesystem::path& genlib_path,
1271 const bool optimize_area)
1273 const auto verilog_module = build_functional_verilog_module_from(bfs);
1276 if (base_path_res.is_error())
1278 return ERR_APPEND(base_path_res.get_error(),
"unable to resynthesize Boolean functions with yosys: failed to get unique temp directory");
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";
1284 std::filesystem::create_directory(base_path);
1286 std::ofstream out(functional_netlist_path);
1287 out << verilog_module;
1291 if (yosys_query_res.is_error())
1293 return ERR_APPEND(yosys_query_res.get_error(),
"unable to resynthesize Boolean functions with yosys: failed to find yosys path");
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\"";
1301 system(command.c_str());
1306 if (resynth_nl ==
nullptr)
1308 return ERR(
"unable to resynthesize Boolean functions with yosys: failed to load re-synthesized netlist at " + resynthesized_netlist_path.string());
1315 for (
const auto& pin : resynth_nl->get_top_module()->get_input_pins())
1317 auto net = pin->get_net();
1318 net->set_name(pin->get_name());
1322 std::filesystem::remove_all(base_path);
1324 return OK(std::move(resynth_nl));
GateType * get_type() const
Result< BooleanFunction > get_resolved_boolean_function(const GatePin *pin, const bool use_net_variables=false) const
const std::string & get_name() const
Result< std::vector< std::string > > get_init_data() const
GateType * get_gate_type_by_name(const std::string &name) const
std::string get_name() const
std::vector< GatePin * > get_output_pins() const
const std::string & get_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...