Refactor ice40_dsp.pmg
[yosys.git] / passes / pmgen / ice40_dsp.pmg
1 pattern ice40_dsp
2
3 state <SigBit> clock
4 state <bool> clock_pol cd_signed o_lo
5 state <SigSpec> sigA sigB sigCD sigH sigO
6 state <Cell*> add mux
7 state <IdString> addAB muxAB
8
9 state <bool> ffAcepol ffBcepol ffCDcepol ffOcepol
10 state <bool> ffArstpol ffBrstpol ffCDrstpol ffFJKGrstpol ffOrstpol
11
12 state <Cell*> ffA ffAcemux ffArstmux ffB ffBcemux ffBrstmux ffCD ffCDcemux ffCDrstmux
13 state <Cell*> ffFJKG ffFJKGrstmux ffO ffOcemux ffOrstmux
14
15 // subpattern
16 state <SigSpec> argQ argD
17 state <bool> ffcepol ffrstpol
18 state <int> ffoffset
19 udata <SigSpec> dffD dffQ
20 udata <SigBit> dffclock
21 udata <Cell*> dff dffcemux dffrstmux
22 udata <bool> dffcepol dffrstpol dffclock_pol
23
24 match mul
25 select mul->type.in($mul, \SB_MAC16)
26 select GetSize(mul->getPort(\A)) + GetSize(mul->getPort(\B)) > 10
27 endmatch
28
29 code sigA sigB sigH
30 SigSpec O;
31 if (mul->type == $mul)
32 O = mul->getPort(\Y);
33 else if (mul->type == \SB_MAC16)
34 O = mul->getPort(\O);
35 else log_abort();
36 if (GetSize(O) <= 10)
37 reject;
38
39 sigA = port(mul, \A);
40 int i;
41 for (i = GetSize(sigA)-1; i > 0; i--)
42 if (sigA[i] != sigA[i-1])
43 break;
44 // Do not remove non-const sign bit
45 if (sigA[i].wire)
46 ++i;
47 sigA.remove(i, GetSize(sigA)-i);
48 sigB = port(mul, \B);
49 for (i = GetSize(sigB)-1; i > 0; i--)
50 if (sigB[i] != sigB[i-1])
51 break;
52 // Do not remove non-const sign bit
53 if (sigB[i].wire)
54 ++i;
55 sigB.remove(i, GetSize(sigB)-i);
56
57 // Only care about those bits that are used
58 for (i = 0; i < GetSize(O); i++) {
59 if (nusers(O[i]) <= 1)
60 break;
61 sigH.append(O[i]);
62 }
63 log_assert(nusers(O.extract_end(i)) <= 1);
64 endcode
65
66 code argQ ffA ffAcemux ffArstmux ffAcepol ffArstpol sigA clock clock_pol
67 if (mul->type != \SB_MAC16 || !param(mul, \A_REG).as_bool()) {
68 argQ = sigA;
69 subpattern(in_dffe);
70 if (dff) {
71 ffA = dff;
72 clock = dffclock;
73 clock_pol = dffclock_pol;
74 if (dffrstmux) {
75 ffArstmux = dffrstmux;
76 ffArstpol = dffrstpol;
77 }
78 if (dffcemux) {
79 ffAcemux = dffcemux;
80 ffAcepol = dffcepol;
81 }
82 sigA = dffD;
83 }
84 }
85 endcode
86
87 code argQ ffB ffBcemux ffBrstmux ffBcepol ffBrstpol sigB clock clock_pol
88 if (mul->type != \SB_MAC16 || !param(mul, \B_REG).as_bool()) {
89 argQ = sigB;
90 subpattern(in_dffe);
91 if (dff) {
92 ffB = dff;
93 clock = dffclock;
94 clock_pol = dffclock_pol;
95 if (dffrstmux) {
96 ffBrstmux = dffrstmux;
97 ffBrstpol = dffrstpol;
98 }
99 if (dffcemux) {
100 ffBcemux = dffcemux;
101 ffBcepol = dffcepol;
102 }
103 sigB = dffD;
104 }
105 }
106 endcode
107
108 code argD ffFJKG ffFJKGrstmux ffFJKGrstpol sigH sigO clock clock_pol
109 if (nusers(sigH) == 2 &&
110 (mul->type != \SB_MAC16 ||
111 (!param(mul, \TOP_8x8_MULT_REG).as_bool() && !param(mul, \BOT_8x8_MULT_REG).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG2).as_bool()))) {
112 argD = sigH;
113 subpattern(out_dffe);
114 if (dff) {
115 ffFJKG = dff;
116 clock = dffclock;
117 clock_pol = dffclock_pol;
118 if (dffrstmux) {
119 ffFJKGrstmux = dffrstmux;
120 ffFJKGrstpol = dffrstpol;
121 }
122 // F/J/K/G do not have a CE-like (hold) input
123 if (dffcemux)
124 reject;
125
126 // Reset signal of F/J (IRSTTOP) and K/G (IRSTBOT)
127 // shared with A and B
128 if ((ffArstmux != NULL) != (ffFJKGrstmux != NULL))
129 reject;
130 if ((ffBrstmux != NULL) != (ffFJKGrstmux != NULL))
131 reject;
132 if (ffArstmux) {
133 if (port(ffArstmux, \S) != port(ffFJKGrstmux, \S))
134 reject;
135 if (ffArstpol != ffFJKGrstpol)
136 reject;
137 }
138 if (ffBrstmux) {
139 if (port(ffBrstmux, \S) != port(ffFJKGrstmux, \S))
140 reject;
141 if (ffBrstpol != ffFJKGrstpol)
142 reject;
143 }
144
145 sigH = dffQ;
146 }
147 }
148
149 sigO = sigH;
150 endcode
151
152 match add
153 if mul->type != \SB_MAC16 || (param(mul, \TOPOUTPUT_SELECT).as_int() == 3 && param(mul, \BOTOUTPUT_SELECT).as_int() == 3)
154 select add->type.in($add)
155 choice <IdString> AB {\A, \B}
156 select nusers(port(add, AB)) == 2
157 index <SigBit> port(add, AB)[0] === sigH[0]
158 filter GetSize(port(add, AB)) <= GetSize(sigH)
159 filter port(add, AB) == sigH.extract(0, GetSize(port(add, AB)))
160 set addAB AB
161 optional
162 endmatch
163
164 code sigCD sigO cd_signed
165 if (add) {
166 sigCD = port(add, addAB == \A ? \B : \A);
167 cd_signed = param(add, addAB == \A ? \B_SIGNED : \A_SIGNED).as_bool();
168
169 int natural_mul_width = GetSize(sigA) + GetSize(sigB);
170 int actual_mul_width = GetSize(sigH);
171 int actual_acc_width = GetSize(sigCD);
172
173 if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width))
174 reject;
175 // If accumulator, check adder width and signedness
176 if (sigCD == sigH && (actual_acc_width != actual_mul_width) && (param(mul, \A_SIGNED).as_bool() != param(add, \A_SIGNED).as_bool()))
177 reject;
178
179 sigO = port(add, \Y);
180 }
181 endcode
182
183 match mux
184 select mux->type == $mux
185 choice <IdString> AB {\A, \B}
186 index <int> nusers(port(mux, AB)) === 2
187 index <SigSpec> port(mux, AB) === sigO
188 set muxAB AB
189 optional
190 endmatch
191
192 code sigO
193 if (mux)
194 sigO = port(mux, \Y);
195 endcode
196
197 code argD ffO ffOcemux ffOrstmux ffOcepol ffOrstpol sigO sigCD clock clock_pol cd_signed o_lo
198 if (mul->type != \SB_MAC16 ||
199 // Ensure that register is not already used
200 ((mul->parameters.at(\TOPOUTPUT_SELECT, 0).as_int() != 1 && mul->parameters.at(\BOTOUTPUT_SELECT, 0).as_int() != 1) &&
201 // Ensure that OLOADTOP/OLOADBOT is unused or zero
202 (mul->connections_.at(\OLOADTOP, State::S0).is_fully_zero() && mul->connections_.at(\OLOADBOT, State::S0).is_fully_zero()))) {
203
204 dff = nullptr;
205
206 // First try entire sigO
207 if (nusers(sigO) == 2) {
208 argD = sigO;
209 subpattern(out_dffe);
210 }
211
212 // Otherwise try just its least significant 16 bits
213 if (!dff && GetSize(sigO) > 16) {
214 argD = sigO.extract(0, 16);
215 if (nusers(argD) == 2) {
216 subpattern(out_dffe);
217 o_lo = dff;
218 }
219 }
220
221 if (dff) {
222 ffO = dff;
223 clock = dffclock;
224 clock_pol = dffclock_pol;
225 if (dffrstmux) {
226 ffOrstmux = dffrstmux;
227 ffOrstpol = dffrstpol;
228 }
229 if (dffcemux) {
230 ffOcemux = dffcemux;
231 ffOcepol = dffcepol;
232 }
233
234 sigO.replace(sigO.extract(0, GetSize(dffQ)), dffQ);
235 }
236
237 // Loading value into output register is not
238 // supported unless using accumulator
239 if (mux) {
240 if (sigCD != sigO)
241 reject;
242 sigCD = port(mux, muxAB == \B ? \A : \B);
243
244 cd_signed = add && param(add, \A_SIGNED).as_bool() && param(add, \B_SIGNED).as_bool();
245 }
246 }
247 sigCD.extend_u0(32, cd_signed);
248 endcode
249
250 code
251 accept;
252 endcode
253
254 // #######################
255
256 subpattern in_dffe
257 arg argD argQ clock clock_pol
258
259 code
260 dff = nullptr;
261 for (auto c : argQ.chunks()) {
262 if (!c.wire)
263 reject;
264 if (c.wire->get_bool_attribute(\keep))
265 reject;
266 }
267 endcode
268
269 match ff
270 select ff->type.in($dff)
271 // DSP48E1 does not support clock inversion
272 select param(ff, \CLK_POLARITY).as_bool()
273
274 slice offset GetSize(port(ff, \D))
275 index <SigBit> port(ff, \Q)[offset] === argQ[0]
276
277 // Check that the rest of argQ is present
278 filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ)
279 filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
280
281 set ffoffset offset
282 endmatch
283
284 code argQ argD
285 {
286 if (clock != SigBit()) {
287 if (port(ff, \CLK) != clock)
288 reject;
289 if (param(ff, \CLK_POLARITY).as_bool() != clock_pol)
290 reject;
291 }
292
293 SigSpec Q = port(ff, \Q);
294 dff = ff;
295 dffclock = port(ff, \CLK);
296 dffclock_pol = param(ff, \CLK_POLARITY).as_bool();
297 dffD = argQ;
298 argD = port(ff, \D);
299 argQ = Q;
300 dffD.replace(argQ, argD);
301 // Only search for ffrstmux if dffD only
302 // has two (ff, ffrstmux) users
303 if (nusers(dffD) > 2)
304 argD = SigSpec();
305 }
306 endcode
307
308 match ffrstmux
309 if !argD.empty()
310 select ffrstmux->type.in($mux)
311 index <SigSpec> port(ffrstmux, \Y) === argD
312
313 choice <IdString> BA {\B, \A}
314 // DSP48E1 only supports reset to zero
315 select port(ffrstmux, BA).is_fully_zero()
316
317 define <bool> pol (BA == \B)
318 set ffrstpol pol
319 semioptional
320 endmatch
321
322 code argD
323 if (ffrstmux) {
324 dffrstmux = ffrstmux;
325 dffrstpol = ffrstpol;
326 argD = port(ffrstmux, ffrstpol ? \A : \B);
327 dffD.replace(port(ffrstmux, \Y), argD);
328
329 // Only search for ffcemux if argQ has at
330 // least 3 users (ff, <upstream>, ffrstmux) and
331 // dffD only has two (ff, ffrstmux)
332 if (!(nusers(argQ) >= 3 && nusers(dffD) == 2))
333 argD = SigSpec();
334 }
335 else
336 dffrstmux = nullptr;
337 endcode
338
339 match ffcemux
340 if !argD.empty()
341 select ffcemux->type.in($mux)
342 index <SigSpec> port(ffcemux, \Y) === argD
343 choice <IdString> AB {\A, \B}
344 index <SigSpec> port(ffcemux, AB) === argQ
345 define <bool> pol (AB == \A)
346 set ffcepol pol
347 semioptional
348 endmatch
349
350 code argD
351 if (ffcemux) {
352 dffcemux = ffcemux;
353 dffcepol = ffcepol;
354 argD = port(ffcemux, ffcepol ? \B : \A);
355 dffD.replace(port(ffcemux, \Y), argD);
356 }
357 else
358 dffcemux = nullptr;
359 endcode
360
361 // #######################
362
363 subpattern out_dffe
364 arg argD argQ clock clock_pol
365
366 code
367 dff = nullptr;
368 endcode
369
370 match ffcemux
371 select ffcemux->type.in($mux)
372 // ffcemux output must have two users: ffcemux and ff.D
373 select nusers(port(ffcemux, \Y)) == 2
374
375 choice <IdString> AB {\A, \B}
376 // keep-last-value net must have at least three users: ffcemux, ff, downstream sink(s)
377 select nusers(port(ffcemux, AB)) >= 3
378
379 slice offset GetSize(port(ffcemux, \Y))
380 define <IdString> BA (AB == \A ? \B : \A)
381 index <SigBit> port(ffcemux, BA)[offset] === argD[0]
382
383 // Check that the rest of argD is present
384 filter GetSize(BA) >= offset + GetSize(argD)
385 filter port(ffcemux, BA).extract(offset, GetSize(argD)) == argD
386
387 set ffoffset offset
388 define <bool> pol (BA == \B)
389 set ffcepol pol
390
391 semioptional
392 endmatch
393
394 code argD argQ
395 dffcemux = ffcemux;
396 if (ffcemux) {
397 SigSpec BA = port(ffcemux, ffcepol ? \B : \A);
398 if (ffoffset + GetSize(argD) > GetSize(BA))
399 reject;
400 for (int i = 1; i < GetSize(argD); i++)
401 if (BA[ffoffset+i] != argD[i])
402 reject;
403
404 SigSpec Y = port(ffcemux, \Y);
405 argQ = argD;
406 argD.replace(BA, Y);
407 argQ.replace(BA, port(ffcemux, ffcepol ? \A : \B));
408
409 dffcemux = ffcemux;
410 dffcepol = ffcepol;
411 }
412 endcode
413
414 match ffrstmux
415 select ffrstmux->type.in($mux)
416 // ffrstmux output must have two users: ffrstmux and ff.D
417 select nusers(port(ffrstmux, \Y)) == 2
418
419 choice <IdString> BA {\B, \A}
420 // DSP48E1 only supports reset to zero
421 select port(ffrstmux, BA).is_fully_zero()
422
423 slice offset GetSize(port(ffrstmux, \Y))
424 define <IdString> AB (BA == \B ? \A : \B)
425 index <SigBit> port(ffrstmux, AB)[offset] === argD[0]
426
427 // Check that offset is consistent
428 filter !ffcemux || ffoffset == offset
429 // Check that the rest of argD is present
430 filter GetSize(AB) >= offset + GetSize(argD)
431 filter port(ffrstmux, AB).extract(offset, GetSize(argD)) == argD
432
433 set ffoffset offset
434 define <bool> pol (AB == \A)
435 set ffrstpol pol
436
437 semioptional
438 endmatch
439
440 code argD argQ
441 dffrstmux = ffrstmux;
442 if (ffrstmux) {
443 SigSpec AB = port(ffrstmux, ffrstpol ? \A : \B);
444 SigSpec Y = port(ffrstmux, \Y);
445 argD.replace(AB, Y);
446
447 dffrstmux = ffrstmux;
448 dffrstpol = ffrstpol;
449 }
450 endcode
451
452 match ff
453 select ff->type.in($dff)
454 // DSP48E1 does not support clock inversion
455 select param(ff, \CLK_POLARITY).as_bool()
456
457 slice offset GetSize(port(ff, \D))
458 index <SigBit> port(ff, \D)[offset] === argD[0]
459
460 // Check that offset is consistent
461 filter (!ffcemux && !ffrstmux) || ffoffset == offset
462 // Check that the rest of argD is present
463 filter GetSize(port(ff, \D)) >= offset + GetSize(argD)
464 filter port(ff, \D).extract(offset, GetSize(argD)) == argD
465 // Check that FF.Q is connected to CE-mux
466 filter !ffcemux || port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
467
468 set ffoffset offset
469
470 semioptional
471 endmatch
472
473 code argQ
474 if (ff) {
475 if (clock != SigBit()) {
476 if (port(ff, \CLK) != clock)
477 reject;
478 if (param(ff, \CLK_POLARITY).as_bool() != clock_pol)
479 reject;
480 }
481
482 SigSpec D = port(ff, \D);
483 SigSpec Q = port(ff, \Q);
484 if (!ffcemux) {
485 argQ = argD;
486 argQ.replace(D, Q);
487 }
488
489 for (auto c : argQ.chunks()) {
490 if (c.wire->get_bool_attribute(\keep))
491 reject;
492 Const init = c.wire->attributes.at(\init, State::Sx);
493 if (!init.is_fully_undef() && !init.is_fully_zero())
494 reject;
495 }
496
497 dff = ff;
498 dffQ = argQ;
499 dffclock = port(ff, \CLK);
500 dffclock_pol = param(ff, \CLK_POLARITY).as_bool();
501 }
502 // No enable/reset mux possible without flop
503 else if (dffcemux || dffrstmux)
504 reject;
505 endcode