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
+ if (sig[i].wire)
+ ++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 ffAholdmux ffArstmux ffAholdpol ffArstpol sigA clock clock_pol
- if (mul->type != \SB_MAC16 || !param(mul, \A_REG).as_bool()) {
+ if (mul->type != \SB_MAC16 || !param(mul, \A_REG, State::S0).as_bool()) {
argQ = sigA;
subpattern(in_dffe);
if (dff) {
endcode
code argQ ffB ffBholdmux ffBrstmux ffBholdpol ffBrstpol sigB clock clock_pol
- if (mul->type != \SB_MAC16 || !param(mul, \B_REG).as_bool()) {
+ if (mul->type != \SB_MAC16 || !param(mul, \B_REG, State::S0).as_bool()) {
argQ = sigB;
subpattern(in_dffe);
if (dff) {
}
endcode
-code argD ffFJKG sigH sigO clock clock_pol
+code argD 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()))) {
+ (!param(mul, \TOP_8x8_MULT_REG, State::S0).as_bool() && !param(mul, \BOT_8x8_MULT_REG, State::S0).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1, State::S0).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1, State::S0).as_bool()))) {
argD = sigH;
subpattern(out_dffe);
if (dff) {
clock = dffclock;
clock_pol = dffclock_pol;
sigH = dffQ;
- }
- }
- if (0) {
-reject_ffFJKG: ;
+reject_ffFJKG: ;
+ }
}
endcode
code argD ffH sigH sigO clock clock_pol
if (ffFJKG && nusers(sigH) == 2 &&
- (mul->type != \SB_MAC16 || !param(mul, \PIPELINE_16x16_MULT_REG2).as_bool())) {
+ (mul->type != \SB_MAC16 || !param(mul, \PIPELINE_16x16_MULT_REG2, State::S0).as_bool())) {
argD = sigH;
subpattern(out_dffe);
if (dff) {
clock = dffclock;
clock_pol = dffclock_pol;
sigH = dffQ;
- }
- }
- if (0) {
-reject_ffH: ;
+reject_ffH: ;
+ }
}
sigO = sigH;
endcode
match add
- if mul->type != \SB_MAC16 || (param(mul, \TOPOUTPUT_SELECT).as_int() == 3 && param(mul, \BOTOUTPUT_SELECT).as_int() == 3)
+ if mul->type != \SB_MAC16 || (param(mul, \TOPOUTPUT_SELECT, State::S0).as_int() == 3 && param(mul, \BOTOUTPUT_SELECT, State::S0).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
if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width))
reject;
// If accumulator, check adder width and signedness
- if (sigCD == sigH && (actual_acc_width != actual_mul_width) && (param(mul, \A_SIGNED).as_bool() != param(add, \A_SIGNED).as_bool()))
+ if (sigCD == sigH && (actual_acc_width != actual_mul_width) && (param(mul, \A_SIGNED, State::S0).as_bool() != param(add, \A_SIGNED).as_bool()))
reject;
sigO = port(add, \Y);
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
code argD ffO ffOholdmux ffOrstmux ffOholdpol ffOrstpol 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, 0).as_int() != 1 && param(mul, \BOTOUTPUT_SELECT, 0).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;
endcode
code argQ ffCD ffCDholdmux ffCDholdpol ffCDrstpol sigCD clock clock_pol
- if (!sigCD.empty() &&
- (mul->type != \SB_MAC16 || (!param(mul, \C_REG).as_bool() && !param(mul, \D_REG).as_bool()))) {
+ if (!sigCD.empty() && sigCD != sigO &&
+ (mul->type != \SB_MAC16 || (!param(mul, \C_REG, State::S0).as_bool() && !param(mul, \D_REG, State::S0).as_bool()))) {
argQ = sigCD;
subpattern(in_dffe);
if (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
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
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