bddf9d2d936fef604829af70aa1f3bd406d781e6
[yosys.git] / passes / techmap / abc9.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 * (C) 2019 Eddie Hung <eddie@fpgeh.com>
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 *
19 */
20
21 // [[CITE]] ABC
22 // Berkeley Logic Synthesis and Verification Group, ABC: A System for Sequential Synthesis and Verification
23 // http://www.eecs.berkeley.edu/~alanmi/abc/
24
25 #include "kernel/register.h"
26 #include "kernel/celltypes.h"
27 #include "kernel/rtlil.h"
28 #include "kernel/log.h"
29
30 // abc9_exe.cc
31 std::string fold_abc9_cmd(std::string str);
32
33 USING_YOSYS_NAMESPACE
34 PRIVATE_NAMESPACE_BEGIN
35
36 struct Abc9Pass : public ScriptPass
37 {
38 Abc9Pass() : ScriptPass("abc9", "use ABC9 for technology mapping") { }
39 void on_register() YS_OVERRIDE
40 {
41 RTLIL::constpad["abc9.script.default"] = "+&scorr; &sweep; &dc2; &dch -f; &ps; &if {C} {W} {D} {R} -v; &mfs";
42 RTLIL::constpad["abc9.script.default.area"] = "+&scorr; &sweep; &dc2; &dch -f; &ps; &if {C} {W} {D} {R} -a -v; &mfs";
43 RTLIL::constpad["abc9.script.default.fast"] = "+&if {C} {W} {D} {R} -v";
44 // Based on ABC's &flow
45 RTLIL::constpad["abc9.script.flow"] = "+&scorr; &sweep;" \
46 "&dch -C 500;" \
47 /* Round 1 */ \
48 /* Map 1 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
49 "&st; &dsdb;" \
50 /* Map 2 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
51 "&st; &syn2 -m -R 10; &dsdb;" \
52 "&blut -a -K 6;" \
53 /* Map 3 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
54 /* Round 2 */ \
55 "&st; &sopb;" \
56 /* Map 1 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
57 "&st; &dsdb;" \
58 /* Map 2 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
59 "&st; &syn2 -m -R 10; &dsdb;" \
60 "&blut -a -K 6;" \
61 /* Map 3 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
62 /* Round 3 */ \
63 /* Map 1 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
64 "&st; &dsdb;" \
65 /* Map 2 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;" \
66 "&st; &syn2 -m -R 10; &dsdb;" \
67 "&blut -a -K 6;" \
68 /* Map 3 */ "&unmap; &if {C} {W} {D} {R} -v; &save; &load; &mfs;";
69 // Based on ABC's &flow2
70 RTLIL::constpad["abc9.script.flow2"] = "+&scorr; &sweep;" \
71 /* Comm1 */ "&synch2 -K 6 -C 500; &if -m {C} {W} {D} {R} -v; &mfs "/*"-W 4 -M 500 -C 7000"*/"; &save;"\
72 /* Comm2 */ "&dch -C 500; &if -m {C} {W} {D} {R} -v; &mfs "/*"-W 4 -M 500 -C 7000"*/"; &save;"\
73 "&load; &st; &sopb -R 10 -C 4; " \
74 /* Comm3 */ "&synch2 -K 6 -C 500; &if -m "/*"-E 5"*/" {C} {W} {D} {R} -v; &mfs "/*"-W 4 -M 500 -C 7000"*/"; &save;"\
75 /* Comm2 */ "&dch -C 500; &if -m {C} {W} {D} {R} -v; &mfs "/*"-W 4 -M 500 -C 7000"*/"; &save; "\
76 "&load";
77 // Based on ABC's &flow3
78 RTLIL::constpad["abc9.script.flow3"] = "+&scorr; &sweep;" \
79 "&if {C} {W} {D}; &save; &st; &syn2; &if {C} {W} {D} {R} -v; &save; &load;"\
80 "&st; &if {C} -g -K 6; &dch -f; &if {C} {W} {D} {R} -v; &save; &load;"\
81 "&st; &if {C} -g -K 6; &synch2; &if {C} {W} {D} {R} -v; &save; &load;"\
82 "&mfs";
83 }
84 void help() YS_OVERRIDE
85 {
86 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
87 log("\n");
88 log(" abc9 [options] [selection]\n");
89 log("\n");
90 log("This script pass performs a sequence of commands to facilitate the use of the ABC\n");
91 log("tool [1] for technology mapping of the current design to a target FPGA\n");
92 log("architecture. Only fully-selected modules are supported.\n");
93 log("\n");
94 log(" -run <from_label>:<to_label>\n");
95 log(" only run the commands between the labels (see below). an empty\n");
96 log(" from label is synonymous to 'begin', and empty to label is\n");
97 log(" synonymous to the end of the command list.\n");
98 log("\n");
99 log(" -exe <command>\n");
100 #ifdef ABCEXTERNAL
101 log(" use the specified command instead of \"" ABCEXTERNAL "\" to execute ABC.\n");
102 #else
103 log(" use the specified command instead of \"<yosys-bindir>/%syosys-abc\" to execute ABC.\n", proc_program_prefix().c_str());
104 #endif
105 log(" This can e.g. be used to call a specific version of ABC or a wrapper.\n");
106 log("\n");
107 log(" -script <file>\n");
108 log(" use the specified ABC script file instead of the default script.\n");
109 log("\n");
110 log(" if <file> starts with a plus sign (+), then the rest of the filename\n");
111 log(" string is interpreted as the command string to be passed to ABC. The\n");
112 log(" leading plus sign is removed and all commas (,) in the string are\n");
113 log(" replaced with blanks before the string is passed to ABC.\n");
114 log("\n");
115 log(" if no -script parameter is given, the following scripts are used:\n");
116 log("%s\n", fold_abc9_cmd(RTLIL::constpad.at("abc9.script.default").substr(1,std::string::npos)).c_str());
117 log("\n");
118 log(" -fast\n");
119 log(" use different default scripts that are slightly faster (at the cost\n");
120 log(" of output quality):\n");
121 log("%s\n", fold_abc9_cmd(RTLIL::constpad.at("abc9.script.default.fast").substr(1,std::string::npos)).c_str());
122 log("\n");
123 log(" -D <picoseconds>\n");
124 log(" set delay target. the string {D} in the default scripts above is\n");
125 log(" replaced by this option when used, and an empty string otherwise\n");
126 log(" (indicating best possible delay).\n");
127 log("\n");
128 // log(" -S <num>\n");
129 // log(" maximum number of LUT inputs shared.\n");
130 // log(" (replaces {S} in the default scripts above, default: -S 1)\n");
131 // log("\n");
132 log(" -lut <width>\n");
133 log(" generate netlist using luts of (max) the specified width.\n");
134 log("\n");
135 log(" -lut <w1>:<w2>\n");
136 log(" generate netlist using luts of (max) the specified width <w2>. All\n");
137 log(" luts with width <= <w1> have constant cost. for luts larger than <w1>\n");
138 log(" the area cost doubles with each additional input bit. the delay cost\n");
139 log(" is still constant for all lut widths.\n");
140 log("\n");
141 log(" -lut <file>\n");
142 log(" pass this file with lut library to ABC.\n");
143 log("\n");
144 log(" -luts <cost1>,<cost2>,<cost3>,<sizeN>:<cost4-N>,..\n");
145 log(" generate netlist using luts. Use the specified costs for luts with 1,\n");
146 log(" 2, 3, .. inputs.\n");
147 log("\n");
148 log(" -maxlut <width>\n");
149 log(" when auto-generating the lut library, discard all luts equal to or\n");
150 log(" greater than this size (applicable when neither -lut nor -luts is\n");
151 log(" specified).\n");
152 log("\n");
153 log(" -dff\n");
154 log(" also pass $_DFF_[NP]_ cells through to ABC. modules with many clock\n");
155 log(" domains are supported and automatically partitioned by ABC.\n");
156 log("\n");
157 log(" -nocleanup\n");
158 log(" when this option is used, the temporary files created by this pass\n");
159 log(" are not removed. this is useful for debugging.\n");
160 log("\n");
161 log(" -showtmp\n");
162 log(" print the temp dir name in log. usually this is suppressed so that the\n");
163 log(" command output is identical across runs.\n");
164 log("\n");
165 log(" -box <file>\n");
166 log(" pass this file with box library to ABC.\n");
167 log("\n");
168 log("Note that this is a logic optimization pass within Yosys that is calling ABC\n");
169 log("internally. This is not going to \"run ABC on your design\". It will instead run\n");
170 log("ABC on logic snippets extracted from your design. You will not get any useful\n");
171 log("output when passing an ABC script that writes a file. Instead write your full\n");
172 log("design as an XAIGER file with `write_xaiger' and then load that into ABC\n");
173 log("externally if you want to use ABC to convert your design into another format.\n");
174 log("\n");
175 log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n");
176 log("\n");
177 help_script();
178 log("\n");
179 }
180
181 std::stringstream exe_cmd;
182 bool dff_mode, cleanup;
183 bool lut_mode;
184 int maxlut;
185 std::string box_file;
186
187 void clear_flags() YS_OVERRIDE
188 {
189 exe_cmd.str("");
190 exe_cmd << "abc9_exe";
191 dff_mode = false;
192 cleanup = true;
193 lut_mode = false;
194 maxlut = 0;
195 box_file = "";
196 }
197
198 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
199 {
200 std::string run_from, run_to;
201 clear_flags();
202
203 // get arguments from scratchpad first, then override by command arguments
204 dff_mode = design->scratchpad_get_bool("abc9.dff", dff_mode);
205 cleanup = !design->scratchpad_get_bool("abc9.nocleanup", !cleanup);
206
207 if (design->scratchpad_get_bool("abc9.debug")) {
208 cleanup = false;
209 exe_cmd << " -showtmp";
210 }
211
212 size_t argidx;
213 for (argidx = 1; argidx < args.size(); argidx++) {
214 std::string arg = args[argidx];
215 if ((arg == "-exe" || arg == "-script" || arg == "-D" ||
216 /*arg == "-S" ||*/ arg == "-lut" || arg == "-luts" ||
217 /*arg == "-box" ||*/ arg == "-W") &&
218 argidx+1 < args.size()) {
219 if (arg == "-lut" || arg == "-luts")
220 lut_mode = true;
221 exe_cmd << " " << arg << " " << args[++argidx];
222 continue;
223 }
224 if (arg == "-fast" || /* arg == "-dff" || */
225 /* arg == "-nocleanup" || */ arg == "-showtmp") {
226 exe_cmd << " " << arg;
227 continue;
228 }
229 if (arg == "-dff") {
230 dff_mode = true;
231 exe_cmd << " " << arg;
232 continue;
233 }
234 if (arg == "-nocleanup") {
235 cleanup = false;
236 continue;
237 }
238 if (arg == "-box" && argidx+1 < args.size()) {
239 box_file = args[++argidx];
240 continue;
241 }
242 if (arg == "-maxlut" && argidx+1 < args.size()) {
243 maxlut = atoi(args[++argidx].c_str());
244 continue;
245 }
246 if (arg == "-run" && argidx+1 < args.size()) {
247 size_t pos = args[argidx+1].find(':');
248 if (pos == std::string::npos)
249 break;
250 run_from = args[++argidx].substr(0, pos);
251 run_to = args[argidx].substr(pos+1);
252 continue;
253 }
254 break;
255 }
256 extra_args(args, argidx, design);
257
258 if (maxlut && lut_mode)
259 log_cmd_error("abc9 '-maxlut' option only applicable without '-lut' nor '-luts'.\n");
260
261 log_assert(design);
262 if (design->selected_modules().empty()) {
263 log_warning("No modules selected for ABC9 techmapping.\n");
264 return;
265 }
266
267 log_header(design, "Executing ABC9 pass.\n");
268 log_push();
269
270 run_script(design, run_from, run_to);
271
272 log_pop();
273 }
274
275 void script() YS_OVERRIDE
276 {
277 if (check_label("check")) {
278 run("abc9_ops -check");
279 }
280
281 if (check_label("dff", "(only if -dff)")) {
282 if (dff_mode || help_mode) {
283 run("abc9_ops -prep_dff_hier"); // derive all used (* abc9_flop *) modules
284 run("design -stash $abc9");
285 run("design -copy-from $abc9 @$abc9_flops"); // copy derived modules in
286 run("proc");
287 run("wbflip");
288 run("techmap");
289 run("opt");
290 run("abc9_ops -prep_dff_map"); // rewrite specify
291 // TODO: Select fan-in cone $_DFF_[NP]_.Q
292 run("setattr -set submod \"$abc9_flop\" t:* t:$_DFF_N_ %d t:$_DFF_P_ %d");
293 run("submod");
294 run("design -copy-to $abc9 *_$abc9_flop"); // copy submod out
295 run("delete *_$abc9_flop");
296 if (help_mode) {
297 run("foreach module in design");
298 run(" rename <module-name>_$abc9_flop _TECHMAP_REPLACE_");
299 }
300 else {
301 // Rename all submod-s to _TECHMAP_REPLACE_ to inherit name + attrs
302 for (auto module : active_design->selected_modules()) {
303 active_design->selected_active_module = module->name.str();
304 run(stringf("rename %s_$abc9_flop _TECHMAP_REPLACE_", module->name.c_str()));
305 }
306 }
307 run("design -stash $abc9_map");
308 run("design -load $abc9");
309 run("abc9_ops -prep_dff_unmap"); // create $abc9_unmap design
310 run("techmap -map %$abc9_map"); // techmap user design into submod + $_DFF_[NP]_
311 run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop");
312 run("design -delete $abc9");
313 run("design -delete $abc9_map");
314 run("select -unset $abc9_flops");
315 }
316 }
317
318 if (check_label("pre")) {
319 run("scc -set_attr abc9_scc_id {}");
320 if (help_mode)
321 run("abc9_ops -mark_scc -prep_delays -prep_xaiger [-dff]", "(option for -dff)");
322 else
323 run("abc9_ops -mark_scc -prep_delays -prep_xaiger" + std::string(dff_mode ? " -dff" : ""));
324 if (help_mode)
325 run("abc9_ops -prep_lut <maxlut>", "(skip if -lut or -luts)");
326 else if (!lut_mode)
327 run(stringf("abc9_ops -prep_lut %d", maxlut));
328 if (help_mode)
329 run("abc9_ops -prep_box", "(skip if -box)");
330 else if (box_file.empty()) {
331 run("abc9_ops -prep_box");
332 }
333 run("select -set abc9_holes A:abc9_holes");
334 run("flatten -wb @abc9_holes");
335 run("techmap @abc9_holes");
336 run("opt -purge @abc9_holes");
337 run("aigmap");
338 run("wbflip @abc9_holes");
339 }
340
341 if (check_label("map")) {
342 if (help_mode) {
343 run("foreach module in selection");
344 run(" abc9_ops -write_lut <abc-temp-dir>/input.lut", "(skip if '-lut' or '-luts')");
345 run(" abc9_ops -write_box <abc-temp-dir>/input.box", "(skip if '-box')");
346 run(" write_xaiger -map <abc-temp-dir>/input.sym [-dff] <abc-temp-dir>/input.xaig");
347 run(" abc9_exe [options] -cwd <abc-temp-dir> -lut [<abc-temp-dir>/input.lut] -box [<abc-temp-dir>/input.box]");
348 run(" read_aiger -xaiger -wideports -module_name <module-name>$abc9 -map <abc-temp-dir>/input.sym <abc-temp-dir>/output.aig");
349 run(" abc9_ops -reintegrate [-dff]");
350 }
351 else {
352 auto selected_modules = active_design->selected_modules();
353 active_design->selection_stack.emplace_back(false);
354
355 for (auto mod : selected_modules) {
356 if (mod->processes.size() > 0) {
357 log("Skipping module %s as it contains processes.\n", log_id(mod));
358 continue;
359 }
360 log_assert(!mod->attributes.count(ID::abc9_box_id));
361
362 log_push();
363 active_design->selection().select(mod);
364
365 if (!active_design->selected_whole_module(mod))
366 log_error("Can't handle partially selected module %s!\n", log_id(mod));
367
368 std::string tempdir_name = "/tmp/" + proc_program_prefix() + "yosys-abc-XXXXXX";
369 if (!cleanup)
370 tempdir_name[0] = tempdir_name[4] = '_';
371 tempdir_name = make_temp_dir(tempdir_name);
372
373 if (!lut_mode)
374 run_nocheck(stringf("abc9_ops -write_lut %s/input.lut", tempdir_name.c_str()));
375 if (box_file.empty())
376 run_nocheck(stringf("abc9_ops -write_box %s/input.box", tempdir_name.c_str()));
377 run_nocheck(stringf("write_xaiger -map %s/input.sym %s %s/input.xaig", tempdir_name.c_str(), dff_mode ? "-dff" : "", tempdir_name.c_str()));
378
379 int num_outputs = active_design->scratchpad_get_int("write_xaiger.num_outputs");
380
381 log("Extracted %d AND gates and %d wires from module `%s' to a netlist network with %d inputs and %d outputs.\n",
382 active_design->scratchpad_get_int("write_xaiger.num_ands"),
383 active_design->scratchpad_get_int("write_xaiger.num_wires"),
384 log_id(mod),
385 active_design->scratchpad_get_int("write_xaiger.num_inputs"),
386 num_outputs);
387 if (num_outputs) {
388 std::string abc9_exe_cmd;
389 abc9_exe_cmd += stringf("%s -cwd %s", exe_cmd.str().c_str(), tempdir_name.c_str());
390 if (!lut_mode)
391 abc9_exe_cmd += stringf(" -lut %s/input.lut", tempdir_name.c_str());
392 if (box_file.empty())
393 abc9_exe_cmd += stringf(" -box %s/input.box", tempdir_name.c_str());
394 else
395 abc9_exe_cmd += stringf(" -box %s", box_file.c_str());
396 run_nocheck(abc9_exe_cmd);
397 run_nocheck(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod), tempdir_name.c_str(), tempdir_name.c_str()));
398 run_nocheck(stringf("abc9_ops -reintegrate %s", dff_mode ? "-dff" : ""));
399 }
400 else
401 log("Don't call ABC as there is nothing to map.\n");
402
403 if (cleanup) {
404 log("Removing temp directory.\n");
405 remove_directory(tempdir_name);
406 }
407 mod->check();
408 active_design->selection().selected_modules.clear();
409 log_pop();
410 }
411
412 active_design->selection_stack.pop_back();
413 }
414 }
415
416 if (check_label("post")) {
417 if (dff_mode || help_mode) {
418 run("techmap -wb -map %$abc9_unmap", "(only if -dff)"); // techmap user design from submod back to original cell
419 // ($_DFF_[NP]_ already shorted by -reintegrate)
420 run("design -delete $abc9_unmap");
421 }
422 }
423 }
424 } Abc9Pass;
425
426 PRIVATE_NAMESPACE_END