From: Eddie Hung Date: Thu, 26 Sep 2019 19:09:57 +0000 (-0700) Subject: Try recursive pmgen for P cascade X-Git-Tag: working-ls180~1039^2~8 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=832216dab072cb4f1793aeda07604fb2eb32b399;p=yosys.git Try recursive pmgen for P cascade --- diff --git a/passes/pmgen/xilinx_dsp_cascade.pmg b/passes/pmgen/xilinx_dsp_cascade.pmg index 37674efea..59cd1267d 100644 --- a/passes/pmgen/xilinx_dsp_cascade.pmg +++ b/passes/pmgen/xilinx_dsp_cascade.pmg @@ -1,100 +1,133 @@ pattern xilinx_dsp_cascadeP -udata > unextend -state 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 >> 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 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 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 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 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 > unextend state clock state sigA sigB @@ -113,8 +146,13 @@ udata dffclock udata dff dffcemux dffrstmux udata 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")