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())
{
else log_abort();
}
if (st.ffP) {
- SigSpec P = cell->getPort("\\P");
SigSpec D;
//if (st.muxP)
// D = st.muxP->getPort("\\B");
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);
log("\n");
}
+ if (GetSize(P) < 48)
+ P.append(pm.module->addWire(NEW_ID, 48-GetSize(P)));
+ cell->setPort("\\P", P);
+
pm.blacklist(cell);
}
pattern xilinx_dsp
state <SigBit> clock
-state <SigSpec> sigPused
+state <SigSpec> sigC sigP sigPused
+state <Cell*> addAB
match dsp
select dsp->type.in(\DSP48E1)
}
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 <SigSpec> 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 <SigSpec> 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