From ed187ef1cf118727a8964e26c36530560f3e37db Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 20 Sep 2019 10:00:09 -0700 Subject: [PATCH] Add a xilinx_dsp_cascade matcher for PCIN -> PCOUT --- passes/pmgen/Makefile.inc | 3 +- passes/pmgen/xilinx_dsp.cc | 60 +++--------------- passes/pmgen/xilinx_dsp.pmg | 2 +- passes/pmgen/xilinx_dsp_cascade.pmg | 94 +++++++++++++++++++++++++++++ 4 files changed, 105 insertions(+), 54 deletions(-) create mode 100644 passes/pmgen/xilinx_dsp_cascade.pmg diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc index 21f29a49a..82bb40ac8 100644 --- a/passes/pmgen/Makefile.inc +++ b/passes/pmgen/Makefile.inc @@ -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)) # -------------------------------------- diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index abd145723..0d0c60375 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -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 &selected_cells) } -void pack_xilinx_dsp(dict &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 &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 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; diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 20565f47d..0ee230ccc 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -1,4 +1,4 @@ -pattern xilinx_dsp +pattern xilinx_dsp_pack udata > unextend state clock diff --git a/passes/pmgen/xilinx_dsp_cascade.pmg b/passes/pmgen/xilinx_dsp_cascade.pmg new file mode 100644 index 000000000..901173724 --- /dev/null +++ b/passes/pmgen/xilinx_dsp_cascade.pmg @@ -0,0 +1,94 @@ +pattern xilinx_dsp_cascade + +udata > unextend +state 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 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 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 -- 2.30.2