diff options
Diffstat (limited to 'passes/pmgen/xilinx_dsp.pmg')
-rw-r--r-- | passes/pmgen/xilinx_dsp.pmg | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg new file mode 100644 index 000000000..7a175123e --- /dev/null +++ b/passes/pmgen/xilinx_dsp.pmg @@ -0,0 +1,102 @@ +pattern xilinx_dsp + +state <SigBit> clock +state <SigSpec> P_used + +match dsp + select dsp->type.in(\DSP48E1) +endmatch + +match ffA + select ffA->type.in($dff, $dffe) + // DSP48E1 does not support clock inversion + select param(ffA, \CLK_POLARITY).as_bool() + filter !port(dsp, \A).remove_const().empty() + filter includes(port(ffA, \Q).to_sigbit_set(), port(dsp, \A).remove_const().to_sigbit_set()) + optional +endmatch + +code clock + if (ffA) + clock = port(ffA, \CLK).as_bit(); +endcode + +match ffB + select ffB->type.in($dff, $dffe) + // DSP48E1 does not support clock inversion + select param(ffB, \CLK_POLARITY).as_bool() + filter !port(dsp, \B).remove_const().empty() + filter includes(port(ffB, \Q).to_sigbit_set(), port(dsp, \B).remove_const().to_sigbit_set()) + optional +endmatch + +code clock + if (ffB) { + SigBit c = port(ffB, \CLK).as_bit(); + + if (clock != SigBit() && c != clock) + reject; + + clock = c; + } +endcode + +// Extract the bits of P that actually have a consumer +// (as opposed to being a sign extension) +code P_used + SigSpec P = port(dsp, \P); + int i; + for (i = GetSize(P); i > 0; i--) + if (nusers(P[i-1]) > 1) + break; + P_used = P.extract(0, i).remove_const(); +endcode + +match ffP + if !P_used.empty() + select ffP->type.in($dff, $dffe) + select nusers(port(ffP, \D)) == 2 + // DSP48E1 does not support clock inversion + select param(ffP, \CLK_POLARITY).as_bool() + filter param(ffP, \WIDTH).as_int() >= GetSize(P_used) + filter includes(port(ffP, \D).to_sigbit_set(), P_used.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 !P_used.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(P_used) + filter includes(port(muxP, \B).to_sigbit_set(), P_used.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(P_used) + 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 |