Merge pull request #2466 from whitequark/cxxrtl-reset
[yosys.git] / techlibs / nexus / synth_nexus.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2020 David Shah <dave@ds0.me>
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 #include "kernel/register.h"
21 #include "kernel/celltypes.h"
22 #include "kernel/rtlil.h"
23 #include "kernel/log.h"
24
25 USING_YOSYS_NAMESPACE
26 PRIVATE_NAMESPACE_BEGIN
27
28 struct SynthNexusPass : public ScriptPass
29 {
30 SynthNexusPass() : ScriptPass("synth_nexus", "synthesis for Lattice Nexus FPGAs") { }
31
32 void on_register() override
33 {
34 RTLIL::constpad["synth_nexus.abc9.W"] = "300";
35 }
36
37 void help() override
38 {
39 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
40 log("\n");
41 log(" synth_nexus [options]\n");
42 log("\n");
43 log("This command runs synthesis for Lattice Nexus FPGAs.\n");
44 log("\n");
45 log(" -top <module>\n");
46 log(" use the specified module as top module\n");
47 log("\n");
48 log(" -family <device>\n");
49 log(" run synthesis for the specified Nexus device\n");
50 log(" supported values: lifcl, lfd2nx\n");
51 log("\n");
52 log(" -json <file>\n");
53 log(" write the design to the specified JSON file. writing of an output file\n");
54 log(" is omitted if this parameter is not specified.\n");
55 log("\n");
56 log(" -vm <file>\n");
57 log(" write the design to the specified structural Verilog file. writing of\n");
58 log(" an output file is omitted if this parameter is not specified.\n");
59 log("\n");
60 log(" -run <from_label>:<to_label>\n");
61 log(" only run the commands between the labels (see below). an empty\n");
62 log(" from label is synonymous to 'begin', and empty to label is\n");
63 log(" synonymous to the end of the command list.\n");
64 log("\n");
65 log(" -noflatten\n");
66 log(" do not flatten design before synthesis\n");
67 log("\n");
68 log(" -dff\n");
69 log(" run 'abc'/'abc9' with -dff option\n");
70 log("\n");
71 log(" -retime\n");
72 log(" run 'abc' with '-dff -D 1' options\n");
73 log("\n");
74 log(" -noccu2\n");
75 log(" do not use CCU2 cells in output netlist\n");
76 log("\n");
77 log(" -nodffe\n");
78 log(" do not use flipflops with CE in output netlist\n");
79 log("\n");
80 log(" -nobram\n");
81 log(" do not use block RAM cells in output netlist\n");
82 log("\n");
83 log(" -nolutram\n");
84 log(" do not use LUT RAM cells in output netlist\n");
85 log("\n");
86 log(" -nowidelut\n");
87 log(" do not use PFU muxes to implement LUTs larger than LUT4s\n");
88 log("\n");
89 log(" -noiopad\n");
90 log(" do not insert IO buffers\n");
91 log("\n");
92 log(" -nodsp\n");
93 log(" do not infer DSP multipliers\n");
94 log("\n");
95 log(" -abc9\n");
96 log(" use new ABC9 flow (EXPERIMENTAL)\n");
97 log("\n");
98 log("The following commands are executed by this synthesis command:\n");
99 help_script();
100 log("\n");
101 }
102
103 string top_opt, json_file, vm_file, family;
104 bool noccu2, nodffe, nobram, nolutram, nowidelut, noiopad, nodsp, flatten, dff, retime, abc9;
105
106 void clear_flags() override
107 {
108 top_opt = "-auto-top";
109 family = "lifcl";
110 json_file = "";
111 vm_file = "";
112 noccu2 = false;
113 nodffe = false;
114 nobram = false;
115 nolutram = false;
116 nowidelut = false;
117 noiopad = false;
118 nodsp = false;
119 flatten = true;
120 dff = false;
121 retime = false;
122 }
123
124 void execute(std::vector<std::string> args, RTLIL::Design *design) override
125 {
126 string run_from, run_to;
127 clear_flags();
128
129 size_t argidx;
130 for (argidx = 1; argidx < args.size(); argidx++)
131 {
132 if (args[argidx] == "-top" && argidx+1 < args.size()) {
133 top_opt = "-top " + args[++argidx];
134 continue;
135 }
136 if (args[argidx] == "-json" && argidx+1 < args.size()) {
137 json_file = args[++argidx];
138 continue;
139 }
140 if (args[argidx] == "-vm" && argidx+1 < args.size()) {
141 vm_file = args[++argidx];
142 continue;
143 }
144 if (args[argidx] == "-run" && argidx+1 < args.size()) {
145 size_t pos = args[argidx+1].find(':');
146 if (pos == std::string::npos)
147 break;
148 run_from = args[++argidx].substr(0, pos);
149 run_to = args[argidx].substr(pos+1);
150 continue;
151 }
152 if ((args[argidx] == "-family") && argidx+1 < args.size()) {
153 family = args[++argidx];
154 continue;
155 }
156 if (args[argidx] == "-flatten") {
157 flatten = true;
158 continue;
159 }
160 if (args[argidx] == "-noflatten") {
161 flatten = false;
162 continue;
163 }
164 if (args[argidx] == "-dff") {
165 dff = true;
166 continue;
167 }
168 if (args[argidx] == "-nodsp") {
169 nodsp = true;
170 continue;
171 }
172 if (args[argidx] == "-retime") {
173 retime = true;
174 continue;
175 }
176 if (args[argidx] == "-noccu2") {
177 noccu2 = true;
178 continue;
179 }
180 if (args[argidx] == "-nodffe") {
181 nodffe = true;
182 continue;
183 }
184 if (args[argidx] == "-nobram") {
185 nobram = true;
186 continue;
187 }
188 if (args[argidx] == "-nolutram") {
189 nolutram = true;
190 continue;
191 }
192 if (args[argidx] == "-nowidelut") {
193 nowidelut = true;
194 continue;
195 }
196 if (args[argidx] == "-noiopad") {
197 noiopad = true;
198 continue;
199 }
200 if (args[argidx] == "-abc9") {
201 abc9 = true;
202 continue;
203 }
204 break;
205 }
206 extra_args(args, argidx, design);
207
208 if (!design->full_selection())
209 log_cmd_error("This command only operates on fully selected designs!\n");
210
211 if (abc9 && retime)
212 log_cmd_error("-retime option not currently compatible with -abc9!\n");
213
214 log_header(design, "Executing SYNTH_NEXUS pass.\n");
215 log_push();
216
217 run_script(design, run_from, run_to);
218
219 log_pop();
220 }
221
222 struct DSPRule {
223 int a_maxwidth;
224 int b_maxwidth;
225 int a_minwidth;
226 int b_minwidth;
227 std::string prim;
228 };
229
230 const std::vector<DSPRule> dsp_rules = {
231 {36, 36, 22, 22, "$__NX_MUL36X36"},
232 {36, 18, 22, 10, "$__NX_MUL36X18"},
233 {18, 18, 10, 4, "$__NX_MUL18X18"},
234 {18, 18, 4, 10, "$__NX_MUL18X18"},
235 { 9, 9, 4, 4, "$__NX_MUL9X9"},
236 };
237
238 void script() override
239 {
240
241 if (family != "lifcl" && family != "lfd2nx")
242 log_cmd_error("Invalid Nexus -family setting: '%s'.\n", family.c_str());
243
244 if (check_label("begin"))
245 {
246 run("read_verilog -lib -specify +/nexus/cells_sim.v +/nexus/cells_xtra.v");
247 run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
248 }
249
250 if (check_label("coarse"))
251 {
252 run("proc");
253 if (flatten || help_mode)
254 run("flatten");
255 run("tribuf -logic");
256 run("deminout");
257 run("opt_expr");
258 run("opt_clean");
259 run("check");
260 run("opt -nodffe -nosdff");
261 run("fsm");
262 run("opt");
263 run("wreduce");
264 run("peepopt");
265 run("opt_clean");
266 run("share");
267 run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4");
268 run("opt_expr");
269 run("opt_clean");
270
271 if (help_mode) {
272 run("techmap -map +/mul2dsp.v [...]", "(unless -nodsp)");
273 run("techmap -map +/nexus/dsp_map.v", "(unless -nodsp)");
274 } else if (!nodsp) {
275 for (const auto &rule : dsp_rules) {
276 run(stringf("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=%d -D DSP_B_MAXWIDTH=%d -D DSP_A_MINWIDTH=%d -D DSP_B_MINWIDTH=%d -D DSP_NAME=%s",
277 rule.a_maxwidth, rule.b_maxwidth, rule.a_minwidth, rule.b_minwidth, rule.prim.c_str()));
278 run("chtype -set $mul t:$__soft_mul");
279 }
280 run("techmap -map +/nexus/dsp_map.v");
281 }
282
283 run("alumacc");
284 run("opt");
285 run("memory -nomap");
286 run("opt_clean");
287 }
288
289 if (!nobram && check_label("map_bram", "(skip if -nobram)"))
290 {
291 run("memory_bram -rules +/nexus/brams.txt");
292 run("setundef -zero -params t:$__NX_PDP16K");
293 run("techmap -map +/nexus/brams_map.v");
294 }
295
296 if (!nolutram && check_label("map_lutram", "(skip if -nolutram)"))
297 {
298 run("memory_bram -rules +/nexus/lutrams.txt");
299 run("setundef -zero -params t:$__NEXUS_DPR16X4");
300 run("techmap -map +/nexus/lutrams_map.v");
301 }
302
303 if (check_label("map_ffram"))
304 {
305 run("opt -fast -mux_undef -undriven -fine");
306 run("memory_map -iattr -attr !ram_block -attr !rom_block -attr logic_block "
307 "-attr syn_ramstyle=auto -attr syn_ramstyle=registers "
308 "-attr syn_romstyle=auto -attr syn_romstyle=logic");
309 run("opt -undriven -fine");
310 }
311
312 if (check_label("map_gates"))
313 {
314 if (noccu2)
315 run("techmap");
316 else
317 run("techmap -map +/techmap.v -map +/nexus/arith_map.v");
318 if (help_mode || !noiopad)
319 run("iopadmap -bits -outpad OB I:O -inpad IB O:I -toutpad $__NX_TOUTPAD OE:I:O -tinoutpad $__NX_TINOUTPAD OE:O:I:B A:top", "(skip if '-noiopad')");
320 run("opt -fast");
321 if (retime || help_mode)
322 run("abc -dff -D 1", "(only if -retime)");
323 }
324
325 if (check_label("map_ffs"))
326 {
327 run("opt_clean");
328 std::string dfflegalize_args = " -cell $_DFF_P_ 01 -cell $_DFF_PP?_ r -cell $_SDFF_PP?_ r -cell $_DLATCH_?_ x";
329 if (help_mode) {
330 dfflegalize_args += " [-cell $_DFFE_PP_ 01 -cell $_DFFE_PP?P_ r -cell $_SDFFE_PP?P_ r]";
331 } else if (!nodffe) {
332 dfflegalize_args += " -cell $_DFFE_PP_ 01 -cell $_DFFE_PP?P_ r -cell $_SDFFE_PP?P_ r";
333 }
334 run("dfflegalize" + dfflegalize_args, "($_*DFFE_* only if not -nodffe)");
335 if ((abc9 && dff) || help_mode)
336 run("zinit -all w:* t:$_DFF_?_ t:$_DFFE_??_ t:$_SDFF*", "(only if -abc9 and -dff");
337 run("techmap -D NO_LUT -map +/nexus/cells_map.v");
338 run("opt_expr -undriven -mux_undef");
339 run("simplemap");
340 run("attrmvcp -copy -attr syn_useioff");
341 run("opt_clean");
342 }
343
344 if (check_label("map_luts"))
345 {
346 run("techmap -map +/nexus/latches_map.v");
347
348 if (abc9) {
349 std::string abc9_opts;
350 if (nowidelut)
351 abc9_opts += " -maxlut 4";
352 std::string k = "synth_nexus.abc9.W";
353 if (active_design && active_design->scratchpad.count(k))
354 abc9_opts += stringf(" -W %s", active_design->scratchpad_get_string(k).c_str());
355 else
356 abc9_opts += stringf(" -W %s", RTLIL::constpad.at(k).c_str());
357 if (nowidelut)
358 abc9_opts += " -maxlut 4";
359 if (dff)
360 abc9_opts += " -dff";
361 run("abc9" + abc9_opts);
362 } else {
363 std::string abc_args = " -dress";
364 if (nowidelut)
365 abc_args += " -lut 4";
366 else
367 abc_args += " -lut 4:5";
368 if (dff)
369 abc_args += " -dff";
370 run("abc" + abc_args);
371 }
372 run("clean");
373 }
374
375 if (check_label("map_cells"))
376 {
377 run("techmap -map +/nexus/cells_map.v");
378
379 // This is needed for Radiant, but perhaps not optimal for nextpnr...
380 run("setundef -zero");
381
382 run("hilomap -singleton -hicell VHI Z -locell VLO Z");
383 run("clean");
384 }
385
386 if (check_label("check"))
387 {
388 run("autoname");
389 run("hierarchy -check");
390 run("stat");
391 run("check -noinit");
392 }
393
394 if (check_label("json"))
395 {
396 if (!json_file.empty() || help_mode)
397 run(stringf("write_json %s", help_mode ? "<file-name>" : json_file.c_str()));
398 }
399
400 if (check_label("vm"))
401 {
402 if (!vm_file.empty() || help_mode)
403 run(stringf("write_verilog %s", help_mode ? "<file-name>" : vm_file.c_str()));
404 }
405 }
406 } SynthNexusPass;
407
408 PRIVATE_NAMESPACE_END