Add a xilinx_dsp_cascade matcher for PCIN -> PCOUT
authorEddie Hung <eddie@fpgeh.com>
Fri, 20 Sep 2019 17:00:09 +0000 (10:00 -0700)
committerEddie Hung <eddie@fpgeh.com>
Fri, 20 Sep 2019 17:00:09 +0000 (10:00 -0700)
passes/pmgen/Makefile.inc
passes/pmgen/xilinx_dsp.cc
passes/pmgen/xilinx_dsp.pmg
passes/pmgen/xilinx_dsp_cascade.pmg [new file with mode: 0644]

index 21f29a49a584c405973ea8f5fe8ab2ba21bddf58..82bb40ac8b63da7d9af3ab8f853d9cda6ab84f66 100644 (file)
@@ -22,8 +22,9 @@ $(eval $(call add_extra_objs,passes/pmgen/ice40_wrapcarry_pm.h))
 # --------------------------------------
 
 OBJS += passes/pmgen/xilinx_dsp.o
-passes/pmgen/xilinx_dsp.o: passes/pmgen/xilinx_dsp_pm.h
+passes/pmgen/xilinx_dsp.o: passes/pmgen/xilinx_dsp_pm.h passes/pmgen/xilinx_dsp_cascade_pm.h
 $(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp_pm.h))
+$(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp_cascade_pm.h))
 
 # --------------------------------------
 
index abd1457232a7b283024a358a22126eb9284bba55..0d0c6037531cbc5e9af6474bad5338dd2d5afe5c 100644 (file)
@@ -25,6 +25,7 @@ USING_YOSYS_NAMESPACE
 PRIVATE_NAMESPACE_BEGIN
 
 #include "passes/pmgen/xilinx_dsp_pm.h"
+#include "passes/pmgen/xilinx_dsp_cascade_pm.h"
 
 static Cell* addDsp(Module *module) {
        Cell *cell = module->addCell(NEW_ID, ID(DSP48E1));
@@ -253,9 +254,9 @@ void pack_xilinx_simd(Module *module, const std::vector<Cell*> &selected_cells)
 }
 
 
-void pack_xilinx_dsp(dict<SigBit, Cell*> &bit_to_driver, xilinx_dsp_pm &pm)
+void pack_xilinx_dsp(xilinx_dsp_pm &pm)
 {
-       auto &st = pm.st_xilinx_dsp;
+       auto &st = pm.st_xilinx_dsp_pack;
 
 #if 1
        log("\n");
@@ -487,9 +488,6 @@ void pack_xilinx_dsp(dict<SigBit, Cell*> &bit_to_driver, xilinx_dsp_pm &pm)
                P.append(pm.module->addWire(NEW_ID, 48-GetSize(P)));
        cell->setPort(ID(P), P);
 
-       bit_to_driver.insert(std::make_pair(P[0], cell));
-       bit_to_driver.insert(std::make_pair(P[17], cell));
-
        pm.blacklist(cell);
 }
 
@@ -508,7 +506,7 @@ struct XilinxDspPass : public Pass {
                log("Multiply-accumulate operations using the post-adder with feedback on the 'C'\n");
                log("input will be folded into the DSP. In this scenario only, the 'C' input can be\n");
                log("used to override the current accumulation result with a new value, which will\n");
-        log("be added to the multiplier result to form the next accumulation result.\n");
+               log("be added to the multiplier result to form the next accumulation result.\n");
                log("\n");
                log("Use of the dedicated 'PCOUT' -> 'PCIN' cascade path is detected for 'P' -> 'C'\n");
                log("connections (optionally, where 'P' is right-shifted by 18-bits and used as an\n");
@@ -545,52 +543,10 @@ struct XilinxDspPass : public Pass {
                        pack_xilinx_simd(module, module->selected_cells());
 
                        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);
-
-                       auto &unextend = pm.ud_xilinx_dsp.unextend;
-                       // 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 != ID(DSP48E1))
-                                       continue;
-                               if (cell->parameters.at(ID(CREG), State::S1).as_bool())
-                                       continue;
-                               SigSpec &opmode = cell->connections_.at(ID(OPMODE));
-                               if (opmode.extract(4,3) != Const::from_string("011"))
-                                       continue;
-                               SigSpec C = unextend(pm.sigmap(cell->getPort(ID(C))));
-                               if (!C[0].wire)
-                                       continue;
-                               auto it = bit_to_driver.find(C[0]);
-                               if (it == bit_to_driver.end())
-                                       continue;
-                               auto driver = it->second;
-
-                               SigSpec P = driver->getPort(ID(P));
-                               if (GetSize(P) >= GetSize(C) && P.extract(0, GetSize(C)) == C) {
-                                       cell->setPort(ID(C), Const(0, 48));
-                                       Wire *cascade = module->addWire(NEW_ID, 48);
-                                       driver->setPort(ID(PCOUT), cascade);
-                                       cell->setPort(ID(PCIN), cascade);
-                                       opmode[6] = State::S0;
-                                       opmode[5] = State::S0;
-                                       opmode[4] = State::S1;
-                                       bit_to_driver.erase(it);
-                               }
-                               else if (GetSize(P) >= GetSize(C)+17 && P.extract(17, GetSize(C)) == C) {
-                                       cell->setPort(ID(C), Const(0, 48));
-                                       Wire *cascade = module->addWire(NEW_ID, 48);
-                                       driver->setPort(ID(PCOUT), cascade);
-                                       cell->setPort(ID(PCIN), cascade);
-                                       opmode[6] = State::S1;
-                                       opmode[5] = State::S0;
-                                       opmode[4] = State::S1;
-                                       bit_to_driver.erase(it);
-                               }
-                       }
+                       pm.run_xilinx_dsp_pack(pack_xilinx_dsp);
+
+                       xilinx_dsp_cascade_pm pmc(module, module->selected_cells());
+                       pmc.run_xilinx_dsp_cascade();
                }
        }
 } XilinxDspPass;
