mirror of https://github.com/YosysHQ/yosys.git
synth_ice40: Use opt_dff.
The main part is converting ice40_dsp to recognize the new FF types created in opt_dff instead of trying to recognize the mux patterns on its own. The fsm call has been moved upwards because the passes cannot deal with $dffe/$sdff*, and other optimizations don't help it much anyway.
This commit is contained in:
parent
8501342fc5
commit
cf60699884
|
@ -31,15 +31,15 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
|
|||
|
||||
log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(st.mul));
|
||||
|
||||
log_debug("ffA: %s %s %s\n", log_id(st.ffA, "--"), log_id(st.ffAholdmux, "--"), log_id(st.ffArstmux, "--"));
|
||||
log_debug("ffB: %s %s %s\n", log_id(st.ffB, "--"), log_id(st.ffBholdmux, "--"), log_id(st.ffBrstmux, "--"));
|
||||
log_debug("ffCD: %s %s\n", log_id(st.ffCD, "--"), log_id(st.ffCDholdmux, "--"));
|
||||
log_debug("ffA: %s\n", log_id(st.ffA, "--"));
|
||||
log_debug("ffB: %s\n", log_id(st.ffB, "--"));
|
||||
log_debug("ffCD: %s\n", log_id(st.ffCD, "--"));
|
||||
log_debug("mul: %s\n", log_id(st.mul, "--"));
|
||||
log_debug("ffFJKG: %s\n", log_id(st.ffFJKG, "--"));
|
||||
log_debug("ffH: %s\n", log_id(st.ffH, "--"));
|
||||
log_debug("add: %s\n", log_id(st.add, "--"));
|
||||
log_debug("mux: %s\n", log_id(st.mux, "--"));
|
||||
log_debug("ffO: %s %s %s\n", log_id(st.ffO, "--"), log_id(st.ffOholdmux, "--"), log_id(st.ffOrstmux, "--"));
|
||||
log_debug("ffO: %s\n", log_id(st.ffO, "--"));
|
||||
log_debug("\n");
|
||||
|
||||
if (GetSize(st.sigA) > 16) {
|
||||
|
@ -97,16 +97,16 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
|
|||
cell->setParam(ID(D_REG), st.ffCD ? State::S1 : State::S0);
|
||||
|
||||
SigSpec AHOLD, BHOLD, CDHOLD;
|
||||
if (st.ffAholdmux)
|
||||
AHOLD = st.ffAholdpol ? st.ffAholdmux->getPort(ID::S) : pm.module->Not(NEW_ID, st.ffAholdmux->getPort(ID::S));
|
||||
if (st.ffA && st.ffA->hasPort(ID::EN))
|
||||
AHOLD = st.ffA->getParam(ID::EN_POLARITY).as_bool() ? pm.module->Not(NEW_ID, st.ffA->getPort(ID::EN)) : st.ffA->getPort(ID::EN);
|
||||
else
|
||||
AHOLD = State::S0;
|
||||
if (st.ffBholdmux)
|
||||
BHOLD = st.ffBholdpol ? st.ffBholdmux->getPort(ID::S) : pm.module->Not(NEW_ID, st.ffBholdmux->getPort(ID::S));
|
||||
if (st.ffB && st.ffB->hasPort(ID::EN))
|
||||
BHOLD = st.ffB->getParam(ID::EN_POLARITY).as_bool() ? pm.module->Not(NEW_ID, st.ffB->getPort(ID::EN)) : st.ffB->getPort(ID::EN);
|
||||
else
|
||||
BHOLD = State::S0;
|
||||
if (st.ffCDholdmux)
|
||||
CDHOLD = st.ffCDholdpol ? st.ffCDholdmux->getPort(ID::S) : pm.module->Not(NEW_ID, st.ffCDholdmux->getPort(ID::S));
|
||||
if (st.ffCD && st.ffCD->hasPort(ID::EN))
|
||||
CDHOLD = st.ffCD->getParam(ID::EN_POLARITY).as_bool() ? pm.module->Not(NEW_ID, st.ffCD->getPort(ID::EN)) : st.ffCD->getPort(ID::EN);
|
||||
else
|
||||
CDHOLD = State::S0;
|
||||
cell->setPort(ID(AHOLD), AHOLD);
|
||||
|
@ -115,12 +115,12 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
|
|||
cell->setPort(ID(DHOLD), CDHOLD);
|
||||
|
||||
SigSpec IRSTTOP, IRSTBOT;
|
||||
if (st.ffArstmux)
|
||||
IRSTTOP = st.ffArstpol ? st.ffArstmux->getPort(ID::S) : pm.module->Not(NEW_ID, st.ffArstmux->getPort(ID::S));
|
||||
if (st.ffA && st.ffA->hasPort(ID::ARST))
|
||||
IRSTTOP = st.ffA->getParam(ID::ARST_POLARITY).as_bool() ? st.ffA->getPort(ID::ARST) : pm.module->Not(NEW_ID, st.ffA->getPort(ID::ARST));
|
||||
else
|
||||
IRSTTOP = State::S0;
|
||||
if (st.ffBrstmux)
|
||||
IRSTBOT = st.ffBrstpol ? st.ffBrstmux->getPort(ID::S) : pm.module->Not(NEW_ID, st.ffBrstmux->getPort(ID::S));
|
||||
if (st.ffB && st.ffB->hasPort(ID::ARST))
|
||||
IRSTBOT = st.ffB->getParam(ID::ARST_POLARITY).as_bool() ? st.ffB->getPort(ID::ARST) : pm.module->Not(NEW_ID, st.ffB->getPort(ID::ARST));
|
||||
else
|
||||
IRSTBOT = State::S0;
|
||||
cell->setPort(ID(IRSTTOP), IRSTTOP);
|
||||
|
@ -207,16 +207,16 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
|
|||
}
|
||||
|
||||
SigSpec OHOLD;
|
||||
if (st.ffOholdmux)
|
||||
OHOLD = st.ffOholdpol ? st.ffOholdmux->getPort(ID::S) : pm.module->Not(NEW_ID, st.ffOholdmux->getPort(ID::S));
|
||||
if (st.ffO && st.ffO->hasPort(ID::EN))
|
||||
OHOLD = st.ffO->getParam(ID::EN_POLARITY).as_bool() ? pm.module->Not(NEW_ID, st.ffO->getPort(ID::EN)) : st.ffO->getPort(ID::EN);
|
||||
else
|
||||
OHOLD = State::S0;
|
||||
cell->setPort(ID(OHOLDTOP), OHOLD);
|
||||
cell->setPort(ID(OHOLDBOT), OHOLD);
|
||||
|
||||
SigSpec ORST;
|
||||
if (st.ffOrstmux)
|
||||
ORST = st.ffOrstpol ? st.ffOrstmux->getPort(ID::S) : pm.module->Not(NEW_ID, st.ffOrstmux->getPort(ID::S));
|
||||
if (st.ffO && st.ffO->hasPort(ID::ARST))
|
||||
ORST = st.ffO->getParam(ID::ARST_POLARITY).as_bool() ? st.ffO->getPort(ID::ARST) : pm.module->Not(NEW_ID, st.ffO->getPort(ID::ARST));
|
||||
else
|
||||
ORST = State::S0;
|
||||
cell->setPort(ID(ORSTTOP), ORST);
|
||||
|
@ -228,6 +228,8 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
|
|||
acc_reset = st.mux->getPort(ID::S);
|
||||
else
|
||||
acc_reset = pm.module->Not(NEW_ID, st.mux->getPort(ID::S));
|
||||
} else if (st.ffO && st.ffO->hasPort(ID::SRST)) {
|
||||
acc_reset = st.ffO->getParam(ID::SRST_POLARITY).as_bool() ? st.ffO->getPort(ID::SRST) : pm.module->Not(NEW_ID, st.ffO->getPort(ID::SRST));
|
||||
}
|
||||
cell->setPort(ID(OLOADTOP), acc_reset);
|
||||
cell->setPort(ID(OLOADBOT), acc_reset);
|
||||
|
|
|
@ -6,20 +6,16 @@ state <SigSpec> sigA sigB sigCD sigH sigO
|
|||
state <Cell*> add mux
|
||||
state <IdString> addAB muxAB
|
||||
|
||||
state <bool> ffAholdpol ffBholdpol ffCDholdpol ffOholdpol
|
||||
state <bool> ffArstpol ffBrstpol ffCDrstpol ffOrstpol
|
||||
|
||||
state <Cell*> ffA ffAholdmux ffArstmux ffB ffBholdmux ffBrstmux ffCD ffCDholdmux
|
||||
state <Cell*> ffFJKG ffH ffO ffOholdmux ffOrstmux
|
||||
state <Cell*> ffA ffB ffCD
|
||||
state <Cell*> ffFJKG ffH ffO
|
||||
|
||||
// subpattern
|
||||
state <bool> argSdff
|
||||
state <SigSpec> argQ argD
|
||||
state <bool> ffholdpol ffrstpol
|
||||
state <int> ffoffset
|
||||
udata <SigSpec> dffD dffQ
|
||||
udata <SigBit> dffclock
|
||||
udata <Cell*> dff dffholdmux dffrstmux
|
||||
udata <bool> dffholdpol dffrstpol dffclock_pol
|
||||
udata <Cell*> dff
|
||||
udata <bool> dffclock_pol
|
||||
|
||||
match mul
|
||||
select mul->type.in($mul, \SB_MAC16)
|
||||
|
@ -64,7 +60,7 @@ code sigA sigB sigH
|
|||
log_assert(nusers(O.extract_end(i)) <= 1);
|
||||
endcode
|
||||
|
||||
code argQ ffA ffAholdmux ffArstmux ffAholdpol ffArstpol sigA clock clock_pol
|
||||
code argQ ffA sigA clock clock_pol
|
||||
if (mul->type != \SB_MAC16 || !param(mul, \A_REG).as_bool()) {
|
||||
argQ = sigA;
|
||||
subpattern(in_dffe);
|
||||
|
@ -72,20 +68,12 @@ code argQ ffA ffAholdmux ffArstmux ffAholdpol ffArstpol sigA clock clock_pol
|
|||
ffA = dff;
|
||||
clock = dffclock;
|
||||
clock_pol = dffclock_pol;
|
||||
if (dffrstmux) {
|
||||
ffArstmux = dffrstmux;
|
||||
ffArstpol = dffrstpol;
|
||||
}
|
||||
if (dffholdmux) {
|
||||
ffAholdmux = dffholdmux;
|
||||
ffAholdpol = dffholdpol;
|
||||
}
|
||||
sigA = dffD;
|
||||
}
|
||||
}
|
||||
endcode
|
||||
|
||||
code argQ ffB ffBholdmux ffBrstmux ffBholdpol ffBrstpol sigB clock clock_pol
|
||||
code argQ ffB sigB clock clock_pol
|
||||
if (mul->type != \SB_MAC16 || !param(mul, \B_REG).as_bool()) {
|
||||
argQ = sigB;
|
||||
subpattern(in_dffe);
|
||||
|
@ -93,47 +81,44 @@ code argQ ffB ffBholdmux ffBrstmux ffBholdpol ffBrstpol sigB clock clock_pol
|
|||
ffB = dff;
|
||||
clock = dffclock;
|
||||
clock_pol = dffclock_pol;
|
||||
if (dffrstmux) {
|
||||
ffBrstmux = dffrstmux;
|
||||
ffBrstpol = dffrstpol;
|
||||
}
|
||||
if (dffholdmux) {
|
||||
ffBholdmux = dffholdmux;
|
||||
ffBholdpol = dffholdpol;
|
||||
}
|
||||
sigB = dffD;
|
||||
}
|
||||
}
|
||||
endcode
|
||||
|
||||
code argD ffFJKG sigH clock clock_pol
|
||||
code argD argSdff ffFJKG sigH clock clock_pol
|
||||
if (nusers(sigH) == 2 &&
|
||||
(mul->type != \SB_MAC16 ||
|
||||
(!param(mul, \TOP_8x8_MULT_REG).as_bool() && !param(mul, \BOT_8x8_MULT_REG).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1).as_bool()))) {
|
||||
argD = sigH;
|
||||
argSdff = false;
|
||||
subpattern(out_dffe);
|
||||
if (dff) {
|
||||
// F/J/K/G do not have a CE-like (hold) input
|
||||
if (dffholdmux)
|
||||
if (dff->hasPort(\EN))
|
||||
goto reject_ffFJKG;
|
||||
|
||||
// Reset signal of F/J (IRSTTOP) and K/G (IRSTBOT)
|
||||
// shared with A and B
|
||||
if ((ffArstmux != NULL) != (dffrstmux != NULL))
|
||||
goto reject_ffFJKG;
|
||||
if ((ffBrstmux != NULL) != (dffrstmux != NULL))
|
||||
goto reject_ffFJKG;
|
||||
if (ffArstmux) {
|
||||
if (port(ffArstmux, \S) != port(dffrstmux, \S))
|
||||
goto reject_ffFJKG;
|
||||
if (ffArstpol != dffrstpol)
|
||||
if (ffA) {
|
||||
if (ffA->hasPort(\ARST) != dff->hasPort(\ARST))
|
||||
goto reject_ffFJKG;
|
||||
if (ffA->hasPort(\ARST)) {
|
||||
if (port(ffA, \ARST) != port(dff, \ARST))
|
||||
goto reject_ffFJKG;
|
||||
if (param(ffA, \ARST_POLARITY) != param(dff, \ARST_POLARITY))
|
||||
goto reject_ffFJKG;
|
||||
}
|
||||
}
|
||||
if (ffBrstmux) {
|
||||
if (port(ffBrstmux, \S) != port(dffrstmux, \S))
|
||||
goto reject_ffFJKG;
|
||||
if (ffBrstpol != dffrstpol)
|
||||
if (ffB) {
|
||||
if (ffB->hasPort(\ARST) != dff->hasPort(\ARST))
|
||||
goto reject_ffFJKG;
|
||||
if (ffB->hasPort(\ARST)) {
|
||||
if (port(ffB, \ARST) != port(dff, \ARST))
|
||||
goto reject_ffFJKG;
|
||||
if (param(ffB, \ARST_POLARITY) != param(dff, \ARST_POLARITY))
|
||||
goto reject_ffFJKG;
|
||||
}
|
||||
}
|
||||
|
||||
ffFJKG = dff;
|
||||
|
@ -146,23 +131,24 @@ reject_ffFJKG: ;
|
|||
}
|
||||
endcode
|
||||
|
||||
code argD ffH sigH sigO clock clock_pol
|
||||
code argD argSdff ffH sigH sigO clock clock_pol
|
||||
if (ffFJKG && nusers(sigH) == 2 &&
|
||||
(mul->type != \SB_MAC16 || !param(mul, \PIPELINE_16x16_MULT_REG2).as_bool())) {
|
||||
argD = sigH;
|
||||
argSdff = false;
|
||||
subpattern(out_dffe);
|
||||
if (dff) {
|
||||
// H does not have a CE-like (hold) input
|
||||
if (dffholdmux)
|
||||
if (dff->hasPort(\EN))
|
||||
goto reject_ffH;
|
||||
|
||||
// Reset signal of H (IRSTBOT) shared with B
|
||||
if ((ffBrstmux != NULL) != (dffrstmux != NULL))
|
||||
if (ffB->hasPort(\ARST) != dff->hasPort(\ARST))
|
||||
goto reject_ffH;
|
||||
if (ffBrstmux) {
|
||||
if (port(ffBrstmux, \S) != port(dffrstmux, \S))
|
||||
if (ffB->hasPort(\ARST)) {
|
||||
if (port(ffB, \ARST) != port(dff, \ARST))
|
||||
goto reject_ffH;
|
||||
if (ffBrstpol != dffrstpol)
|
||||
if (param(ffB, \ARST_POLARITY) != param(dff, \ARST_POLARITY))
|
||||
goto reject_ffH;
|
||||
}
|
||||
|
||||
|
@ -226,7 +212,7 @@ code sigO
|
|||
sigO = port(mux, \Y);
|
||||
endcode
|
||||
|
||||
code argD ffO ffOholdmux ffOrstmux ffOholdpol ffOrstpol sigO sigCD clock clock_pol cd_signed o_lo
|
||||
code argD argSdff ffO sigO sigCD clock clock_pol cd_signed o_lo
|
||||
if (mul->type != \SB_MAC16 ||
|
||||
// Ensure that register is not already used
|
||||
((param(mul, \TOPOUTPUT_SELECT).as_int() != 1 && param(mul, \BOTOUTPUT_SELECT).as_int() != 1) &&
|
||||
|
@ -238,6 +224,7 @@ code argD ffO ffOholdmux ffOrstmux ffOholdpol ffOrstpol sigO sigCD clock clock_p
|
|||
// First try entire sigO
|
||||
if (nusers(sigO) == 2) {
|
||||
argD = sigO;
|
||||
argSdff = !mux;
|
||||
subpattern(out_dffe);
|
||||
}
|
||||
|
||||
|
@ -245,6 +232,7 @@ code argD ffO ffOholdmux ffOrstmux ffOholdpol ffOrstpol sigO sigCD clock clock_p
|
|||
if (!dff && GetSize(sigO) > 16) {
|
||||
argD = sigO.extract(0, 16);
|
||||
if (nusers(argD) == 2) {
|
||||
argSdff = !mux;
|
||||
subpattern(out_dffe);
|
||||
o_lo = dff;
|
||||
}
|
||||
|
@ -254,14 +242,6 @@ code argD ffO ffOholdmux ffOrstmux ffOholdpol ffOrstpol sigO sigCD clock clock_p
|
|||
ffO = dff;
|
||||
clock = dffclock;
|
||||
clock_pol = dffclock_pol;
|
||||
if (dffrstmux) {
|
||||
ffOrstmux = dffrstmux;
|
||||
ffOrstpol = dffrstpol;
|
||||
}
|
||||
if (dffholdmux) {
|
||||
ffOholdmux = dffholdmux;
|
||||
ffOholdpol = dffholdpol;
|
||||
}
|
||||
|
||||
sigO.replace(sigO.extract(0, GetSize(dffQ)), dffQ);
|
||||
}
|
||||
|
@ -273,39 +253,44 @@ code argD ffO ffOholdmux ffOrstmux ffOholdpol ffOrstpol sigO sigCD clock clock_p
|
|||
reject;
|
||||
sigCD = port(mux, muxAB == \B ? \A : \B);
|
||||
|
||||
cd_signed = add && param(add, \A_SIGNED).as_bool() && param(add, \B_SIGNED).as_bool();
|
||||
} else if (dff && dff->hasPort(\SRST)) {
|
||||
if (sigCD != sigO)
|
||||
reject;
|
||||
sigCD = param(dff, \SRST_VALUE);
|
||||
|
||||
cd_signed = add && param(add, \A_SIGNED).as_bool() && param(add, \B_SIGNED).as_bool();
|
||||
}
|
||||
}
|
||||
endcode
|
||||
|
||||
code argQ ffCD ffCDholdmux ffCDholdpol ffCDrstpol sigCD clock clock_pol
|
||||
code argQ ffCD sigCD clock clock_pol
|
||||
if (!sigCD.empty() && sigCD != sigO &&
|
||||
(mul->type != \SB_MAC16 || (!param(mul, \C_REG).as_bool() && !param(mul, \D_REG).as_bool()))) {
|
||||
argQ = sigCD;
|
||||
subpattern(in_dffe);
|
||||
if (dff) {
|
||||
if (dffholdmux) {
|
||||
ffCDholdmux = dffholdmux;
|
||||
ffCDholdpol = dffholdpol;
|
||||
}
|
||||
|
||||
// Reset signal of C (IRSTTOP) and D (IRSTBOT)
|
||||
// shared with A and B
|
||||
if ((ffArstmux != NULL) != (dffrstmux != NULL))
|
||||
goto reject_ffCD;
|
||||
if ((ffBrstmux != NULL) != (dffrstmux != NULL))
|
||||
goto reject_ffCD;
|
||||
if (ffArstmux) {
|
||||
if (port(ffArstmux, \S) != port(dffrstmux, \S))
|
||||
goto reject_ffCD;
|
||||
if (ffArstpol != dffrstpol)
|
||||
if (ffA) {
|
||||
if (ffA->hasPort(\ARST) != dff->hasPort(\ARST))
|
||||
goto reject_ffCD;
|
||||
if (ffA->hasPort(\ARST)) {
|
||||
if (port(ffA, \ARST) != port(dff, \ARST))
|
||||
goto reject_ffCD;
|
||||
if (param(ffA, \ARST_POLARITY) != param(dff, \ARST_POLARITY))
|
||||
goto reject_ffCD;
|
||||
}
|
||||
}
|
||||
if (ffBrstmux) {
|
||||
if (port(ffBrstmux, \S) != port(dffrstmux, \S))
|
||||
goto reject_ffCD;
|
||||
if (ffBrstpol != dffrstpol)
|
||||
if (ffB) {
|
||||
if (ffB->hasPort(\ARST) != dff->hasPort(\ARST))
|
||||
goto reject_ffCD;
|
||||
if (ffB->hasPort(\ARST)) {
|
||||
if (port(ffB, \ARST) != port(dff, \ARST))
|
||||
goto reject_ffCD;
|
||||
if (param(ffB, \ARST_POLARITY) != param(dff, \ARST_POLARITY))
|
||||
goto reject_ffCD;
|
||||
}
|
||||
}
|
||||
|
||||
ffCD = dff;
|
||||
|
@ -347,7 +332,7 @@ code
|
|||
endcode
|
||||
|
||||
match ff
|
||||
select ff->type.in($dff)
|
||||
select ff->type.in($dff, $dffe)
|
||||
// DSP48E1 does not support clock inversion
|
||||
select param(ff, \CLK_POLARITY).as_bool()
|
||||
|
||||
|
@ -357,8 +342,6 @@ match ff
|
|||
// Check that the rest of argQ is present
|
||||
filter GetSize(port(ff, \Q)) >= offset + GetSize(argQ)
|
||||
filter port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
|
||||
|
||||
set ffoffset offset
|
||||
endmatch
|
||||
|
||||
code argQ argD
|
||||
|
@ -378,72 +361,13 @@ code argQ argD
|
|||
argD = port(ff, \D);
|
||||
argQ = Q;
|
||||
dffD.replace(argQ, argD);
|
||||
// Only search for ffrstmux if dffD only
|
||||
// has two (ff, ffrstmux) users
|
||||
if (nusers(dffD) > 2)
|
||||
argD = SigSpec();
|
||||
}
|
||||
endcode
|
||||
|
||||
match ffrstmux
|
||||
if false /* TODO: ice40 resets are actually async */
|
||||
|
||||
if !argD.empty()
|
||||
select ffrstmux->type.in($mux)
|
||||
index <SigSpec> port(ffrstmux, \Y) === argD
|
||||
|
||||
choice <IdString> BA {\B, \A}
|
||||
// DSP48E1 only supports reset to zero
|
||||
select port(ffrstmux, BA).is_fully_zero()
|
||||
|
||||
define <bool> pol (BA == \B)
|
||||
set ffrstpol pol
|
||||
semioptional
|
||||
endmatch
|
||||
|
||||
code argD
|
||||
if (ffrstmux) {
|
||||
dffrstmux = ffrstmux;
|
||||
dffrstpol = ffrstpol;
|
||||
argD = port(ffrstmux, ffrstpol ? \A : \B);
|
||||
dffD.replace(port(ffrstmux, \Y), argD);
|
||||
|
||||
// Only search for ffholdmux if argQ has at
|
||||
// least 3 users (ff, <upstream>, ffrstmux) and
|
||||
// dffD only has two (ff, ffrstmux)
|
||||
if (!(nusers(argQ) >= 3 && nusers(dffD) == 2))
|
||||
argD = SigSpec();
|
||||
}
|
||||
else
|
||||
dffrstmux = nullptr;
|
||||
endcode
|
||||
|
||||
match ffholdmux
|
||||
if !argD.empty()
|
||||
select ffholdmux->type.in($mux)
|
||||
index <SigSpec> port(ffholdmux, \Y) === argD
|
||||
choice <IdString> BA {\B, \A}
|
||||
index <SigSpec> port(ffholdmux, BA) === argQ
|
||||
define <bool> pol (BA == \B)
|
||||
set ffholdpol pol
|
||||
semioptional
|
||||
endmatch
|
||||
|
||||
code argD
|
||||
if (ffholdmux) {
|
||||
dffholdmux = ffholdmux;
|
||||
dffholdpol = ffholdpol;
|
||||
argD = port(ffholdmux, ffholdpol ? \A : \B);
|
||||
dffD.replace(port(ffholdmux, \Y), argD);
|
||||
}
|
||||
else
|
||||
dffholdmux = nullptr;
|
||||
endcode
|
||||
|
||||
// #######################
|
||||
|
||||
subpattern out_dffe
|
||||
arg argD argQ clock clock_pol
|
||||
arg argD argSdff argQ clock clock_pol
|
||||
|
||||
code
|
||||
dff = nullptr;
|
||||
|
@ -452,101 +376,19 @@ code
|
|||
reject;
|
||||
endcode
|
||||
|
||||
match ffholdmux
|
||||
select ffholdmux->type.in($mux)
|
||||
// ffholdmux output must have two users: ffholdmux and ff.D
|
||||
select nusers(port(ffholdmux, \Y)) == 2
|
||||
|
||||
choice <IdString> BA {\B, \A}
|
||||
// keep-last-value net must have at least three users: ffholdmux, ff, downstream sink(s)
|
||||
select nusers(port(ffholdmux, BA)) >= 3
|
||||
|
||||
slice offset GetSize(port(ffholdmux, \Y))
|
||||
define <IdString> AB (BA == \B ? \A : \B)
|
||||
index <SigBit> port(ffholdmux, AB)[offset] === argD[0]
|
||||
|
||||
// Check that the rest of argD is present
|
||||
filter GetSize(port(ffholdmux, AB)) >= offset + GetSize(argD)
|
||||
filter port(ffholdmux, AB).extract(offset, GetSize(argD)) == argD
|
||||
|
||||
set ffoffset offset
|
||||
define <bool> pol (BA == \B)
|
||||
set ffholdpol pol
|
||||
|
||||
semioptional
|
||||
endmatch
|
||||
|
||||
code argD argQ
|
||||
dffholdmux = ffholdmux;
|
||||
if (ffholdmux) {
|
||||
SigSpec AB = port(ffholdmux, ffholdpol ? \A : \B);
|
||||
SigSpec Y = port(ffholdmux, \Y);
|
||||
argQ = argD;
|
||||
argD.replace(AB, Y);
|
||||
argQ.replace(AB, port(ffholdmux, ffholdpol ? \B : \A));
|
||||
|
||||
dffholdmux = ffholdmux;
|
||||
dffholdpol = ffholdpol;
|
||||
}
|
||||
endcode
|
||||
|
||||
match ffrstmux
|
||||
if false /* TODO: ice40 resets are actually async */
|
||||
|
||||
select ffrstmux->type.in($mux)
|
||||
// ffrstmux output must have two users: ffrstmux and ff.D
|
||||
select nusers(port(ffrstmux, \Y)) == 2
|
||||
|
||||
choice <IdString> BA {\B, \A}
|
||||
// DSP48E1 only supports reset to zero
|
||||
select port(ffrstmux, BA).is_fully_zero()
|
||||
|
||||
slice offset GetSize(port(ffrstmux, \Y))
|
||||
define <IdString> AB (BA == \B ? \A : \B)
|
||||
index <SigBit> port(ffrstmux, AB)[offset] === argD[0]
|
||||
|
||||
// Check that offset is consistent
|
||||
filter !ffholdmux || ffoffset == offset
|
||||
// Check that the rest of argD is present
|
||||
filter GetSize(port(ffrstmux, AB)) >= offset + GetSize(argD)
|
||||
filter port(ffrstmux, AB).extract(offset, GetSize(argD)) == argD
|
||||
|
||||
set ffoffset offset
|
||||
define <bool> pol (AB == \A)
|
||||
set ffrstpol pol
|
||||
|
||||
semioptional
|
||||
endmatch
|
||||
|
||||
code argD argQ
|
||||
dffrstmux = ffrstmux;
|
||||
if (ffrstmux) {
|
||||
SigSpec AB = port(ffrstmux, ffrstpol ? \A : \B);
|
||||
SigSpec Y = port(ffrstmux, \Y);
|
||||
argD.replace(AB, Y);
|
||||
|
||||
dffrstmux = ffrstmux;
|
||||
dffrstpol = ffrstpol;
|
||||
}
|
||||
endcode
|
||||
|
||||
match ff
|
||||
select ff->type.in($dff)
|
||||
select ff->type.in($dff, $dffe, $sdff, $sdffce)
|
||||
// SB_MAC16 does not support clock inversion
|
||||
select param(ff, \CLK_POLARITY).as_bool()
|
||||
|
||||
slice offset GetSize(port(ff, \D))
|
||||
index <SigBit> port(ff, \D)[offset] === argD[0]
|
||||
|
||||
// Check that offset is consistent
|
||||
filter (!ffholdmux && !ffrstmux) || ffoffset == offset
|
||||
// Only allow sync reset if requested.
|
||||
filter argSdff || ff->type.in($dff, $dffe)
|
||||
// Check that the rest of argD is present
|
||||
filter GetSize(port(ff, \D)) >= offset + GetSize(argD)
|
||||
filter port(ff, \D).extract(offset, GetSize(argD)) == argD
|
||||
// Check that FF.Q is connected to CE-mux
|
||||
filter !ffholdmux || port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
|
||||
|
||||
set ffoffset offset
|
||||
endmatch
|
||||
|
||||
code argQ
|
||||
|
@ -559,10 +401,8 @@ code argQ
|
|||
}
|
||||
SigSpec D = port(ff, \D);
|
||||
SigSpec Q = port(ff, \Q);
|
||||
if (!ffholdmux) {
|
||||
argQ = argD;
|
||||
argQ.replace(D, Q);
|
||||
}
|
||||
argQ = argD;
|
||||
argQ.replace(D, Q);
|
||||
|
||||
for (auto c : argQ.chunks()) {
|
||||
Const init = c.wire->attributes.at(\init, State::Sx);
|
||||
|
@ -575,7 +415,4 @@ code argQ
|
|||
dffclock = port(ff, \CLK);
|
||||
dffclock_pol = param(ff, \CLK_POLARITY).as_bool();
|
||||
}
|
||||
// No enable/reset mux possible without flop
|
||||
else if (dffholdmux || dffrstmux)
|
||||
reject;
|
||||
endcode
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
|
||||
OBJS += techlibs/ice40/synth_ice40.o
|
||||
OBJS += techlibs/ice40/ice40_braminit.o
|
||||
OBJS += techlibs/ice40/ice40_ffssr.o
|
||||
OBJS += techlibs/ice40/ice40_opt.o
|
||||
|
||||
GENFILES += techlibs/ice40/brams_init1.vh
|
||||
|
|
|
@ -1,131 +0,0 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "kernel/yosys.h"
|
||||
#include "kernel/sigtools.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
struct Ice40FfssrPass : public Pass {
|
||||
Ice40FfssrPass() : Pass("ice40_ffssr", "iCE40: merge synchronous set/reset into FF cells") { }
|
||||
void help() override
|
||||
{
|
||||
log("\n");
|
||||
log(" ice40_ffssr [options] [selection]\n");
|
||||
log("\n");
|
||||
log("Merge synchronous set/reset $_MUX_ cells into iCE40 FFs.\n");
|
||||
log("\n");
|
||||
}
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||
{
|
||||
log_header(design, "Executing ICE40_FFSSR pass (merge synchronous set/reset into FF cells).\n");
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
{
|
||||
// if (args[argidx] == "-singleton") {
|
||||
// singleton_mode = true;
|
||||
// continue;
|
||||
// }
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
||||
pool<IdString> sb_dff_types;
|
||||
sb_dff_types.insert(ID(SB_DFF));
|
||||
sb_dff_types.insert(ID(SB_DFFE));
|
||||
sb_dff_types.insert(ID(SB_DFFN));
|
||||
sb_dff_types.insert(ID(SB_DFFNE));
|
||||
|
||||
for (auto module : design->selected_modules())
|
||||
{
|
||||
log("Merging set/reset $_MUX_ cells into SB_FFs in %s.\n", log_id(module));
|
||||
|
||||
SigMap sigmap(module);
|
||||
dict<SigBit, Cell*> sr_muxes;
|
||||
vector<Cell*> ff_cells;
|
||||
|
||||
for (auto cell : module->selected_cells())
|
||||
{
|
||||
if (sb_dff_types.count(cell->type)) {
|
||||
ff_cells.push_back(cell);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cell->type != ID($_MUX_))
|
||||
continue;
|
||||
|
||||
SigBit bit_a = sigmap(cell->getPort(ID::A));
|
||||
SigBit bit_b = sigmap(cell->getPort(ID::B));
|
||||
|
||||
if (bit_a.wire == nullptr || bit_b.wire == nullptr)
|
||||
sr_muxes[sigmap(cell->getPort(ID::Y))] = cell;
|
||||
}
|
||||
|
||||
for (auto cell : ff_cells)
|
||||
{
|
||||
if (cell->get_bool_attribute(ID(dont_touch)))
|
||||
continue;
|
||||
|
||||
SigSpec sig_d = cell->getPort(ID::D);
|
||||
|
||||
if (GetSize(sig_d) < 1)
|
||||
continue;
|
||||
|
||||
SigBit bit_d = sigmap(sig_d[0]);
|
||||
|
||||
if (sr_muxes.count(bit_d) == 0)
|
||||
continue;
|
||||
|
||||
Cell *mux_cell = sr_muxes.at(bit_d);
|
||||
SigBit bit_a = sigmap(mux_cell->getPort(ID::A));
|
||||
SigBit bit_b = sigmap(mux_cell->getPort(ID::B));
|
||||
SigBit bit_s = sigmap(mux_cell->getPort(ID::S));
|
||||
|
||||
log(" Merging %s (A=%s, B=%s, S=%s) into %s (%s).\n", log_id(mux_cell),
|
||||
log_signal(bit_a), log_signal(bit_b), log_signal(bit_s), log_id(cell), log_id(cell->type));
|
||||
|
||||
SigBit sr_val, sr_sig;
|
||||
if (bit_a.wire == nullptr) {
|
||||
bit_d = bit_b;
|
||||
sr_val = bit_a;
|
||||
sr_sig = module->NotGate(NEW_ID, bit_s);
|
||||
} else {
|
||||
log_assert(bit_b.wire == nullptr);
|
||||
bit_d = bit_a;
|
||||
sr_val = bit_b;
|
||||
sr_sig = bit_s;
|
||||
}
|
||||
|
||||
if (sr_val == State::S1) {
|
||||
cell->type = cell->type.str() + "SS";
|
||||
cell->setPort(ID::S, sr_sig);
|
||||
cell->setPort(ID::D, bit_d);
|
||||
} else {
|
||||
cell->type = cell->type.str() + "SR";
|
||||
cell->setPort(ID::R, sr_sig);
|
||||
cell->setPort(ID::D, bit_d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} Ice40FfssrPass;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
|
@ -215,7 +215,7 @@ struct Ice40OptPass : public Pass {
|
|||
log(" <ice40 specific optimizations>\n");
|
||||
log(" opt_expr -mux_undef -undriven [-full]\n");
|
||||
log(" opt_merge\n");
|
||||
log(" opt_rmdff\n");
|
||||
log(" opt_dff\n");
|
||||
log(" opt_clean\n");
|
||||
log(" while <changed design>\n");
|
||||
log("\n");
|
||||
|
@ -247,7 +247,7 @@ struct Ice40OptPass : public Pass {
|
|||
|
||||
Pass::call(design, "opt_expr " + opt_expr_args);
|
||||
Pass::call(design, "opt_merge");
|
||||
Pass::call(design, "opt_rmdff");
|
||||
Pass::call(design, "opt_dff");
|
||||
Pass::call(design, "opt_clean");
|
||||
|
||||
if (design->scratchpad_get_bool("opt.did_something") == false)
|
||||
|
|
|
@ -293,6 +293,10 @@ struct SynthIce40Pass : public ScriptPass
|
|||
run("opt_clean");
|
||||
run("check");
|
||||
run("opt");
|
||||
run("fsm");
|
||||
run("opt");
|
||||
run("opt_dff");
|
||||
run("opt");
|
||||
run("wreduce");
|
||||
run("peepopt");
|
||||
run("opt_clean");
|
||||
|
@ -316,8 +320,6 @@ struct SynthIce40Pass : public ScriptPass
|
|||
}
|
||||
run("alumacc");
|
||||
run("opt");
|
||||
run("fsm");
|
||||
run("opt -fast");
|
||||
run("memory -nomap");
|
||||
run("opt_clean");
|
||||
}
|
||||
|
@ -354,11 +356,6 @@ struct SynthIce40Pass : public ScriptPass
|
|||
|
||||
if (check_label("map_ffs"))
|
||||
{
|
||||
if (!nodffe)
|
||||
run("dff2dffe -direct-match $_DFF_*");
|
||||
if (min_ce_use >= 0) {
|
||||
run("opt_merge");
|
||||
}
|
||||
if (nodffe)
|
||||
run(stringf("dfflegalize -cell $_DFF_?_ 0 -cell $_DFF_?P?_ 0 -cell $_SDFF_?P?_ 0 -cell $_DLATCH_?_ x"));
|
||||
else
|
||||
|
@ -366,7 +363,6 @@ struct SynthIce40Pass : public ScriptPass
|
|||
run("techmap -map +/ice40/ff_map.v");
|
||||
run("opt_expr -mux_undef");
|
||||
run("simplemap");
|
||||
run("ice40_ffssr");
|
||||
run("ice40_opt -full");
|
||||
}
|
||||
|
||||
|
|
|
@ -12,5 +12,5 @@ cd fsm # Constrain all select calls below inside the top module
|
|||
|
||||
select -assert-count 4 t:SB_DFF
|
||||
select -assert-count 2 t:SB_DFFESR
|
||||
select -assert-count 15 t:SB_LUT4
|
||||
select -assert-max 15 t:SB_LUT4
|
||||
select -assert-none t:SB_DFFESR t:SB_DFF t:SB_LUT4 %% t:* %D
|
||||
|
|
Loading…
Reference in New Issue