diff --git a/passes/pmgen/xilinx_dsp.cc b/passes/pmgen/xilinx_dsp.cc index 389f0cb56..cd88f9449 100644 --- a/passes/pmgen/xilinx_dsp.cc +++ b/passes/pmgen/xilinx_dsp.cc @@ -37,16 +37,26 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) log("ffA: %s\n", log_id(st.ffA, "--")); log("ffB: %s\n", log_id(st.ffB, "--")); log("dsp: %s\n", log_id(st.dsp, "--")); + log("addAB: %s\n", log_id(st.addAB, "--")); log("ffP: %s\n", log_id(st.ffP, "--")); //log("muxP: %s\n", log_id(st.muxP, "--")); log("sigPused: %s\n", log_signal(st.sigPused)); - log_module(pm.module); #endif - log("Analysing %s.%s for Xilinx DSP register packing.\n", log_id(pm.module), log_id(st.dsp)); + log("Analysing %s.%s for Xilinx DSP packing.\n", log_id(pm.module), log_id(st.dsp)); Cell *cell = st.dsp; - log_assert(cell); + SigSpec P = st.sigP; + + if (st.addAB) { + log(" adder %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type)); + cell->setPort("\\C", st.sigC.extend_u0(48, true)); + SigSpec &opmode = cell->connections_.at("\\OPMODE"); + opmode[6] = State::S0; + opmode[5] = State::S1; + opmode[4] = State::S1; + pm.autoremove(st.addAB); + } if (st.clock != SigBit()) { @@ -79,7 +89,6 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) else log_abort(); } if (st.ffP) { - SigSpec P = cell->getPort("\\P"); SigSpec D; //if (st.muxP) // D = st.muxP->getPort("\\B"); @@ -87,7 +96,6 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) D = st.ffP->getPort("\\D"); SigSpec Q = st.ffP->getPort("\\Q"); P.replace(pm.sigmap(D), Q); - cell->setPort("\\P", P); cell->setParam("\\PREG", State::S1); if (st.ffP->type == "$dff") cell->setPort("\\CEP", State::S1); @@ -112,6 +120,10 @@ void pack_xilinx_dsp(xilinx_dsp_pm &pm) log("\n"); } + if (GetSize(P) < 48) + P.append(pm.module->addWire(NEW_ID, 48-GetSize(P))); + cell->setPort("\\P", P); + pm.blacklist(cell); } diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index f95de9410..4f5fae8df 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -1,7 +1,8 @@ pattern xilinx_dsp state clock -state sigPused +state sigC sigP sigPused +state addAB match dsp select dsp->type.in(\DSP48E1) @@ -43,13 +44,69 @@ code clock } endcode +code sigP + sigP = port(dsp, \P); +endcode + +match addA + select addA->type.in($add) + select param(addA, \A_SIGNED).as_bool() && param(addA, \B_SIGNED).as_bool() + select nusers(port(addA, \A)) == 2 + //index port(addA, \A) === sigP.extract(0, param(addA, \A_WIDTH).as_int()) + filter GetSize(sigP) >= param(addA, \A_WIDTH).as_int() + filter port(addA, \A) == sigP.extract(0, param(addA, \A_WIDTH).as_int()) + optional +endmatch + +match addB + if !addA + select addB->type.in($add, $sub) + select param(addB, \A_SIGNED).as_bool() && param(addB, \B_SIGNED).as_bool() + select nusers(port(addB, \B)) == 2 + //index port(addB, \B) === sigP.extract(0, param(addB, \B_WIDTH).as_int()) + filter GetSize(sigP) >= param(addB, \B_WIDTH).as_int() + filter port(addB, \B) == sigP.extract(0, param(addB, \B_WIDTH).as_int()) + optional +endmatch + +code addAB sigC sigP + bool C_SIGNED = false; + if (addA) { + addAB = addA; + sigC = port(addAB, \B); + C_SIGNED = param(addAB, \B_SIGNED).as_bool(); + } + if (addB) { + addAB = addB; + sigC = port(addAB, \A); + C_SIGNED = param(addAB, \B_SIGNED).as_bool(); + } + if (addAB) { + // Ensure that adder is not used + SigSpec opmodeZ = port(dsp, \OPMODE).extract(4,3); + if (!opmodeZ.is_fully_zero()) + reject; + + int natural_mul_width = GetSize(port(dsp, \A)) + GetSize(port(dsp, \B)); + int actual_mul_width = GetSize(sigP); + int actual_acc_width = GetSize(sigC); + + if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width)) + reject; + //if ((actual_acc_width != actual_mul_width) && (param(dsp, \A_SIGNED).as_bool() != param(addAB, \A_SIGNED).as_bool())) + // reject; + + sigP = port(addAB, \Y); + sigC.extend_u0(32, C_SIGNED); + } +endcode + // Extract the bits of P that actually have a consumer // (as opposed to being a dummy) code sigPused - SigSpec P = port(dsp, \P); - for (int i = 0; i < GetSize(P); i++) - if (P[i].wire && nusers(P[i]) > 1) - sigPused.append(P[i]); + for (int i = 0; i < GetSize(sigP); i++) + if (sigP[i].wire && nusers(sigP[i]) > 1) + sigPused.append(sigP[i]); endcode match ffP diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 7b1fe5e3b..a54b3ac52 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -287,6 +287,8 @@ struct SynthXilinxPass : public ScriptPass if (!nodsp || help_mode) { // NB: Xilinx multipliers are signed only run("techmap -map +/mul2dsp.v -map +/xilinx/dsp_map.v -D DSP_A_MAXWIDTH=25 -D DSP_B_MAXWIDTH=18 -D DSP_SIGNEDONLY=1 -D DSP_NAME=$__MUL25X18", "(skip if '-nodsp')"); + run("opt_expr -fine", " (skip if '-nodsp')"); + run("wreduce", " (skip if '-nodsp')"); run("xilinx_dsp", " (skip if '-nodsp')"); run("chtype -set $mul t:$__soft_mul"," (skip if '-nodsp')"); }