Pack CREG
authorEddie Hung <eddie@fpgeh.com>
Sat, 7 Sep 2019 04:01:36 +0000 (21:01 -0700)
committerEddie Hung <eddie@fpgeh.com>
Sat, 7 Sep 2019 04:01:36 +0000 (21:01 -0700)
passes/pmgen/xilinx_dsp.cc
passes/pmgen/xilinx_dsp.pmg

index ba8a1de05396cb511e40d110609eb25163bcc79b..10308de57275e7ca3b6e8a8b2c2cf1d3a2f1ea7d 100644 (file)
@@ -38,6 +38,8 @@ void pack_xilinx_dsp(dict<SigBit, Cell*> &bit_to_driver, xilinx_dsp_pm &pm)
        log("ffAmux:     %s\n", log_id(st.ffAmux, "--"));
        log("ffB:        %s\n", log_id(st.ffB, "--"));
        log("ffBmux:     %s\n", log_id(st.ffBmux, "--"));
+       log("ffC:        %s\n", log_id(st.ffC, "--"));
+       log("ffCmux:     %s\n", log_id(st.ffCmux, "--"));
        log("ffD:        %s\n", log_id(st.ffD, "--"));
        log("ffDmux:     %s\n", log_id(st.ffDmux, "--"));
        log("dsp:        %s\n", log_id(st.dsp, "--"));
@@ -53,7 +55,6 @@ void pack_xilinx_dsp(dict<SigBit, Cell*> &bit_to_driver, xilinx_dsp_pm &pm)
 
        Cell *cell = st.dsp;
        bit_to_driver.insert(std::make_pair(cell->getPort("\\P")[17], cell));
-       SigSpec C = st.sigC;
        SigSpec P = st.sigP;
 
        if (st.preAdd) {
@@ -91,15 +92,21 @@ void pack_xilinx_dsp(dict<SigBit, Cell*> &bit_to_driver, xilinx_dsp_pm &pm)
                        opmode[4] = st.postAddMux->getPort("\\S");
                        pm.autoremove(st.postAddMux);
                }
-               else if (st.ffP && C == P) {
-                       C = SigSpec();
+               else if (st.ffP && st.sigC == P)
                        opmode[4] = State::S0;
-               }
                else
                        opmode[4] = State::S1;
                opmode[6] = State::S0;
                opmode[5] = State::S1;
 
+               if (opmode[4] != State::S0) {
+                       if (st.postAddMuxAB == "\\A")
+                               st.sigC.extend_u0(48, st.postAdd->getParam("\\B_SIGNED").as_bool());
+                       else
+                               st.sigC.extend_u0(48, st.postAdd->getParam("\\A_SIGNED").as_bool());
+                       cell->setPort("\\C", st.sigC);
+               }
+
                pm.autoremove(st.postAdd);
        }
 
@@ -143,10 +150,30 @@ void pack_xilinx_dsp(dict<SigBit, Cell*> &bit_to_driver, xilinx_dsp_pm &pm)
 
                        cell->setParam("\\BREG", 1);
                }
