Add support {A,B,P}REG packing
authorEddie Hung <eddie@fpgeh.com>
Tue, 16 Jul 2019 21:06:32 +0000 (14:06 -0700)
committerEddie Hung <eddie@fpgeh.com>
Tue, 16 Jul 2019 21:06:32 +0000 (14:06 -0700)
passes/pmgen/xilinx_dsp.cc
passes/pmgen/xilinx_dsp.pmg

index b98703de3f0ea76f218d9709df535d945fd381ef..a09f96a7fb5af1a79259ad442c345aef09f68939 100644 (file)
@@ -25,46 +25,60 @@ PRIVATE_NAMESPACE_BEGIN
 
 #include "passes/pmgen/xilinx_dsp_pm.h"
 
-void create_xilinx_dsp(xilinx_dsp_pm &pm)
+void pack_xilinx_dsp(xilinx_dsp_pm &pm)
 {
        auto &st = pm.st_xilinx_dsp;
 
-#if 0
+#if 1
        log("\n");
        log("ffA:   %s\n", log_id(st.ffA, "--"));
        log("ffB:   %s\n", log_id(st.ffB, "--"));
-       log("mul:   %s\n", log_id(st.mul, "--"));
-       log("ffY:   %s\n", log_id(st.ffY, "--"));
+       log("dsp:   %s\n", log_id(st.dsp, "--"));
+       log("ffP:   %s\n", log_id(st.ffP, "--"));
+       log("muxP:  %s\n", log_id(st.muxP, "--"));
+       log("P_WIDTH:  %d\n", st.P_WIDTH);
 #endif
 
-       log("Analysing %s.%s for Xilinx DSP register packing.\n", log_id(pm.module), log_id(st.mul));
+       log("Analysing %s.%s for Xilinx DSP register packing.\n", log_id(pm.module), log_id(st.dsp));
 
-       Cell *cell = st.mul;
+       Cell *cell = st.dsp;
        log_assert(cell);
 
-       // Input Interface
-
-       cell->setPort("\\A", st.sigA);
-       cell->setPort("\\B", st.sigB);
-
-       cell->setParam("\\AREG", st.ffA ? State::S1 : State::S0);
-       cell->setParam("\\BREG", st.ffB ? State::S1 : State::S0);
-
        if (st.clock != SigBit())
        {
                cell->setPort("\\CLK", st.clock);
 
                if (st.ffA) {
+                       SigSpec D = st.ffA->getPort("\\D");
+                       cell->setPort("\\A", D.extend_u0(30));
                        cell->setParam("\\AREG", State::S1);
-                       cell->setPort("\\CEA2", State::S1);
+                       if (st.ffA->type == "$dff")
+                               cell->setPort("\\CEA2", State::S1);
+                       else if (st.ffA->type == "$dffe")
+                               cell->setPort("\\CEA2", st.ffA->getPort("\\EN"));
+                       else log_abort();
                }
                if (st.ffB) {
+                       SigSpec D = st.ffB->getPort("\\D");
+                       cell->setPort("\\B", D.extend_u0(18));
                        cell->setParam("\\BREG", State::S1);
-                       cell->setPort("\\CEA2", State::S1);
+                       if (st.ffB->type == "$dff")
+                               cell->setPort("\\CEB2", State::S1);
+                       else if (st.ffB->type == "$dffe")
+                               cell->setPort("\\CEB2", st.ffB->getPort("\\EN"));
+                       else log_abort();
                }
-               if (st.ffY) {
-                       cell->setPort("\\PREG", State::S1);
-                       cell->setPort("\\CEP", State::S1);
+               if (st.ffP) {
+                       SigSpec P = cell->getPort("\\P");
+                       SigSpec Q = st.ffP->getPort("\\Q");
+                       Q.append(P.extract(GetSize(Q), -1));
+                       cell->setPort("\\P", Q);
+                       cell->setParam("\\PREG", State::S1);
+                       if (st.ffP->type == "$dff")
+                               cell->setPort("\\CEP", State::S1);
+                       else if (st.ffP->type == "$dffe")
+                               cell->setPort("\\CEP", st.ffP->getPort("\\EN"));
+                       else log_abort();
                }
 
                log("  clock: %s (%s)", log_signal(st.clock), "posedge");
@@ -75,15 +89,17 @@ void create_xilinx_dsp(xilinx_dsp_pm &pm)
                if (st.ffB)
                        log(" ffB:%s", log_id(st.ffB));
 
-               if (st.ffY)
-                       log(" ffY:%s", log_id(st.ffY));
+               if (st.ffP)
+                       log(" ffY:%s", log_id(st.ffP));
 
                log("\n");
        }
 
-       // Output Interface
-
-       pm.autoremove(st.ffY);
+       pm.autoremove(st.ffA);
+       pm.autoremove(st.ffB);
+       pm.autoremove(st.ffP);
+       pm.autoremove(st.muxP);
+       pm.blacklist(cell);
 }
 
 struct Ice40DspPass : public Pass {
@@ -99,7 +115,7 @@ struct Ice40DspPass : public Pass {
        }
        void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
        {
-               log_header(design, "Executing ICE40_DSP pass (map multipliers).\n");
+               log_header(design, "Executing XILINX_DSP pass (pack DSPs).\n");
 
                size_t argidx;
                for (argidx = 1; argidx < args.size(); argidx++)
@@ -113,7 +129,7 @@ struct Ice40DspPass : public Pass {
                extra_args(args, argidx, design);
 
                for (auto module : design->selected_modules())
-                       xilinx_dsp_pm(module, module->selected_cells()).run_xilinx_dsp(create_xilinx_dsp);
+                       xilinx_dsp_pm(module, module->selected_cells()).run_xilinx_dsp(pack_xilinx_dsp);
        }
 } Ice40DspPass;
 
index 6bb4e7bd8cefec104afd6d1a87f792759642f4bd..ceed64b3079d31947865a591f6e3788036c325e3 100644 (file)
@@ -1,44 +1,36 @@
 pattern xilinx_dsp
 
 state <SigBit> clock
-state <SigSpec> sigA sigB sigY sigS
-state <Cell*> addAB muxAB
+state <int> P_WIDTH
 
-match mul
-       select mul->type.in($__MUL25X18)
+match dsp
+       select dsp->type.in(\DSP48E1)
 endmatch
 
 match ffA
-       select ffA->type.in($dff) /* TODO: $dffe */
+       select ffA->type.in($dff, $dffe)
        // select nusers(port(ffA, \Q)) == 2
-       index <SigSpec> port(ffA, \Q) === port(mul, \A)
+       index <SigSpec> port(ffA, \Q).extend_u0(30) === port(dsp, \A)
        // DSP48E1 does not support clock inversion
-       index <SigBit> port(ffA, \CLK_POLARITY) === State::S1
+       index <Const> param(ffA, \CLK_POLARITY).as_bool() === true
        optional
 endmatch
 
-code sigA clock
-       sigA = port(mul, \A);
-
-       if (ffA) {
-               sigA = port(ffA, \D);
+code clock
+       if (ffA)
                clock = port(ffA, \CLK).as_bit();
-       }
 endcode
 
 match ffB
-       select ffB->type.in($dff)
+       select ffB->type.in($dff, $dffe)
        // select nusers(port(ffB, \Q)) == 2
-       index <SigSpec> port(ffB, \Q) === port(mul, \B)
-       index <SigBit> port(ffB, \CLK_POLARITY) === State::S1
+       index <SigSpec> port(ffB, \Q).extend_u0(18) === port(dsp, \B)
+       index <Const> param(ffB, \CLK_POLARITY).as_bool() === true
        optional
 endmatch
 
-code sigB clock 
-       sigB = port(mul, \B);
-
+code clock
        if (ffB) {
-               sigB = port(ffB, \D);
                SigBit c = port(ffB, \CLK).as_bit();
 
                if (clock != SigBit() && c != clock)
@@ -48,20 +40,51 @@ code sigB clock
        }
 endcode
 
+code P_WIDTH
+       SigSpec P = port(dsp, \P);
+       int i;
+       for (i = GetSize(P); i > 0; i--)
+               if (nusers(P[i-1]) > 1)
+                       break;
+       P_WIDTH = i;
+endcode
+
+match ffP
+       select ffP->type.in($dff, $dffe)
+       select nusers(port(ffP, \D)) == 2
+       filter param(ffP, \WIDTH).as_int() == P_WIDTH
+       filter port(ffP, \D) == port(dsp, \P).extract(0, P_WIDTH)
+       index <Const> param(ffP, \CLK_POLARITY) === State::S1
+       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 !ffP
+       select muxP->type.in($mux)
+       select port(muxP, \A).is_fully_undef()
+       filter param(muxP, \WIDTH).as_int() == P_WIDTH
+       filter port(muxP, \B) == port(dsp, \P).extract(0, P_WIDTH)
+       select nusers(port(muxP, \B)) == 2
+       optional
+endmatch
+
 match ffY
-       select ffY->type.in($dff)
+       if muxP
+       select ffY->type.in($dff, $dffe)
        select nusers(port(ffY, \D)) == 2
-       index <SigSpec> port(ffY, \D) === port(mul, \Y)
-       index <SigBit> port(ffY, \CLK_POLARITY) === State::S1
-       optional
+       index <SigSpec> port(ffY, \D) === port(muxP, \Y)
 endmatch
 
-code sigY clock
-       sigY = port(mul, \Y);
+code ffP clock
+       if (ffY)
+               ffP = ffY;
 
-       if (ffY) {
-               sigY = port(ffY, \Q);
-               SigBit c = port(ffY, \CLK).as_bit();
+       if (ffP) {
+               SigBit c = port(ffP, \CLK).as_bit();
 
                if (clock != SigBit() && c != clock)
                        reject;