Add comment for why opt_expr is necessary
[yosys.git] / techlibs / xilinx / synth_xilinx.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 #include "kernel/register.h"
22 #include "kernel/celltypes.h"
23 #include "kernel/rtlil.h"
24 #include "kernel/log.h"
25
26 USING_YOSYS_NAMESPACE
27 PRIVATE_NAMESPACE_BEGIN
28
29 #define XC7_WIRE_DELAY 300 // Number with which ABC will map a 6-input gate
30 // to one LUT6 (instead of a LUT5 + LUT2)
31
32 struct SynthXilinxPass : public ScriptPass
33 {
34 SynthXilinxPass() : ScriptPass("synth_xilinx", "synthesis for Xilinx FPGAs") { }
35
36 void help() YS_OVERRIDE
37 {
38 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
39 log("\n");
40 log(" synth_xilinx [options]\n");
41 log("\n");
42 log("This command runs synthesis for Xilinx FPGAs. This command does not operate on\n");
43 log("partly selected designs. At the moment this command creates netlists that are\n");
44 log("compatible with 7-Series Xilinx devices.\n");
45 log("\n");
46 log(" -top <module>\n");
47 log(" use the specified module as top module\n");
48 log("\n");
49 log(" -family {xcup|xcu|xc7|xc6s}\n");
50 log(" run synthesis for the specified Xilinx architecture\n");
51 log(" generate the synthesis netlist for the specified family.\n");
52 log(" default: xc7\n");
53 log("\n");
54 log(" -edif <file>\n");
55 log(" write the design to the specified edif file. writing of an output file\n");
56 log(" is omitted if this parameter is not specified.\n");
57 log("\n");
58 log(" -blif <file>\n");
59 log(" write the design to the specified BLIF file. writing of an output file\n");
60 log(" is omitted if this parameter is not specified.\n");
61 log("\n");
62 log(" -vpr\n");
63 log(" generate an output netlist (and BLIF file) suitable for VPR\n");
64 log(" (this feature is experimental and incomplete)\n");
65 log("\n");
66 log(" -ise\n");
67 log(" generate an output netlist suitable for ISE (enables -iopad)\n");
68 log("\n");
69 log(" -nobram\n");
70 log(" do not use block RAM cells in output netlist\n");
71 log("\n");
72 log(" -nolutram\n");
73 log(" do not use distributed RAM cells in output netlist\n");
74 log("\n");
75 log(" -nosrl\n");
76 log(" do not use distributed SRL cells in output netlist\n");
77 log("\n");
78 log(" -nocarry\n");
79 log(" do not use XORCY/MUXCY/CARRY4 cells in output netlist\n");
80 log("\n");
81 log(" -nowidelut\n");
82 log(" do not use MUXF[78] resources to implement LUTs larger than LUT6s\n");
83 log("\n");
84 log(" -nodsp\n");
85 log(" do not use DSP48E1s to implement multipliers and associated logic\n");
86 log(" -iopad\n");
87 log(" enable I/O buffer insertion (selected automatically by -ise)\n");
88 log("\n");
89 log(" -noiopad\n");
90 log(" disable I/O buffer insertion (only useful with -ise)\n");
91 log("\n");
92 log(" -noclkbuf\n");
93 log(" disable automatic clock buffer insertion\n");
94 log("\n");
95 log(" -widemux <int>\n");
96 log(" enable inference of hard multiplexer resources (MUXF[78]) for muxes at or\n");
97 log(" above this number of inputs (minimum value 2, recommended value >= 5).\n");
98 log(" default: 0 (no inference)\n");
99 log("\n");
100 log(" -run <from_label>:<to_label>\n");
101 log(" only run the commands between the labels (see below). an empty\n");
102 log(" from label is synonymous to 'begin', and empty to label is\n");
103 log(" synonymous to the end of the command list.\n");
104 log("\n");
105 log(" -flatten\n");
106 log(" flatten design before synthesis\n");
107 log("\n");
108 log(" -retime\n");
109 log(" run 'abc' with -dff option\n");
110 log("\n");
111 log(" -abc9\n");
112 log(" use new ABC9 flow (EXPERIMENTAL)\n");
113 log("\n");
114 log("\n");
115 log("The following commands are executed by this synthesis command:\n");
116 help_script();
117 log("\n");
118 }
119
120 std::string top_opt, edif_file, blif_file, family;
121 bool flatten, retime, vpr, ise, iopad, noiopad, noclkbuf, nobram, nolutram, nosrl, nocarry, nowidelut, nodsp, abc9;
122 bool flatten_before_abc;
123 int widemux;
124
125 void clear_flags() YS_OVERRIDE
126 {
127 top_opt = "-auto-top";
128 edif_file.clear();
129 blif_file.clear();
130 family = "xc7";
131 flatten = false;
132 retime = false;
133 vpr = false;
134 ise = false;
135 iopad = false;
136 noiopad = false;
137 noclkbuf = false;
138 nocarry = false;
139 nobram = false;
140 nolutram = false;
141 nosrl = false;
142 nocarry = false;
143 nowidelut = false;
144 nodsp = false;
145 abc9 = false;
146 flatten_before_abc = false;
147 widemux = 0;
148 }
149
150 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
151 {
152 std::string run_from, run_to;
153 clear_flags();
154
155 size_t argidx;
156 for (argidx = 1; argidx < args.size(); argidx++)
157 {
158 if (args[argidx] == "-top" && argidx+1 < args.size()) {
159 top_opt = "-top " + args[++argidx];
160 continue;
161 }
162 if ((args[argidx] == "-family" || args[argidx] == "-arch") && argidx+1 < args.size()) {
163 family = args[++argidx];
164 continue;
165 }
166 if (args[argidx] == "-edif" && argidx+1 < args.size()) {
167 edif_file = args[++argidx];
168 continue;
169 }
170 if (args[argidx] == "-blif" && argidx+1 < args.size()) {
171 blif_file = args[++argidx];
172 continue;
173 }
174 if (args[argidx] == "-run" && argidx+1 < args.size()) {
175 size_t pos = args[argidx+1].find(':');
176 if (pos == std::string::npos)
177 break;
178 run_from = args[++argidx].substr(0, pos);
179 run_to = args[argidx].substr(pos+1);
180 continue;
181 }
182 if (args[argidx] == "-flatten") {
183 flatten = true;
184 continue;
185 }
186 if (args[argidx] == "-flatten_before_abc") {
187 flatten_before_abc = true;
188 continue;
189 }
190 if (args[argidx] == "-retime") {
191 retime = true;
192 continue;
193 }
194 if (args[argidx] == "-nocarry") {
195 nocarry = true;
196 continue;
197 }
198 if (args[argidx] == "-nowidelut") {
199 nowidelut = true;
200 continue;
201 }
202 if (args[argidx] == "-vpr") {
203 vpr = true;
204 continue;
205 }
206 if (args[argidx] == "-ise") {
207 ise = true;
208 continue;
209 }
210 if (args[argidx] == "-iopad") {
211 iopad = true;
212 continue;
213 }
214 if (args[argidx] == "-noiopad") {
215 noiopad = true;
216 continue;
217 }
218 if (args[argidx] == "-noclkbuf") {
219 noclkbuf = true;
220 continue;
221 }
222 if (args[argidx] == "-nocarry") {
223 nocarry = true;
224 continue;
225 }
226 if (args[argidx] == "-nobram") {
227 nobram = true;
228 continue;
229 }
230 if (args[argidx] == "-nolutram" || /*deprecated alias*/ args[argidx] == "-nodram") {
231 nolutram = true;
232 continue;
233 }
234 if (args[argidx] == "-nosrl") {
235 nosrl = true;
236 continue;
237 }
238 if (args[argidx] == "-widemux" && argidx+1 < args.size()) {
239 widemux = atoi(args[++argidx].c_str());
240 continue;
241 }
242 if (args[argidx] == "-abc9") {
243 abc9 = true;
244 continue;
245 }
246 if (args[argidx] == "-nodsp") {
247 nodsp = true;
248 continue;
249 }
250 break;
251 }
252 extra_args(args, argidx, design);
253
254 if (family != "xcup" && family != "xcu" && family != "xc7" && family != "xc6s")
255 log_cmd_error("Invalid Xilinx -family setting: '%s'.\n", family.c_str());
256
257 if (widemux != 0 && widemux < 2)
258 log_cmd_error("-widemux value must be 0 or >= 2.\n");
259
260 if (!design->full_selection())
261 log_cmd_error("This command only operates on fully selected designs!\n");
262
263 if (abc9 && retime)
264 log_cmd_error("-retime option not currently compatible with -abc9!\n");
265
266 log_header(design, "Executing SYNTH_XILINX pass.\n");
267 log_push();
268
269 run_script(design, run_from, run_to);
270
271 log_pop();
272 }
273
274 void script() YS_OVERRIDE
275 {
276 if (check_label("begin")) {
277 if (vpr)
278 run("read_verilog -lib -D_EXPLICIT_CARRY +/xilinx/cells_sim.v");
279 else
280 run("read_verilog -lib +/xilinx/cells_sim.v");
281
282 run("read_verilog -lib +/xilinx/cells_xtra.v");
283
284 if (help_mode) {
285 run("read_verilog -lib +/xilinx/{family}_brams_bb.v");
286 } else if (family == "xc6s") {
287 run("read_verilog -lib +/xilinx/xc6s_brams_bb.v");
288 } else if (family == "xc7") {
289 run("read_verilog -lib +/xilinx/xc7_brams_bb.v");
290 }
291
292 run(stringf("hierarchy -check %s", top_opt.c_str()));
293 }
294
295 if (check_label("prepare")) {
296 run("proc");
297 if (flatten || help_mode)
298 run("flatten", "(with '-flatten')");
299 run("opt_expr");
300 run("opt_clean");
301 run("check");
302 run("opt");
303 if (help_mode)
304 run("wreduce [-keepdc]", "(option for '-widemux')");
305 else
306 run("wreduce" + std::string(widemux > 0 ? " -keepdc" : ""));
307 run("peepopt");
308 run("opt_clean");
309
310 if (widemux > 0 || help_mode)
311 run("muxpack", " ('-widemux' only)");
312
313 // xilinx_srl looks for $shiftx cells for identifying variable-length
314 // shift registers, so attempt to convert $pmux-es to this
315 // Also: wide multiplexer inference benefits from this too
316 if (!(nosrl && widemux == 0) || help_mode) {
317 run("pmux2shiftx", "(skip if '-nosrl' and '-widemux=0')");
318 run("clean", " (skip if '-nosrl' and '-widemux=0')");
319 }
320
321 run("techmap -map +/cmp2lut.v -D LUT_WIDTH=6");
322 }
323
324 if (check_label("map_dsp")) {
325 if (!nodsp || help_mode) {
326 // NB: Xilinx multipliers are signed only
327 run("techmap -map +/mul2dsp.v -map +/xilinx/dsp_map.v -D DSP_A_MAXWIDTH=25 -D DSP_A_MAXWIDTH_PARTIAL=18 -D DSP_B_MAXWIDTH=18 -D DSP_SIGNEDONLY=1 -D DSP_NAME=$__MUL25X18", "(skip if '-nodsp')");
328 // Necessary for optimising away $shl cells, as well as $add cells
329 // that have inputs with 1'b0 LSBs
330 run("opt_expr -fine", " (skip if '-nodsp')");
331 run("wreduce", " (skip if '-nodsp')");
332 run("xilinx_dsp", " (skip if '-nodsp')");
333 run("chtype -set $mul t:$__soft_mul"," (skip if '-nodsp')");
334 }
335 }
336
337 if (check_label("coarse")) {
338 run("alumacc");
339 run("share");
340 run("opt");
341 run("fsm");
342 run("opt -fast");
343 run("memory -nomap");
344 run("opt_clean");
345 }
346
347 if (check_label("map_bram", "(skip if '-nobram')")) {
348 if (help_mode) {
349 run("memory_bram -rules +/xilinx/{family}_brams.txt");
350 run("techmap -map +/xilinx/{family}_brams_map.v");
351 } else if (!nobram) {
352 if (family == "xc6s") {
353 run("memory_bram -rules +/xilinx/xc6s_brams.txt");
354 run("techmap -map +/xilinx/xc6s_brams_map.v");
355 } else if (family == "xc7") {
356 run("memory_bram -rules +/xilinx/xc7_brams.txt");
357 run("techmap -map +/xilinx/xc7_brams_map.v");
358 } else {
359 log_warning("Block RAM inference not yet supported for family %s.\n", family.c_str());
360 }
361 }
362 }
363
364 if (check_label("map_lutram", "(skip if '-nolutram')")) {
365 if (!nolutram || help_mode) {
366 run("memory_bram -rules +/xilinx/lutrams.txt");
367 run("techmap -map +/xilinx/lutrams_map.v");
368 }
369 }
370
371 if (check_label("map_ffram")) {
372 if (widemux > 0)
373 run("opt -fast -mux_bool -undriven -fine"); // Necessary to omit -mux_undef otherwise muxcover
374 // performs less efficiently
375 else
376 run("opt -fast -full");
377 run("memory_map");
378 }
379
380 if (check_label("fine")) {
381 run("dffsr2dff");
382 run("dff2dffe");
383 if (help_mode) {
384 run("simplemap t:$mux", " ('-widemux' only)");
385 run("muxcover <internal options>, ('-widemux' only)");
386 }
387 else if (widemux > 0) {
388 run("simplemap t:$mux");
389 constexpr int cost_mux2 = 100;
390 std::string muxcover_args = stringf(" -nodecode -mux2=%d", cost_mux2);
391 switch (widemux) {
392 case 2: muxcover_args += stringf(" -mux4=%d -mux8=%d -mux16=%d", cost_mux2+1, cost_mux2+2, cost_mux2+3); break;
393 case 3:
394 case 4: muxcover_args += stringf(" -mux4=%d -mux8=%d -mux16=%d", cost_mux2*(widemux-1)-2, cost_mux2*(widemux-1)-1, cost_mux2*(widemux-1)); break;
395 case 5:
396 case 6:
397 case 7:
398 case 8: muxcover_args += stringf(" -mux8=%d -mux16=%d", cost_mux2*(widemux-1)-1, cost_mux2*(widemux-1)); break;
399 case 9:
400 case 10:
401 case 11:
402 case 12:
403 case 13:
404 case 14:
405 case 15:
406 default: muxcover_args += stringf(" -mux16=%d", cost_mux2*(widemux-1)-1); break;
407 }
408 run("muxcover " + muxcover_args);
409 }
410 run("opt -full");
411
412 if (!nosrl || help_mode)
413 run("xilinx_srl -variable -minlen 3", "(skip if '-nosrl')");
414
415 std::string techmap_args = " -map +/techmap.v";
416 if (help_mode)
417 techmap_args += " [-map +/xilinx/mux_map.v]";
418 else if (widemux > 0)
419 techmap_args += stringf(" -D MIN_MUX_INPUTS=%d -map +/xilinx/mux_map.v", widemux);
420 if (help_mode)
421 techmap_args += " [-map +/xilinx/arith_map.v]";
422 else if (!nocarry) {
423 techmap_args += " -map +/xilinx/arith_map.v";
424 if (vpr)
425 techmap_args += " -D _EXPLICIT_CARRY";
426 else if (abc9)
427 techmap_args += " -D _CLB_CARRY";
428 }
429 run("techmap " + techmap_args);
430 run("opt -fast");
431 }
432
433 if (check_label("map_cells")) {
434 std::string techmap_args = "-map +/techmap.v -map +/xilinx/cells_map.v";
435 if (widemux > 0)
436 techmap_args += stringf(" -D MIN_MUX_INPUTS=%d", widemux);
437 run("techmap " + techmap_args);
438 run("clean");
439 }
440
441 if (check_label("map_ffs")) {
442 if (abc9 || help_mode) {
443 run("techmap -map +/xilinx/ff_map.v", "('-abc9' only)");
444 run("dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT "
445 "-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT", "('-abc9' only)");
446 }
447 }
448
449 if (check_label("map_luts")) {
450 run("opt_expr -mux_undef");
451 if (flatten_before_abc)
452 run("flatten");
453 if (help_mode)
454 run("abc -luts 2:2,3,6:5[,10,20] [-dff]", "(option for 'nowidelut'; option for '-retime')");
455 else if (abc9) {
456 if (family != "xc7")
457 log_warning("'synth_xilinx -abc9' currently supports '-family xc7' only.\n");
458 run("techmap -map +/xilinx/abc_map.v -max_iter 1");
459 run("read_verilog -icells -lib +/xilinx/abc_model.v");
460 if (nowidelut)
461 run("abc9 -lut +/xilinx/abc_xc7_nowide.lut -box +/xilinx/abc_xc7.box -W " + std::to_string(XC7_WIRE_DELAY));
462 else
463 run("abc9 -lut +/xilinx/abc_xc7.lut -box +/xilinx/abc_xc7.box -W " + std::to_string(XC7_WIRE_DELAY));
464 }
465 else {
466 if (nowidelut)
467 run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : ""));
468 else
469 run("abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : ""));
470 }
471 run("clean");
472
473 // This shregmap call infers fixed length shift registers after abc
474 // has performed any necessary retiming
475 if (!nosrl || help_mode)
476 run("xilinx_srl -fixed -minlen 3", "(skip if '-nosrl')");
477 std::string techmap_args = "-map +/xilinx/lut_map.v -map +/xilinx/cells_map.v";
478 if (help_mode)
479 techmap_args += " [-map +/xilinx/ff_map.v]";
480 else if (abc9)
481 techmap_args += " -map +/xilinx/abc_unmap.v";
482 else
483 techmap_args += " -map +/xilinx/ff_map.v";
484 run("techmap " + techmap_args);
485 if (!abc9 || help_mode)
486 run("dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT "
487 "-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT", "(without '-abc9' only)");
488 run("clean");
489 }
490
491 if (check_label("finalize")) {
492 bool do_iopad = iopad || (ise && !noiopad);
493 if (help_mode || !noclkbuf) {
494 if (help_mode || do_iopad)
495 run("clkbufmap -buf BUFG O:I -inpad IBUFG O:I", "(skip if '-noclkbuf', '-inpad' passed if '-iopad' or '-ise' and not '-noiopad')");
496 else
497 run("clkbufmap -buf BUFG O:I");
498 }
499 if (do_iopad)
500 run("iopadmap -bits -outpad OBUF I:O -inpad IBUF O:I A:top", "(only if '-iopad' or '-ise' and not '-noiopad')");
501 }
502
503 if (check_label("check")) {
504 run("hierarchy -check");
505 run("stat -tech xilinx");
506 run("check -noinit");
507 }
508
509 if (check_label("edif")) {
510 if (!edif_file.empty() || help_mode)
511 run(stringf("write_edif -pvector bra %s", edif_file.c_str()));
512 }
513
514 if (check_label("blif")) {
515 if (!blif_file.empty() || help_mode)
516 run(stringf("write_blif %s", edif_file.c_str()));
517 }
518 }
519 } SynthXilinxPass;
520
521 PRIVATE_NAMESPACE_END