state <Cell*> add mux
state <IdString> addAB muxAB
-state <bool> ffAcepol ffBcepol ffCDcepol ffOcepol
-state <bool> ffArstpol ffBrstpol ffCDrstpol ffOrstpol
-
-state <Cell*> ffA ffAcemux ffArstmux ffB ffBcemux ffBrstmux ffCD ffCDcemux
-state <Cell*> ffFJKG ffH ffO ffOcemux ffOrstmux
+state <Cell*> ffA ffB ffCD
+state <Cell*> ffFJKG ffH ffO
// subpattern
+state <bool> argSdff
state <SigSpec> argQ argD
-state <bool> ffcepol ffrstpol
-state <int> ffoffset
udata <SigSpec> dffD dffQ
udata <SigBit> dffclock
-udata <Cell*> dff dffcemux dffrstmux
-udata <bool> dffcepol dffrstpol dffclock_pol
+udata <Cell*> dff
+udata <bool> dffclock_pol
match mul
select mul->type.in($mul, \SB_MAC16)
endmatch
code sigA sigB sigH
+ auto 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
+ ++i;
+ return sig.extract(0, i);
+ };
+ sigA = unextend(port(mul, \A));
+ sigB = unextend(port(mul, \B));
+
SigSpec O;
if (mul->type == $mul)
O = mul->getPort(\Y);
if (GetSize(O) <= 10)
reject;
- sigA = port(mul, \A);
- int i;
- for (i = GetSize(sigA)-1; i > 0; i--)
- if (sigA[i] != sigA[i-1])
- break;
- // Do not remove non-const sign bit
- if (sigA[i].wire)
- ++i;
- sigA.remove(i, GetSize(sigA)-i);
- sigB = port(mul, \B);
- for (i = GetSize(sigB)-1; i > 0; i--)
- if (sigB[i] != sigB[i-1])
- break;
- // Do not remove non-const sign bit
- if (sigB[i].wire)
- ++i;
- sigB.remove(i, GetSize(sigB)-i);
-
// Only care about those bits that are used
+ int i;
for (i = 0; i < GetSize(O); i++) {
if (nusers(O[i]) <= 1)
break;
sigH.append(O[i]);
}
+ // This sigM could have no users if downstream sinks (e.g. $add) is
+ // narrower than $mul result, for example
+ if (i == 0)
+ reject;
+
log_assert(nusers(O.extract_end(i)) <= 1);
endcode
-code argQ ffA ffAcemux ffArstmux ffAcepol 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);
ffA = dff;
clock = dffclock;
clock_pol = dffclock_pol;
- if (dffrstmux) {
- ffArstmux = dffrstmux;
- ffArstpol = dffrstpol;
- }
- if (dffcemux) {
- ffAcemux = dffcemux;
- ffAcepol = dffcepol;
- }
sigA = dffD;
}
}
endcode
-code argQ ffB ffBcemux ffBrstmux ffBcepol 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);
ffB = dff;
clock = dffclock;
clock_pol = dffclock_pol;
- if (dffrstmux) {
- ffBrstmux = dffrstmux;
- ffBrstpol = dffrstpol;
- }
- if (dffcemux) {
- ffBcemux = dffcemux;
- ffBcepol = dffcepol;
- }
sigB = dffD;
}
}
endcode
-code argD ffFJKG sigH sigO 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 (dffcemux)
+ 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;
clock = dffclock;
clock_pol = dffclock_pol;
sigH = dffQ;
- }
- }
- if (0) {
-reject_ffFJKG: ;
+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 (dffcemux)
+ 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;
}
clock = dffclock;
clock_pol = dffclock_pol;
sigH = dffQ;
- }
- }
- if (0) {
-reject_ffH: ;
+reject_ffH: ;
+ }
}
sigO = sigH;
match add
if mul->type != \SB_MAC16 || (param(mul, \TOPOUTPUT_SELECT).as_int() == 3 && param(mul, \BOTOUTPUT_SELECT).as_int() == 3)
+
select add->type.in($add)
choice <IdString> AB {\A, \B}
select nusers(port(add, AB)) == 2
+
index <SigBit> port(add, AB)[0] === sigH[0]
filter GetSize(port(add, AB)) <= GetSize(sigH)
- filter port(add, AB) == sigH.extract(0, GetSize(port(add, AB)))
+ filter port(add, AB) == sigH.extract(0, GetSize(port(add, AB)))
+ filter nusers(sigH.extract_end(GetSize(port(add, AB)))) <= 1
set addAB AB
optional
endmatch
match mux
select mux->type == $mux
choice <IdString> AB {\A, \B}
- index <int> nusers(port(mux, AB)) === 2
+ select nusers(port(mux, AB)) == 2
index <SigSpec> port(mux, AB) === sigO
set muxAB AB
optional
sigO = port(mux, \Y);
endcode
-code argD ffO ffOcemux ffOrstmux ffOcepol 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
- ((mul->parameters.at(\TOPOUTPUT_SELECT, 0).as_int() != 1 && mul->parameters.at(\BOTOUTPUT_SELECT, 0).as_int() != 1) &&
+ ((param(mul, \TOPOUTPUT_SELECT).as_int() != 1 && param(mul, \BOTOUTPUT_SELECT).as_int() != 1) &&
// Ensure that OLOADTOP/OLOADBOT is unused or zero
- (mul->connections_.at(\OLOADTOP, State::S0).is_fully_zero() && mul->connections_.at(\OLOADBOT, State::S0).is_fully_zero()))) {
+ (port(mul, \OLOADTOP, State::S0).is_fully_zero() && port(mul, \OLOADBOT, State::S0).is_fully_zero()))) {
dff = nullptr;
// First try entire sigO
if (nusers(sigO) == 2) {
argD = sigO;
+ argSdff = !mux;
subpattern(out_dffe);
}
if (!dff && GetSize(sigO) > 16) {
argD = sigO.extract(0, 16);
if (nusers(argD) == 2) {
+ argSdff = !mux;
subpattern(out_dffe);
o_lo = dff;
}
ffO = dff;
clock = dffclock;
clock_pol = dffclock_pol;
- if (dffrstmux) {
- ffOrstmux = dffrstmux;
- ffOrstpol = dffrstpol;
- }
- if (dffcemux) {
- ffOcemux = dffcemux;
- ffOcepol = dffcepol;
- }
sigO.replace(sigO.extract(0, GetSize(dffQ)), dffQ);
}
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 ffCDcemux ffCDcepol ffCDrstpol sigCD clock clock_pol
- if (!sigCD.empty() &&
+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 (dffcemux) {
- ffCDcemux = dffcemux;
- ffCDcepol = dffcepol;
- }
-
// 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;
clock = dffclock;
clock_pol = dffclock_pol;
sigCD = dffD;
- }
- }
- if (0) {
-reject_ffCD: ;
+reject_ffCD: ;
+ }
}
endcode
code
dff = nullptr;
+ if (argQ.empty())
+ reject;
for (auto c : argQ.chunks()) {
if (!c.wire)
reject;
if (c.wire->get_bool_attribute(\keep))
reject;
+ Const init = c.wire->attributes.at(\init, State::Sx);
+ if (!init.is_fully_undef() && !init.is_fully_zero())
+ reject;
}
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()
// 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
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 !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 ffcemux 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 ffcemux
- if !argD.empty()
- select ffcemux->type.in($mux)
- index <SigSpec> port(ffcemux, \Y) === argD
- choice <IdString> AB {\A, \B}
- index <SigSpec> port(ffcemux, AB) === argQ
- define <bool> pol (AB == \A)
- set ffcepol pol
- semioptional
-endmatch
-
-code argD
- if (ffcemux) {
- dffcemux = ffcemux;
- dffcepol = ffcepol;
- argD = port(ffcemux, ffcepol ? \B : \A);
- dffD.replace(port(ffcemux, \Y), argD);
- }
- else
- dffcemux = nullptr;
-endcode
-
// #######################
subpattern out_dffe
-arg argD argQ clock clock_pol
+arg argD argSdff argQ clock clock_pol
code
dff = nullptr;
reject;
endcode
-match ffcemux
- select ffcemux->type.in($mux)
- // ffcemux output must have two users: ffcemux and ff.D
- select nusers(port(ffcemux, \Y)) == 2
-
- choice <IdString> AB {\A, \B}
- // keep-last-value net must have at least three users: ffcemux, ff, downstream sink(s)
- select nusers(port(ffcemux, AB)) >= 3
-
- slice offset GetSize(port(ffcemux, \Y))
- define <IdString> BA (AB == \A ? \B : \A)
- index <SigBit> port(ffcemux, BA)[offset] === argD[0]
-
- // Check that the rest of argD is present
- filter GetSize(port(ffcemux, BA)) >= offset + GetSize(argD)
- filter port(ffcemux, BA).extract(offset, GetSize(argD)) == argD
-
- set ffoffset offset
- define <bool> pol (BA == \B)
- set ffcepol pol
-
- semioptional
-endmatch
-
-code argD argQ
- dffcemux = ffcemux;
- if (ffcemux) {
- SigSpec BA = port(ffcemux, ffcepol ? \B : \A);
- SigSpec Y = port(ffcemux, \Y);
- argQ = argD;
- argD.replace(BA, Y);
- argQ.replace(BA, port(ffcemux, ffcepol ? \A : \B));
-
- dffcemux = ffcemux;
- dffcepol = ffcepol;
- }
-endcode
-
-match ffrstmux
- 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 !ffcemux || 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)
- // DSP48E1 does not support clock inversion
+ 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 (!ffcemux && !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 !ffcemux || port(ff, \Q).extract(offset, GetSize(argQ)) == argQ
-
- set ffoffset offset
endmatch
code argQ
}
SigSpec D = port(ff, \D);
SigSpec Q = port(ff, \Q);
- if (!ffcemux) {
- 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);
dffclock = port(ff, \CLK);
dffclock_pol = param(ff, \CLK_POLARITY).as_bool();
}
- // No enable/reset mux possible without flop
- else if (dffcemux || dffrstmux)
- reject;
endcode