Try recursive pmgen for P cascade
authorEddie Hung <eddie@fpgeh.com>
Thu, 26 Sep 2019 19:09:57 +0000 (12:09 -0700)
committerEddie Hung <eddie@fpgeh.com>
Thu, 26 Sep 2019 19:09:57 +0000 (12:09 -0700)
passes/pmgen/xilinx_dsp_cascade.pmg

index 37674efea6c019867755b7335a06710d50b9aedf..59cd1267d632fcf0d885750736ca5fb845ddf6c5 100644 (file)
 pattern xilinx_dsp_cascadeP
 
-udata <std::function<SigSpec(const SigSpec&)>> unextend
-state <SigSpec> sigC
-
-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
+udata <vector<std::pair<Cell*,bool>>> chain longest_chain
+
+code
+#define MAX_DSP_CASCADE 20
+endcode
+
+match first
+       select first->type.in(\DSP48E1)
+       select port(first, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("000")
+       select nusers(port(first, \PCOUT, SigSpec())) <= 1
 endmatch
 
-code sigC
-       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);
-       };
-       sigC = unextend(port(dsp_pcin, \C));
+code
+       longest_chain.clear();
+       chain.emplace_back(first, false);
+       subpattern(tail);
+finally
+       chain.pop_back();
+       log_assert(chain.empty());
+       if (GetSize(longest_chain) > 1) {
+               Cell *dsp = longest_chain.front().first;
+
+               for (int i = 1; i < GetSize(longest_chain); i++) {
+                       Cell *dsp_pcin = longest_chain[i].first;
+                       bool shift17 = longest_chain[i].second;
+
+                       dsp_pcin->setPort(ID(C), Const(0, 48));
+
+                       if (i % MAX_DSP_CASCADE > 0) {
+                               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 = port(dsp_pcin, \OPMODE, Const(0, 7));
+                               if (shift17)
+                                       opmode[6] = State::S1;
+                               else
+                                       opmode[6] = State::S0;
+
+                               opmode[5] = State::S0;
+                               opmode[4] = State::S1;
+                               dsp_pcin->setPort(\OPMODE, opmode);
+
+                               log_debug("PCOUT -> PCIN cascade for %s -> %s\n", log_id(dsp), log_id(dsp_pcin));
+                       }
+                       else {
+                               log_debug("Blocking PCOUT -> PCIN cascade for %s -> %s (exceeds max: %d)\n", log_id(dsp), log_id(dsp_pcin), MAX_DSP_CASCADE);
+                       }
+
+                       dsp = dsp_pcin;
+               }
+
+               did_something = true;
+               accept;
+       }
 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 <SigBit> 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
+subpattern tail
+arg first
 
-       optional
+match next
+       select next->type.in(\DSP48E1)
+       select !param(next, \CREG, State::S1).as_bool()
+       select port(next, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("011")
+       select nusers(port(next, \C, SigSpec())) > 1
+       select nusers(port(next, \PCIN, SigSpec())) == 0
+       index <SigBit> port(next, \C)[0] === port(chain.back().first, \P)[0]
+       semioptional
 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 <SigBit> 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
+match next_shift17
+       if !next_shift17
+       select next_shift17->type.in(\DSP48E1)
+       select !param(next_shift17, \CREG, State::S1).as_bool()
+       select port(next_shift17, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("011")
+       select nusers(port(next_shift17, \C, SigSpec())) > 1
+       select nusers(port(next_shift17, \PCIN, SigSpec())) == 0
+       index <SigBit> port(next_shift17, \C)[0] === port(chain.back().first, \P)[17]
+       semioptional
 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 = port(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(\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);
-       }
+code next
+       if (!next)
+               next = next_shift17;
+       if (next) {
+               chain.emplace_back(next, next_shift17);
+
+               auto 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);
+               };
+               SigSpec sigC = unextend(port(next, \C));
+
+               // TODO: Cannot use 'reject' since semioptional
+               if (next_shift17) {
+                       if (GetSize(sigC)+17 <= GetSize(port(chain.back().first, \P)) &&
+                                       port(chain.back().first, \P).extract(17, GetSize(sigC)) != sigC)
+                               subpattern(tail);
+               }
+               else {
+                       if (GetSize(sigC) <= GetSize(port(chain.back().first, \P)) &&
+                                       port(chain.back().first, \P).extract(0, GetSize(sigC)) != sigC)
+                               subpattern(tail);
 
-       did_something = true;
-       accept;
+               }
+       } else {
+               if (GetSize(chain) > GetSize(longest_chain))
+                       longest_chain = chain;
+       }
+finally
+       if (next)
+               chain.pop_back();
 endcode
 
 // ##########
 
 pattern xilinx_dsp_cascadeAB
 
-udata <std::function<SigSpec(const SigSpec&)>> unextend
 state <SigBit> clock
 state <SigSpec> sigA sigB
 
@@ -113,8 +146,13 @@ udata <SigBit> dffclock
 udata <Cell*> dff dffcemux dffrstmux
 udata <bool> dffcepol dffrstpol
 
-code
-       unextend = [](const SigSpec &sig) {
+match dspD
+       select dspD->type.in(\DSP48E1)
+       select (param(dspD, \A_INPUT, Const("DIRECT")).decode_string() == "DIRECT" && nusers(port(dspD, \A, SigSpec())) > 1 && nusers(port(dspD, \ACIN, SigSpec())) == 0) || (param(dspD, \B_INPUT, Const("DIRECT")).decode_string() == "DIRECT" && nusers(port(dspD, \B, SigSpec())) > 1 && nusers(port(dspD, \BCIN, SigSpec())) == 0)
+endmatch
+
+code sigA sigB
+       auto unextend = [](const SigSpec &sig) {
                int i;
                for (i = GetSize(sig)-1; i > 0; i--)
                        if (sig[i] != sig[i-1])
@@ -124,14 +162,6 @@ code
                        ++i;
                return sig.extract(0, i);
        };
-endcode
-
-match dspD
-       select dspD->type.in(\DSP48E1)
-       select (param(dspD, \A_INPUT, Const("DIRECT")).decode_string() == "DIRECT" && nusers(port(dspD, \A, SigSpec())) > 1 && nusers(port(dspD, \ACIN, SigSpec())) == 0) || (param(dspD, \B_INPUT, Const("DIRECT")).decode_string() == "DIRECT" && nusers(port(dspD, \B, SigSpec())) > 1 && nusers(port(dspD, \BCIN, SigSpec())) == 0)
-endmatch
-
-code sigA sigB
        if (param(dspD, \A_INPUT, Const("DIRECT")).decode_string() == "DIRECT")
                sigA = unextend(port(dspD, \A));
        if (param(dspD, \B_INPUT, Const("DIRECT")).decode_string() == "DIRECT")