2019-04-29 06:02:05 -05:00
|
|
|
pattern ice40_dsp
|
|
|
|
|
2019-01-13 03:57:11 -06:00
|
|
|
state <SigBit> clock
|
2019-09-05 19:58:19 -05:00
|
|
|
state <bool> clock_pol cd_signed
|
2019-09-05 20:06:59 -05:00
|
|
|
state <SigSpec> sigA sigB sigCD sigH sigO
|
2019-09-05 23:39:52 -05:00
|
|
|
state <Cell*> addAB muxAB ffO
|
2019-01-11 07:02:16 -06:00
|
|
|
|
|
|
|
match mul
|
2019-08-08 14:56:05 -05:00
|
|
|
select mul->type.in($mul, \SB_MAC16)
|
2019-01-11 07:02:16 -06:00
|
|
|
select GetSize(mul->getPort(\A)) + GetSize(mul->getPort(\B)) > 10
|
|
|
|
endmatch
|
|
|
|
|
2019-09-05 20:06:59 -05:00
|
|
|
code sigA sigB sigH
|
2019-09-05 19:58:19 -05:00
|
|
|
SigSpec O;
|
2019-08-08 14:56:05 -05:00
|
|
|
if (mul->type == $mul)
|
2019-09-05 19:58:19 -05:00
|
|
|
O = mul->getPort(\Y);
|
2019-08-08 14:56:05 -05:00
|
|
|
else if (mul->type == \SB_MAC16)
|
2019-09-05 19:58:19 -05:00
|
|
|
O = mul->getPort(\O);
|
2019-08-08 14:56:05 -05:00
|
|
|
else log_abort();
|
2019-09-05 19:58:19 -05:00
|
|
|
if (GetSize(O) <= 10)
|
2019-08-08 14:56:05 -05:00
|
|
|
reject;
|
2019-09-05 20:06:59 -05:00
|
|
|
|
|
|
|
sigA = port(mul, \A);
|
2019-09-05 19:58:19 -05:00
|
|
|
int i;
|
2019-09-05 20:06:59 -05:00
|
|
|
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
|
2019-09-05 19:58:19 -05:00
|
|
|
for (i = 0; i < GetSize(O); i++) {
|
|
|
|
if (nusers(O[i]) <= 1)
|
|
|
|
break;
|
|
|
|
sigH.append(O[i]);
|
|
|
|
}
|
|
|
|
log_assert(nusers(O.extract_end(i)) <= 1);
|
2019-08-08 14:56:05 -05:00
|
|
|
endcode
|
|
|
|
|
2019-01-11 07:02:16 -06:00
|
|
|
match ffA
|
2019-08-09 17:47:40 -05:00
|
|
|
if mul->type != \SB_MAC16 || !param(mul, \A_REG).as_bool()
|
2019-01-11 07:02:16 -06:00
|
|
|
select ffA->type.in($dff)
|
2019-09-05 20:06:59 -05:00
|
|
|
filter GetSize(port(ffA, \Q)) >= GetSize(sigA)
|
|
|
|
slice offset GetSize(port(ffA, \Q))
|
|
|
|
filter offset+GetSize(sigA) <= GetSize(port(ffA, \Q)) && port(ffA, \Q).extract(offset, GetSize(sigA)) == sigA
|
2019-01-11 07:02:16 -06:00
|
|
|
optional
|
|
|
|
endmatch
|
|
|
|
|
2019-07-19 12:57:32 -05:00
|
|
|
code sigA clock clock_pol
|
2019-01-13 10:03:58 -06:00
|
|
|
if (ffA) {
|
2019-08-08 14:56:05 -05:00
|
|
|
for (auto b : port(ffA, \Q))
|
|
|
|
if (b.wire->get_bool_attribute(\keep))
|
|
|
|
reject;
|
2019-08-07 14:57:10 -05:00
|
|
|
|
2019-01-11 07:02:16 -06:00
|
|
|
clock = port(ffA, \CLK).as_bit();
|
|
|
|
clock_pol = param(ffA, \CLK_POLARITY).as_bool();
|
2019-07-19 22:25:28 -05:00
|
|
|
|
|
|
|
sigA.replace(port(ffA, \Q), port(ffA, \D));
|
2019-01-11 07:02:16 -06:00
|
|
|
}
|
|
|
|
endcode
|
|
|
|
|
|
|
|
match ffB
|
2019-08-09 17:47:40 -05:00
|
|
|
if mul->type != \SB_MAC16 || !param(mul, \B_REG).as_bool()
|
2019-01-11 07:02:16 -06:00
|
|
|
select ffB->type.in($dff)
|
2019-09-05 20:06:59 -05:00
|
|
|
filter GetSize(port(ffB, \Q)) >= GetSize(sigB)
|
|
|
|
slice offset GetSize(port(ffB, \Q))
|
|
|
|
filter offset+GetSize(sigB) <= GetSize(port(ffB, \Q)) && port(ffB, \Q).extract(offset, GetSize(sigB)) == sigB
|
2019-01-11 07:02:16 -06:00
|
|
|
optional
|
|
|
|
endmatch
|
|
|
|
|
2019-07-19 12:57:32 -05:00
|
|
|
code sigB clock clock_pol
|
2019-01-13 10:03:58 -06:00
|
|
|
if (ffB) {
|
2019-08-08 14:56:05 -05:00
|
|
|
for (auto b : port(ffB, \Q))
|
|
|
|
if (b.wire->get_bool_attribute(\keep))
|
|
|
|
reject;
|
2019-08-07 14:57:10 -05:00
|
|
|
|
2019-01-11 07:02:16 -06:00
|
|
|
SigBit c = port(ffB, \CLK).as_bit();
|
|
|
|
bool cp = param(ffB, \CLK_POLARITY).as_bool();
|
|
|
|
|
2019-07-19 12:57:32 -05:00
|
|
|
if (clock != SigBit() && (c != clock || cp != clock_pol))
|
2019-01-11 07:02:16 -06:00
|
|
|
reject;
|
|
|
|
|
|
|
|
clock = c;
|
|
|
|
clock_pol = cp;
|
2019-07-19 22:25:28 -05:00
|
|
|
|
|
|
|
sigB.replace(port(ffB, \Q), port(ffB, \D));
|
2019-01-11 07:02:16 -06:00
|
|
|
}
|
|
|
|
endcode
|
|
|
|
|
2019-08-15 14:19:34 -05:00
|
|
|
match ffFJKG
|
2019-08-30 17:00:40 -05:00
|
|
|
// Ensure pipeline register is not already used
|
2019-08-09 17:47:40 -05:00
|
|
|
if 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_REG2).as_bool())
|
2019-08-15 14:19:34 -05:00
|
|
|
select ffFJKG->type.in($dff)
|
|
|
|
select nusers(port(ffFJKG, \D)) == 2
|
|
|
|
index <SigSpec> port(ffFJKG, \D) === sigH
|
2019-01-11 07:02:16 -06:00
|
|
|
optional
|
|
|
|
endmatch
|
|
|
|
|
2019-07-22 18:12:57 -05:00
|
|
|
code sigH sigO clock clock_pol
|
2019-08-15 14:19:34 -05:00
|
|
|
if (ffFJKG) {
|
|
|
|
sigH = port(ffFJKG, \Q);
|
2019-08-08 14:56:05 -05:00
|
|
|
for (auto b : sigH)
|
|
|
|
if (b.wire->get_bool_attribute(\keep))
|
|
|
|
reject;
|
2019-08-07 14:57:10 -05:00
|
|
|
|
2019-08-15 14:19:34 -05:00
|
|
|
SigBit c = port(ffFJKG, \CLK).as_bit();
|
|
|
|
bool cp = param(ffFJKG, \CLK_POLARITY).as_bool();
|
2019-01-11 07:02:16 -06:00
|
|
|
|
2019-07-19 12:57:32 -05:00
|
|
|
if (clock != SigBit() && (c != clock || cp != clock_pol))
|
2019-01-11 07:02:16 -06:00
|
|
|
reject;
|
|
|
|
|
|
|
|
clock = c;
|
|
|
|
clock_pol = cp;
|
|
|
|
}
|
2019-08-15 14:30:46 -05:00
|
|
|
|
|
|
|
sigO = sigH;
|
2019-01-11 07:02:16 -06:00
|
|
|
endcode
|
2019-01-13 10:03:58 -06:00
|
|
|
|
|
|
|
match addA
|
2019-02-17 08:35:48 -06:00
|
|
|
select addA->type.in($add)
|
2019-01-13 10:03:58 -06:00
|
|
|
select nusers(port(addA, \A)) == 2
|
2019-08-09 19:23:12 -05:00
|
|
|
filter param(addA, \A_WIDTH).as_int() <= GetSize(sigH)
|
|
|
|
//index <SigSpec> port(addA, \A) === sigH.extract(0, param(addA, \A_WIDTH).as_int())
|
|
|
|
filter port(addA, \A) == sigH.extract(0, param(addA, \A_WIDTH).as_int())
|
2019-01-13 10:03:58 -06:00
|
|
|
optional
|
|
|
|
endmatch
|
|
|
|
|
|
|
|
match addB
|
|
|
|
if !addA
|
|
|
|
select addB->type.in($add, $sub)
|
|
|
|
select nusers(port(addB, \B)) == 2
|
2019-08-09 19:23:12 -05:00
|
|
|
filter param(addB, \B_WIDTH).as_int() <= GetSize(sigH)
|
|
|
|
//index <SigSpec> port(addB, \B) === sigH.extract(0, param(addB, \B_WIDTH).as_int())
|
|
|
|
filter port(addB, \B) == sigH.extract(0, param(addB, \B_WIDTH).as_int())
|
2019-01-13 10:03:58 -06:00
|
|
|
optional
|
|
|
|
endmatch
|
|
|
|
|
2019-09-05 19:58:19 -05:00
|
|
|
code addAB sigCD sigO cd_signed
|
2019-01-13 10:03:58 -06:00
|
|
|
if (addA) {
|
|
|
|
addAB = addA;
|
2019-07-23 15:58:56 -05:00
|
|
|
sigCD = port(addAB, \B);
|
2019-09-05 19:58:19 -05:00
|
|
|
cd_signed = param(addAB, \B_SIGNED).as_bool();
|
2019-01-13 10:03:58 -06:00
|
|
|
}
|
2019-09-05 19:58:19 -05:00
|
|
|
else if (addB) {
|
2019-01-13 10:03:58 -06:00
|
|
|
addAB = addB;
|
2019-07-23 15:58:56 -05:00
|
|
|
sigCD = port(addAB, \A);
|
2019-09-05 19:58:19 -05:00
|
|
|
cd_signed = param(addAB, \A_SIGNED).as_bool();
|
2019-01-13 10:03:58 -06:00
|
|
|
}
|
2019-02-20 04:18:19 -06:00
|
|
|
if (addAB) {
|
2019-08-08 14:56:05 -05:00
|
|
|
if (mul->type == \SB_MAC16) {
|
|
|
|
// Ensure that adder is not used
|
|
|
|
if (param(mul, \TOPOUTPUT_SELECT).as_int() != 3 ||
|
|
|
|
param(mul, \BOTOUTPUT_SELECT).as_int() != 3)
|
|
|
|
reject;
|
|
|
|
}
|
|
|
|
|
2019-02-20 04:18:19 -06:00
|
|
|
int natural_mul_width = GetSize(sigA) + GetSize(sigB);
|
2019-07-22 17:08:26 -05:00
|
|
|
int actual_mul_width = GetSize(sigH);
|
2019-08-09 16:27:08 -05:00
|
|
|
int actual_acc_width = GetSize(sigCD);
|
2019-02-20 04:18:19 -06:00
|
|
|
|
|
|
|
if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width))
|
|
|
|
reject;
|
2019-08-09 19:23:12 -05:00
|
|
|
// If accumulator, check adder width and signedness
|
|
|
|
if (sigCD == sigH && (actual_acc_width != actual_mul_width) && (param(mul, \A_SIGNED).as_bool() != param(addAB, \A_SIGNED).as_bool()))
|
2019-02-20 04:18:19 -06:00
|
|
|
reject;
|
2019-07-22 18:12:57 -05:00
|
|
|
|
|
|
|
sigO = port(addAB, \Y);
|
2019-02-20 04:18:19 -06:00
|
|
|
}
|
2019-01-13 10:03:58 -06:00
|
|
|
endcode
|
|
|
|
|
|
|
|
match muxA
|
|
|
|
select muxA->type.in($mux)
|
2019-08-09 17:47:40 -05:00
|
|
|
index <int> nusers(port(muxA, \A)) === 2
|
2019-07-23 15:58:56 -05:00
|
|
|
index <SigSpec> port(muxA, \A) === sigO
|
2019-01-13 10:03:58 -06:00
|
|
|
optional
|
|
|
|
endmatch
|
|
|
|
|
|
|
|
match muxB
|
|
|
|
if !muxA
|
|
|
|
select muxB->type.in($mux)
|
2019-08-09 17:47:40 -05:00
|
|
|
index <int> nusers(port(muxB, \B)) === 2
|
2019-07-23 15:58:56 -05:00
|
|
|
index <SigSpec> port(muxB, \B) === sigO
|
2019-01-13 10:03:58 -06:00
|
|
|
optional
|
|
|
|
endmatch
|
|
|
|
|
2019-09-05 19:58:19 -05:00
|
|
|
code muxAB sigO
|
2019-07-23 16:20:34 -05:00
|
|
|
if (muxA)
|
2019-01-13 10:03:58 -06:00
|
|
|
muxAB = muxA;
|
2019-07-23 16:20:34 -05:00
|
|
|
else if (muxB)
|
2019-01-13 10:03:58 -06:00
|
|
|
muxAB = muxB;
|
2019-09-05 19:58:19 -05:00
|
|
|
if (muxAB)
|
|
|
|
sigO = port(muxAB, \Y);
|
2019-01-13 10:03:58 -06:00
|
|
|
endcode
|
|
|
|
|
2019-09-05 23:39:52 -05:00
|
|
|
match ffO_hilo
|
2019-09-05 19:58:19 -05:00
|
|
|
// Ensure that register is not already used
|
|
|
|
if mul->type != \SB_MAC16 || (mul->parameters.at(\TOPOUTPUT_SELECT, 0).as_int() != 1 && mul->parameters.at(\BOTOUTPUT_SELECT, 0).as_int() != 1)
|
|
|
|
// Ensure that OLOADTOP/OLOADBOT is unused or zero
|
|
|
|
if mul->type != \SB_MAC16 || (mul->connections_.at(\OLOADTOP, State::S0).is_fully_zero() && mul->connections_.at(\OLOADBOT, State::S0).is_fully_zero())
|
|
|
|
if nusers(sigO) == 2
|
2019-09-05 23:39:52 -05:00
|
|
|
select ffO_hilo->type.in($dff)
|
|
|
|
filter GetSize(port(ffO_hilo, \D)) >= GetSize(sigO)
|
|
|
|
slice offset GetSize(port(ffO_hilo, \D))
|
|
|
|
filter offset+GetSize(sigO) <= GetSize(port(ffO_hilo, \D)) && port(ffO_hilo, \D).extract(offset, GetSize(sigO)) == sigO
|
2019-07-22 18:12:57 -05:00
|
|
|
optional
|
|
|
|
endmatch
|
|
|
|
|
2019-09-05 19:58:19 -05:00
|
|
|
match ffO_lo
|
2019-09-05 23:39:52 -05:00
|
|
|
if !ffO_hilo && GetSize(sigO) > 16
|
2019-09-05 19:58:19 -05:00
|
|
|
// Ensure that register is not already used
|
|
|
|
if mul->type != \SB_MAC16 || (mul->parameters.at(\TOPOUTPUT_SELECT, 0).as_int() != 1 && mul->parameters.at(\BOTOUTPUT_SELECT, 0).as_int() != 1)
|
|
|
|
// Ensure that OLOADTOP/OLOADBOT is unused or zero
|
|
|
|
if mul->type != \SB_MAC16 || (mul->connections_.at(\OLOADTOP, State::S0).is_fully_zero() && mul->connections_.at(\OLOADBOT, State::S0).is_fully_zero())
|
|
|
|
if nusers(sigO.extract(0, 16)) == 2
|
|
|
|
select ffO_lo->type.in($dff)
|
|
|
|
filter GetSize(port(ffO_lo, \D)) >= 16
|
|
|
|
slice offset GetSize(port(ffO_lo, \D))
|
|
|
|
filter offset+GetSize(sigO) <= GetSize(port(ffO_lo, \D)) && port(ffO_lo, \D).extract(offset, 16) == sigO.extract(0, 16)
|
2019-07-22 15:01:49 -05:00
|
|
|
optional
|
2019-01-13 10:03:58 -06:00
|
|
|
endmatch
|
2019-02-17 08:35:48 -06:00
|
|
|
|
2019-09-05 23:39:52 -05:00
|
|
|
code ffO clock clock_pol sigO sigCD cd_signed
|
|
|
|
ffO = nullptr;
|
|
|
|
if (ffO_hilo)
|
|
|
|
ffO = ffO_hilo;
|
2019-09-05 19:58:19 -05:00
|
|
|
else if (ffO_lo)
|
2019-09-05 23:39:52 -05:00
|
|
|
ffO = ffO_lo;
|
|
|
|
if (ffO) {
|
|
|
|
for (auto b : port(ffO, \Q))
|
2019-09-05 19:58:19 -05:00
|
|
|
if (b.wire->get_bool_attribute(\keep))
|
2019-07-22 18:12:57 -05:00
|
|
|
reject;
|
|
|
|
|
2019-09-05 23:39:52 -05:00
|
|
|
SigBit c = port(ffO, \CLK).as_bit();
|
|
|
|
bool cp = param(ffO, \CLK_POLARITY).as_bool();
|
2019-02-17 08:35:48 -06:00
|
|
|
|
2019-09-05 19:58:19 -05:00
|
|
|
if (clock != SigBit() && (c != clock || cp != clock_pol))
|
|
|
|
reject;
|
2019-07-22 18:12:57 -05:00
|
|
|
|
2019-09-05 19:58:19 -05:00
|
|
|
clock = c;
|
|
|
|
clock_pol = cp;
|
2019-07-22 18:12:57 -05:00
|
|
|
|
2019-09-05 23:39:52 -05:00
|
|
|
sigO.replace(port(ffO, \D), port(ffO, \Q));
|
2019-07-23 16:20:34 -05:00
|
|
|
|
|
|
|
// Loading value into output register is not
|
|
|
|
// supported unless using accumulator
|
2019-07-23 16:52:14 -05:00
|
|
|
if (muxAB) {
|
|
|
|
if (sigCD != sigO)
|
2019-07-23 16:20:34 -05:00
|
|
|
reject;
|
|
|
|
if (muxA)
|
|
|
|
sigCD = port(muxAB, \B);
|
|
|
|
else if (muxB)
|
|
|
|
sigCD = port(muxAB, \A);
|
|
|
|
else log_abort();
|
2019-09-05 19:58:19 -05:00
|
|
|
|
|
|
|
cd_signed = addAB && param(addAB, \A_SIGNED).as_bool() && param(addAB, \B_SIGNED).as_bool();
|
2019-07-23 16:20:34 -05:00
|
|
|
}
|
2019-02-17 08:35:48 -06:00
|
|
|
}
|
2019-09-05 19:58:19 -05:00
|
|
|
sigCD.extend_u0(32, cd_signed);
|
|
|
|
endcode
|
|
|
|
|
|
|
|
code
|
2019-08-15 15:47:59 -05:00
|
|
|
accept;
|
2019-02-17 08:35:48 -06:00
|
|
|
endcode
|