Add support for pre-adder and AD register
authorEddie Hung <eddie@fpgeh.com>
Fri, 6 Sep 2019 21:06:57 +0000 (14:06 -0700)
committerEddie Hung <eddie@fpgeh.com>
Fri, 6 Sep 2019 21:06:57 +0000 (14:06 -0700)
passes/pmgen/xilinx_dsp.cc
passes/pmgen/xilinx_dsp.pmg

index 38b1a12be642788713dc4d4121ead1cb94f5d298..9587ed28af6f92f3756f854bceed0000b28a1d3f 100644 (file)
@@ -31,6 +31,9 @@ void pack_xilinx_dsp(dict<SigBit, Cell*> &bit_to_driver, xilinx_dsp_pm &pm)
 
 #if 1
        log("\n");
+       log("preAdd:     %s\n", log_id(st.preAdd, "--"));
+       log("ffAD:       %s\n", log_id(st.ffAD, "--"));
+       log("ffADmux:    %s\n", log_id(st.ffADmux, "--"));
        log("ffA:        %s\n", log_id(st.ffA, "--"));
        log("ffAmux:     %s\n", log_id(st.ffAmux, "--"));
        log("ffB:        %s\n", log_id(st.ffB, "--"));
@@ -51,8 +54,34 @@ void pack_xilinx_dsp(dict<SigBit, Cell*> &bit_to_driver, xilinx_dsp_pm &pm)
        SigSpec C = st.sigC;
        SigSpec P = st.sigP;
 
