diff options
Diffstat (limited to 'passes/pmgen/xilinx_dsp_cascade.pmg')
-rw-r--r-- | passes/pmgen/xilinx_dsp_cascade.pmg | 94 |
1 files changed, 94 insertions, 0 deletions
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 <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 |