synth_nexus: Initial implementation
[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(" -abc9\n");
93 log(" use new ABC9 flow (EXPERIMENTAL)\n");
94 log("\n");
95 log("The following commands are executed by this synthesis command:\n");
96 help_script();
97 log("\n");
98 }
99
100 string top_opt, json_file, vm_file, family;
101 bool noccu2, nodffe, nobram, nolutram, nowidelut, noiopad, flatten, dff, retime, abc9;
102
103 void clear_flags() override
104 {
105 top_opt = "-auto-top";
106 family = "lifcl";
107 json_file = "";
108 vm_file = "";
109 noccu2 = false;
110 nodffe = false;
111 nobram = false;
112 nolutram = false;
113 nowidelut = false;
114 noiopad = false;
115 flatten = true;
116 dff = false;
117 retime = false;
118 }
119
120 void execute(std::vector<std::string> args, RTLIL::Design *design) override
121 {
122 string run_from, run_to;
123 clear_flags();
124
125 size_t argidx;
126 for (argidx = 1; argidx < args.size(); argidx++)
127 {
128 if (args[argidx] == "-top" && argidx+1 < args.size()) {
129 top_opt = "-top " + args[++argidx];
130 continue;
131 }
132 if (args[argidx] == "-json" && argidx+1 < args.size()) {
133 json_file = args[++argidx];
134 continue;
135 }
136 if (args[argidx] == "-vm" && argidx+1 < args.size()) {
137 vm_file = args[++argidx];
138 continue;
139 }
140 if (args[argidx] == "-run" && argidx+1 < args.size()) {
141 size_t pos = args[argidx+1].find(':');
142 if (pos == std::string::npos)
143 break;
144 run_from = args[++argidx].substr(0, pos);
145 run_to = args[argidx].substr(pos+1);
146 continue;
147 }
148 if ((args[argidx] == "-family") && argidx+1 < args.size()) {
149 family = args[++argidx];
150 continue;
151 }
152 if (args[argidx] == "-flatten") {
153 flatten = true;
154 continue;
155 }
156 if (args[argidx] == "-noflatten") {
157 flatten = false;
158 continue;
159 }
160 if (args[argidx] == "-dff") {
161 dff = true;
162 continue;
163 }
164 if (args[argidx] == "-retime") {
165 retime = true;
166 continue;
167 }
168 if (args[argidx] == "-noccu2") {
169 noccu2 = true;
170 continue;
171 }
172 if (args[argidx] == "-nodffe") {
173 nodffe = true;
174 continue;
175 }
176 if (args[argidx] == "-nobram") {
177 nobram = true;
178 continue;
179 }
180 if (args[argidx] == "-nolutram") {
181 nolutram = true;
182 continue;
183 }
184 if (args[argidx] == "-nowidelut") {
185 nowidelut = true;
186 continue;
187 }
188 if (args[argidx] == "-noiopad") {
189 noiopad = true;
190 continue;
191 }
192 if (args[argidx] == "-abc9") {
193 abc9 = true;
194 continue;
195 }
196 break;
197 }
198 extra_args(args, argidx, design);
199
200 if (!design->full_selection())
201 log_cmd_error("This command only operates on fully selected designs!\n");
202
203 if (abc9 && retime)
204 log_cmd_error("-retime option not currently compatible with -abc9!\n");
205
206 log_header(design, "Executing SYNTH_NEXUS pass.\n");
207 log_push();
208
209 run_script(design, run_from, run_to);
210
211 log_pop();
212 }
213
214 void script() override
215 {
216
217 if (family != "lifcl" && family != "lfd2nx")
218 log_cmd_error("Invalid Nexus -family setting: '%s'.\n", family.c_str());
219
220 if (check_label("begin"))
221 {
222 run("read_verilog -lib -specify +/nexus/cells_sim.v +/nexus/cells_xtra.v");
223 run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
224 }
225
226 if (check_label("coarse"))
227 {
228 run("proc");
229 if (flatten || help_mode)
230 run("flatten");
231 run("tribuf -logic");
232 run("deminout");
233 run("opt_expr");
234 run("opt_clean");
235 run("check");
236 run("opt -nodffe -nosdff");
237 run("fsm");
238 run("opt");
239 run("wreduce");
240 run("peepopt");
241 run("opt_clean");
242 run("share");
243 run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4");
244 run("opt_expr");
245 run("opt_clean");
246
247 run("alumacc");
248 run("opt");
249 run("memory -nomap");
250 run("opt_clean");
251 }
252
253 if (!nobram && check_label("map_bram", "(skip if -nobram)"))
254 {
255 run("memory_bram -rules +/nexus/brams.txt");
256 run("setundef -zero -params t:$__NX_PDP16K");
257 run("techmap -map +/nexus/brams_map.v");
258 }
259
260 if (!nolutram && check_label("map_lutram", "(skip if -nolutram)"))
261 {
262 run("memory_bram -rules +/nexus/lutrams.txt");
263 run("setundef -zero -params t:$__NEXUS_DPR16X4");
264 run("techmap -map +/nexus/lutrams_map.v");
265 }
266
267 if (check_label("map_ffram"))
268 {
269 run("opt -fast -mux_undef -undriven -fine");
270 run("memory_map -iattr -attr !ram_block -attr !rom_block -attr logic_block "
271 "-attr syn_ramstyle=auto -attr syn_ramstyle=registers "
272 "-attr syn_romstyle=auto -attr syn_romstyle=logic");
273 run("opt -undriven -fine");
274 }
275
276 if (check_label("map_gates"))
277 {
278 if (noccu2)
279 run("techmap");
280 else
281 run("techmap -map +/techmap.v -map +/nexus/arith_map.v");
282 if (help_mode || !noiopad)
283 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')");
284 run("opt -fast");
285 if (retime || help_mode)
286 run("abc -dff -D 1", "(only if -retime)");
287 }
288
289 if (check_label("map_ffs"))
290 {
291 run("opt_clean");
292 std::string dfflegalize_args = " -cell $_DFF_P_ 01 -cell $_DFF_PP?_ r -cell $_SDFF_PP?_ r -cell $_DLATCH_?_ x";
293 if (help_mode) {
294 dfflegalize_args += " [-cell $_DFFE_PP_ 01 -cell $_DFFE_PP?P_ r -cell $_SDFFE_PP?P_ r]";
295 } else if (!nodffe) {
296 dfflegalize_args += " -cell $_DFFE_PP_ 01 -cell $_DFFE_PP?P_ r -cell $_SDFFE_PP?P_ r";
297 }
298 run("dfflegalize" + dfflegalize_args, "($_*DFFE_* only if not -nodffe)");
299 if ((abc9 && dff) || help_mode)
300 run("zinit -all w:* t:$_DFF_?_ t:$_DFFE_??_ t:$_SDFF*", "(only if -abc9 and -dff");
301 run("techmap -D NO_LUT -map +/nexus/cells_map.v");
302 run("opt_expr -undriven -mux_undef");
303 run("simplemap");
304 run("attrmvcp -copy -attr syn_useioff");
305 run("opt_clean");
306 }
307
308 if (check_label("map_luts"))
309 {
310 run("techmap -map +/nexus/latches_map.v");
311
312 if (abc9) {
313 std::string abc9_opts;
314 if (nowidelut)
315 abc9_opts += " -maxlut 4";
316 std::string k = "synth_nexus.abc9.W";
317 if (active_design && active_design->scratchpad.count(k))
318 abc9_opts += stringf(" -W %s", active_design->scratchpad_get_string(k).c_str());
319 else
320 abc9_opts += stringf(" -W %s", RTLIL::constpad.at(k).c_str());
321 if (nowidelut)
322 abc9_opts += " -maxlut 4";
323 if (dff)
324 abc9_opts += " -dff";
325 run("abc9" + abc9_opts);
326 } else {
327 std::string abc_args = " -dress";
328 if (nowidelut)
329 abc_args += " -lut 4";
330 else
331 abc_args += " -lut 4:5";
332 if (dff)
333 abc_args += " -dff";
334 run("abc" + abc_args);
335 }
336 run("clean");
337 }
338
339 if (check_label("map_cells"))
340 {
341 run("techmap -map +/nexus/cells_map.v");
342
343 // This is needed for Radiant, but perhaps not optimal for nextpnr...
344 run("setundef -zero");
345
346 run("hilomap -singleton -hicell VHI Z -locell VLO Z");
347 run("clean");
348 }
349
350 if (check_label("check"))
351 {
352 run("autoname");
353 run("hierarchy -check");
354 run("stat");
355 run("check -noinit");
356 }
357
358 if (check_label("json"))
359 {
360 if (!json_file.empty() || help_mode)
361 run(stringf("write_json %s", help_mode ? "<file-name>" : json_file.c_str()));
362 }
363
364 if (check_label("vm"))
365 {
366 if (!vm_file.empty() || help_mode)
367 run(stringf("write_verilog %s", help_mode ? "<file-name>" : vm_file.c_str()));
368 }
369 }
370 } SynthNexusPass;
371
372 PRIVATE_NAMESPACE_END