Add _pm.h files to GENLIST, fixes vcxsrc target
[yosys.git] / passes / pmgen / xilinx_dsp48a.pmg
index 16f5e598ddfd4a3e7e9fea2f7d4ca62f10ab9983..dce1b61b005dabee7c55b9aff82b7bb528b0c4d3 100644 (file)
@@ -4,8 +4,6 @@
 // At a high level, it works as follows:
 //   ( 1) Starting from a DSP48A/DSP48A1 cell
 //   ( 2) Match the driver of the 'B' input to a possible $dff cell (B1REG)
-//        (attached to at most two $mux cells that implement clock-enable or
-//         reset functionality, using a subpattern discussed below)
 //        If B1REG matched, treat 'B' input as input of B1REG
 //   ( 3) Match the driver of the 'B' and 'D' inputs for a possible $add cell
 //       (pre-adder)
@@ -40,20 +38,15 @@ pattern xilinx_dsp48a_pack
 state <SigBit> clock
 state <SigSpec> sigA sigB sigC sigD sigM sigP
 state <IdString> postAddAB postAddMuxAB
-state <bool> ffAcepol ffBcepol ffDcepol ffMcepol ffPcepol
-state <bool> ffArstpol ffBrstpol ffDrstpol ffMrstpol ffPrstpol
-state <Cell*> ffA0 ffA0cemux ffA0rstmux ffA1 ffA1cemux ffA1rstmux
-state <Cell*> ffB0 ffB0cemux ffB0rstmux ffB1 ffB1cemux ffB1rstmux
-state <Cell*> ffD ffDcemux ffDrstmux ffM ffMcemux ffMrstmux ffP ffPcemux ffPrstmux
+state <Cell*> ffA0 ffA1
+state <Cell*> ffB0 ffB1
+state <Cell*> ffD ffM ffP
 
 // Variables used for subpatterns
 state <SigSpec> argQ argD
-state <bool> ffcepol ffrstpol
-state <int> ffoffset
 udata <SigSpec> dffD dffQ
 udata <SigBit> dffclock
-udata <Cell*> dff dffcemux dffrstmux
-udata <bool> dffcepol dffrstpol
+udata <Cell*> dff
 
 // (1) Starting from a DSP48A/DSP48A1 cell
 match dsp
@@ -98,21 +91,13 @@ endcode
 //     (attached to at most two $mux cells that implement clock-enable or
 //      reset functionality, using a subpattern discussed above)
 //     If matched, treat 'B' input as input of B1REG
-code argQ ffB1 ffB1cemux ffB1rstmux ffBcepol ffBrstpol sigB clock
+code argQ ffB1 sigB clock
        if (param(dsp, \B1REG).as_int() == 0 && param(dsp, \B0REG).as_int() == 0 && port(dsp, \OPMODE, SigSpec()).extract(4, 1).is_fully_zero()) {
                argQ = sigB;
                subpattern(in_dffe);
                if (dff) {
                        ffB1 = dff;
                        clock = dffclock;
-                       if (dffrstmux) {
-                               ffB1rstmux = dffrstmux;
-                               ffBrstpol = dffrstpol;
-                       }
-                       if (dffcemux) {
-                               ffB1cemux = dffcemux;
-                               ffBcepol = dffcepol;
-                       }
                        sigB = dffD;
                }
        }
@@ -147,41 +132,29 @@ code sigB sigD
 endcode
 
 // (4) Match 'B' input for B0REG