index 20565f47d327a6f64fe7965bd188a8073b773dbf..0ee230ccc72674ee7340fe1599e8a1476afd2767 100644 (file)
@@ -1,4 +1,4 @@
-pattern xilinx_dsp
+pattern xilinx_dsp_pack
 
 udata <std::function<SigSpec(const SigSpec&)>> unextend
 state <SigBit> clock
diff --git a/passes/pmgen/xilinx_dsp_cascade.pmg b/passes/pmgen/xilinx_dsp_cascade.pmg
new file mode 100644 (file)
index 0000000..9011737
--- /dev/null
@@ -0,0 +1,94 @@
+pattern xilinx_dsp_cascade
+
+udata <std::function<SigSpec(const SigSpec&)>> unextend
+state <SigSpec> sigC
+
+code
+       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 (sig[i].wire)
+                       ++i;
+               return sig.extract(0, i);
+       };
+endcode
+
+match dsp_pcin
+       select dsp_pcin->type.in(\DSP48E1)
+       select !param(dsp_pcin, \CREG, State::S1).as_bool()
+       select port(dsp_pcin, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("011")
+       select nusers(port(dsp_pcin, \C, SigSpec())) > 1
+       select nusers(port(dsp_pcin, \PCIN, SigSpec())) == 0
+endmatch
+
+code sigC
+       sigC = unextend(port(dsp_pcin, \C));
+endcode
+
+match dsp_pcout
+       select dsp_pcout->type.in(\DSP48E1)
+       select nusers(port(dsp_pcout, \P, SigSpec())) > 1
+       select nusers(port(dsp_pcout, \PCOUT, SigSpec())) <= 1
+
+       index <SigSpec> port(dsp_pcout, \P)[0] === sigC[0]
+       filter GetSize(port(dsp_pcin, \P)) >= GetSize(sigC)
+       filter port(dsp_pcout, \P).extract(0, GetSize(sigC)) == sigC
+
+       optional
+endmatch
+
+match dsp_pcout_shift17
+       if !dsp_pcout
+       select dsp_pcout_shift17->type.in(\DSP48E1)
+       select nusers(port(dsp_pcout_shift17, \P, SigSpec())) > 1
+       select nusers(port(dsp_pcout_shift17, \PCOUT, SigSpec())) <= 1
+
+       index <SigSpec> port(dsp_pcout_shift17, \P)[17] === sigC[0]
+       filter GetSize(port(dsp_pcout_shift17, \P)) >= GetSize(sigC)+17
+       filter port(dsp_pcout_shift17, \P).extract(17, GetSize(sigC)) == sigC
+endmatch
+
+code
+       Cell *dsp;
+       if (dsp_pcout)
+               dsp = dsp_pcout;
+       else if (dsp_pcout_shift17)
+               dsp = dsp_pcout_shift17;
+       else log_abort();
+
+       dsp_pcin->setPort(ID(C), Const(0, 48));
+
+       Wire *cascade = module->addWire(NEW_ID, 48);
+       dsp_pcin->setPort(ID(PCIN), cascade);
+       dsp->setPort(ID(PCOUT), cascade);
+       add_siguser(cascade, dsp_pcin);
+       add_siguser(cascade, dsp);
+
+       SigSpec opmode = param(dsp_pcin, \OPMODE, Const(0, 7));
+       if (dsp_pcout)
+               opmode[6] = State::S0;
+       else if (dsp_pcout_shift17)
+               opmode[6] = State::S1;
+       else log_abort();
+
+
+       opmode[5] = State::S0;
+       opmode[4] = State::S1;
+       dsp_pcin->setPort(ID(OPMODE), opmode);
+
+       log_debug("PCOUT -> PCIN cascade for %s -> %s\n", log_id(dsp), log_id(dsp_pcin));
+
+       if (nusers(port(dsp_pcin, \PCOUT, SigSpec())) > 1) {
+               log_debug("  Saturated PCIN/PCOUT on %s\n", log_id(dsp_pcin));
+               blacklist(dsp_pcin);
+       }
+       if (nusers(port(dsp, \PCIN, SigSpec())) > 1)  {
+               log_debug("  Saturated PCIN/PCOUT on %s\n", log_id(dsp));
+               blacklist(dsp_pcout);
+       }
+
+       accept;
+endcode