3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-06-06 06:03:23 +00:00

Support unregistered cascades for A and B inputs

This commit is contained in:
Eddie Hung 2019-12-23 12:38:18 -08:00
parent d00533eaa8
commit 71cac30309

View file

@ -119,6 +119,7 @@ finally
add_siguser(cascade, dsp_pcin); add_siguser(cascade, dsp_pcin);
add_siguser(cascade, dsp); add_siguser(cascade, dsp);
if (dsp->type.in(\DSP48E1))
dsp->setParam(ID(ACASCREG), AREG); dsp->setParam(ID(ACASCREG), AREG);
dsp_pcin->setParam(ID(A_INPUT), Const("CASCADE")); dsp_pcin->setParam(ID(A_INPUT), Const("CASCADE"));
@ -126,14 +127,34 @@ finally
} }
if (BREG >= 0) { if (BREG >= 0) {
Wire *cascade = module->addWire(NEW_ID, 18); Wire *cascade = module->addWire(NEW_ID, 18);
if (dsp->type.in(\DSP48A, \DSP48A1)) {
// According to UG389 p9 [https://www.xilinx.com/support/documentation/user_guides/ug389.pdf]
// "The DSP48A1 component uses this input when cascading
// BCOUT from an adjacent DSP48A1 slice. The tools then
// translate BCOUT cascading to the dedicated BCIN input
// and set the B_INPUT attribute for implementation."
dsp_pcin->setPort(ID(B), cascade);
}
else {
dsp_pcin->setPort(ID(B), Const(0, 18)); dsp_pcin->setPort(ID(B), Const(0, 18));
dsp_pcin->setPort(ID(BCIN), cascade); dsp_pcin->setPort(ID(BCIN), cascade);
}
dsp->setPort(ID(BCOUT), cascade); dsp->setPort(ID(BCOUT), cascade);
add_siguser(cascade, dsp_pcin); add_siguser(cascade, dsp_pcin);
add_siguser(cascade, dsp); add_siguser(cascade, dsp);
if (dsp->type.in(\DSP48E1)) {
dsp->setParam(ID(BCASCREG), BREG); dsp->setParam(ID(BCASCREG), BREG);
// According to UG389 p13 [https://www.xilinx.com/support/documentation/user_guides/ug389.pdf]
// "The attribute is only used by place and route tools and
// is not necessary for the users to set for synthesis. The
// attribute is determined by the connection to the B port
// of the DSP48A1 slice. If the B port is connected to the
// BCOUT of another DSP48A1 slice, then the tools automatically
// set the attribute to 'CASCADE', otherwise it is set to
// 'DIRECT'".
dsp_pcin->setParam(ID(B_INPUT), Const("CASCADE")); dsp_pcin->setParam(ID(B_INPUT), Const("CASCADE"));
}
log_debug("BCOUT -> BCIN cascade for %s -> %s\n", log_id(dsp), log_id(dsp_pcin)); log_debug("BCOUT -> BCIN cascade for %s -> %s\n", log_id(dsp), log_id(dsp_pcin));
} }
@ -202,21 +223,23 @@ code next
endcode endcode
// (3) For this subequent DSP48E1 match (i.e. PCOUT -> PCIN cascade exists) // (3) For this subequent DSP48E1 match (i.e. PCOUT -> PCIN cascade exists)
// if (a) the previous DSP48E1 uses either the A2REG or A1REG, (b) this // if (a) this DSP48 does not use A2REG nor A1REG, (b) this DSP48E1 does
// DSP48 does not use A2REG nor A1REG, (c) this DSP48E1 does not already // not already have an ACOUT -> ACIN cascade, (c) the previous DSP does
// have an ACOUT -> ACIN cascade, (d) the previous DSP does not already // not already use its ACOUT port, then examine if an ACOUT -> ACIN cascade
// use its ACOUT port, then examine if an ACOUT -> ACIN cascade // opportunity exists if (i) A ports are identical, or (ii) separated by a
// opportunity exists by matching for a $dff-with-optional-clock-enable- // $dff-with-optional-clock-enable-or-reset and checking that the 'D' input
// or-reset and checking that the 'D' input of this register is the same // of this register is the same as the 'A' input of the previous DSP
// as the 'A' input of the previous DSP // TODO: Check for two levels of flops, instead of just one
code argQ clock AREG code argQ clock AREG
AREG = -1; AREG = -1;
if (next) { if (next && next->type.in(\DSP48E1)) {
Cell *prev = std::get<0>(chain.back()); Cell *prev = std::get<0>(chain.back());
if (param(prev, \AREG, 2).as_int() > 0 && if (param(next, \AREG, 2).as_int() == 0 &&
param(next, \AREG, 2).as_int() > 0 &&
param(next, \A_INPUT, Const("DIRECT")).decode_string() == "DIRECT" && param(next, \A_INPUT, Const("DIRECT")).decode_string() == "DIRECT" &&
nusers(port(prev, \ACOUT, SigSpec())) <= 1) { nusers(port(prev, \ACOUT, SigSpec())) <= 1) {
if (port(prev, \A) == port(next, \A))
AREG = 0;
else {
argQ = unextend(port(next, \A)); argQ = unextend(port(next, \A));
clock = port(prev, \CLK); clock = port(prev, \CLK);
subpattern(in_dffe); subpattern(in_dffe);
@ -235,6 +258,7 @@ reject_AREG: ;
} }
} }
} }
}
endcode endcode
// (4) Same as (3) but for BCOUT -> BCIN cascade // (4) Same as (3) but for BCOUT -> BCIN cascade
@ -242,11 +266,13 @@ code argQ clock BREG
BREG = -1; BREG = -1;
if (next) { if (next) {
Cell *prev = std::get<0>(chain.back()); Cell *prev = std::get<0>(chain.back());
if (param(prev, \BREG, 2).as_int() > 0 && if (((next->type.in(\DSP48A, \DSP48A1) && param(next, \B1REG, 1) == 0) || (next->type.in(\DSP48E1) && param(next, \BREG, 2).as_int() == 0)) &&
param(next, \BREG, 2).as_int() > 0 &&
param(next, \B_INPUT, Const("DIRECT")).decode_string() == "DIRECT" && param(next, \B_INPUT, Const("DIRECT")).decode_string() == "DIRECT" &&
port(next, \BCIN, SigSpec()).is_fully_zero() && port(next, \BCIN, SigSpec()).is_fully_zero() &&
nusers(port(prev, \BCOUT, SigSpec())) <= 1) { nusers(port(prev, \BCOUT, SigSpec())) <= 1) {
if (port(prev, \B) == port(next, \B))
BREG = 0;
else {
argQ = unextend(port(next, \B)); argQ = unextend(port(next, \B));
clock = port(prev, \CLK); clock = port(prev, \CLK);
subpattern(in_dffe); subpattern(in_dffe);
@ -265,6 +291,7 @@ reject_BREG: ;
} }
} }
} }
}
endcode endcode
// (5) Recursively go to (2.1) until no more matches possible, recording the // (5) Recursively go to (2.1) until no more matches possible, recording the