pattern xilinx_dsp state clock state > sigAset sigBset state sigC sigP sigPused state addAB match dsp select dsp->type.in(\DSP48E1) endmatch code sigAset sigBset SigSpec A = port(dsp, \A); A.remove_const(); sigAset = A.to_sigbit_set(); SigSpec B = port(dsp, \B); B.remove_const(); sigBset = B.to_sigbit_set(); endcode match ffA if param(dsp, \AREG).as_int() == 0 if !sigAset.empty() select ffA->type.in($dff) // DSP48E1 does not support clock inversion select param(ffA, \CLK_POLARITY).as_bool() filter includes(port(ffA, \Q).to_sigbit_set(), sigAset) optional endmatch code clock if (ffA) clock = port(ffA, \CLK).as_bit(); endcode match ffB if param(dsp, \BREG).as_int() == 0 if !sigBset.empty() select ffB->type.in($dff) // DSP48E1 does not support clock inversion select param(ffB, \CLK_POLARITY).as_bool() filter includes(port(ffB, \Q).to_sigbit_set(), sigBset) optional endmatch code clock if (ffB) { SigBit c = port(ffB, \CLK).as_bit(); if (clock != SigBit() && c != clock) reject; clock = c; } endcode code sigP sigP = port(dsp, \P); endcode match addA select addA->type.in($add) select param(addA, \A_SIGNED).as_bool() && param(addA, \B_SIGNED).as_bool() index nusers(port(addA, \A)) === 2 //index port(addA, \A) === sigP.extract(0, param(addA, \A_WIDTH).as_int()) filter param(addA, \A_WIDTH).as_int() <= GetSize(sigP) filter port(addA, \A) == sigP.extract(0, param(addA, \A_WIDTH).as_int()) optional endmatch match addB if !addA select addB->type.in($add, $sub) select param(addB, \A_SIGNED).as_bool() && param(addB, \B_SIGNED).as_bool() index nusers(port(addB, \B)) === 2 //index port(addB, \B) === sigP.extract(0, param(addB, \B_WIDTH).as_int()) filter param(addB, \B_WIDTH).as_int() <= GetSize(sigP) filter port(addB, \B) == sigP.extract(0, param(addB, \B_WIDTH).as_int()) optional endmatch code addAB sigC sigP if (addA) { addAB = addA; sigC = port(addAB, \B); } if (addB) { addAB = addB; sigC = port(addAB, \A); } if (addAB) { // Ensure that adder is not used SigSpec opmodeZ = port(dsp, \OPMODE).extract(4,3); if (!opmodeZ.is_fully_zero()) reject; int natural_mul_width = GetSize(port(dsp, \A)) + GetSize(port(dsp, \B)); int actual_mul_width = GetSize(sigP); int actual_acc_width = GetSize(sigC); if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width)) reject; //if ((actual_acc_width != actual_mul_width) && (param(dsp, \A_SIGNED).as_bool() != param(addAB, \A_SIGNED).as_bool())) // reject; sigP = port(addAB, \Y); } endcode // Extract the bits of P that actually have a consumer // (as opposed to being a dummy) code sigPused for (int i = 0; i < GetSize(sigP); i++) if (sigP[i].wire && nusers(sigP[i]) > 1) sigPused.append(sigP[i]); endcode match ffP if param(dsp, \PREG).as_int() == 0 if !sigPused.empty() if nusers(sigPused) == 2 select ffP->type.in($dff) // DSP48E1 does not support clock inversion select param(ffP, \CLK_POLARITY).as_bool() filter param(ffP, \WIDTH).as_int() >= GetSize(sigPused) filter includes(port(ffP, \D).to_sigbit_set(), sigPused.to_sigbit_set()) optional endmatch //// $mux cell left behind by dff2dffe //// would prefer not to run 'opt_expr -mux_undef' //// since that would lose information helpful for //// efficient wide-mux inference //match muxP // if !sigPused.empty() && !ffP // select muxP->type.in($mux) // select nusers(port(muxP, \B)) == 2 // select port(muxP, \A).is_fully_undef() // filter param(muxP, \WIDTH).as_int() >= GetSize(sigPused) // filter includes(port(muxP, \B).to_sigbit_set(), sigPused.to_sigbit_set()) // optional //endmatch // //match ffY // if muxP // select ffY->type.in($dff, $dffe) // select nusers(port(ffY, \D)) == 2 // // DSP48E1 does not support clock inversion // select param(ffY, \CLK_POLARITY).as_bool() // filter param(ffY, \WIDTH).as_int() >= GetSize(sigPused) // filter includes(port(ffY, \D).to_sigbit_set(), port(muxP, \Y).to_sigbit_set()) //endmatch code ffP clock // if (ffY) // ffP = ffY; if (ffP) { SigBit c = port(ffP, \CLK).as_bit(); if (clock != SigBit() && c != clock) reject; clock = c; } endcode