mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-12 20:18:20 +00:00
Add a xilinx_dsp_cascade matcher for PCIN -> PCOUT
This commit is contained in:
parent
1844498c5f
commit
ed187ef1cf
|
@ -22,8 +22,9 @@ $(eval $(call add_extra_objs,passes/pmgen/ice40_wrapcarry_pm.h))
|
||||||
# --------------------------------------
|
# --------------------------------------
|
||||||
|
|
||||||
OBJS += passes/pmgen/xilinx_dsp.o
|
OBJS += passes/pmgen/xilinx_dsp.o
|
||||||
passes/pmgen/xilinx_dsp.o: passes/pmgen/xilinx_dsp_pm.h
|
passes/pmgen/xilinx_dsp.o: passes/pmgen/xilinx_dsp_pm.h passes/pmgen/xilinx_dsp_cascade_pm.h
|
||||||
$(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp_pm.h))
|
$(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp_pm.h))
|
||||||
|
$(eval $(call add_extra_objs,passes/pmgen/xilinx_dsp_cascade_pm.h))
|
||||||
|
|
||||||
# --------------------------------------
|
# --------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ USING_YOSYS_NAMESPACE
|
||||||
PRIVATE_NAMESPACE_BEGIN
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
#include "passes/pmgen/xilinx_dsp_pm.h"
|
#include "passes/pmgen/xilinx_dsp_pm.h"
|
||||||
|
#include "passes/pmgen/xilinx_dsp_cascade_pm.h"
|
||||||
|
|
||||||
static Cell* addDsp(Module *module) {
|
static Cell* addDsp(Module *module) {
|
||||||
Cell *cell = module->addCell(NEW_ID, ID(DSP48E1));
|
Cell *cell = module->addCell(NEW_ID, ID(DSP48E1));
|
||||||
|
@ -253,9 +254,9 @@ void pack_xilinx_simd(Module *module, const std::vector<Cell*> &selected_cells)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void pack_xilinx_dsp(dict<SigBit, Cell*> &bit_to_driver, xilinx_dsp_pm &pm)
|
void pack_xilinx_dsp(xilinx_dsp_pm &pm)
|
||||||
{
|
{
|
||||||
auto &st = pm.st_xilinx_dsp;
|
auto &st = pm.st_xilinx_dsp_pack;
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
log("\n");
|
log("\n");
|
||||||
|
@ -487,9 +488,6 @@ void pack_xilinx_dsp(dict<SigBit, Cell*> &bit_to_driver, xilinx_dsp_pm &pm)
|
||||||
P.append(pm.module->addWire(NEW_ID, 48-GetSize(P)));
|
P.append(pm.module->addWire(NEW_ID, 48-GetSize(P)));
|
||||||
cell->setPort(ID(P), P);
|
cell->setPort(ID(P), P);
|
||||||
|
|
||||||
bit_to_driver.insert(std::make_pair(P[0], cell));
|
|
||||||
bit_to_driver.insert(std::make_pair(P[17], cell));
|
|
||||||
|
|
||||||
pm.blacklist(cell);
|
pm.blacklist(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,7 +506,7 @@ struct XilinxDspPass : public Pass {
|
||||||
log("Multiply-accumulate operations using the post-adder with feedback on the 'C'\n");
|
log("Multiply-accumulate operations using the post-adder with feedback on the 'C'\n");
|
||||||
log("input will be folded into the DSP. In this scenario only, the 'C' input can be\n");
|
log("input will be folded into the DSP. In this scenario only, the 'C' input can be\n");
|
||||||
log("used to override the current accumulation result with a new value, which will\n");
|
log("used to override the current accumulation result with a new value, which will\n");
|
||||||
log("be added to the multiplier result to form the next accumulation result.\n");
|
log("be added to the multiplier result to form the next accumulation result.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("Use of the dedicated 'PCOUT' -> 'PCIN' cascade path is detected for 'P' -> 'C'\n");
|
log("Use of the dedicated 'PCOUT' -> 'PCIN' cascade path is detected for 'P' -> 'C'\n");
|
||||||
log("connections (optionally, where 'P' is right-shifted by 18-bits and used as an\n");
|
log("connections (optionally, where 'P' is right-shifted by 18-bits and used as an\n");
|
||||||
|
@ -545,52 +543,10 @@ struct XilinxDspPass : public Pass {
|
||||||
pack_xilinx_simd(module, module->selected_cells());
|
pack_xilinx_simd(module, module->selected_cells());
|
||||||
|
|
||||||
xilinx_dsp_pm pm(module, module->selected_cells());
|
xilinx_dsp_pm pm(module, module->selected_cells());
|
||||||
dict<SigBit, Cell*> bit_to_driver;
|
pm.run_xilinx_dsp_pack(pack_xilinx_dsp);
|
||||||
auto f = [&bit_to_driver](xilinx_dsp_pm &pm){ pack_xilinx_dsp(bit_to_driver, pm); };
|
|
||||||
pm.run_xilinx_dsp(f);
|
|
||||||
|
|
||||||
auto &unextend = pm.ud_xilinx_dsp.unextend;
|
xilinx_dsp_cascade_pm pmc(module, module->selected_cells());
|
||||||
// Look for ability to convert C input from another DSP into PCIN
|
pmc.run_xilinx_dsp_cascade();
|
||||||
// NB: Needs to be done after pattern matcher has folded all
|
|
||||||
// $add cells into the DSP
|
|
||||||
for (auto cell : module->cells()) {
|
|
||||||
if (cell->type != ID(DSP48E1))
|
|
||||||
continue;
|
|
||||||
if (cell->parameters.at(ID(CREG), State::S1).as_bool())
|
|
||||||
continue;
|
|
||||||
SigSpec &opmode = cell->connections_.at(ID(OPMODE));
|
|
||||||
if (opmode.extract(4,3) != Const::from_string("011"))
|
|
||||||
continue;
|
|
||||||
SigSpec C = unextend(pm.sigmap(cell->getPort(ID(C))));
|
|
||||||
if (!C[0].wire)
|
|
||||||
continue;
|
|
||||||
auto it = bit_to_driver.find(C[0]);
|
|
||||||
if (it == bit_to_driver.end())
|
|
||||||
continue;
|
|
||||||
auto driver = it->second;
|
|
||||||
|
|
||||||
SigSpec P = driver->getPort(ID(P));
|
|
||||||
if (GetSize(P) >= GetSize(C) && P.extract(0, GetSize(C)) == C) {
|
|
||||||
cell->setPort(ID(C), Const(0, 48));
|
|
||||||
Wire *cascade = module->addWire(NEW_ID, 48);
|
|
||||||
driver->setPort(ID(PCOUT), cascade);
|
|
||||||
cell->setPort(ID(PCIN), cascade);
|
|
||||||
opmode[6] = State::S0;
|
|
||||||
opmode[5] = State::S0;
|
|
||||||
opmode[4] = State::S1;
|
|
||||||
bit_to_driver.erase(it);
|
|
||||||
}
|
|
||||||
else if (GetSize(P) >= GetSize(C)+17 && P.extract(17, GetSize(C)) == C) {
|
|
||||||
cell->setPort(ID(C), Const(0, 48));
|
|
||||||
Wire *cascade = module->addWire(NEW_ID, 48);
|
|
||||||
driver->setPort(ID(PCOUT), cascade);
|
|
||||||
cell->setPort(ID(PCIN), cascade);
|
|
||||||
opmode[6] = State::S1;
|
|
||||||
opmode[5] = State::S0;
|
|
||||||
opmode[4] = State::S1;
|
|
||||||
bit_to_driver.erase(it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} XilinxDspPass;
|
} XilinxDspPass;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
pattern xilinx_dsp
|
pattern xilinx_dsp_pack
|
||||||
|
|
||||||
udata <std::function<SigSpec(const SigSpec&)>> unextend
|
udata <std::function<SigSpec(const SigSpec&)>> unextend
|
||||||
state <SigBit> clock
|
state <SigBit> clock
|
||||||
|
|
94
passes/pmgen/xilinx_dsp_cascade.pmg
Normal file
94
passes/pmgen/xilinx_dsp_cascade.pmg
Normal file
|
@ -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
|
Loading…
Reference in a new issue