4 state <bool> clock_pol cd_signed o_lo
5 state <SigSpec> sigA sigB sigCD sigH sigO
7 state <IdString> addAB muxAB
9 state <bool> ffAcepol ffBcepol ffCDcepol ffOcepol
10 state <bool> ffArstpol ffBrstpol ffCDrstpol ffOrstpol
12 state <Cell*> ffA ffAcemux ffArstmux ffB ffBcemux ffBrstmux ffCD ffCDcemux
13 state <Cell*> ffFJKG ffH ffO ffOcemux ffOrstmux
16 state <SigSpec> argQ argD
17 state <bool> ffcepol ffrstpol
19 udata <SigSpec> dffD dffQ
20 udata <SigBit> dffclock
21 udata <Cell*> dff dffcemux dffrstmux
22 udata <bool> dffcepol dffrstpol dffclock_pol
25 select mul->type.in($mul, \SB_MAC16)
26 select GetSize(mul->getPort(\A)) + GetSize(mul->getPort(\B)) > 10
31 if (mul->type == $mul)
33 else if (mul->type == \SB_MAC16)
41 for (i = GetSize(sigA)-1; i > 0; i--)
42 if (sigA[i] != sigA[i-1])
44 // Do not remove non-const sign bit
47 sigA.remove(i, GetSize(sigA)-i);
49 for (i = GetSize(sigB)-1; i > 0; i--)
50 if (sigB[i] != sigB[i-1])
52 // Do not remove non-const sign bit
55 sigB.remove(i, GetSize(sigB)-i);
57 // Only care about those bits that are used
58 for (i = 0; i < GetSize(O); i++) {
59 if (nusers(O[i]) <= 1)
63 log_assert(nusers(O.extract_end(i)) <= 1);
66 code argQ ffA ffAcemux ffArstmux ffAcepol ffArstpol sigA clock clock_pol
67 if (mul->type != \SB_MAC16 || !param(mul, \A_REG).as_bool()) {
73 clock_pol = dffclock_pol;
75 ffArstmux = dffrstmux;
76 ffArstpol = dffrstpol;
87 code argQ ffB ffBcemux ffBrstmux ffBcepol ffBrstpol sigB clock clock_pol
88 if (mul->type != \SB_MAC16 || !param(mul, \B_REG).as_bool()) {
94 clock_pol = dffclock_pol;
96 ffBrstmux = dffrstmux;
97 ffBrstpol = dffrstpol;
108 code argD ffFJKG 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_REG1).as_bool()))) {
113 subpattern(out_dffe);
115 // F/J/K/G do not have a CE-like (hold) input
119 // Reset signal of F/J (IRSTTOP) and K/G (IRSTBOT)
120 // shared with A and B
121 if ((ffArstmux != NULL) != (dffrstmux != NULL))
123 if ((ffBrstmux != NULL) != (dffrstmux != NULL))
126 if (port(ffArstmux, \S) != port(dffrstmux, \S))
128 if (ffArstpol != dffrstpol)
132 if (port(ffBrstmux, \S) != port(dffrstmux, \S))
134 if (ffBrstpol != dffrstpol)
140 clock_pol = dffclock_pol;
150 code argD ffH sigH sigO clock clock_pol
151 if (ffFJKG && nusers(sigH) == 2 &&
152 (mul->type != \SB_MAC16 || !param(mul, \PIPELINE_16x16_MULT_REG2).as_bool())) {
154 subpattern(out_dffe);
156 // H does not have a CE-like (hold) input
160 // Reset signal of H (IRSTBOT) shared with B
161 if ((ffBrstmux != NULL) != (dffrstmux != NULL))
164 if (port(ffBrstmux, \S) != port(dffrstmux, \S))
166 if (ffBrstpol != dffrstpol)
172 clock_pol = dffclock_pol;
185 if mul->type != \SB_MAC16 || (param(mul, \TOPOUTPUT_SELECT).as_int() == 3 && param(mul, \BOTOUTPUT_SELECT).as_int() == 3)
186 select add->type.in($add)
187 choice <IdString> AB {\A, \B}
188 select nusers(port(add, AB)) == 2
189 index <SigBit> port(add, AB)[0] === sigH[0]
190 filter GetSize(port(add, AB)) <= GetSize(sigH)
191 filter port(add, AB) == sigH.extract(0, GetSize(port(add, AB)))
196 code sigCD sigO cd_signed
198 sigCD = port(add, addAB == \A ? \B : \A);
199 cd_signed = param(add, addAB == \A ? \B_SIGNED : \A_SIGNED).as_bool();
201 int natural_mul_width = GetSize(sigA) + GetSize(sigB);
202 int actual_mul_width = GetSize(sigH);
203 int actual_acc_width = GetSize(sigCD);
205 if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width))
207 // If accumulator, check adder width and signedness
208 if (sigCD == sigH && (actual_acc_width != actual_mul_width) && (param(mul, \A_SIGNED).as_bool() != param(add, \A_SIGNED).as_bool()))
211 sigO = port(add, \Y);
216 select mux->type == $mux
217 choice <IdString> AB {\A, \B}
218 index <int> nusers(port(mux, AB)) === 2
219 index <SigSpec> port(mux, AB) === sigO
226 sigO = port(mux, \Y);
229 code argD ffO ffOcemux ffOrstmux ffOcepol ffOrstpol sigO sigCD clock clock_pol cd_signed o_lo
230 if (mul->type != \SB_MAC16 ||
231 // Ensure that register is not already used
232 ((mul->parameters.at(\TOPOUTPUT_SELECT, 0).as_int() != 1 && mul->parameters.at(\BOTOUTPUT_SELECT, 0).as_int() != 1) &&
233 // Ensure that OLOADTOP/OLOADBOT is unused or zero
234 (mul->connections_.at(\OLOADTOP, State::S0).is_fully_zero() && mul->connections_.at(\OLOADBOT, State::S0).is_fully_zero()))) {
238 // First try entire sigO
239 if (nusers(sigO) == 2) {
241 subpattern(out_dffe);
244 // Otherwise try just its least significant 16 bits
245 if (!dff && GetSize(sigO) > 16) {
246 argD = sigO.extract(0, 16);
247 if (nusers(argD) == 2) {
248 subpattern(out_dffe);
256 clock_pol = dffclock_pol;
258 ffOrstmux = dffrstmux;
259 ffOrstpol = dffrstpol;
266 sigO.replace(sigO.extract(0, GetSize(dffQ)), dffQ);
269 // Loading value into output register is not
270 // supported unless using accumulator
274 sigCD = port(mux, muxAB == \B ? \A : \B);
276 cd_signed = add && param(add, \A_SIGNED).as_bool() && param(add, \B_SIGNED).as_bool();
281 code argQ ffCD ffCDcemux ffCDcepol ffCDrstpol sigCD clock clock_pol
282 if (!sigCD.empty() &&
283 (mul->type != \SB_MAC16 || (!param(mul, \C_REG).as_bool() && !param(mul, \D_REG).as_bool()))) {
288 ffCDcemux = dffcemux;
289 ffCDcepol = dffcepol;
292 // Reset signal of C (IRSTTOP) and D (IRSTBOT)
293 // shared with A and B
294 if ((ffArstmux != NULL) != (dffrstmux != NULL))
296 if ((ffBrstmux != NULL) != (dffrstmux != NULL))
299 if (port(ffArstmux, \S) != port(dffrstmux, \S))
301 if (ffArstpol != dffrstpol)
305 if (port(ffBrstmux, \S) != port(dffrstmux, \S))
307 if (ffBrstpol != dffrstpol)
313 clock_pol = dffclock_pol;
324 sigCD.extend_u0(32, cd_signed);
331 // #######################
334 arg argD argQ clock clock_pol
338 for (auto c : argQ.chunks()) {
341 if (c.wire->get_bool_attribute(\keep))
347 select ff->type.in($dff)
348 // DSP48E1 does not support clock inversion
349 select param(ff, \CLK_POLARITY).as_bool()
351 slice offset GetSize(port(ff, \D))
352 index <SigBit> port(ff, \Q)[offset] === argQ[0]
354 // Check that the rest of argQ is present
355 filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ)
356 filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
363 if (clock != SigBit()) {
364 if (port(ff, \CLK) != clock)
366 if (param(ff, \CLK_POLARITY).as_bool() != clock_pol)
370 SigSpec Q = port(ff, \Q);
372 dffclock = port(ff, \CLK);
373 dffclock_pol = param(ff, \CLK_POLARITY).as_bool();
377 dffD.replace(argQ, argD);
378 // Only search for ffrstmux if dffD only
379 // has two (ff, ffrstmux) users
380 if (nusers(dffD) > 2)
387 select ffrstmux->type.in($mux)
388 index <SigSpec> port(ffrstmux, \Y) === argD
390 choice <IdString> BA {\B, \A}
391 // DSP48E1 only supports reset to zero
392 select port(ffrstmux, BA).is_fully_zero()
394 define <bool> pol (BA == \B)
401 dffrstmux = ffrstmux;
402 dffrstpol = ffrstpol;
403 argD = port(ffrstmux, ffrstpol ? \A : \B);
404 dffD.replace(port(ffrstmux, \Y), argD);
406 // Only search for ffcemux if argQ has at
407 // least 3 users (ff, <upstream>, ffrstmux) and
408 // dffD only has two (ff, ffrstmux)
409 if (!(nusers(argQ) >= 3 && nusers(dffD) == 2))
418 select ffcemux->type.in($mux)
419 index <SigSpec> port(ffcemux, \Y) === argD
420 choice <IdString> AB {\A, \B}
421 index <SigSpec> port(ffcemux, AB) === argQ
422 define <bool> pol (AB == \A)
431 argD = port(ffcemux, ffcepol ? \B : \A);
432 dffD.replace(port(ffcemux, \Y), argD);
438 // #######################
441 arg argD argQ clock clock_pol
445 for (auto c : argD.chunks())
446 if (c.wire->get_bool_attribute(\keep))
451 select ffcemux->type.in($mux)
452 // ffcemux output must have two users: ffcemux and ff.D
453 select nusers(port(ffcemux, \Y)) == 2
455 choice <IdString> AB {\A, \B}
456 // keep-last-value net must have at least three users: ffcemux, ff, downstream sink(s)
457 select nusers(port(ffcemux, AB)) >= 3
459 slice offset GetSize(port(ffcemux, \Y))
460 define <IdString> BA (AB == \A ? \B : \A)
461 index <SigBit> port(ffcemux, BA)[offset] === argD[0]
463 // Check that the rest of argD is present
464 filter GetSize(port(ffcemux, BA)) >= offset + GetSize(argD)
465 filter port(ffcemux, BA).extract(offset, GetSize(argD)) == argD
468 define <bool> pol (BA == \B)
477 SigSpec BA = port(ffcemux, ffcepol ? \B : \A);
478 SigSpec Y = port(ffcemux, \Y);
481 argQ.replace(BA, port(ffcemux, ffcepol ? \A : \B));
489 select ffrstmux->type.in($mux)
490 // ffrstmux output must have two users: ffrstmux and ff.D
491 select nusers(port(ffrstmux, \Y)) == 2
493 choice <IdString> BA {\B, \A}
494 // DSP48E1 only supports reset to zero
495 select port(ffrstmux, BA).is_fully_zero()
497 slice offset GetSize(port(ffrstmux, \Y))
498 define <IdString> AB (BA == \B ? \A : \B)
499 index <SigBit> port(ffrstmux, AB)[offset] === argD[0]
501 // Check that offset is consistent
502 filter !ffcemux || ffoffset == offset
503 // Check that the rest of argD is present
504 filter GetSize(port(ffrstmux, AB)) >= offset + GetSize(argD)
505 filter port(ffrstmux, AB).extract(offset, GetSize(argD)) == argD
508 define <bool> pol (AB == \A)
515 dffrstmux = ffrstmux;
517 SigSpec AB = port(ffrstmux, ffrstpol ? \A : \B);
518 SigSpec Y = port(ffrstmux, \Y);
521 dffrstmux = ffrstmux;
522 dffrstpol = ffrstpol;
527 select ff->type.in($dff)
528 // DSP48E1 does not support clock inversion
529 select param(ff, \CLK_POLARITY).as_bool()
531 slice offset GetSize(port(ff, \D))
532 index <SigBit> port(ff, \D)[offset] === argD[0]
534 // Check that offset is consistent
535 filter (!ffcemux && !ffrstmux) || ffoffset == offset
536 // Check that the rest of argD is present
537 filter GetSize(port(ff, \D)) >= offset + GetSize(argD)
538 filter port(ff, \D).extract(offset, GetSize(argD)) == argD
539 // Check that FF.Q is connected to CE-mux
540 filter !ffcemux || port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
547 if (clock != SigBit()) {
548 if (port(ff, \CLK) != clock)
550 if (param(ff, \CLK_POLARITY).as_bool() != clock_pol)
553 SigSpec D = port(ff, \D);
554 SigSpec Q = port(ff, \Q);
560 for (auto c : argQ.chunks()) {
561 Const init = c.wire->attributes.at(\init, State::Sx);
562 if (!init.is_fully_undef() && !init.is_fully_zero())
568 dffclock = port(ff, \CLK);
569 dffclock_pol = param(ff, \CLK_POLARITY).as_bool();
571 // No enable/reset mux possible without flop
572 else if (dffcemux || dffrstmux)