Merge pull request #2301 from zachjs/for-loop-errors
[yosys.git] / techlibs / intel_alm / synth_intel_alm.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Claire Wolf <claire@symbioticeda.com>
5 * Copyright (C) 2019 Dan Ravensloft <dan.ravensloft@gmail.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/celltypes.h"
22 #include "kernel/log.h"
23 #include "kernel/register.h"
24 #include "kernel/rtlil.h"
25
26 USING_YOSYS_NAMESPACE
27 PRIVATE_NAMESPACE_BEGIN
28
29 struct SynthIntelALMPass : public ScriptPass {
30 SynthIntelALMPass() : ScriptPass("synth_intel_alm", "synthesis for ALM-based Intel (Altera) FPGAs.") {}
31
32 void help() override
33 {
34 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
35 log("\n");
36 log(" synth_intel_alm [options]\n");
37 log("\n");
38 log("This command runs synthesis for ALM-based Intel FPGAs.\n");
39 log("\n");
40 log(" -top <module>\n");
41 log(" use the specified module as top module\n");
42 log("\n");
43 log(" -family <family>\n");
44 log(" target one of:\n");
45 log(" \"cyclonev\" - Cyclone V (default)\n");
46 log(" \"cyclone10gx\" - Cyclone 10GX\n");
47 log("\n");
48 log(" -vqm <file>\n");
49 log(" write the design to the specified Verilog Quartus Mapping File. Writing of an\n");
50 log(" output file is omitted if this parameter is not specified. Implies -quartus.\n");
51 log("\n");
52 log(" -noflatten\n");
53 log(" do not flatten design before synthesis; useful for per-module area statistics\n");
54 log("\n");
55 log(" -quartus\n");
56 log(" output a netlist using Quartus cells instead of MISTRAL_* cells\n");
57 log("\n");
58 log(" -dff\n");
59 log(" pass DFFs to ABC to perform sequential logic optimisations (EXPERIMENTAL)\n");
60 log("\n");
61 log(" -run <from_label>:<to_label>\n");
62 log(" only run the commands between the labels (see below). an empty\n");
63 log(" from label is synonymous to 'begin', and empty to label is\n");
64 log(" synonymous to the end of the command list.\n");
65 log("\n");
66 log(" -nolutram\n");
67 log(" do not use LUT RAM cells in output netlist\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(" -nodsp\n");
73 log(" do not map multipliers to MISTRAL_MUL cells\n");
74 log("\n");
75 log("The following commands are executed by this synthesis command:\n");
76 help_script();
77 log("\n");
78 }
79
80 string top_opt, family_opt, bram_type, vout_file;
81 bool flatten, quartus, nolutram, nobram, dff, nodsp;
82
83 void clear_flags() override
84 {
85 top_opt = "-auto-top";
86 family_opt = "cyclonev";
87 bram_type = "m10k";
88 vout_file = "";
89 flatten = true;
90 quartus = false;
91 nolutram = false;
92 nobram = false;
93 dff = false;
94 nodsp = false;
95 }
96
97 void execute(std::vector<std::string> args, RTLIL::Design *design) override
98 {
99 string run_from, run_to;
100 clear_flags();
101
102 size_t argidx;
103 for (argidx = 1; argidx < args.size(); argidx++) {
104 if (args[argidx] == "-family" && argidx + 1 < args.size()) {
105 family_opt = args[++argidx];
106 continue;
107 }
108 if (args[argidx] == "-top" && argidx + 1 < args.size()) {
109 top_opt = "-top " + args[++argidx];
110 continue;
111 }
112 if (args[argidx] == "-vqm" && argidx + 1 < args.size()) {
113 quartus = true;
114 vout_file = args[++argidx];
115 continue;
116 }
117 if (args[argidx] == "-run" && argidx + 1 < args.size()) {
118 size_t pos = args[argidx + 1].find(':');
119 if (pos == std::string::npos)
120 break;
121 run_from = args[++argidx].substr(0, pos);
122 run_to = args[argidx].substr(pos + 1);
123 continue;
124 }
125 if (args[argidx] == "-quartus") {
126 quartus = true;
127 continue;
128 }
129 if (args[argidx] == "-nolutram") {
130 nolutram = true;
131 continue;
132 }
133 if (args[argidx] == "-nobram") {
134 nobram = true;
135 continue;
136 }
137 if (args[argidx] == "-nodsp") {
138 nodsp = true;
139 continue;
140 }
141 if (args[argidx] == "-noflatten") {
142 flatten = false;
143 continue;
144 }
145 if (args[argidx] == "-dff") {
146 dff = true;
147 continue;
148 }
149 break;
150 }
151 extra_args(args, argidx, design);
152
153 if (!design->full_selection())
154 log_cmd_error("This command only operates on fully selected designs!\n");
155
156 if (family_opt == "cyclonev") {
157 bram_type = "m10k";
158 } else if (family_opt == "cyclone10gx") {
159 bram_type = "m20k";
160 } else {
161 log_cmd_error("Invalid family specified: '%s'\n", family_opt.c_str());
162 }
163
164 log_header(design, "Executing SYNTH_INTEL_ALM pass.\n");
165 log_push();
166
167 run_script(design, run_from, run_to);
168
169 log_pop();
170 }
171
172 void script() override
173 {
174 if (help_mode) {
175 family_opt = "<family>";
176 bram_type = "<bram_type>";
177 }
178
179 if (check_label("begin")) {
180 if (family_opt == "cyclonev")
181 run(stringf("read_verilog -sv -lib +/intel/%s/cells_sim.v", family_opt.c_str()));
182 run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/alm_sim.v", family_opt.c_str()));
183 run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/dff_sim.v", family_opt.c_str()));
184 run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/dsp_sim.v", family_opt.c_str()));
185 run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/mem_sim.v", family_opt.c_str()));
186 run(stringf("read_verilog -specify -lib -D %s -icells +/intel_alm/common/abc9_model.v", family_opt.c_str()));
187
188 // Misc and common cells
189 run("read_verilog -lib +/intel/common/altpll_bb.v");
190 run("read_verilog -lib +/intel_alm/common/megafunction_bb.v");
191 run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
192 }
193
194 if (check_label("coarse")) {
195 run("proc");
196 if (flatten || help_mode)
197 run("flatten", "(skip if -noflatten)");
198 run("tribuf -logic");
199 run("deminout");
200 run("opt_expr");
201 run("opt_clean");
202 run("check");
203 run("opt");
204 run("wreduce");
205 run("peepopt");
206 run("opt_clean");
207 run("share");
208 run("techmap -map +/cmp2lut.v -D LUT_WIDTH=6");
209 run("opt_expr");
210 run("opt_clean");
211 if (help_mode) {
212 run("techmap -map +/mul2dsp.v [...]", "(unless -nodsp)");
213 } else if (!nodsp) {
214 // Cyclone V supports 9x9 multiplication, Cyclone 10 GX does not.
215 run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=27 -D DSP_B_MAXWIDTH=27 -D DSP_A_MINWIDTH=19 -D DSP_B_MINWIDTH=19 -D DSP_SIGNEDONLY -D DSP_NAME=__MUL27X27");
216 run("chtype -set $mul t:$__soft_mul");
217 if (family_opt == "cyclonev") {
218 run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18 -D DSP_A_MINWIDTH=10 -D DSP_B_MINWIDTH=10 -D DSP_SIGNEDONLY -D DSP_NAME=__MUL18X18");
219 run("chtype -set $mul t:$__soft_mul");
220 run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=9 -D DSP_B_MAXWIDTH=9 -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=4 -D DSP_SIGNEDONLY -D DSP_NAME=__MUL9X9");
221 run("chtype -set $mul t:$__soft_mul");
222 } else if (family_opt == "cyclone10gx") {
223 run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18 -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=4 -D DSP_SIGNEDONLY -D DSP_NAME=__MUL18X18");
224 run("chtype -set $mul t:$__soft_mul");
225 }
226 }
227 run("alumacc");
228 run("techmap -map +/intel_alm/common/arith_alm_map.v -map +/intel_alm/common/dsp_map.v");
229 run("opt");
230 run("fsm");
231 run("opt -fast");
232 run("memory -nomap");
233 run("opt_clean");
234 }
235
236 if (!nobram && check_label("map_bram", "(skip if -nobram)")) {
237 run(stringf("memory_bram -rules +/intel_alm/common/bram_%s.txt", bram_type.c_str()));
238 if (help_mode || bram_type != "m10k")
239 run(stringf("techmap -map +/intel_alm/common/bram_%s_map.v", bram_type.c_str()));
240 }
241
242 if (!nolutram && check_label("map_lutram", "(skip if -nolutram)")) {
243 run("memory_bram -rules +/intel_alm/common/lutram_mlab.txt", "(for Cyclone V / Cyclone 10GX)");
244 }
245
246 if (check_label("map_ffram")) {
247 run("memory_map");
248 run("opt -full");
249 }
250
251 if (check_label("map_ffs")) {
252 run("techmap");
253 run("dff2dffe");
254 run("dfflegalize -cell $_DFFE_PN0P_ 0 -cell $_SDFFCE_PP0P_ 0");
255 run("techmap -map +/intel_alm/common/dff_map.v");
256 run("opt -full -undriven -mux_undef");
257 run("clean -purge");
258 }
259
260 if (check_label("map_luts")) {
261 run("techmap -map +/intel_alm/common/abc9_map.v");
262 run(stringf("abc9 %s -maxlut 6 -W 600", help_mode ? "[-dff]" : dff ? "-dff" : ""));
263 run("techmap -map +/intel_alm/common/abc9_unmap.v");
264 run("techmap -map +/intel_alm/common/alm_map.v");
265 run("opt -fast");
266 run("autoname");
267 run("clean");
268 }
269
270 if (check_label("check")) {
271 run("hierarchy -check");
272 run("stat");
273 run("check");
274 }
275
276 if (check_label("quartus")) {
277 if (quartus || help_mode) {
278 // Quartus ICEs if you have a wire which has `[]` in its name,
279 // which Yosys produces when building memories out of flops.
280 run("rename -hide w:*[* w:*]*");
281 // VQM mode does not support 'x, so replace those with zero.
282 run("setundef -zero");
283 // VQM mode does not support multi-bit constant assignments
284 // (e.g. 2'b00 is an error), so as a workaround use references
285 // to constant driver cells, which Quartus accepts.
286 run("hilomap -singleton -hicell __MISTRAL_VCC Q -locell __MISTRAL_GND Q");
287 // Rename from Yosys-internal MISTRAL_* cells to Quartus cells.
288 run(stringf("techmap -D %s -map +/intel_alm/common/quartus_rename.v", family_opt.c_str()));
289 }
290 }
291
292 if (check_label("vqm")) {
293 if (!vout_file.empty() || help_mode) {
294 run(stringf("write_verilog -attr2comment -defparam -nohex -decimal %s", help_mode ? "<file-name>" : vout_file.c_str()));
295 }
296 }
297 }
298 } SynthIntelALMPass;
299
300 PRIVATE_NAMESPACE_END