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