Merge branch 'master' into mwk/xilinx_bufgmap
[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(" -iopad\n");
85 log(" enable I/O buffer insertion (selected automatically by -ise)\n");
86 log("\n");
87 log(" -noiopad\n");
88 log(" disable I/O buffer insertion (only useful with -ise)\n");
89 log("\n");
90 log(" -noclkbuf\n");
91 log(" disable automatic clock buffer insertion\n");
92 log("\n");
93 log(" -widemux <int>\n");
94 log(" enable inference of hard multiplexer resources (MUXF[78]) for muxes at or\n");
95 log(" above this number of inputs (minimum value 2, recommended value >= 5).\n");
96 log(" default: 0 (no inference)\n");
97 log("\n");
98 log(" -run <from_label>:<to_label>\n");
99 log(" only run the commands between the labels (see below). an empty\n");
100 log(" from label is synonymous to 'begin', and empty to label is\n");
101 log(" synonymous to the end of the command list.\n");
102 log("\n");
103 log(" -flatten\n");
104 log(" flatten design before synthesis\n");
105 log("\n");
106 log(" -retime\n");
107 log(" run 'abc' with -dff option\n");
108 log("\n");
109 log(" -abc9\n");
110 log(" use new ABC9 flow (EXPERIMENTAL)\n");
111 log("\n");
112 log("\n");
113 log("The following commands are executed by this synthesis command:\n");
114 help_script();
115 log("\n");
116 }
117
118 std::string top_opt, edif_file, blif_file, family;
119 bool flatten, retime, vpr, ise, iopad, noiopad, noclkbuf, nobram, nolutram, nosrl, nocarry, nowidelut, abc9;
120 bool flatten_before_abc;
121 int widemux;
122
123 void clear_flags() YS_OVERRIDE
124 {
125 top_opt = "-auto-top";
126 edif_file.clear();
127 blif_file.clear();
128 family = "xc7";
129 flatten = false;
130 retime = false;
131 vpr = false;
132 ise = false;
133 iopad = false;
134 noiopad = false;
135 noclkbuf = false;
136 nocarry = false;
137 nobram = false;
138 nolutram = false;
139 nosrl = false;
140 nocarry = false;
141 nowidelut = false;
142 abc9 = false;
143 flatten_before_abc = false;
144 widemux = 0;
145 }
146
147 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
148 {
149 std::string run_from, run_to;
150 clear_flags();
151
152 size_t argidx;
153 for (argidx = 1; argidx < args.size(); argidx++)
154 {
155 if (args[argidx] == "-top" && argidx+1 < args.size()) {
156 top_opt = "-top " + args[++argidx];
157 continue;
158 }
159 if ((args[argidx] == "-family" || args[argidx] == "-arch") && argidx+1 < args.size()) {
160 family = args[++argidx];
161 continue;
162 }
163 if (args[argidx] == "-edif" && argidx+1 < args.size()) {
164 edif_file = args[++argidx];
165 continue;
166 }
167 if (args[argidx] == "-blif" && argidx+1 < args.size()) {
168 blif_file = args[++argidx];
169 continue;
170 }
171 if (args[argidx] == "-run" && argidx+1 < args.size()) {
172 size_t pos = args[argidx+1].find(':');
173 if (pos == std::string::npos)
174 break;
175 run_from = args[++argidx].substr(0, pos);
176 run_to = args[argidx].substr(pos+1);
177 continue;
178 }
179 if (args[argidx] == "-flatten") {
180 flatten = true;
181 continue;
182 }
183 if (args[argidx] == "-flatten_before_abc") {
184 flatten_before_abc = true;
185 continue;
186 }
187 if (args[argidx] == "-retime") {
188 retime = true;
189 continue;
190 }
191 if (args[argidx] == "-nocarry") {
192 nocarry = true;
193 continue;
194 }
195 if (args[argidx] == "-nowidelut") {
196 nowidelut = true;
197 continue;
198 }
199 if (args[argidx] == "-vpr") {
200 vpr = true;
201 continue;
202 }
203 if (args[argidx] == "-ise") {
204 ise = true;
205 continue;
206 }
207 if (args[argidx] == "-iopad") {
208 iopad = true;
209 continue;
210 }
211 if (args[argidx] == "-noiopad") {
212 noiopad = true;
213 continue;
214 }
215 if (args[argidx] == "-noclkbuf") {
216 noclkbuf = true;
217 continue;
218 }
219 if (args[argidx] == "-nocarry") {
220 nocarry = true;
221 continue;
222 }
223 if (args[argidx] == "-nobram") {
224 nobram = true;
225 continue;
226 }
227 if (args[argidx] == "-nolutram" || /*deprecated alias*/ args[argidx] == "-nodram") {
228 nolutram = true;
229 continue;
230 }
231 if (args[argidx] == "-nosrl") {
232 nosrl = true;
233 continue;
234 }
235 if (args[argidx] == "-widemux" && argidx+1 < args.size()) {
236 widemux = atoi(args[++argidx].c_str());
237 continue;
238 }
239 if (args[argidx] == "-abc9") {
240 abc9 = true;
241 continue;
242 }
243 break;
244 }
245 extra_args(args, argidx, design);
246
247 if (family != "xcup" && family != "xcu" && family != "xc7" && family != "xc6s")
248 log_cmd_error("Invalid Xilinx -family setting: '%s'.\n", family.c_str());
249
250 if (widemux != 0 && widemux < 2)
251 log_cmd_error("-widemux value must be 0 or >= 2.\n");
252
253 if (!design->full_selection())
254 log_cmd_error("This command only operates on fully selected designs!\n");
255
256 if (abc9 && retime)
257 log_cmd_error("-retime option not currently compatible with -abc9!\n");
258
259 log_header(design, "Executing SYNTH_XILINX pass.\n");
260 log_push();
261
262 run_script(design, run_from, run_to);
263
264 log_pop();
265 }
266
267 void script() YS_OVERRIDE
268 {
269 if (check_label("begin")) {
270 if (vpr)
271 run("read_verilog -lib -icells -D _ABC -D_EXPLICIT_CARRY +/xilinx/cells_sim.v");
272 else
273 run("read_verilog -lib -icells -D _ABC +/xilinx/cells_sim.v");
274
275 run("read_verilog -lib +/xilinx/cells_xtra.v");
276
277 if (help_mode) {
278 run("read_verilog -lib +/xilinx/{family}_brams_bb.v");
279 } else if (family == "xc6s") {
280 run("read_verilog -lib +/xilinx/xc6s_brams_bb.v");
281 } else if (family == "xc7") {
282 run("read_verilog -lib +/xilinx/xc7_brams_bb.v");
283 }
284
285 run(stringf("hierarchy -check %s", top_opt.c_str()));
286 }
287
288 if (check_label("coarse")) {
289 run("proc");
290 if (help_mode || flatten)
291 run("flatten", "(if -flatten)");
292 run("opt_expr");
293 run("opt_clean");
294 run("check");
295 run("opt");
296 if (help_mode)
297 run("wreduce [-keepdc]", "(option for '-widemux')");
298 else
299 run("wreduce" + std::string(widemux > 0 ? " -keepdc" : ""));
300 run("peepopt");
301 run("opt_clean");
302
303 if (widemux > 0 || help_mode)
304 run("muxpack", " ('-widemux' only)");
305
306 // shregmap -tech xilinx can cope with $shiftx and $mux
307 // cells for identifying variable-length shift registers,
308 // so attempt to convert $pmux-es to the former
309 // Also: wide multiplexer inference benefits from this too
310 if (!(nosrl && widemux == 0) || help_mode) {
311 run("pmux2shiftx", "(skip if '-nosrl' and '-widemux=0')");
312 run("clean", " (skip if '-nosrl' and '-widemux=0')");
313 }
314
315 run("techmap -map +/cmp2lut.v -D LUT_WIDTH=6");
316 run("alumacc");
317 run("share");
318 run("opt");
319 run("fsm");
320 run("opt -fast");
321 run("memory -nomap");
322 run("opt_clean");
323 }
324
325 if (check_label("map_bram", "(skip if '-nobram')")) {
326 if (help_mode) {
327 run("memory_bram -rules +/xilinx/{family}_brams.txt");
328 run("techmap -map +/xilinx/{family}_brams_map.v");
329 } else if (!nobram) {
330 if (family == "xc6s") {
331 run("memory_bram -rules +/xilinx/xc6s_brams.txt");
332 run("techmap -map +/xilinx/xc6s_brams_map.v");
333 } else if (family == "xc7") {
334 run("memory_bram -rules +/xilinx/xc7_brams.txt");
335 run("techmap -map +/xilinx/xc7_brams_map.v");
336 } else {
337 log_warning("Block RAM inference not yet supported for family %s.\n", family.c_str());
338 }
339 }
340 }
341
342 if (check_label("map_lutram", "(skip if '-nolutram')")) {
343 if (!nolutram || help_mode) {
344 run("memory_bram -rules +/xilinx/lutrams.txt");
345 run("techmap -map +/xilinx/lutrams_map.v");
346 }
347 }
348
349 if (check_label("map_ffram")) {
350 if (widemux > 0)
351 run("opt -fast -mux_bool -undriven -fine"); // Necessary to omit -mux_undef otherwise muxcover
352 // performs less efficiently
353 else
354 run("opt -fast -full");
355 run("memory_map");
356 }
357
358 if (check_label("fine")) {
359 run("dffsr2dff");
360 run("dff2dffe");
361 if (help_mode) {
362 run("simplemap t:$mux", " ('-widemux' only)");
363 run("muxcover <internal options>, ('-widemux' only)");
364 }
365 else if (widemux > 0) {
366 run("simplemap t:$mux");
367 constexpr int cost_mux2 = 100;
368 std::string muxcover_args = stringf(" -nodecode -mux2=%d", cost_mux2);
369 switch (widemux) {
370 case 2: muxcover_args += stringf(" -mux4=%d -mux8=%d -mux16=%d", cost_mux2+1, cost_mux2+2, cost_mux2+3); break;
371 case 3:
372 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;
373 case 5:
374 case 6:
375 case 7:
376 case 8: muxcover_args += stringf(" -mux8=%d -mux16=%d", cost_mux2*(widemux-1)-1, cost_mux2*(widemux-1)); break;
377 case 9:
378 case 10:
379 case 11:
380 case 12:
381 case 13:
382 case 14:
383 case 15:
384 default: muxcover_args += stringf(" -mux16=%d", cost_mux2*(widemux-1)-1); break;
385 }
386 run("muxcover " + muxcover_args);
387 }
388 run("opt -full");
389
390 if (!nosrl || help_mode) {
391 // shregmap operates on bit-level flops, not word-level,
392 // so break those down here
393 run("simplemap t:$dff t:$dffe", " (skip if '-nosrl')");
394 // shregmap with '-tech xilinx' infers variable length shift regs
395 run("shregmap -tech xilinx -minlen 3", "(skip if '-nosrl')");
396 }
397
398 std::string techmap_args = " -map +/techmap.v";
399 if (help_mode)
400 techmap_args += " [-map +/xilinx/mux_map.v]";
401 else if (widemux > 0)
402 techmap_args += stringf(" -D MIN_MUX_INPUTS=%d -map +/xilinx/mux_map.v", widemux);
403 if (help_mode)
404 techmap_args += " [-map +/xilinx/arith_map.v]";
405 else if (!nocarry) {
406 techmap_args += " -map +/xilinx/arith_map.v";
407 if (vpr)
408 techmap_args += " -D _EXPLICIT_CARRY";
409 else if (abc9)
410 techmap_args += " -D _CLB_CARRY";
411 }
412 run("techmap " + techmap_args);
413 run("opt -fast");
414 }
415
416 if (check_label("map_cells")) {
417 std::string techmap_args = "-map +/techmap.v -D _ABC -map +/xilinx/cells_map.v";
418 if (widemux > 0)
419 techmap_args += stringf(" -D MIN_MUX_INPUTS=%d", widemux);
420 run("techmap " + techmap_args);
421 run("clean");
422 }
423
424 if (check_label("map_luts")) {
425 run("opt_expr -mux_undef");
426 if (flatten_before_abc)
427 run("flatten");
428 if (help_mode)
429 run("abc -luts 2:2,3,6:5[,10,20] [-dff]", "(option for 'nowidelut', option for '-retime')");
430 else if (abc9) {
431 if (family != "xc7")
432 log_warning("'synth_xilinx -abc9' currently supports '-family xc7' only.\n");
433 if (nowidelut)
434 run("abc9 -lut +/xilinx/abc_xc7_nowide.lut -box +/xilinx/abc_xc7.box -W " + std::to_string(XC7_WIRE_DELAY));
435 else
436 run("abc9 -lut +/xilinx/abc_xc7.lut -box +/xilinx/abc_xc7.box -W " + std::to_string(XC7_WIRE_DELAY));
437 }
438 else {
439 if (nowidelut)
440 run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : ""));
441 else
442 run("abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : ""));
443 }
444 run("clean");
445
446 // This shregmap call infers fixed length shift registers after abc
447 // has performed any necessary retiming
448 if (!nosrl || help_mode)
449 run("shregmap -minlen 3 -init -params -enpol any_or_none", "(skip if '-nosrl')");
450 run("techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v");
451 run("dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT "
452 "-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT");
453 run("clean");
454 }
455
456 if (check_label("finalize")) {
457 bool do_iopad = iopad || (ise && !noiopad);
458 if (help_mode || !noclkbuf) {
459 if (help_mode || do_iopad)
460 run("clkbufmap -buf BUFG O:I -inpad IBUFG O:I", "(skip if '-noclkbuf', '-inpad' passed if '-iopad' or '-ise' and not '-noiopad')");
461 else
462 run("clkbufmap -buf BUFG O:I");
463 }
464 if (do_iopad)
465 run("iopadmap -bits -outpad OBUF I:O -inpad IBUF O:I A:top", "(only if '-iopad' or '-ise' and not '-noiopad')");
466 }
467
468 if (check_label("check")) {
469 run("hierarchy -check");
470 run("stat -tech xilinx");
471 run("check -noinit");
472 }
473
474 if (check_label("edif")) {
475 if (!edif_file.empty() || help_mode)
476 run(stringf("write_edif -pvector bra %s", edif_file.c_str()));
477 }
478
479 if (check_label("blif")) {
480 if (!blif_file.empty() || help_mode)
481 run(stringf("write_blif %s", edif_file.c_str()));
482 }
483 }
484 } SynthXilinxPass;
485
486 PRIVATE_NAMESPACE_END