Pack partial-product adder DSP48E1 packing
authorEddie Hung <eddie@fpgeh.com>
Fri, 9 Aug 2019 22:19:33 +0000 (15:19 -0700)
committerEddie Hung <eddie@fpgeh.com>
Fri, 9 Aug 2019 22:19:33 +0000 (15:19 -0700)
passes/pmgen/xilinx_dsp.cc
passes/pmgen/xilinx_dsp.pmg
techlibs/xilinx/synth_xilinx.cc

index 389f0cb568b7b396548faa32a9cef5be870aaf7d..cd88f9449313e57105ae88a0b891233d39cf81b7 100644 (file)
@@ -37,16 +37,26 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm)
        log("ffA:   %s\n", log_id(st.ffA, "--"));
        log("ffB:   %s\n", log_id(st.ffB, "--"));
        log("dsp:   %s\n", log_id(st.dsp, "--"));
+       log("addAB: %s\n", log_id(st.addAB, "--"));
        log("ffP:   %s\n", log_id(st.ffP, "--"));
        //log("muxP:  %s\n", log_id(st.muxP, "--"));
        log("sigPused: %s\n", log_signal(st.sigPused));
-       log_module(pm.module);
 #endif
 
-       log("Analysing %s.%s for Xilinx DSP register packing.\n", log_id(pm.module), log_id(st.dsp));
+       log("Analysing %s.%s for Xilinx DSP packing.\n", log_id(pm.module), log_id(st.dsp));
 
        Cell *cell = st.dsp;
-       log_assert(cell);
+       SigSpec P = st.sigP;
+
+       if (st.addAB) {
+               log("  adder %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type));
+               cell->setPort("\\C", st.sigC.extend_u0(48, true));
+               SigSpec &opmode = cell->connections_.at("\\OPMODE");
+               opmode[6] = State::S0;
+               opmode[5] = State::S1;
+               opmode[4] = State::S1;
+               pm.autoremove(st.addAB);
+       }
 
        if (st.clock != SigBit())
        {
@@ -79,7 +89,6 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm)
                        else log_abort();
                }
                if (st.ffP) {
-                       SigSpec P = cell->getPort("\\P");
                        SigSpec D;
                        //if (st.muxP)
                        //      D = st.muxP->getPort("\\B");
@@ -87,7 +96,6 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm)
                                D = st.ffP->getPort("\\D");
                        SigSpec Q = st.ffP->getPort("\\Q");
                        P.replace(pm.sigmap(D), Q);
-                       cell->setPort("\\P", P);
                        cell->setParam("\\PREG", State::S1);
                        if (st.ffP->type == "$dff")
                                cell->setPort("\\CEP", State::S1);
@@ -112,6 +120,10 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm)
                log("\n");
        }
 
+       if (GetSize(P) < 48)
+               P.append(pm.module->addWire(NEW_ID, 48-GetSize(P)));
+       cell->setPort("\\P", P);
+
        pm.blacklist(cell);
 }
 
index f95de94104c256b96a75e52eeb7746642563c9af..4f5fae8df6d4e3816fd1e3e392731fa30241a27e 100644 (file)
@@ -1,7 +1,8 @@
 pattern xilinx_dsp
 
 state <SigBit> clock
-state <SigSpec> sigPused
+state <SigSpec> sigC sigP sigPused
+state <Cell*> addAB
 
 match dsp
        select dsp->type.in(\DSP48E1)
@@ -43,13 +44,69 @@ code clock
        }
 endcode
 
+code sigP
+       sigP = port(dsp, \P);
+endcode
+
+match addA
+       select addA->type.in($add)
+       select param(addA, \A_SIGNED).as_bool() && param(addA, \B_SIGNED).as_bool()
+       select nusers(port(addA, \A)) == 2
+       //index <SigSpec> port(addA, \A) === sigP.extract(0, param(addA, \A_WIDTH).as_int())
+       filter GetSize(sigP) >= param(addA, \A_WIDTH).as_int()
+       filter port(addA, \A) == sigP.extract(0, param(addA, \A_WIDTH).as_int())
+       optional
+endmatch
+
+match addB
+       if !addA
+       select addB->type.in($add, $sub)
+       select param(addB, \A_SIGNED).as_bool() && param(addB, \B_SIGNED).as_bool()
+       select nusers(port(addB, \B)) == 2
+       //index <SigSpec> port(addB, \B) === sigP.extract(0, param(addB, \B_WIDTH).as_int())
+       filter GetSize(sigP) >= param(addB, \B_WIDTH).as_int()
+       filter port(addB, \B) ==  sigP.extract(0, param(addB, \B_WIDTH).as_int())
+       optional
+endmatch
+
+code addAB sigC sigP
+       bool C_SIGNED = false;
+       if (addA) {
+               addAB = addA;
+               sigC = port(addAB, \B);
+               C_SIGNED = param(addAB, \B_SIGNED).as_bool();
+       }
+       if (addB) {
+               addAB = addB;
+               sigC = port(addAB, \A);
+               C_SIGNED = param(addAB, \B_SIGNED).as_bool();
+       }
+       if (addAB) {
+               // Ensure that adder is not used
+               SigSpec opmodeZ = port(dsp, \OPMODE).extract(4,3);
+               if (!opmodeZ.is_fully_zero())
+                       reject;
+
+               int natural_mul_width = GetSize(port(dsp, \A)) + GetSize(port(dsp, \B));
+               int actual_mul_width = GetSize(sigP);
+               int actual_acc_width = GetSize(sigC);
+
+               if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width))
+                       reject;
+               //if ((actual_acc_width != actual_mul_width) && (param(dsp, \A_SIGNED).as_bool() != param(addAB, \A_SIGNED).as_bool()))
+               //      reject;
+
+               sigP = port(addAB, \Y);
+                sigC.extend_u0(32, C_SIGNED);
+       }
+endcode
+
 // Extract the bits of P that actually have a consumer
 // (as opposed to being a dummy)
 code sigPused
-       SigSpec P = port(dsp, \P);
-       for (int i = 0; i < GetSize(P); i++)
-               if (P[i].wire && nusers(P[i]) > 1)
-                       sigPused.append(P[i]);
+       for (int i = 0; i < GetSize(sigP); i++)
+               if (sigP[i].wire && nusers(sigP[i]) > 1)
+                       sigPused.append(sigP[i]);
 endcode
 
 match ffP
index 7b1fe5e3b8a7c959f20e5bf942018730e9395b07..a54b3ac521c587a80f7e0f0443699c5ff65da27d 100644 (file)
@@ -287,6 +287,8 @@ struct SynthXilinxPass : public ScriptPass
                        if (!nodsp || help_mode) {
                                // NB: Xilinx multipliers are signed only
                                run("techmap -map +/mul2dsp.v -map +/xilinx/dsp_map.v -D DSP_A_MAXWIDTH=25 -D DSP_B_MAXWIDTH=18 -D DSP_SIGNEDONLY=1 -D DSP_NAME=$__MUL25X18", "(skip if '-nodsp')");
+                               run("opt_expr -fine", "                 (skip if '-nodsp')");
+                               run("wreduce", "                        (skip if '-nodsp')");
                                run("xilinx_dsp", "                     (skip if '-nodsp')");
                                run("chtype -set $mul t:$__soft_mul","  (skip if '-nodsp')");
                        }