From 9616dbd125171905bccf55fa7fd564e4ae2ca5ab Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 16 Jul 2019 14:06:32 -0700 Subject: [PATCH] Add support {A,B,P}REG packing --- passes/pmgen/xilinx_dsp.cc | 68 +++++++++++++++++++------------ passes/pmgen/xilinx_dsp.pmg | 81 ++++++++++++++++++++++++------------- 2 files changed, 94 insertions(+), 55 deletions(-) diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index b98703de3..a09f96a7f 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -25,46 +25,60 @@ PRIVATE_NAMESPACE_BEGIN #include "passes/pmgen/xilinx_dsp_pm.h" -void create_xilinx_dsp(xilinx_dsp_pm &pm) +void pack_xilinx_dsp(xilinx_dsp_pm &pm) { auto &st = pm.st_xilinx_dsp; -#if 0 +#if 1 log("\n"); log("ffA: %s\n", log_id(st.ffA, "--")); log("ffB: %s\n", log_id(st.ffB, "--")); - log("mul: %s\n", log_id(st.mul, "--")); - log("ffY: %s\n", log_id(st.ffY, "--")); + log("dsp: %s\n", log_id(st.dsp, "--")); + log("ffP: %s\n", log_id(st.ffP, "--")); + log("muxP: %s\n", log_id(st.muxP, "--")); + log("P_WIDTH: %d\n", st.P_WIDTH); #endif - log("Analysing %s.%s for Xilinx DSP register packing.\n", log_id(pm.module), log_id(st.mul)); + log("Analysing %s.%s for Xilinx DSP register packing.\n", log_id(pm.module), log_id(st.dsp)); - Cell *cell = st.mul; + Cell *cell = st.dsp; log_assert(cell); - // Input Interface - - cell->setPort("\\A", st.sigA); - cell->setPort("\\B", st.sigB); - - cell->setParam("\\AREG", st.ffA ? State::S1 : State::S0); - cell->setParam("\\BREG", st.ffB ? State::S1 : State::S0); - if (st.clock != SigBit()) { cell->setPort("\\CLK", st.clock); if (st.ffA) { + SigSpec D = st.ffA->getPort("\\D"); + cell->setPort("\\A", D.extend_u0(30)); cell->setParam("\\AREG", State::S1); - cell->setPort("\\CEA2", State::S1); + if (st.ffA->type == "$dff") + cell->setPort("\\CEA2", State::S1); + else if (st.ffA->type == "$dffe") + cell->setPort("\\CEA2", st.ffA->getPort("\\EN")); + else log_abort(); } if (st.ffB) { + SigSpec D = st.ffB->getPort("\\D"); + cell->setPort("\\B", D.extend_u0(18)); cell->setParam("\\BREG", State::S1); - cell->setPort("\\CEA2", State::S1); + if (st.ffB->type == "$dff") + cell->setPort("\\CEB2", State::S1); + else if (st.ffB->type == "$dffe") + cell->setPort("\\CEB2", st.ffB->getPort("\\EN")); + else log_abort(); } - if (st.ffY) { - cell->setPort("\\PREG", State::S1); - cell->setPort("\\CEP", State::S1); + if (st.ffP) { + SigSpec P = cell->getPort("\\P"); + SigSpec Q = st.ffP->getPort("\\Q"); + Q.append(P.extract(GetSize(Q), -1)); + cell->setPort("\\P", Q); + cell->setParam("\\PREG", State::S1); + if (st.ffP->type == "$dff") + cell->setPort("\\CEP", State::S1); + else if (st.ffP->type == "$dffe") + cell->setPort("\\CEP", st.ffP->getPort("\\EN")); + else log_abort(); } log(" clock: %s (%s)", log_signal(st.clock), "posedge"); @@ -75,15 +89,17 @@ void create_xilinx_dsp(xilinx_dsp_pm &pm) if (st.ffB) log(" ffB:%s", log_id(st.ffB)); - if (st.ffY) - log(" ffY:%s", log_id(st.ffY)); + if (st.ffP) + log(" ffY:%s", log_id(st.ffP)); log("\n"); } - // Output Interface - - pm.autoremove(st.ffY); + pm.autoremove(st.ffA); + pm.autoremove(st.ffB); + pm.autoremove(st.ffP); + pm.autoremove(st.muxP); + pm.blacklist(cell); } struct Ice40DspPass : public Pass { @@ -99,7 +115,7 @@ struct Ice40DspPass : public Pass { } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { - log_header(design, "Executing ICE40_DSP pass (map multipliers).\n"); + log_header(design, "Executing XILINX_DSP pass (pack DSPs).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -113,7 +129,7 @@ struct Ice40DspPass : public Pass { extra_args(args, argidx, design); for (auto module : design->selected_modules()) - xilinx_dsp_pm(module, module->selected_cells()).run_xilinx_dsp(create_xilinx_dsp); + xilinx_dsp_pm(module, module->selected_cells()).run_xilinx_dsp(pack_xilinx_dsp); } } Ice40DspPass; diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index 6bb4e7bd8..ceed64b30 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -1,44 +1,36 @@ pattern xilinx_dsp state clock -state sigA sigB sigY sigS -state addAB muxAB +state P_WIDTH -match mul - select mul->type.in($__MUL25X18) +match dsp + select dsp->type.in(\DSP48E1) endmatch match ffA - select ffA->type.in($dff) /* TODO: $dffe */ + select ffA->type.in($dff, $dffe) // select nusers(port(ffA, \Q)) == 2 - index port(ffA, \Q) === port(mul, \A) + index port(ffA, \Q).extend_u0(30) === port(dsp, \A) // DSP48E1 does not support clock inversion - index port(ffA, \CLK_POLARITY) === State::S1 + index param(ffA, \CLK_POLARITY).as_bool() === true optional endmatch -code sigA clock - sigA = port(mul, \A); - - if (ffA) { - sigA = port(ffA, \D); +code clock + if (ffA) clock = port(ffA, \CLK).as_bit(); - } endcode match ffB - select ffB->type.in($dff) + select ffB->type.in($dff, $dffe) // select nusers(port(ffB, \Q)) == 2 - index port(ffB, \Q) === port(mul, \B) - index port(ffB, \CLK_POLARITY) === State::S1 + index port(ffB, \Q).extend_u0(18) === port(dsp, \B) + index param(ffB, \CLK_POLARITY).as_bool() === true optional endmatch -code sigB clock - sigB = port(mul, \B); - +code clock if (ffB) { - sigB = port(ffB, \D); SigBit c = port(ffB, \CLK).as_bit(); if (clock != SigBit() && c != clock) @@ -48,20 +40,51 @@ code sigB clock } endcode +code P_WIDTH + SigSpec P = port(dsp, \P); + int i; + for (i = GetSize(P); i > 0; i--) + if (nusers(P[i-1]) > 1) + break; + P_WIDTH = i; +endcode + +match ffP + select ffP->type.in($dff, $dffe) + select nusers(port(ffP, \D)) == 2 + filter param(ffP, \WIDTH).as_int() == P_WIDTH + filter port(ffP, \D) == port(dsp, \P).extract(0, P_WIDTH) + index param(ffP, \CLK_POLARITY) === State::S1 + optional +endmatch + +// $mux cell left behind by dff2dffe +// would prefer not to run 'opt_expr -mux_undef' +// since that would lose information helpful for +// efficient wide-mux inference +match muxP + if !ffP + select muxP->type.in($mux) + select port(muxP, \A).is_fully_undef() + filter param(muxP, \WIDTH).as_int() == P_WIDTH + filter port(muxP, \B) == port(dsp, \P).extract(0, P_WIDTH) + select nusers(port(muxP, \B)) == 2 + optional +endmatch + match ffY - select ffY->type.in($dff) + if muxP + select ffY->type.in($dff, $dffe) select nusers(port(ffY, \D)) == 2 - index port(ffY, \D) === port(mul, \Y) - index port(ffY, \CLK_POLARITY) === State::S1 - optional + index port(ffY, \D) === port(muxP, \Y) endmatch -code sigY clock - sigY = port(mul, \Y); +code ffP clock + if (ffY) + ffP = ffY; - if (ffY) { - sigY = port(ffY, \Q); - SigBit c = port(ffY, \CLK).as_bit(); + if (ffP) { + SigBit c = port(ffP, \CLK).as_bit(); if (clock != SigBit() && c != clock) reject; -- 2.30.2