USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-template<class T> bool includes(const T &lhs, const T &rhs) {
+template<class T> inline bool includes(const T &lhs, const T &rhs) {
return std::includes(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
+#include <set>
#include "passes/pmgen/xilinx_dsp_pm.h"
-void pack_xilinx_dsp(xilinx_dsp_pm &pm)
+void pack_xilinx_dsp(dict<SigBit, Cell*> &bit_to_driver, xilinx_dsp_pm &pm)
{
auto &st = pm.st_xilinx_dsp;
#if 1
log("\n");
- 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("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));
#endif
log("Analysing %s.%s for Xilinx DSP packing.\n", log_id(pm.module), log_id(st.dsp));
Cell *cell = st.dsp;
+ bit_to_driver.insert(std::make_pair(cell->getPort("\\P")[17], cell));
SigSpec P = st.sigP;
if (st.addAB) {
+ log_assert(st.addAB->getParam("\\A_SIGNED").as_bool());
+ log_assert(st.addAB->getParam("\\B_SIGNED").as_bool());
log(" adder %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type));
- cell->setPort("\\C", st.sigC.extend_u0(48, true));
+
+ SigSpec C = st.sigC;
+ C.extend_u0(48, true);
+ cell->setPort("\\C", C);
SigSpec &opmode = cell->connections_.at("\\OPMODE");
opmode[6] = State::S0;
opmode[5] = State::S1;
}
extra_args(args, argidx, design);
- for (auto module : design->selected_modules())
- xilinx_dsp_pm(module, module->selected_cells()).run_xilinx_dsp(pack_xilinx_dsp);
+ for (auto module : design->selected_modules()) {
+ xilinx_dsp_pm pm(module, module->selected_cells());
+ dict<SigBit, Cell*> bit_to_driver;
+ auto f = [&bit_to_driver](xilinx_dsp_pm &pm){ pack_xilinx_dsp(bit_to_driver, pm); };
+ pm.run_xilinx_dsp(f);
+
+ // 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 != "\\DSP48E1")
+ continue;
+ SigSpec &opmode = cell->connections_.at("\\OPMODE");
+ if (opmode.extract(4,3) != Const::from_string("011"))
+ continue;
+ SigSpec C = pm.sigmap(cell->getPort("\\C"));
+ if (C.has_const())
+ continue;
+ auto it = bit_to_driver.find(C[0]);
+ if (it == bit_to_driver.end())
+ continue;
+ auto driver = it->second;
+
+ // Unextend C
+ int i;
+ for (i = GetSize(C)-1; i > 0; i--)
+ if (C[i] != C[i-1])
+ break;
+ if (i > 48-17)
+ continue;
+ if (driver->getPort("\\P").extract(17, i) == C.extract(0, i)) {
+ cell->setPort("\\C", Const(0, 48));
+ Wire *cascade = module->addWire(NEW_ID, 48);
+ driver->setPort("\\PCOUT", cascade);
+ cell->setPort("\\PCIN", cascade);
+ opmode[6] = State::S1;
+ opmode[5] = State::S0;
+ opmode[4] = State::S1;
+ bit_to_driver.erase(it);
+ }
+ }
+ }
}
} XilinxDspPass;
pattern xilinx_dsp
state <SigBit> clock
+state <std::set<SigBit>> sigAset sigBset
state <SigSpec> sigC sigP sigPused
state <Cell*> addAB
select dsp->type.in(\DSP48E1)
endmatch
+code sigAset sigBset
+ SigSpec A = port(dsp, \A);
+ A.remove_const();
+ sigAset = A.to_sigbit_set();
+ SigSpec B = port(dsp, \B);
+ B.remove_const();
+ sigBset = B.to_sigbit_set();
+endcode
+
match ffA
if param(dsp, \AREG).as_int() == 0
- if !port(dsp, \A).remove_const().empty()
+ if !sigAset.empty()
select ffA->type.in($dff)
// DSP48E1 does not support clock inversion
select param(ffA, \CLK_POLARITY).as_bool()
- filter includes(port(ffA, \Q).to_sigbit_set(), port(dsp, \A).remove_const().to_sigbit_set())
+ filter includes(port(ffA, \Q).to_sigbit_set(), sigAset)
optional
endmatch
match ffB
if param(dsp, \BREG).as_int() == 0
- if !port(dsp, \B).remove_const().empty()
+ if !sigBset.empty()
select ffB->type.in($dff)
// DSP48E1 does not support clock inversion
select param(ffB, \CLK_POLARITY).as_bool()
- filter includes(port(ffB, \Q).to_sigbit_set(), port(dsp, \B).remove_const().to_sigbit_set())
+ filter includes(port(ffB, \Q).to_sigbit_set(), sigBset)
optional
endmatch
index <int> nusers(port(addB, \B)) === 2
//index <SigSpec> port(addB, \B) === sigP.extract(0, param(addB, \B_WIDTH).as_int())
filter param(addB, \B_WIDTH).as_int() <= GetSize(sigP)
- filter port(addB, \B) == sigP.extract(0, 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
// reject;
sigP = port(addAB, \Y);
- sigC.extend_u0(32, C_SIGNED);
}
endcode