Perform C -> PCIN optimisation after pattern matcher
authorEddie Hung <eddie@fpgeh.com>
Wed, 14 Aug 2019 00:11:35 +0000 (17:11 -0700)
committerEddie Hung <eddie@fpgeh.com>
Wed, 14 Aug 2019 00:11:35 +0000 (17:11 -0700)
passes/pmgen/xilinx_dsp.cc
passes/pmgen/xilinx_dsp.pmg

index 31c0d48c5e8d5ee888b6358090c1e0bc40288f2c..e7b72e31209893e93d0e82d8d2f2ecc500de8f2c 100644 (file)
 USING_YOSYS_NAMESPACE
 PRIVATE_NAMESPACE_BEGIN
 
-template<class T> bool includes(const T &lhs, const T &rhs) {
+template<class T> inline bool includes(const T &lhs, const T &rhs) {
        return std::includes(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
 }
+#include <set>
 #include "passes/pmgen/xilinx_dsp_pm.h"
 
-void pack_xilinx_dsp(xilinx_dsp_pm &pm)
+void pack_xilinx_dsp(dict<SigBit, Cell*> &bit_to_driver, xilinx_dsp_pm &pm)
 {
        auto &st = pm.st_xilinx_dsp;
 
 #if 1
        log("\n");
-       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("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));
 #endif
@@ -46,11 +47,17 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm)
        log("Analysing %s.%s for Xilinx DSP packing.\n", log_id(pm.module), log_id(st.dsp));
 
        Cell *cell = st.dsp;
+       bit_to_driver.insert(std::make_pair(cell->getPort("\\P")[17], cell));
        SigSpec P = st.sigP;
 
        if (st.addAB) {
+               log_assert(st.addAB->getParam("\\A_SIGNED").as_bool());
+               log_assert(st.addAB->getParam("\\B_SIGNED").as_bool());
                log("  adder %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type));
-               cell->setPort("\\C", st.sigC.extend_u0(48, true));
+
+               SigSpec C = st.sigC;
+               C.extend_u0(48, true);
+               cell->setPort("\\C", C);
                SigSpec &opmode = cell->connections_.at("\\OPMODE");
                opmode[6] = State::S0;
                opmode[5] = State::S1;
@@ -153,8 +160,48 @@ struct XilinxDspPass : public Pass {
                }
                extra_args(args, argidx, design);
 
-               for (auto module : design->selected_modules())
-                       xilinx_dsp_pm(module, module->selected_cells()).run_xilinx_dsp(pack_xilinx_dsp);
+               for (auto module : design->selected_modules()) {
+                       xilinx_dsp_pm pm(module, module->selected_cells());
+                       dict<SigBit, Cell*> bit_to_driver;
+                       auto f = [&bit_to_driver](xilinx_dsp_pm &pm){ pack_xilinx_dsp(bit_to_driver, pm); };
+                       pm.run_xilinx_dsp(f);
+
+                       // Look for ability to convert C input from another DSP into PCIN
+                       //   NB: Needs to be done after pattern matcher has folded all
+                       //       $add cells into the DSP
+                       for (auto cell : module->cells()) {
+                               if (cell->type != "\\DSP48E1")
+                                       continue;
+                               SigSpec &opmode = cell->connections_.at("\\OPMODE");
+                               if (opmode.extract(4,3) != Const::from_string("011"))
+                                       continue;
+                               SigSpec C = pm.sigmap(cell->getPort("\\C"));
+                               if (C.has_const())
+                                       continue;
+                               auto it = bit_to_driver.find(C[0]);
+                               if (it == bit_to_driver.end())
+                                       continue;
+                               auto driver = it->second;
+
+                               // Unextend C
+                               int i;
+                               for (i = GetSize(C)-1; i > 0; i--)
+                                       if (C[i] != C[i-1])
+                                               break;
+                               if (i > 48-17)
+                                       continue;
+                               if (driver->getPort("\\P").extract(17, i) == C.extract(0, i)) {
+                                       cell->setPort("\\C", Const(0, 48));
+                                       Wire *cascade = module->addWire(NEW_ID, 48);
+                                       driver->setPort("\\PCOUT", cascade);
+                                       cell->setPort("\\PCIN", cascade);
+                                       opmode[6] = State::S1;
+                                       opmode[5] = State::S0;
+                                       opmode[4] = State::S1;
+                                       bit_to_driver.erase(it);
+                               }
+                       }
+               }
        }
 } XilinxDspPass;
 
index 5dee36a11d62ec28da249a0d9b0352abd6016e84..1a3dcdcbb11106be4803b0a45d4fe8f0dc0f30de 100644 (file)
@@ -1,6 +1,7 @@
 pattern xilinx_dsp
 
 state <SigBit> clock
+state <std::set<SigBit>> sigAset sigBset
 state <SigSpec> sigC sigP sigPused
 state <Cell*> addAB
 
@@ -8,13 +9,22 @@ match dsp
        select dsp->type.in(\DSP48E1)
 endmatch
 
+code sigAset sigBset
+       SigSpec A = port(dsp, \A);
+       A.remove_const();
+       sigAset = A.to_sigbit_set();
+       SigSpec B = port(dsp, \B);
+       B.remove_const();
+       sigBset = B.to_sigbit_set();
+endcode
+
 match ffA
        if param(dsp, \AREG).as_int() == 0
-       if !port(dsp, \A).remove_const().empty()
+       if !sigAset.empty()
        select ffA->type.in($dff)
        // DSP48E1 does not support clock inversion
        select param(ffA, \CLK_POLARITY).as_bool()
-       filter includes(port(ffA, \Q).to_sigbit_set(), port(dsp, \A).remove_const().to_sigbit_set())
+       filter includes(port(ffA, \Q).to_sigbit_set(), sigAset)
        optional
 endmatch
 
@@ -25,11 +35,11 @@ endcode
 
 match ffB
        if param(dsp, \BREG).as_int() == 0
-       if !port(dsp, \B).remove_const().empty()
+       if !sigBset.empty()
        select ffB->type.in($dff)
        // DSP48E1 does not support clock inversion
        select param(ffB, \CLK_POLARITY).as_bool()
-       filter includes(port(ffB, \Q).to_sigbit_set(), port(dsp, \B).remove_const().to_sigbit_set())
+       filter includes(port(ffB, \Q).to_sigbit_set(), sigBset)
        optional
 endmatch
 
@@ -65,21 +75,18 @@ match addB
        index <int> nusers(port(addB, \B)) === 2
        //index <SigSpec> port(addB, \B) === sigP.extract(0, param(addB, \B_WIDTH).as_int())
        filter param(addB, \B_WIDTH).as_int() <= GetSize(sigP)
-       filter port(addB, \B) ==  sigP.extract(0, 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
@@ -97,7 +104,6 @@ code addAB sigC sigP
                //      reject;
 
                sigP = port(addAB, \Y);
-                sigC.extend_u0(32, C_SIGNED);
        }
 endcode