Renamed temp module generated by "abc" pass from "logic" to "netlist"
[yosys.git] / passes / abc / abc.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 */
19
20 // [[CITE]] ABC
21 // Berkeley Logic Synthesis and Verification Group, ABC: A System for Sequential Synthesis and Verification
22 // http://www.eecs.berkeley.edu/~alanmi/abc/
23
24 // [[CITE]] Kahn's Topological sorting algorithm
25 // Kahn, Arthur B. (1962), "Topological sorting of large networks", Communications of the ACM 5 (11): 558–562, doi:10.1145/368996.369025
26 // http://en.wikipedia.org/wiki/Topological_sorting
27
28 #include "kernel/register.h"
29 #include "kernel/sigtools.h"
30 #include "kernel/log.h"
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <assert.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <dirent.h>
37 #include <sstream>
38
39 #include "vlparse.h"
40 #include "blifparse.h"
41
42 struct gate_t
43 {
44 int id;
45 char type;
46 int in1, in2, in3;
47 bool is_port;
48 RTLIL::SigSpec sig;
49 };
50
51 static int map_autoidx;
52 static SigMap assign_map;
53 static RTLIL::Module *module;
54 static std::vector<gate_t> signal_list;
55 static std::map<RTLIL::SigSpec, int> signal_map;
56
57 static int map_signal(RTLIL::SigSpec sig, char gate_type = -1, int in1 = -1, int in2 = -1, int in3 = -1)
58 {
59 assert(sig.width == 1);
60 assert(sig.chunks.size() == 1);
61
62 assign_map.apply(sig);
63
64 if (signal_map.count(sig) == 0) {
65 gate_t gate;
66 gate.id = signal_list.size();
67 gate.type = -1;
68 gate.in1 = -1;
69 gate.in2 = -1;
70 gate.in3 = -1;
71 gate.is_port = false;
72 gate.sig = sig;
73 signal_list.push_back(gate);
74 signal_map[sig] = gate.id;
75 }
76
77 gate_t &gate = signal_list[signal_map[sig]];
78
79 if (gate_type >= 0)
80 gate.type = gate_type;
81 if (in1 >= 0)
82 gate.in1 = in1;
83 if (in2 >= 0)
84 gate.in2 = in2;
85 if (in3 >= 0)
86 gate.in3 = in3;
87
88 return gate.id;
89 }
90
91 static void mark_port(RTLIL::SigSpec sig)
92 {
93 assign_map.apply(sig);
94 sig.expand();
95 for (auto &c : sig.chunks) {
96 if (c.wire != NULL && signal_map.count(c) > 0)
97 signal_list[signal_map[c]].is_port = true;
98 }
99 }
100
101 static void extract_cell(RTLIL::Cell *cell)
102 {
103 if (cell->type == "$_INV_")
104 {
105 RTLIL::SigSpec sig_a = cell->connections["\\A"];
106 RTLIL::SigSpec sig_y = cell->connections["\\Y"];
107
108 assign_map.apply(sig_a);
109 assign_map.apply(sig_y);
110
111 map_signal(sig_y, 'n', map_signal(sig_a));
112
113 module->cells.erase(cell->name);
114 delete cell;
115 return;
116 }
117
118 if (cell->type == "$_AND_" || cell->type == "$_OR_" || cell->type == "$_XOR_")
119 {
120 RTLIL::SigSpec sig_a = cell->connections["\\A"];
121 RTLIL::SigSpec sig_b = cell->connections["\\B"];
122 RTLIL::SigSpec sig_y = cell->connections["\\Y"];
123
124 assign_map.apply(sig_a);
125 assign_map.apply(sig_b);
126 assign_map.apply(sig_y);
127
128 int mapped_a = map_signal(sig_a);
129 int mapped_b = map_signal(sig_b);
130
131 if (cell->type == "$_AND_")
132 map_signal(sig_y, 'a', mapped_a, mapped_b);
133 else if (cell->type == "$_OR_")
134 map_signal(sig_y, 'o', mapped_a, mapped_b);
135 else if (cell->type == "$_XOR_")
136 map_signal(sig_y, 'x', mapped_a, mapped_b);
137 else
138 abort();
139
140 module->cells.erase(cell->name);
141 delete cell;
142 return;
143 }
144
145 if (cell->type == "$_MUX_")
146 {
147 RTLIL::SigSpec sig_a = cell->connections["\\A"];
148 RTLIL::SigSpec sig_b = cell->connections["\\B"];
149 RTLIL::SigSpec sig_s = cell->connections["\\S"];
150 RTLIL::SigSpec sig_y = cell->connections["\\Y"];
151
152 assign_map.apply(sig_a);
153 assign_map.apply(sig_b);
154 assign_map.apply(sig_s);
155 assign_map.apply(sig_y);
156
157 int mapped_a = map_signal(sig_a);
158 int mapped_b = map_signal(sig_b);
159 int mapped_s = map_signal(sig_s);
160
161 map_signal(sig_y, 'm', mapped_a, mapped_b, mapped_s);
162
163 module->cells.erase(cell->name);
164 delete cell;
165 return;
166 }
167 }
168
169 static std::string remap_name(std::string abc_name)
170 {
171 std::stringstream sstr;
172 sstr << "$abc$" << map_autoidx << "$" << abc_name.substr(1);
173 return sstr.str();
174 }
175
176 static void dump_loop_graph(FILE *f, int &nr, std::map<int, std::set<int>> &edges, std::set<int> &workpool, std::vector<int> &in_counts)
177 {
178 if (f == NULL)
179 return;
180
181 log("Dumping loop state graph to slide %d.\n", ++nr);
182
183 fprintf(f, "digraph slide%d {\n", nr);
184 fprintf(f, " rankdir=\"LR\";\n");
185
186 std::set<int> nodes;
187 for (auto &e : edges) {
188 nodes.insert(e.first);
189 for (auto n : e.second)
190 nodes.insert(n);
191 }
192
193 for (auto n : nodes)
194 fprintf(f, " n%d [label=\"%s\\nid=%d, count=%d\"%s];\n", n, log_signal(signal_list[n].sig),
195 n, in_counts[n], workpool.count(n) ? ", shape=box" : "");
196
197 for (auto &e : edges)
198 for (auto n : e.second)
199 fprintf(f, " n%d -> n%d;\n", e.first, n);
200
201 fprintf(f, "}\n");
202 }
203
204 static void handle_loops()
205 {
206 // http://en.wikipedia.org/wiki/Topological_sorting
207 // (Kahn, Arthur B. (1962), "Topological sorting of large networks")
208
209 std::map<int, std::set<int>> edges;
210 std::vector<int> in_edges_count(signal_list.size());
211 std::set<int> workpool;
212
213 FILE *dot_f = NULL;
214 int dot_nr = 0;
215
216 // uncomment for troubleshooting the loop detection code
217 // dot_f = fopen("test.dot", "w");
218
219 for (auto &g : signal_list) {
220 if (g.type == -1) {
221 workpool.insert(g.id);
222 }
223 if (g.in1 >= 0) {
224 edges[g.in1].insert(g.id);
225 in_edges_count[g.id]++;
226 }
227 if (g.in2 >= 0 && g.in2 != g.in1) {
228 edges[g.in2].insert(g.id);
229 in_edges_count[g.id]++;
230 }
231 if (g.in3 >= 0 && g.in3 != g.in2 && g.in3 != g.in1) {
232 edges[g.in3].insert(g.id);
233 in_edges_count[g.id]++;
234 }
235 }
236
237 dump_loop_graph(dot_f, dot_nr, edges, workpool, in_edges_count);
238
239 while (workpool.size() > 0)
240 {
241 int id = *workpool.begin();
242 workpool.erase(id);
243
244 // log("Removing non-loop node %d from graph: %s\n", id, log_signal(signal_list[id].sig));
245
246 for (int id2 : edges[id]) {
247 assert(in_edges_count[id2] > 0);
248 if (--in_edges_count[id2] == 0)
249 workpool.insert(id2);
250 }
251 edges.erase(id);
252
253 dump_loop_graph(dot_f, dot_nr, edges, workpool, in_edges_count);
254
255 while (workpool.size() == 0)
256 {
257 if (edges.size() == 0)
258 break;
259
260 int id1 = edges.begin()->first;
261
262 for (auto &edge_it : edges) {
263 int id2 = edge_it.first;
264 RTLIL::Wire *w1 = signal_list[id1].sig.chunks[0].wire;
265 RTLIL::Wire *w2 = signal_list[id2].sig.chunks[0].wire;
266 if (w1 != NULL)
267 continue;
268 else if (w2 == NULL)
269 id1 = id2;
270 else if (w1->name[0] == '$' && w2->name[0] == '\\')
271 id1 = id2;
272 else if (w1->name[0] == '\\' && w2->name[0] == '$')
273 continue;
274 else if (edges[id1].size() < edges[id2].size())
275 id1 = id2;
276 else if (edges[id1].size() > edges[id2].size())
277 continue;
278 else if (w1->name > w2->name)
279 id1 = id2;
280 }
281
282 if (edges[id1].size() == 0) {
283 edges.erase(id1);
284 continue;
285 }
286
287 RTLIL::Wire *wire = new RTLIL::Wire;
288 std::stringstream sstr;
289 sstr << "$abcloop$" << (RTLIL::autoidx++);
290 wire->name = sstr.str();
291 module->wires[wire->name] = wire;
292
293 bool first_line = true;
294 for (int id2 : edges[id1]) {
295 if (first_line)
296 log("Breaking loop using new signal %s: %s -> %s\n", log_signal(RTLIL::SigSpec(wire)),
297 log_signal(signal_list[id1].sig), log_signal(signal_list[id2].sig));
298 else
299 log(" %*s %s -> %s\n", int(strlen(log_signal(RTLIL::SigSpec(wire)))), "",
300 log_signal(signal_list[id1].sig), log_signal(signal_list[id2].sig));
301 first_line = false;
302 }
303
304 int id3 = map_signal(RTLIL::SigSpec(wire));
305 signal_list[id1].is_port = true;
306 signal_list[id3].is_port = true;
307 assert(id3 == int(in_edges_count.size()));
308 in_edges_count.push_back(0);
309 workpool.insert(id3);
310
311 for (int id2 : edges[id1]) {
312 if (signal_list[id2].in1 == id1)
313 signal_list[id2].in1 = id3;
314 if (signal_list[id2].in2 == id1)
315 signal_list[id2].in2 = id3;
316 if (signal_list[id2].in3 == id1)
317 signal_list[id2].in3 = id3;
318 }
319 edges[id1].swap(edges[id3]);
320
321 module->connections.push_back(RTLIL::SigSig(signal_list[id3].sig, signal_list[id1].sig));
322 dump_loop_graph(dot_f, dot_nr, edges, workpool, in_edges_count);
323 }
324 }
325
326 if (dot_f != NULL)
327 fclose(dot_f);
328 }
329
330 static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, std::string liberty_file, bool cleanup, int lut_mode)
331 {
332 module = current_module;
333 map_autoidx = RTLIL::autoidx++;
334
335 signal_map.clear();
336 signal_list.clear();
337 assign_map.set(module);
338
339 char tempdir_name[] = "/tmp/yosys-abc-XXXXXX";
340 if (!cleanup)
341 tempdir_name[0] = tempdir_name[4] = '_';
342 char *p = mkdtemp(tempdir_name);
343 log_header("Extracting gate netlist of module `%s' to `%s/input.v'..\n", module->name.c_str(), tempdir_name);
344 if (p == NULL)
345 log_error("For some reason mkdtemp() failed!\n");
346
347 std::vector<RTLIL::Cell*> cells;
348 cells.reserve(module->cells.size());
349 for (auto &it : module->cells)
350 if (design->selected(current_module, it.second))
351 cells.push_back(it.second);
352 for (auto c : cells)
353 extract_cell(c);
354
355 for (auto &wire_it : module->wires) {
356 if (wire_it.second->port_id > 0)
357 mark_port(RTLIL::SigSpec(wire_it.second));
358 }
359
360 for (auto &cell_it : module->cells)
361 for (auto &port_it : cell_it.second->connections)
362 mark_port(port_it.second);
363
364 handle_loops();
365
366 if (asprintf(&p, "%s/input.v", tempdir_name) < 0) abort();
367 FILE *f = fopen(p, "wt");
368 if (f == NULL)
369 log_error("Opening %s for writing failed: %s\n", p, strerror(errno));
370 free(p);
371
372 fprintf(f, "module netlist (");
373 bool first = true;
374 for (auto &si : signal_list) {
375 if (!si.is_port)
376 continue;
377 if (!first)
378 fprintf(f, ", ");
379 fprintf(f, "n%d", si.id);
380 first = false;
381 }
382 fprintf(f, "); // %s\n", module->name.c_str());
383
384 int count_input = 0, count_output = 0;
385 for (auto &si : signal_list) {
386 if (si.is_port) {
387 if (si.type >= 0)
388 count_output++;
389 else
390 count_input++;
391 }
392 fprintf(f, "%s n%d; // %s\n", si.is_port ? si.type >= 0 ?
393 "output" : "input" : "wire", si.id, log_signal(si.sig));
394 }
395 for (auto &si : signal_list) {
396 assert(si.sig.width == 1 && si.sig.chunks.size() == 1);
397 if (si.sig.chunks[0].wire == NULL)
398 fprintf(f, "assign n%d = %c;\n", si.id, si.sig.chunks[0].data.bits[0] == RTLIL::State::S1 ? '1' : '0');
399 }
400
401 int count_gates = 0;
402 for (auto &si : signal_list) {
403 if (si.type == 'n')
404 fprintf(f, "not (n%d, n%d);\n", si.id, si.in1);
405 else if (si.type == 'a')
406 fprintf(f, "and (n%d, n%d, n%d);\n", si.id, si.in1, si.in2);
407 else if (si.type == 'o')
408 fprintf(f, "or (n%d, n%d, n%d);\n", si.id, si.in1, si.in2);
409 else if (si.type == 'x')
410 fprintf(f, "xor (n%d, n%d, n%d);\n", si.id, si.in1, si.in2);
411 else if (si.type == 'm')
412 fprintf(f, "assign n%d = n%d ? n%d : n%d;\n", si.id, si.in3, si.in2, si.in1);
413 else if (si.type >= 0)
414 abort();
415 if (si.type >= 0)
416 count_gates++;
417 }
418
419 fprintf(f, "endmodule\n");
420 fclose(f);
421
422 log("Extracted %d gates and %zd wires to a netlist network with %d inputs and %d outputs.\n",
423 count_gates, signal_list.size(), count_input, count_output);
424 log_push();
425
426 if (count_output > 0)
427 {
428 log_header("Executing ABC.\n");
429
430 if (asprintf(&p, "%s/stdcells.genlib", tempdir_name) < 0) abort();
431 f = fopen(p, "wt");
432 if (f == NULL)
433 log_error("Opening %s for writing failed: %s\n", p, strerror(errno));
434 fprintf(f, "GATE ZERO 1 Y=CONST0;\n");
435 fprintf(f, "GATE ONE 1 Y=CONST1;\n");
436 fprintf(f, "GATE BUF 1 Y=A; PIN * NONINV 1 999 1 0 1 0\n");
437 fprintf(f, "GATE INV 1 Y=!A; PIN * INV 1 999 1 0 1 0\n");
438 fprintf(f, "GATE AND 1 Y=A*B; PIN * NONINV 1 999 1 0 1 0\n");
439 fprintf(f, "GATE OR 1 Y=A+B; PIN * NONINV 1 999 1 0 1 0\n");
440 fprintf(f, "GATE XOR 1 Y=(A*!B)+(!A*B); PIN * UNKNOWN 1 999 1 0 1 0\n");
441 fprintf(f, "GATE MUX 1 Y=(A*B)+(S*B)+(!S*A); PIN * UNKNOWN 1 999 1 0 1 0\n");
442 fclose(f);
443 free(p);
444
445 if (lut_mode) {
446 if (asprintf(&p, "%s/lutdefs.txt", tempdir_name) < 0) abort();
447 f = fopen(p, "wt");
448 if (f == NULL)
449 log_error("Opening %s for writing failed: %s\n", p, strerror(errno));
450 for (int i = 0; i < lut_mode; i++)
451 fprintf(f, "%d 1.00 1.00\n", i+1);
452 fclose(f);
453 free(p);
454 }
455
456 char buffer[1024];
457 int buffer_pos = 0;
458 if (!liberty_file.empty())
459 buffer_pos += snprintf(buffer+buffer_pos, 1024-buffer_pos,
460 "%s -s -c 'read_verilog %s/input.v; read_liberty %s; map; ",
461 exe_file.c_str(), tempdir_name, liberty_file.c_str());
462 else
463 if (!script_file.empty())
464 buffer_pos += snprintf(buffer+buffer_pos, 1024-buffer_pos,
465 "%s -s -c 'read_verilog %s/input.v; source %s; ",
466 exe_file.c_str(), tempdir_name, script_file.c_str());
467 else
468 if (lut_mode)
469 buffer_pos += snprintf(buffer+buffer_pos, 1024-buffer_pos,
470 "%s -s -c 'read_verilog %s/input.v; read_lut %s/lutdefs.txt; if; ",
471 exe_file.c_str(), tempdir_name, tempdir_name);
472 else
473 buffer_pos += snprintf(buffer+buffer_pos, 1024-buffer_pos,
474 "%s -s -c 'read_verilog %s/input.v; read_library %s/stdcells.genlib; map; ",
475 exe_file.c_str(), tempdir_name, tempdir_name);
476 if (lut_mode)
477 buffer_pos += snprintf(buffer+buffer_pos, 1024-buffer_pos, "write_blif %s/output.blif' 2>&1", tempdir_name);
478 else
479 buffer_pos += snprintf(buffer+buffer_pos, 1024-buffer_pos, "write_verilog %s/output.v' 2>&1", tempdir_name);
480
481 errno = ENOMEM; // popen does not set errno if memory allocation fails, therefore set it by hand
482 f = popen(buffer, "r");
483 if (f == NULL)
484 log_error("Opening pipe to `%s' for reading failed: %s\n", buffer, strerror(errno));
485 while (fgets(buffer, 1024, f) != NULL)
486 log("ABC: %s", buffer);
487 errno = 0;
488 int ret = pclose(f);
489 if (ret < 0)
490 log_error("Closing pipe to `%s' failed: %s\n", buffer, strerror(errno));
491 if (WEXITSTATUS(ret) != 0) {
492 switch (WEXITSTATUS(ret)) {
493 case 127: log_error("ABC: execution of command \"%s\" failed: Command not found\n", exe_file.c_str()); break;
494 case 126: log_error("ABC: execution of command \"%s\" failed: Command not executable\n", exe_file.c_str()); break;
495 default: log_error("ABC: execution of command \"%s\" failed: the shell returned %d\n", exe_file.c_str(), WEXITSTATUS(ret)); break;
496 }
497 }
498
499 if (asprintf(&p, "%s/%s", tempdir_name, lut_mode ? "output.blif" : "output.v") < 0) abort();
500 f = fopen(p, "rt");
501 if (f == NULL)
502 log_error("Can't open ABC output file `%s'.\n", p);
503 #if 0
504 RTLIL::Design *mapped_design = new RTLIL::Design;
505 frontend_register["verilog"]->execute(f, p, std::vector<std::string>(), mapped_design);
506 #else
507 RTLIL::Design *mapped_design = lut_mode ? abc_parse_blif(f) : abc_parse_verilog(f);
508 #endif
509 fclose(f);
510 free(p);
511
512 log_header("Re-integrating ABC results.\n");
513 RTLIL::Module *mapped_mod = mapped_design->modules["\\netlist"];
514 if (mapped_mod == NULL)
515 log_error("ABC output file does not contain a module `netlist'.\n");
516 for (auto &it : mapped_mod->wires) {
517 RTLIL::Wire *w = it.second;
518 RTLIL::Wire *wire = new RTLIL::Wire;
519 wire->name = remap_name(w->name);
520 module->wires[wire->name] = wire;
521 design->select(module, wire);
522 }
523
524 std::map<std::string, int> cell_stats;
525 if (liberty_file.empty() && script_file.empty() && !lut_mode)
526 {
527 for (auto &it : mapped_mod->cells) {
528 RTLIL::Cell *c = it.second;
529 cell_stats[c->type.substr(1)]++;
530 if (c->type == "\\ZERO" || c->type == "\\ONE") {
531 RTLIL::SigSig conn;
532 conn.first = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\Y"].chunks[0].wire->name)]);
533 conn.second = RTLIL::SigSpec(c->type == "\\ZERO" ? 0 : 1, 1);
534 module->connections.push_back(conn);
535 continue;
536 }
537 if (c->type == "\\BUF") {
538 RTLIL::SigSig conn;
539 conn.first = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\Y"].chunks[0].wire->name)]);
540 conn.second = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\A"].chunks[0].wire->name)]);
541 module->connections.push_back(conn);
542 continue;
543 }
544 if (c->type == "\\INV") {
545 RTLIL::Cell *cell = new RTLIL::Cell;
546 cell->type = "$_INV_";
547 cell->name = remap_name(c->name);
548 cell->connections["\\A"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\A"].chunks[0].wire->name)]);
549 cell->connections["\\Y"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\Y"].chunks[0].wire->name)]);
550 module->cells[cell->name] = cell;
551 design->select(module, cell);
552 continue;
553 }
554 if (c->type == "\\AND" || c->type == "\\OR" || c->type == "\\XOR") {
555 RTLIL::Cell *cell = new RTLIL::Cell;
556 cell->type = "$_" + c->type.substr(1) + "_";
557 cell->name = remap_name(c->name);
558 cell->connections["\\A"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\A"].chunks[0].wire->name)]);
559 cell->connections["\\B"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\B"].chunks[0].wire->name)]);
560 cell->connections["\\Y"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\Y"].chunks[0].wire->name)]);
561 module->cells[cell->name] = cell;
562 design->select(module, cell);
563 continue;
564 }
565 if (c->type == "\\MUX") {
566 RTLIL::Cell *cell = new RTLIL::Cell;
567 cell->type = "$_MUX_";
568 cell->name = remap_name(c->name);
569 cell->connections["\\A"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\A"].chunks[0].wire->name)]);
570 cell->connections["\\B"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\B"].chunks[0].wire->name)]);
571 cell->connections["\\S"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\S"].chunks[0].wire->name)]);
572 cell->connections["\\Y"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\Y"].chunks[0].wire->name)]);
573 module->cells[cell->name] = cell;
574 design->select(module, cell);
575 continue;
576 }
577 assert(0);
578 }
579 }
580 else
581 {
582 for (auto &it : mapped_mod->cells) {
583 RTLIL::Cell *c = it.second;
584 cell_stats[c->type.substr(1)]++;
585 if (c->type == "$_const0_" || c->type == "$_const1_") {
586 RTLIL::SigSig conn;
587 conn.first = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\Y"].chunks[0].wire->name)]);
588 conn.second = RTLIL::SigSpec(c->type == "$_const0_" ? 0 : 1, 1);
589 module->connections.push_back(conn);
590 continue;
591 }
592 RTLIL::Cell *cell = new RTLIL::Cell;
593 cell->type = c->type;
594 cell->parameters = c->parameters;
595 cell->name = remap_name(c->name);
596 for (auto &conn : c->connections) {
597 RTLIL::SigSpec newsig;
598 for (auto &c : conn.second.chunks) {
599 if (c.width == 0)
600 continue;
601 assert(c.width == 1);
602 newsig.append(module->wires[remap_name(c.wire->name)]);
603 }
604 cell->connections[conn.first] = newsig;
605 }
606 module->cells[cell->name] = cell;
607 design->select(module, cell);
608 }
609 }
610
611 for (auto conn : mapped_mod->connections) {
612 if (!conn.first.is_fully_const())
613 conn.first = RTLIL::SigSpec(module->wires[remap_name(conn.first.chunks[0].wire->name)]);
614 if (!conn.second.is_fully_const())
615 conn.second = RTLIL::SigSpec(module->wires[remap_name(conn.second.chunks[0].wire->name)]);
616 module->connections.push_back(conn);
617 }
618
619 for (auto &it : cell_stats)
620 log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second);
621 int in_wires = 0, out_wires = 0;
622 for (auto &si : signal_list)
623 if (si.is_port) {
624 char buffer[100];
625 snprintf(buffer, 100, "\\n%d", si.id);
626 RTLIL::SigSig conn;
627 if (si.type >= 0) {
628 conn.first = si.sig;
629 conn.second = RTLIL::SigSpec(module->wires[remap_name(buffer)]);
630 out_wires++;
631 } else {
632 conn.first = RTLIL::SigSpec(module->wires[remap_name(buffer)]);
633 conn.second = si.sig;
634 in_wires++;
635 }
636 module->connections.push_back(conn);
637 }
638 log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires);
639 log("ABC RESULTS: input signals: %8d\n", in_wires);
640 log("ABC RESULTS: output signals: %8d\n", out_wires);
641
642 delete mapped_design;
643 }
644 else
645 {
646 log("Don't call ABC as there is nothing to map.\n");
647 }
648
649 if (cleanup)
650 {
651 log_header("Removing temp directory `%s':\n", tempdir_name);
652
653 struct dirent **namelist;
654 int n = scandir(tempdir_name, &namelist, 0, alphasort);
655 assert(n >= 0);
656 for (int i = 0; i < n; i++) {
657 if (strcmp(namelist[i]->d_name, ".") && strcmp(namelist[i]->d_name, "..")) {
658 if (asprintf(&p, "%s/%s", tempdir_name, namelist[i]->d_name) < 0) abort();
659 log("Removing `%s'.\n", p);
660 remove(p);
661 free(p);
662 }
663 free(namelist[i]);
664 }
665 free(namelist);
666 log("Removing `%s'.\n", tempdir_name);
667 rmdir(tempdir_name);
668 }
669
670 log_pop();
671 }
672
673 struct AbcPass : public Pass {
674 AbcPass() : Pass("abc", "use ABC for technology mapping") { }
675 virtual void help()
676 {
677 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
678 log("\n");
679 log(" abc [options] [selection]\n");
680 log("\n");
681 log("This pass uses the ABC tool [1] for technology mapping of yosys's internal gate\n");
682 log("library to a target architecture.\n");
683 log("\n");
684 log(" -exe <command>\n");
685 log(" use the specified command name instead of \"yosys-abc\" to execute ABC.\n");
686 log(" This can e.g. be used to call a specific version of ABC or a wrapper.\n");
687 log("\n");
688 log(" -script <file>\n");
689 log(" use the specified ABC script file instead of the default script.\n");
690 log("\n");
691 log(" -liberty <file>\n");
692 log(" generate netlists for the specified cell library (using the liberty\n");
693 log(" file format). Without this option, ABC is used to optimize the netlist\n");
694 log(" but keeps using yosys's internal gate library. This option is ignored if\n");
695 log(" the -script option is also used.\n");
696 log("\n");
697 log(" -lut <width>\n");
698 log(" generate netlist using luts of (max) the specified width.\n");
699 log("\n");
700 log(" -nocleanup\n");
701 log(" when this option is used, the temporary files created by this pass\n");
702 log(" are not removed. this is useful for debugging.\n");
703 log("\n");
704 log("This pass does not operate on modules with unprocessed processes in it.\n");
705 log("(I.e. the 'proc' pass should be used first to convert processes to netlists.)\n");
706 log("\n");
707 log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n");
708 log("\n");
709 }
710 virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
711 {
712 log_header("Executing ABC pass (technology mapping using ABC).\n");
713 log_push();
714
715 std::string exe_file = rewrite_yosys_exe("yosys-abc");
716 std::string script_file, liberty_file;
717 bool cleanup = true;
718 int lut_mode = 0;
719
720 size_t argidx;
721 char *pwd = get_current_dir_name();
722 for (argidx = 1; argidx < args.size(); argidx++) {
723 std::string arg = args[argidx];
724 if (arg == "-exe" && argidx+1 < args.size()) {
725 exe_file = args[++argidx];
726 continue;
727 }
728 if (arg == "-script" && argidx+1 < args.size() && liberty_file.empty()) {
729 script_file = args[++argidx];
730 if (!script_file.empty() && script_file[0] != '/')
731 script_file = std::string(pwd) + "/" + script_file;
732 continue;
733 }
734 if (arg == "-liberty" && argidx+1 < args.size() && script_file.empty()) {
735 liberty_file = args[++argidx];
736 if (!liberty_file.empty() && liberty_file[0] != '/')
737 liberty_file = std::string(pwd) + "/" + liberty_file;
738 continue;
739 }
740 if (arg == "-lut" && argidx+1 < args.size() && lut_mode == 0) {
741 lut_mode = atoi(args[++argidx].c_str());
742 continue;
743 }
744 if (arg == "-nocleanup") {
745 cleanup = false;
746 continue;
747 }
748 break;
749 }
750 free(pwd);
751 extra_args(args, argidx, design);
752
753 for (auto &mod_it : design->modules)
754 if (design->selected(mod_it.second)) {
755 if (mod_it.second->processes.size() > 0)
756 log("Skipping module %s as it contains processes.\n", mod_it.second->name.c_str());
757 else
758 abc_module(design, mod_it.second, script_file, exe_file, liberty_file, cleanup, lut_mode);
759 }
760
761 assign_map.clear();
762 signal_list.clear();
763 signal_map.clear();
764
765 log_pop();
766 }
767 } AbcPass;
768