+               if (st.ffC) {
+                       SigSpec C = cell->getPort("\\C");
+                       SigSpec D = st.ffC->getPort("\\D");
+                       SigSpec Q = st.ffC->getPort("\\Q");
+                       C.replace(Q, D);
+
+                       if (st.ffCmux) {
+                               SigSpec Y = st.ffCmux->getPort("\\Y");
+                               SigSpec AB = st.ffCmux->getPort(st.ffCenpol ? "\\B" : "\\A");
+                               SigSpec S = st.ffCmux->getPort("\\S");
+                               C.replace(Y, AB);
+
+                               cell->setPort("\\CEC", st.ffCenpol ? S : pm.module->Not(NEW_ID, S));
+                       }
+                       else
+                               cell->setPort("\\CEC", State::S1);
+                       cell->setPort("\\C", C);
+
+                       cell->setParam("\\CREG", 1);
+               }
                if (st.ffD) {
                        SigSpec D_ = cell->getPort("\\D");
-                       SigSpec D = st.ffB->getPort("\\D");
-                       SigSpec Q = st.ffB->getPort("\\Q");
+                       SigSpec D = st.ffD->getPort("\\D");
+                       SigSpec Q = st.ffD->getPort("\\Q");
                        D_.replace(Q, D);
 
                        if (st.ffDmux) {
@@ -205,6 +232,12 @@ void pack_xilinx_dsp(dict<SigBit, Cell*> &bit_to_driver, xilinx_dsp_pm &pm)
                if (st.ffB)
                        log(" ffB:%s", log_id(st.ffB));
 
+               if (st.ffC)
+                       log(" ffC:%s", log_id(st.ffC));
+
+               if (st.ffD)
+                       log(" ffD:%s", log_id(st.ffD));
+
                if (st.ffM)
                        log(" ffM:%s", log_id(st.ffM));
 
@@ -214,12 +247,6 @@ void pack_xilinx_dsp(dict<SigBit, Cell*> &bit_to_driver, xilinx_dsp_pm &pm)
                log("\n");
        }
 
-       if (!C.empty()) {
-               if (GetSize(C) < 48)
-                       C.extend_u0(48, true);
-               cell->setPort("\\C", C);
-       }
-
        if (GetSize(P) < 48)
                P.append(pm.module->addWire(NEW_ID, 48-GetSize(P)));
        cell->setPort("\\P", P);
@@ -265,6 +292,8 @@ struct XilinxDspPass : public Pass {
                        for (auto cell : module->cells()) {
                                if (cell->type != "\\DSP48E1")
                                        continue;
+                               if (cell->parameters.at("\\CREG", State::S1).as_bool())
+                                       continue;
                                SigSpec &opmode = cell->connections_.at("\\OPMODE");
                                if (opmode.extract(4,3) != Const::from_string("011"))
                                        continue;
index 3aab807bd6be36cd10cce4992e3b40b9d42c0079..6b981bc137e49c2a646413f40508ef3d5ac74a9b 100644 (file)
@@ -1,29 +1,29 @@
 pattern xilinx_dsp
 
-state <std::function<SigSpec(const SigSpec&, bool)>> unextend
+state <std::function<SigSpec(const SigSpec&)>> unextend
 state <SigBit> clock
-state <SigSpec> sigA sigffAmuxY sigB sigffBmuxY sigC sigD sigffDmuxY sigM sigP
+state <SigSpec> sigA sigffAmuxY sigB sigffBmuxY sigC sigffCmuxY sigD sigffDmuxY sigM sigP
 state <IdString> postAddAB postAddMuxAB
-state <bool> ffAenpol ffADenpol ffBenpol ffDenpol ffMenpol ffPenpol
+state <bool> ffAenpol ffADenpol ffBenpol ffCenpol ffDenpol ffMenpol ffPenpol
 state <int> ffPoffset
 
 match dsp
        select dsp->type.in(\DSP48E1)
 endmatch
 
-code unextend sigA sigffAmuxY sigB sigffBmuxY sigC sigD sigffDmuxY sigM
-       unextend = [](const SigSpec &sig, bool keep_sign) {
+code unextend sigA sigffAmuxY sigB sigffBmuxY sigC sigffCmuxY sigD sigffDmuxY sigM
+       unextend = [](const SigSpec &sig) {
                int i;
                for (i = GetSize(sig)-1; i > 0; i--)
                        if (sig[i] != sig[i-1])
                                break;
                // Do not remove non-const sign bit
-               if (!keep_sign && sig[i].wire)
+               if (sig[i].wire)
                        ++i;
                return sig.extract(0, i);
        };
-       sigA = unextend(port(dsp, \A), false);
-       sigB = unextend(port(dsp, \B), false);
+       sigA = unextend(port(dsp, \A));
+       sigB = unextend(port(dsp, \B));
 
        sigC = dsp->connections_.at(\C, SigSpec());
        sigD = dsp->connections_.at(\D, SigSpec());
@@ -42,6 +42,7 @@ code unextend sigA sigffAmuxY sigB sigffBmuxY sigC sigD sigffDmuxY sigM
 
        sigffAmuxY = SigSpec();
        sigffBmuxY = SigSpec();
+       sigffCmuxY = SigSpec();
        sigffDmuxY = SigSpec();
 endcode
 
@@ -260,9 +261,9 @@ code sigD sigffDmuxY clock
 
                SigSpec D = sigD;
                D.replace(port(ffD, \Q), port(ffD, \D));
-               // Only search for ffBmux if ffB.Q has at
-               //   least 3 users (ffB, dsp, ffBmux) and
-               //   its ffB.D only has two (ffB, ffBmux)
+               // Only search for ffDmux if ffD.Q has at
+               //   least 3 users (ffD, dsp, ffDmux) and
+               //   its ffD.D only has two (ffD, ffDmux)
                if (nusers(sigD) >= 3 && nusers(D) == 2)
                        sigffDmuxY = sigD;
                sigD = std::move(D);
@@ -276,7 +277,7 @@ match ffDmux
        filter GetSize(port(ffDmux, \Y)) >= GetSize(sigD)
        slice offset GetSize(port(ffDmux, \Y))
        filter offset+GetSize(sigD) <= GetSize(port(ffDmux, \Y))
-       filter port(ffDmux, \Y).extract(offset, GetSize(sigB)) == sigD
+       filter port(ffDmux, \Y).extract(offset, GetSize(sigD)) == sigD
        choice <IdString> AB {\A, \B}
        filter offset+GetSize(sigffDmuxY) <= GetSize(port(ffDmux, \Y))
        filter port(ffDmux, AB).extract(offset, GetSize(sigffDmuxY)) == sigffDmuxY
@@ -290,17 +291,17 @@ match ffMmux
        if nusers(sigM) == 2
        select ffMmux->type.in($mux)
        choice <IdString> BA {\B, \A}
-       // new-value net must have exactly two users: dsp and ffM
+       // new-value net must have exactly two users: dsp and ffMmux
        select nusers(port(ffMmux, BA)) == 2
        define <IdString> AB (BA == \B ? \A : \B)
        // keep-last-value net must have at least three users: ffMmux, ffM, downstream sink(s)
        select nusers(port(ffMmux, AB)) >= 3
        // ffMmux output must have two users: ffMmux and ffM.D
        select nusers(port(ffMmux, \Y)) == 2
-       filter GetSize(port(ffMmux, \Y)) <= GetSize(sigM)
-       filter port(ffMmux, BA) == sigM.extract(0, GetSize(port(ffMmux, \Y)))
+       filter GetSize(unextend(port(ffMmux, BA))) <= GetSize(sigM)
+       filter unextend(port(ffMmux, BA)) == sigM.extract(0, GetSize(unextend(port(ffMmux, BA))))
        // Remaining bits on sigM must not have any other users
-       filter nusers(sigM.extract_end(GetSize(port(ffMmux, BA)))) <= 1
+       filter nusers(sigM.extract_end(GetSize(unextend(port(ffMmux, BA))))) <= 1
        define <bool> pol (AB == \A)
        set ffMenpol pol
        optional
@@ -367,9 +368,9 @@ match postAdd
        select nusers(port(postAdd, AB)) <= 3
        filter ffMmux || nusers(port(postAdd, AB)) == 2
        filter !ffMmux || nusers(port(postAdd, AB)) == 3
-       filter GetSize(port(postAdd, AB)) <= GetSize(sigP)
-       filter port(postAdd, AB) == sigP.extract(0, GetSize(port(postAdd, AB)))
-       filter nusers(sigP.extract_end(GetSize(port(postAdd, AB)))) <= 1
+       filter GetSize(unextend(port(postAdd, AB))) <= GetSize(sigP)
+       filter unextend(port(postAdd, AB)) == sigP.extract(0, GetSize(unextend(port(postAdd, AB))))
+       filter nusers(sigP.extract_end(GetSize(unextend(port(postAdd, AB))))) <= 1
        set postAddAB AB
        optional
 endmatch
@@ -495,6 +496,56 @@ code sigC
                sigC = port(postAddMux, postAddMuxAB == \A ? \B : \A);
 endcode
 
+match ffC
+       if param(dsp, \CREG).as_int() == 0
+       select ffC->type.in($dff)
+       // DSP48E1 does not support clock inversion
+       select param(ffC, \CLK_POLARITY).as_bool()
+       filter GetSize(port(ffC, \Q)) >= GetSize(sigD)
+       slice offset GetSize(port(ffC, \Q))
+       filter offset+GetSize(sigC) <= GetSize(port(ffC, \Q))
+       filter port(ffC, \Q).extract(offset, GetSize(sigC)) == sigC
+       optional
+endmatch
+
+code sigC sigffCmuxY clock
+       if (ffC) {
+               for (auto b : port(ffC, \Q))
+                       if (b.wire->get_bool_attribute(\keep))
+                               reject;
+
+               SigBit c = port(ffC, \CLK).as_bit();
+               if (clock != SigBit() && c != clock)
+                       reject;
+               clock = c;
+
+               SigSpec C = sigC;
+               C.replace(port(ffC, \Q), port(ffC, \D));
+               // Only search for ffCmux if ffC.Q has at
+               //   least 3 users (ffC, dsp, ffCmux) and
+               //   its ffC.D only has two (ffC, ffCmux)
+               if (nusers(sigC) >= 3 && nusers(C) == 2)
+                       sigffCmuxY = sigC;
+               sigC = std::move(C);
+       }
+endcode
+
+match ffCmux
+       if !sigffCmuxY.empty()
+       select ffCmux->type.in($mux)
+       index <SigSpec> port(ffCmux, \Y) === port(ffC, \D)
+       filter GetSize(port(ffCmux, \Y)) >= GetSize(sigC)
+       slice offset GetSize(port(ffCmux, \Y))
+       filter offset+GetSize(sigC) <= GetSize(port(ffCmux, \Y))
+       filter port(ffCmux, \Y).extract(offset, GetSize(sigC)) == sigC
+       choice <IdString> AB {\A, \B}
+       filter offset+GetSize(sigffCmuxY) <= GetSize(port(ffCmux, \Y))
+       filter port(ffCmux, AB).extract(offset, GetSize(sigffCmuxY)) == sigffCmuxY
+       define <bool> pol (AB == \A)
+       set ffCenpol pol
+       optional
+endmatch
+
 code
        accept;
 endcode