1 pattern xilinx_dsp_cascadeP
3 udata <std::function<SigSpec(const SigSpec&)>> unextend
7 unextend = [](const SigSpec &sig) {
9 for (i = GetSize(sig)-1; i > 0; i--)
10 if (sig[i] != sig[i-1])
12 // Do not remove non-const sign bit
15 return sig.extract(0, i);
20 select dsp_pcin->type.in(\DSP48E1)
21 select !param(dsp_pcin, \CREG, State::S1).as_bool()
22 select port(dsp_pcin, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("011")
23 select nusers(port(dsp_pcin, \C, SigSpec())) > 1
24 select nusers(port(dsp_pcin, \PCIN, SigSpec())) == 0
28 sigC = unextend(port(dsp_pcin, \C));
32 select dsp_pcout->type.in(\DSP48E1)
33 select nusers(port(dsp_pcout, \P, SigSpec())) > 1
34 select nusers(port(dsp_pcout, \PCOUT, SigSpec())) <= 1
36 index <SigBit> port(dsp_pcout, \P)[0] === sigC[0]
37 filter GetSize(port(dsp_pcin, \P)) >= GetSize(sigC)
38 filter port(dsp_pcout, \P).extract(0, GetSize(sigC)) == sigC
43 match dsp_pcout_shift17
45 select dsp_pcout_shift17->type.in(\DSP48E1)
46 select nusers(port(dsp_pcout_shift17, \P, SigSpec())) > 1
47 select nusers(port(dsp_pcout_shift17, \PCOUT, SigSpec())) <= 1
49 index <SigBit> port(dsp_pcout_shift17, \P)[17] === sigC[0]
50 filter GetSize(port(dsp_pcout_shift17, \P)) >= GetSize(sigC)+17
51 filter port(dsp_pcout_shift17, \P).extract(17, GetSize(sigC)) == sigC
58 else if (dsp_pcout_shift17)
59 dsp = dsp_pcout_shift17;
62 dsp_pcin->setPort(ID(C), Const(0, 48));
64 Wire *cascade = module->addWire(NEW_ID, 48);
65 dsp_pcin->setPort(ID(PCIN), cascade);
66 dsp->setPort(ID(PCOUT), cascade);
67 add_siguser(cascade, dsp_pcin);
68 add_siguser(cascade, dsp);
70 SigSpec opmode = port(dsp_pcin, \OPMODE, Const(0, 7));
72 opmode[6] = State::S0;
73 else if (dsp_pcout_shift17)
74 opmode[6] = State::S1;
77 opmode[5] = State::S0;
78 opmode[4] = State::S1;
79 dsp_pcin->setPort(\OPMODE, opmode);
81 log_debug("PCOUT -> PCIN cascade for %s -> %s\n", log_id(dsp), log_id(dsp_pcin));
83 if (nusers(port(dsp_pcin, \PCOUT, SigSpec())) > 1) {
84 log_debug(" Saturated PCIN/PCOUT on %s\n", log_id(dsp_pcin));
87 if (nusers(port(dsp, \PCIN, SigSpec())) > 1) {
88 log_debug(" Saturated PCIN/PCOUT on %s\n", log_id(dsp));
98 pattern xilinx_dsp_cascadeAB
100 udata <std::function<SigSpec(const SigSpec&)>> unextend
102 state <SigSpec> sigA sigB
104 state <bool> ffA1cepol ffA2cepol ffB1cepol ffB2cepol
105 state <bool> ffArstpol ffBrstpol
107 state <Cell*> ffA1 ffA1cemux ffA1rstmux ffA2 ffA2cemux ffA2rstmux
108 state <Cell*> ffB1 ffB1cemux ffB1rstmux ffB2 ffB2cemux ffB2rstmux
111 state <SigSpec> argQ argD
112 state <bool> ffcepol ffrstpol
114 udata <SigSpec> dffD dffQ
115 udata <SigBit> dffclock
116 udata <Cell*> dff dffcemux dffrstmux
117 udata <bool> dffcepol dffrstpol
120 unextend = [](const SigSpec &sig) {
122 for (i = GetSize(sig)-1; i > 0; i--)
123 if (sig[i] != sig[i-1])
125 // Do not remove non-const sign bit
128 return sig.extract(0, i);
133 select dspD->type.in(\DSP48E1)
134 select (param(dspD, \A_INPUT, Const("DIRECT")).decode_string() == "DIRECT" && nusers(port(dspD, \A, SigSpec())) > 1 && nusers(port(dspD, \ACIN, SigSpec())) == 0) || (param(dspD, \B_INPUT, Const("DIRECT")).decode_string() == "DIRECT" && nusers(port(dspD, \B, SigSpec())) > 1 && nusers(port(dspD, \BCIN, SigSpec())) == 0)
138 if (param(dspD, \A_INPUT, Const("DIRECT")).decode_string() == "DIRECT")
139 sigA = unextend(port(dspD, \A));
140 if (param(dspD, \B_INPUT, Const("DIRECT")).decode_string() == "DIRECT")
141 sigB = unextend(port(dspD, \B));
144 code argQ ffA2 ffA2cemux ffA2rstmux ffA2cepol ffArstpol ffA1 ffA1cemux ffA1rstmux ffA1cepol sigA clock
152 ffA2rstmux = dffrstmux;
153 ffArstpol = dffrstpol;
156 ffA2cemux = dffcemux;
157 ffA2cepol = dffcepol;
161 // Now attempt to match A1
165 if ((ffA2rstmux != nullptr) ^ (dffrstmux != nullptr))
168 if (ffArstpol != dffrstpol)
170 if (port(ffA2rstmux, \S) != port(dffrstmux, \S))
172 ffA1rstmux = dffrstmux;
179 ffA1cemux = dffcemux;
180 ffA1cepol = dffcepol;
192 select dspQA2->type.in(\DSP48E1)
193 select param(dspQA2, \A_REG, 2).as_int() == 2
194 select nusers(port(dspQA2, \A, SigSpec())) > 1
195 select nusers(port(dspQA2, \ACOUT, SigSpec())) == 0
196 slice offset GetSize(port(dspQA2, \A))
197 index <SigBit> port(dspQA2, \A)[offset] === sigA[0]
198 index <SigBit> port(dspQA2, \CLK, State::S0) === port(dspD, \CLK, State::S0)
200 // Check that the rest of sigA is present
201 filter GetSize(port(dspQA2, \A)) >= offset + GetSize(sigA)
202 filter port(dspQA2, \A).extract(offset, GetSize(sigA)) == sigA
209 // Check CE and RST are compatible
210 if ((ffA1cemux != nullptr) == port(dspQA2, \CEA1, State::S1).is_fully_const())
212 if ((ffA2cemux != nullptr) == port(dspQA2, \CEA2, State::S1).is_fully_const())
214 if ((ffA1rstmux != nullptr) == port(dspQA2, \RSTA, State::S0).is_fully_const())
216 if ((ffA2rstmux != nullptr) == port(dspQA2, \RSTA, State::S0).is_fully_const())
220 if (port(dspQA2, \CEA1) != port(ffA1cemux, \S))
222 // TODO: Support inversions
227 if (port(dspQA2, \CEA2) != port(ffA2cemux, \S))
229 // TODO: Support inversions
234 if (port(dspQA2, \RSTA) != port(ffA1rstmux, \S))
236 // TODO: Support inversions
241 if (port(dspQA2, \RSTA) != port(ffA2rstmux, \S))
243 // TODO: Support inversions
253 select dspQA1->type.in(\DSP48E1)
254 select param(dspQA1, \A_REG, 2).as_int() == 1
255 select nusers(port(dspQA1, \A, SigSpec())) > 1
256 select nusers(port(dspQA1, \ACOUT, SigSpec())) == 0
257 slice offset GetSize(port(dspQA1, \A))
258 index <SigBit> port(dspQA1, \A)[offset] === sigA[0]
259 index <SigBit> port(dspQA1, \CLK, State::S0) === port(dspD, \CLK, State::S0)
261 // Check that the rest of sigA is present
262 filter GetSize(port(dspQA1, \A)) >= offset + GetSize(sigA)
263 filter port(dspQA1, \A).extract(offset, GetSize(sigA)) == sigA
270 // Check CE and RST are compatible
271 if ((ffA2cemux != NULL) == port(dspQA1, \CEA2, State::S1).is_fully_const())
273 if ((ffA2rstmux != NULL) == port(dspQA1, \RSTA, State::S0).is_fully_const())
276 if (!ffA2cepol || !ffArstpol)
280 if (port(dspQA1, \CEA2) != port(ffA2cemux, \S))
282 // TODO: Support inversions
287 if (port(dspQA1, \RSTA) != port(ffA2rstmux, \S))
289 // TODO: Support inversions
296 code argQ ffB2 ffB2cemux ffB2rstmux ffB2cepol ffBrstpol ffB1 ffB1cemux ffB1rstmux ffB1cepol sigB clock
304 ffB2rstmux = dffrstmux;
305 ffBrstpol = dffrstpol;
308 ffB2cemux = dffcemux;
309 ffB2cepol = dffcepol;
313 // Now attempt to match B1
317 if ((ffB2rstmux != nullptr) ^ (dffrstmux != nullptr))
320 if (ffBrstpol != dffrstpol)
322 if (port(ffB2rstmux, \S) != port(dffrstmux, \S))
324 ffB1rstmux = dffrstmux;
331 ffB1cemux = dffcemux;
332 ffB1cepol = dffcepol;
344 select dspQB2->type.in(\DSP48E1)
345 select param(dspQB2, \B_REG, 2).as_int() == 2
346 select nusers(port(dspQB2, \B, SigSpec())) > 1
347 select nusers(port(dspQB2, \BCOUT, SigSpec())) == 0
348 slice offset GetSize(port(dspQB2, \B))
349 index <SigBit> port(dspQB2, \B)[offset] === sigB[0]
350 index <SigBit> port(dspQB2, \CLK, State::S0) === port(dspD, \CLK, State::S0)
352 // Check that the rest of sigB is present
353 filter GetSize(port(dspQB2, \B)) >= offset + GetSize(sigB)
354 filter port(dspQB2, \B).extract(offset, GetSize(sigB)) == sigB
361 // Check CE and RST are compatible
362 if ((ffB1cemux != nullptr) == port(dspQB2, \CEB1, State::S1).is_fully_const())
364 if ((ffB2cemux != NULL) == port(dspQB2, \CEB2, State::S1).is_fully_const())
366 if ((ffB1rstmux != NULL) == port(dspQB2, \RSTB, State::S0).is_fully_const())
368 if ((ffB2rstmux != NULL) == port(dspQB2, \RSTB, State::S0).is_fully_const())
372 if (port(dspQB2, \CEB1) != port(ffB1cemux, \S))
374 // TODO: Support inversions
379 if (port(dspQB2, \CEB2) != port(ffB2cemux, \S))
381 // TODO: Support inversions
386 if (port(dspQB2, \RSTB) != port(ffB2rstmux, \S))
388 // TODO: Support inversions
398 select dspQB1->type.in(\DSP48E1)
399 select param(dspQB1, \B_REG, 2).as_int() >= 1
400 select nusers(port(dspQB1, \B, SigSpec())) > 1
401 select nusers(port(dspQB1, \BCOUT, SigSpec())) == 0
402 slice offset GetSize(port(dspQB1, \B))
403 index <SigBit> port(dspQB1, \B)[offset] === sigB[0]
404 index <SigBit> port(dspQB1, \CLK, State::S0) === port(dspD, \CLK, State::S0)
406 // Check that the rest of sigB is present
407 filter GetSize(port(dspQB1, \B)) >= offset + GetSize(sigB)
408 filter port(dspQB1, \B).extract(offset, GetSize(sigB)) == sigB
415 // Check CE and RST are compatible
416 if ((ffB2cemux != NULL) != port(dspQB1, \CEB2, State::S1).is_fully_const())
418 if ((ffB2rstmux != NULL) != port(dspQB1, \RSTB, State::S0).is_fully_const())
421 if (!ffA2cepol || !ffArstpol)
425 if (port(dspQB1, \CEB2) != port(ffB2cemux, \S))
427 // TODO: Support inversions
432 if (port(dspQB1, \RSTB) != port(ffB2rstmux, \S))
434 // TODO: Support inversions
442 if (dspQA1 || dspQA2) {
443 dspD->setParam(\A_INPUT, Const("CASCADE"));
444 dspD->setPort(\A, Const(0, 30));
446 Wire *cascade = module->addWire(NEW_ID, 30);
448 dspQA1->setParam(\ACASCREG, 1);
449 dspQA1->setPort(\ACOUT, cascade);
450 log_debug("ACOUT -> ACIN cascade for %s -> %s\n", log_id(dspQA1), log_id(dspD));
453 dspQA2->setParam(\ACASCREG, 2);
454 dspQA2->setPort(\ACOUT, cascade);
455 log_debug("ACOUT -> ACIN cascade for %s -> %s\n", log_id(dspQA2), log_id(dspD));
460 dspD->setPort(\ACIN, cascade);
461 did_something = true;
463 if (dspQB1 || dspQB2) {
464 dspD->setParam(\B_INPUT, Const("CASCADE"));
465 dspD->setPort(\B, Const(0, 18));
467 Wire *cascade = module->addWire(NEW_ID, 18);
469 dspQB1->setParam(\BCASCREG, 1);
470 dspQB1->setPort(\BCOUT, cascade);
471 log_debug("BCOUT -> BCIN cascade for %s -> %s\n", log_id(dspQB1), log_id(dspD));
474 dspQB2->setParam(\BCASCREG, 2);
475 dspQB2->setPort(\BCOUT, cascade);
476 log_debug("BCOUT -> BCIN cascade for %s -> %s\n", log_id(dspQB2), log_id(dspD));
481 dspD->setPort(\BCIN, cascade);
482 did_something = true;
489 // #######################
496 for (auto c : argQ.chunks()) {
499 if (c.wire->get_bool_attribute(\keep))
505 select ff->type.in($dff)
506 // DSP48E1 does not support clock inversion
507 select param(ff, \CLK_POLARITY).as_bool()
509 slice offset GetSize(port(ff, \D))
510 index <SigBit> port(ff, \Q)[offset] === argQ[0]
512 // Check that the rest of argQ is present
513 filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ)
514 filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
521 if (clock != SigBit() && port(ff, \CLK) != clock)
524 SigSpec Q = port(ff, \Q);
526 dffclock = port(ff, \CLK);
530 dffD.replace(argQ, argD);
531 // Only search for ffrstmux if dffD only
532 // has two (ff, ffrstmux) users
533 if (nusers(dffD) > 2)
540 select ffrstmux->type.in($mux)
541 index <SigSpec> port(ffrstmux, \Y) === argD
543 choice <IdString> BA {\B, \A}
544 // DSP48E1 only supports reset to zero
545 select port(ffrstmux, BA).is_fully_zero()
547 define <bool> pol (BA == \B)
554 dffrstmux = ffrstmux;
555 dffrstpol = ffrstpol;
556 argD = port(ffrstmux, ffrstpol ? \A : \B);
557 dffD.replace(port(ffrstmux, \Y), argD);
559 // Only search for ffcemux if argQ has at
560 // least 3 users (ff, <upstream>, ffrstmux) and
561 // dffD only has two (ff, ffrstmux)
562 if (!(nusers(argQ) >= 3 && nusers(dffD) == 2))
571 select ffcemux->type.in($mux)
572 index <SigSpec> port(ffcemux, \Y) === argD
573 choice <IdString> AB {\A, \B}
574 index <SigSpec> port(ffcemux, AB) === argQ
575 define <bool> pol (AB == \A)
584 argD = port(ffcemux, ffcepol ? \B : \A);
585 dffD.replace(port(ffcemux, \Y), argD);