+       if (st.preAdd) {
+               log("  preadder %s (%s)\n", log_id(st.preAdd), log_id(st.preAdd->type));
+               bool A_SIGNED = st.preAdd->getParam("\\A_SIGNED").as_bool();
+               bool D_SIGNED = st.preAdd->getParam("\\B_SIGNED").as_bool();
+               if (st.sigA == st.preAdd->getPort("\\B"))
+                       std::swap(A_SIGNED, D_SIGNED);
+               st.sigA.extend_u0(30, A_SIGNED);
+               st.sigD.extend_u0(25, D_SIGNED);
+               cell->setPort("\\A", st.sigA);
+               cell->setPort("\\D", st.sigD);
+               cell->connections_.at("\\INMODE") = Const::from_string("00100");
+
+               if (st.ffAD) {
+                       if (st.ffADmux) {
+                               SigSpec S = st.ffADmux->getPort("\\S");
+                               cell->setPort("\\CEAD", st.ffADenpol ? S : pm.module->Not(NEW_ID, S));
+                       }
+                       else
+                               cell->setPort("\\CEAD", State::S1);
+                       cell->setParam("\\ADREG", 1);
+               }
+
+               cell->setParam("\\USE_DPORT", Const("TRUE"));
+
+               pm.autoremove(st.preAdd);
+       }
        if (st.postAdd) {
-               log("  adder %s (%s)\n", log_id(st.postAdd), log_id(st.postAdd->type));
+               log("  postadder %s (%s)\n", log_id(st.postAdd), log_id(st.postAdd->type));
 
                SigSpec &opmode = cell->connections_.at("\\OPMODE");
                if (st.postAddMux) {
index 5cea69b16c412cf20ce9443fd40f27b1e170b26d..83963804b546d24c022bdac00ed2fd99e9f8ac6c 100644 (file)
@@ -1,16 +1,16 @@
 pattern xilinx_dsp
 
 state <SigBit> clock
-state <SigSpec> sigA sigffAmuxY sigB sigffBmuxY sigC sigM sigP
+state <SigSpec> sigA sigffAmuxY sigB sigffBmuxY sigC sigD sigM sigP
 state <IdString> postAddAB postAddMuxAB
-state <bool> ffAenpol ffBenpol ffMenpol ffPenpol
+state <bool> ffAenpol ffADenpol ffBenpol ffMenpol ffPenpol
 state <int> ffPoffset
 
 match dsp
        select dsp->type.in(\DSP48E1)
 endmatch
 
-code sigA sigffAmuxY sigB sigffBmuxY sigM
+code sigA sigffAmuxY sigB sigffBmuxY sigD sigM
        sigA = port(dsp, \A);
        int i;
        for (i = GetSize(sigA)-1; i > 0; i--)
@@ -29,6 +29,8 @@ code sigA sigffAmuxY sigB sigffBmuxY sigM
                ++i;
        sigB.remove(i, GetSize(sigB)-i);
 
+       sigD = dsp->connections_.at(\D, SigSpec());
+
        SigSpec P = port(dsp, \P);
        // Only care about those bits that are used
        for (i = 0; i < GetSize(P); i++) {
@@ -44,7 +46,85 @@ code sigA sigffAmuxY sigB sigffBmuxY sigM
        sigffBmuxY = SigSpec();
 endcode
 
+match ffAD
+       if param(dsp, \ADREG).as_int() == 0
+       select ffAD->type.in($dff)
+       // DSP48E1 does not support clock inversion
+       select param(ffAD, \CLK_POLARITY).as_bool()
+       filter GetSize(port(ffAD, \Q)) >= GetSize(sigA)
+       slice offset GetSize(port(ffAD, \Q))
+       filter offset+GetSize(sigA) <= GetSize(port(ffAD, \Q))
+       filter port(ffAD, \Q).extract(offset, GetSize(sigA)) == sigA
+       optional
+endmatch
+
+code sigA sigffAmuxY clock
+       if (ffAD) {
+               for (auto b : port(ffAD, \Q))
+                       if (b.wire->get_bool_attribute(\keep))
+                               reject;
+
+               clock = port(ffAD, \CLK).as_bit();
+
+               SigSpec A = sigA;
+               A.replace(port(ffAD, \Q), port(ffAD, \D));
+               // Only search for ffAmux if ffA.Q has at
+               //   least 3 users (ffA, dsp, ffAmux) and
+               //   its ffA.D only has two (ffA, ffAmux)
+               if (nusers(sigA) >= 3 && nusers(A) == 2)
+                       sigffAmuxY = sigA;
+               sigA = std::move(A);
+       }
+endcode
+
+match ffADmux
+       if !sigffAmuxY.empty()
+       select ffADmux->type.in($mux)
+       index <SigSpec> port(ffADmux, \Y) === port(ffAD, \D)
+       filter GetSize(port(ffADmux, \Y)) >= GetSize(sigA)
+       slice offset GetSize(port(ffADmux, \Y))
+       filter offset+GetSize(sigA) <= GetSize(port(ffADmux, \Y))
+       filter port(ffADmux, \Y).extract(offset, GetSize(sigA)) == sigA
+       choice <IdString> BA {\B, \A}
+       filter offset+GetSize(sigffAmuxY) <= GetSize(port(ffADmux, \Y))
+       filter port(ffADmux, BA).extract(offset, GetSize(sigffAmuxY)) == sigffAmuxY
+       define <bool> pol (BA == \B)
+       set ffADenpol pol
+       optional
+endmatch
+
+match preAdd
+       if sigD.empty() || sigD.is_fully_zero()
+       // Ensure that preAdder not already used
+       if dsp->parameters.at(\USE_DPORT, Const("FALSE")).decode_string() == "FALSE"
+       if dsp->connections_.at(\INMODE, Const(0, 5)).is_fully_zero()
+
+       select preAdd->type.in($add)
+       // Output has to be 25 bits or less
+       select GetSize(port(preAdd, \Y)) <= 25
+       select nusers(port(preAdd, \Y)) == 2
+       choice <IdString> AB {\A, \B}
+       // A port has to be 30 bits or less
+       select GetSize(port(preAdd, AB)) <= 30
+       define <IdString> BA (AB == \A ? \B : \A)
+       // D port has to be 25 bits or less
+       select GetSize(port(preAdd, BA)) <= 25
+       index <SigSpec> port(preAdd, \Y) === sigA
+
+       optional
+endmatch
+
+code sigA sigD
+       if (preAdd) {
+               sigA = port(preAdd, \A);
+               sigD = port(preAdd, \B);
+               if (GetSize(sigA) < GetSize(sigD))
+                       std::swap(sigA, sigD);
+       }
+endcode
+
 match ffA
+       if !preAdd
        if param(dsp, \AREG).as_int() == 0
        select ffA->type.in($dff)
        // DSP48E1 does not support clock inversion
@@ -73,6 +153,9 @@ code sigA sigffAmuxY clock
                        sigffAmuxY = sigA;
                sigA = std::move(A);
        }
+       else if (!preAdd) {
+               sigffAmuxY = SigSpec();
+       }
 endcode
 
 match ffAmux
@@ -91,6 +174,18 @@ match ffAmux
        optional
 endmatch
 
+code ffA ffAmux ffAenpol ffAD ffADmux
+       // Move AD register to A if no pre-adder
+       if (!ffA && !preAdd && ffAD) {
+               ffA = ffAD;
+               ffAmux = ffADmux;
+               ffAenpol = ffADenpol;
+
+               ffAD = nullptr;
+               ffADmux = nullptr;
+       }
+endcode
+
 match ffB
        if param(dsp, \BREG).as_int() == 0
        select ffB->type.in($dff)