aboutsummaryrefslogtreecommitdiffstats
path: root/passes/pmgen/xilinx_dsp.pmg
diff options
context:
space:
mode:
Diffstat (limited to 'passes/pmgen/xilinx_dsp.pmg')
-rw-r--r--passes/pmgen/xilinx_dsp.pmg102
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