2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
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.
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.
21 // Berkeley Logic Synthesis and Verification Group, ABC: A System for Sequential Synthesis and Verification
22 // http://www.eecs.berkeley.edu/~alanmi/abc/
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
28 #include "kernel/register.h"
29 #include "kernel/sigtools.h"
30 #include "kernel/log.h"
40 #include "blifparse.h"
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
;
57 static int map_signal(RTLIL::SigSpec sig
, char gate_type
= -1, int in1
= -1, int in2
= -1, int in3
= -1)
59 assert(sig
.width
== 1);
60 assert(sig
.chunks
.size() == 1);
62 assign_map
.apply(sig
);
64 if (signal_map
.count(sig
) == 0) {
66 gate
.id
= signal_list
.size();
73 signal_list
.push_back(gate
);
74 signal_map
[sig
] = gate
.id
;
77 gate_t
&gate
= signal_list
[signal_map
[sig
]];
80 gate
.type
= gate_type
;
91 static void mark_port(RTLIL::SigSpec sig
)
93 assign_map
.apply(sig
);
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;
101 static void extract_cell(RTLIL::Cell
*cell
)
103 if (cell
->type
== "$_INV_")
105 RTLIL::SigSpec sig_a
= cell
->connections
["\\A"];
106 RTLIL::SigSpec sig_y
= cell
->connections
["\\Y"];
108 assign_map
.apply(sig_a
);
109 assign_map
.apply(sig_y
);
111 map_signal(sig_y
, 'n', map_signal(sig_a
));
113 module
->cells
.erase(cell
->name
);
118 if (cell
->type
== "$_AND_" || cell
->type
== "$_OR_" || cell
->type
== "$_XOR_")
120 RTLIL::SigSpec sig_a
= cell
->connections
["\\A"];
121 RTLIL::SigSpec sig_b
= cell
->connections
["\\B"];
122 RTLIL::SigSpec sig_y
= cell
->connections
["\\Y"];
124 assign_map
.apply(sig_a
);
125 assign_map
.apply(sig_b
);
126 assign_map
.apply(sig_y
);
128 int mapped_a
= map_signal(sig_a
);
129 int mapped_b
= map_signal(sig_b
);
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
);
140 module
->cells
.erase(cell
->name
);
145 if (cell
->type
== "$_MUX_")
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"];
152 assign_map
.apply(sig_a
);
153 assign_map
.apply(sig_b
);
154 assign_map
.apply(sig_s
);
155 assign_map
.apply(sig_y
);
157 int mapped_a
= map_signal(sig_a
);
158 int mapped_b
= map_signal(sig_b
);
159 int mapped_s
= map_signal(sig_s
);
161 map_signal(sig_y
, 'm', mapped_a
, mapped_b
, mapped_s
);
163 module
->cells
.erase(cell
->name
);
169 static std::string
remap_name(std::string abc_name
)
171 std::stringstream sstr
;
172 sstr
<< "$abc$" << map_autoidx
<< "$" << abc_name
.substr(1);
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
)
181 log("Dumping loop state graph to slide %d.\n", ++nr
);
183 fprintf(f
, "digraph slide%d {\n", nr
);
184 fprintf(f
, " rankdir=\"LR\";\n");
187 for (auto &e
: edges
) {
188 nodes
.insert(e
.first
);
189 for (auto n
: e
.second
)
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" : "");
197 for (auto &e
: edges
)
198 for (auto n
: e
.second
)
199 fprintf(f
, " n%d -> n%d;\n", e
.first
, n
);
204 static void handle_loops()
206 // http://en.wikipedia.org/wiki/Topological_sorting
207 // (Kahn, Arthur B. (1962), "Topological sorting of large networks")
209 std::map
<int, std::set
<int>> edges
;
210 std::vector
<int> in_edges_count(signal_list
.size());
211 std::set
<int> workpool
;
216 // uncomment for troubleshooting the loop detection code
217 // dot_f = fopen("test.dot", "w");
219 for (auto &g
: signal_list
) {
221 workpool
.insert(g
.id
);
224 edges
[g
.in1
].insert(g
.id
);
225 in_edges_count
[g
.id
]++;
227 if (g
.in2
>= 0 && g
.in2
!= g
.in1
) {
228 edges
[g
.in2
].insert(g
.id
);
229 in_edges_count
[g
.id
]++;
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
]++;
237 dump_loop_graph(dot_f
, dot_nr
, edges
, workpool
, in_edges_count
);
239 while (workpool
.size() > 0)
241 int id
= *workpool
.begin();
244 // log("Removing non-loop node %d from graph: %s\n", id, log_signal(signal_list[id].sig));
246 for (int id2
: edges
[id
]) {
247 assert(in_edges_count
[id2
] > 0);
248 if (--in_edges_count
[id2
] == 0)
249 workpool
.insert(id2
);
253 dump_loop_graph(dot_f
, dot_nr
, edges
, workpool
, in_edges_count
);
255 while (workpool
.size() == 0)
257 if (edges
.size() == 0)
260 int id1
= edges
.begin()->first
;
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
;
270 else if (w1
->name
[0] == '$' && w2
->name
[0] == '\\')
272 else if (w1
->name
[0] == '\\' && w2
->name
[0] == '$')
274 else if (edges
[id1
].size() < edges
[id2
].size())
276 else if (edges
[id1
].size() > edges
[id2
].size())
278 else if (w1
->name
> w2
->name
)
282 if (edges
[id1
].size() == 0) {
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
;
293 bool first_line
= true;
294 for (int id2
: edges
[id1
]) {
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
));
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
));
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
);
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
;
319 edges
[id1
].swap(edges
[id3
]);
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
);
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
)
332 module
= current_module
;
333 map_autoidx
= RTLIL::autoidx
++;
337 assign_map
.set(module
);
339 char tempdir_name
[] = "/tmp/yosys-abc-XXXXXX";
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
);
345 log_error("For some reason mkdtemp() failed!\n");
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
);
355 for (auto &wire_it
: module
->wires
) {
356 if (wire_it
.second
->port_id
> 0)
357 mark_port(RTLIL::SigSpec(wire_it
.second
));
360 for (auto &cell_it
: module
->cells
)
361 for (auto &port_it
: cell_it
.second
->connections
)
362 mark_port(port_it
.second
);
366 if (asprintf(&p
, "%s/input.v", tempdir_name
) < 0) abort();
367 FILE *f
= fopen(p
, "wt");
369 log_error("Opening %s for writing failed: %s\n", p
, strerror(errno
));
372 fprintf(f
, "module netlist (");
374 for (auto &si
: signal_list
) {
379 fprintf(f
, "n%d", si
.id
);
382 fprintf(f
, "); // %s\n", module
->name
.c_str());
384 int count_input
= 0, count_output
= 0;
385 for (auto &si
: signal_list
) {
392 fprintf(f
, "%s n%d; // %s\n", si
.is_port
? si
.type
>= 0 ?
393 "output" : "input" : "wire", si
.id
, log_signal(si
.sig
));
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');
402 for (auto &si
: signal_list
) {
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)
419 fprintf(f
, "endmodule\n");
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
);
426 if (count_output
> 0)
428 log_header("Executing ABC.\n");
430 if (asprintf(&p
, "%s/stdcells.genlib", tempdir_name
) < 0) abort();
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");
446 if (asprintf(&p
, "%s/lutdefs.txt", tempdir_name
) < 0) abort();
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);
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());
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());
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
);
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
);
477 buffer_pos
+= snprintf(buffer
+buffer_pos
, 1024-buffer_pos
, "write_blif %s/output.blif' 2>&1", tempdir_name
);
479 buffer_pos
+= snprintf(buffer
+buffer_pos
, 1024-buffer_pos
, "write_verilog %s/output.v' 2>&1", tempdir_name
);
481 errno
= ENOMEM
; // popen does not set errno if memory allocation fails, therefore set it by hand
482 f
= popen(buffer
, "r");
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
);
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;
499 if (asprintf(&p
, "%s/%s", tempdir_name
, lut_mode
? "output.blif" : "output.v") < 0) abort();
502 log_error("Can't open ABC output file `%s'.\n", p
);
504 RTLIL::Design
*mapped_design
= new RTLIL::Design
;
505 frontend_register
["verilog"]->execute(f
, p
, std::vector
<std::string
>(), mapped_design
);
507 RTLIL::Design
*mapped_design
= lut_mode
? abc_parse_blif(f
) : abc_parse_verilog(f
);
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
);
524 std::map
<std::string
, int> cell_stats
;
525 if (liberty_file
.empty() && script_file
.empty() && !lut_mode
)
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") {
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
);
537 if (c
->type
== "\\BUF") {
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
);
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
);
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
);
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
);
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_") {
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
);
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
) {
601 assert(c
.width
== 1);
602 newsig
.append(module
->wires
[remap_name(c
.wire
->name
)]);
604 cell
->connections
[conn
.first
] = newsig
;
606 module
->cells
[cell
->name
] = cell
;
607 design
->select(module
, cell
);
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
);
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
)
625 snprintf(buffer
, 100, "\\n%d", si
.id
);
629 conn
.second
= RTLIL::SigSpec(module
->wires
[remap_name(buffer
)]);
632 conn
.first
= RTLIL::SigSpec(module
->wires
[remap_name(buffer
)]);
633 conn
.second
= si
.sig
;
636 module
->connections
.push_back(conn
);
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
);
642 delete mapped_design
;
646 log("Don't call ABC as there is nothing to map.\n");
651 log_header("Removing temp directory `%s':\n", tempdir_name
);
653 struct dirent
**namelist
;
654 int n
= scandir(tempdir_name
, &namelist
, 0, alphasort
);
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
);
666 log("Removing `%s'.\n", tempdir_name
);
673 struct AbcPass
: public Pass
{
674 AbcPass() : Pass("abc", "use ABC for technology mapping") { }
677 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
679 log(" abc [options] [selection]\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");
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");
688 log(" -script <file>\n");
689 log(" use the specified ABC script file instead of the default script.\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");
697 log(" -lut <width>\n");
698 log(" generate netlist using luts of (max) the specified width.\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");
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");
707 log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n");
710 virtual void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
)
712 log_header("Executing ABC pass (technology mapping using ABC).\n");
715 std::string exe_file
= rewrite_yosys_exe("yosys-abc");
716 std::string script_file
, liberty_file
;
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
];
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
;
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
;
740 if (arg
== "-lut" && argidx
+1 < args
.size() && lut_mode
== 0) {
741 lut_mode
= atoi(args
[++argidx
].c_str());
744 if (arg
== "-nocleanup") {
751 extra_args(args
, argidx
, design
);
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());
758 abc_module(design
, mod_it
.second
, script_file
, exe_file
, liberty_file
, cleanup
, lut_mode
);