-code argQ ffB0 ffB0cemux ffB0rstmux ffBcepol ffBrstpol sigB clock
+code argQ ffB0 sigB clock
        if (param(dsp, \B0REG).as_int() == 0) {
                argQ = sigB;
                subpattern(in_dffe);
                if (dff) {
                        if (ffB1) {
-                               if ((ffB1rstmux != nullptr) ^ (dffrstmux != nullptr))
+                               if (dff->type != ffB1->type)
                                        goto ffB0_end;
-                               if ((ffB1cemux != nullptr) ^ (dffcemux != nullptr))
-                                       goto ffB0_end;
-                               if (dffrstmux) {
-                                       if (ffBrstpol != dffrstpol)
+                               if (dff->type.in($sdff, $sdffe, $sdffce)) {
+                                       if (param(dff, \SRST_POLARITY) != param(ffB1, \SRST_POLARITY))
                                                goto ffB0_end;
-                                       if (port(ffB1rstmux, \S) != port(dffrstmux, \S))
+                                       if (port(dff, \SRST) != port(ffB1, \SRST))
                                                goto ffB0_end;
-                                       ffB0rstmux = dffrstmux;
                                }
-                               if (dffcemux) {
-                                       if (ffBcepol != dffcepol)
+                               if (dff->type.in($dffe, $sdffe, $sdffce)) {
+                                       if (param(dff, \EN_POLARITY) != param(ffB1, \EN_POLARITY))
                                                goto ffB0_end;
-                                       if (port(ffB1cemux, \S) != port(dffcemux, \S))
+                                       if (port(dff, \EN) != port(ffB1, \EN))
                                                goto ffB0_end;
-                                       ffB0cemux = dffcemux;
                                }
                        }
                        ffB0 = dff;
                        clock = dffclock;
-                       if (dffrstmux) {
-                               ffB0rstmux = dffrstmux;
-                               ffBrstpol = dffrstpol;
-                       }
-                       if (dffcemux) {
-                               ffB0cemux = dffcemux;
-                               ffBcepol = dffcepol;
-                       }
                        sigB = dffD;
                }
        }
@@ -190,21 +163,13 @@ endcode
 
 // (5) Match 'A' input for A1REG
 //     If A1REG, then match 'A' input for A0REG
-code argQ ffA1 ffA1cemux ffA1rstmux ffAcepol ffArstpol sigA clock ffA0 ffA0cemux ffA0rstmux
+code argQ ffA1 sigA clock ffA0
        if (param(dsp, \A0REG).as_int() == 0 && param(dsp, \A1REG).as_int() == 0) {
                argQ = sigA;
                subpattern(in_dffe);
                if (dff) {
                        ffA1 = dff;
                        clock = dffclock;
-                       if (dffrstmux) {
-                               ffA1rstmux = dffrstmux;
-                               ffArstpol = dffrstpol;
-                       }
-                       if (dffcemux) {
-                               ffA1cemux = dffcemux;
-                               ffAcepol = dffcepol;
-                       }
                        sigA = dffD;
 
                        // Now attempt to match A0
@@ -212,32 +177,23 @@ code argQ ffA1 ffA1cemux ffA1rstmux ffAcepol ffArstpol sigA clock ffA0 ffA0cemux
                                argQ = sigA;
                                subpattern(in_dffe);
                                if (dff) {
-                                       if ((ffA1rstmux != nullptr) ^ (dffrstmux != nullptr))
+                                       if (dff->type != ffA1->type)
                                                goto ffA0_end;
-                                       if ((ffA1cemux != nullptr) ^ (dffcemux != nullptr))
-                                               goto ffA0_end;
-                                       if (dffrstmux) {
-                                               if (ffArstpol != dffrstpol)
+                                       if (dff->type.in($sdff, $sdffe, $sdffce)) {
+                                               if (param(dff, \SRST_POLARITY) != param(ffA1, \SRST_POLARITY))
                                                        goto ffA0_end;
-                                               if (port(ffA1rstmux, \S) != port(dffrstmux, \S))
+                                               if (port(dff, \SRST) != port(ffA1, \SRST))
                                                        goto ffA0_end;
-                                               ffA0rstmux = dffrstmux;
                                        }
-                                       if (dffcemux) {
-                                               if (ffAcepol != dffcepol)
+                                       if (dff->type.in($dffe, $sdffe, $sdffce)) {
+                                               if (param(dff, \EN_POLARITY) != param(ffA1, \EN_POLARITY))
                                                        goto ffA0_end;
-                                               if (port(ffA1cemux, \S) != port(dffcemux, \S))
+                                               if (port(dff, \EN) != port(ffA1, \EN))
                                                        goto ffA0_end;
-                                               ffA0cemux = dffcemux;
                                        }
 
                                        ffA0 = dff;
                                        clock = dffclock;
-
-                                       if (dffcemux) {
-                                               ffA0cemux = dffcemux;
-                                               ffAcepol = dffcepol;
-                                       }
                                        sigA = dffD;
 
 ffA0_end:                              ;
@@ -249,42 +205,26 @@ ffA0_end:                         ;
 endcode
 
 // (6) Match 'D' input for DREG
-code argQ ffD ffDcemux ffDrstmux ffDcepol ffDrstpol sigD clock
+code argQ ffD sigD clock
        if (param(dsp, \DREG).as_int() == 0) {
                argQ = sigD;
                subpattern(in_dffe);
                if (dff) {
                        ffD = dff;
                        clock = dffclock;
-                       if (dffrstmux) {
-                               ffDrstmux = dffrstmux;
-                               ffDrstpol = dffrstpol;
-                       }
-                       if (dffcemux) {
-                               ffDcemux = dffcemux;
-                               ffDcepol = dffcepol;
-                       }
                        sigD = dffD;
                }
        }
 endcode
 
 // (7) Match 'P' output that exclusively drives an MREG
-code argD ffM ffMcemux ffMrstmux ffMcepol ffMrstpol sigM sigP clock
+code argD ffM sigM sigP clock
        if (param(dsp, \MREG).as_int() == 0 && nusers(sigM) == 2) {
                argD = sigM;
                subpattern(out_dffe);
                if (dff) {
                        ffM = dff;
                        clock = dffclock;
-                       if (dffrstmux) {
-                               ffMrstmux = dffrstmux;
-                               ffMrstpol = dffrstpol;
-                       }
-                       if (dffcemux) {
-                               ffMcemux = dffcemux;
-                               ffMcepol = dffcepol;
-                       }
                        sigM = dffQ;
                }
        }
@@ -303,9 +243,7 @@ match postAdd
        select postAdd->type.in($add)
        select GetSize(port(postAdd, \Y)) <= 48
        choice <IdString> AB {\A, \B}
-       select nusers(port(postAdd, AB)) <= 3
-       filter ffMcemux || nusers(port(postAdd, AB)) == 2
-       filter !ffMcemux || nusers(port(postAdd, AB)) == 3
+       select nusers(port(postAdd, AB)) == 2
 
        index <SigBit> port(postAdd, AB)[0] === sigP[0]
        filter GetSize(port(postAdd, AB)) >= GetSize(sigP)
@@ -325,25 +263,14 @@ code sigC sigP
 endcode
 
 // (9) Match 'P' output that exclusively drives a PREG
-code argD ffP ffPcemux ffPrstmux ffPcepol ffPrstpol sigP clock
+code argD ffP sigP clock
        if (param(dsp, \PREG).as_int() == 0) {
-               int users = 2;
-               // If ffMcemux and no postAdd new-value net must have three users: ffMcemux, ffM and ffPcemux
-               if (ffMcemux && !postAdd) users++;
-               if (nusers(sigP) == users) {
+               if (nusers(sigP) == 2) {
                        argD = sigP;
                        subpattern(out_dffe);
                        if (dff) {
                                ffP = dff;
                                clock = dffclock;
-                               if (dffrstmux) {
-                                       ffPrstmux = dffrstmux;
-                                       ffPrstpol = dffrstpol;
-                               }
-                               if (dffcemux) {
-                                       ffPcemux = dffcemux;
-                                       ffPcepol = dffcepol;
-                               }
                                sigP = dffQ;
                        }
                }
@@ -387,26 +314,13 @@ endcode
 // #######################
 
 // Subpattern for matching against input registers, based on knowledge of the
-//   'Q' input. Typically, identifying registers with clock-enable and reset
-//   capability would be a task would be handled by other Yosys passes such as
-//   dff2dffe, but since DSP inference happens much before this, these patterns
-//   have to be manually identified.
-// At a high level:
-//   (1) Starting from a $dff cell that (partially or fully) drives the given
-//       'Q' argument
-//   (2) Match for a $mux cell implementing synchronous reset semantics ---
-//       one that exclusively drives the 'D' input of the $dff, with one of its
-//       $mux inputs being fully zero
-//   (3) Match for a $mux cell implement clock enable semantics --- one that
-//       exclusively drives the 'D' input of the $dff (or the other input of
-//       the reset $mux) and where one of this $mux's inputs is connected to
-//       the 'Q' output of the $dff
+//   'Q' input.
 subpattern in_dffe
-arg argD argQ clock
+arg argQ clock
 
 code
        dff = nullptr;
-       if (GetSize(argQ) == 0)
+       if (argQ.empty())
                reject;
        for (const auto &c : argQ.chunks()) {
                // Abandon matches when 'Q' is a constant
@@ -425,13 +339,14 @@ code
        }
 endcode
 
-// (1) Starting from a $dff cell that (partially or fully) drives the given
-//     'Q' argument
 match ff
-       select ff->type.in($dff)
+       select ff->type.in($dff, $dffe, $sdff, $sdffe)
        // DSP48E1 does not support clock inversion
        select param(ff, \CLK_POLARITY).as_bool()
 
+       // Check that reset value, if present, is fully 0.
+       filter ff->type.in($dff, $dffe) || param(ff, \SRST_VALUE).is_fully_zero()
+
        slice offset GetSize(port(ff, \D))
        index <SigBit> port(ff, \Q)[offset] === argQ[0]
 
@@ -440,82 +355,16 @@ match ff
        filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
 
        filter clock == SigBit() || port(ff, \CLK) == clock
-
-       set ffoffset offset
 endmatch
 
-code argQ argD
+code argQ
        SigSpec Q = port(ff, \Q);
        dff = ff;
        dffclock = port(ff, \CLK);
        dffD = argQ;
-       argD = port(ff, \D);
+       SigSpec D = port(ff, \D);
        argQ = Q;
-       dffD.replace(argQ, argD);
-       // Only search for ffrstmux if dffD only
-       //   has two (ff, ffrstmux) users
-       if (nusers(dffD) > 2)
-               argD = SigSpec();
-endcode
-
-// (2) Match for a $mux cell implementing synchronous reset semantics ---
-//     exclusively drives the 'D' input of the $dff, with one of the $mux
-//     inputs being fully zero
-match ffrstmux
-       if !argD.empty()
-       select ffrstmux->type.in($mux)
-       index <SigSpec> port(ffrstmux, \Y) === argD
-
-       choice <IdString> BA {\B, \A}
-       // DSP48E1 only supports reset to zero
-       select port(ffrstmux, BA).is_fully_zero()
-
-       define <bool> pol (BA == \B)
-       set ffrstpol pol
-       semioptional
-endmatch
-
-code argD
-       if (ffrstmux) {
-               dffrstmux = ffrstmux;
-               dffrstpol = ffrstpol;
-               argD = port(ffrstmux, ffrstpol ? \A : \B);
-               dffD.replace(port(ffrstmux, \Y), argD);
-
-               // Only search for ffcemux if argQ has at
-               //   least 3 users (ff, <upstream>, ffrstmux) and
-               //   dffD only has two (ff, ffrstmux)
-               if (!(nusers(argQ) >= 3 && nusers(dffD) == 2))
-                       argD = SigSpec();
-       }
-       else
-               dffrstmux = nullptr;
-endcode
-
-// (3) Match for a $mux cell implement clock enable semantics --- one that
-//     exclusively drives the 'D' input of the $dff (or the other input of
-//     the reset $mux) and where one of this $mux's inputs is connected to
-//     the 'Q' output of the $dff
-match ffcemux
-       if !argD.empty()
-       select ffcemux->type.in($mux)
-       index <SigSpec> port(ffcemux, \Y) === argD
-       choice <IdString> AB {\A, \B}
-       index <SigSpec> port(ffcemux, AB) === argQ
-       define <bool> pol (AB == \A)
-       set ffcepol pol
-       semioptional
-endmatch
-
-code argD
-       if (ffcemux) {
-               dffcemux = ffcemux;
-               dffcepol = ffcepol;
-               argD = port(ffcemux, ffcepol ? \B : \A);
-               dffD.replace(port(ffcemux, \Y), argD);
-       }
-       else
-               dffcemux = nullptr;
+       dffD.replace(argQ, D);
 endcode
 
 // #######################
@@ -543,119 +392,26 @@ code
                        reject;
 endcode
 
-// (1) Starting from an optional $mux cell that implements clock enable
-//     semantics --- one where the given 'D' argument (partially or fully)
-//     drives one of its two inputs
-match ffcemux
-       select ffcemux->type.in($mux)
-       // ffcemux output must have two users: ffcemux and ff.D
-       select nusers(port(ffcemux, \Y)) == 2
-
-       choice <IdString> AB {\A, \B}
-       // keep-last-value net must have at least three users: ffcemux, ff, downstream sink(s)
-       select nusers(port(ffcemux, AB)) >= 3
-
-       slice offset GetSize(port(ffcemux, \Y))
-       define <IdString> BA (AB == \A ? \B : \A)
-       index <SigBit> port(ffcemux, BA)[offset] === argD[0]
-
-       // Check that the rest of argD is present
-       filter GetSize(port(ffcemux, BA)) >= offset + GetSize(argD)
-       filter port(ffcemux, BA).extract(offset, GetSize(argD)) == argD
-
-       set ffoffset offset
-       define <bool> pol (AB == \A)
-       set ffcepol pol
-
-       semioptional
-endmatch
-
-code argD argQ
-       dffcemux = ffcemux;
-       if (ffcemux) {
-               SigSpec BA = port(ffcemux, ffcepol ? \B : \A);
-               SigSpec Y = port(ffcemux, \Y);
-               argQ = argD;
-               argD.replace(BA, Y);
-               argQ.replace(BA, port(ffcemux, ffcepol ? \A : \B));
-
-               dffcemux = ffcemux;
-               dffcepol = ffcepol;
-       }
-endcode
-
-// (2) Starting from, or continuing onto, another optional $mux cell that
-//     implements synchronous reset semantics --- one where the given 'D'
-//     argument (or the clock enable $mux output) drives one of its two inputs
-//     and where the other input is fully zero
-match ffrstmux
-       select ffrstmux->type.in($mux)
-       // ffrstmux output must have two users: ffrstmux and ff.D
-       select nusers(port(ffrstmux, \Y)) == 2
-
-       choice <IdString> BA {\B, \A}
-       // DSP48E1 only supports reset to zero
-       select port(ffrstmux, BA).is_fully_zero()
-
-       slice offset GetSize(port(ffrstmux, \Y))
-       define <IdString> AB (BA == \B ? \A : \B)
-       index <SigBit> port(ffrstmux, AB)[offset] === argD[0]
-
-       // Check that offset is consistent
-       filter !ffcemux || ffoffset == offset
-       // Check that the rest of argD is present
-       filter GetSize(port(ffrstmux, AB)) >= offset + GetSize(argD)
-       filter port(ffrstmux, AB).extract(offset, GetSize(argD)) == argD
-
-       set ffoffset offset
-       define <bool> pol (AB == \A)
-       set ffrstpol pol
-
-       semioptional
-endmatch
-
-code argD argQ
-       dffrstmux = ffrstmux;
-       if (ffrstmux) {
-               SigSpec AB = port(ffrstmux, ffrstpol ? \A : \B);
-               SigSpec Y = port(ffrstmux, \Y);
-               argD.replace(AB, Y);
-
-               dffrstmux = ffrstmux;
-               dffrstpol = ffrstpol;
-       }
-endcode
-
-// (3) Match for a $dff cell (whose 'D' input is the 'D' argument, or the
-//     output of the previous clock enable or reset $mux cells)
 match ff
-       select ff->type.in($dff)
+       select ff->type.in($dff, $dffe, $sdff, $sdffe)
        // DSP48E1 does not support clock inversion
        select param(ff, \CLK_POLARITY).as_bool()
 
        slice offset GetSize(port(ff, \D))
        index <SigBit> port(ff, \D)[offset] === argD[0]
 
-       // Check that offset is consistent
-       filter (!ffcemux && !ffrstmux) || ffoffset == offset
        // Check that the rest of argD is present
        filter GetSize(port(ff, \D)) >= offset + GetSize(argD)
        filter port(ff, \D).extract(offset, GetSize(argD)) == argD
-       // Check that FF.Q is connected to CE-mux
-       filter !ffcemux || port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
 
        filter clock == SigBit() || port(ff, \CLK) == clock
-
-       set ffoffset offset
 endmatch
 
 code argQ
        SigSpec D = port(ff, \D);
        SigSpec Q = port(ff, \Q);
-       if (!ffcemux) {
-               argQ = argD;
-               argQ.replace(D, Q);
-       }
+       argQ = argD;
+       argQ.replace(D, Q);
 
        // Abandon matches when 'Q' has a non-zero init attribute set
        // (not supported by DSP48E1)