diff options
Diffstat (limited to 'passes/pmgen/ice40_dsp.pmg')
-rw-r--r-- | passes/pmgen/ice40_dsp.pmg | 153 |
1 files changed, 96 insertions, 57 deletions
diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 1f3590d4e..73439cfd9 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -1,87 +1,88 @@ pattern ice40_dsp state <SigBit> clock -state <bool> clock_pol clock_vld -state <SigSpec> sigA sigB sigY sigS +state <bool> clock_pol sigCD_signed +state <SigSpec> sigA sigB sigCD sigH sigO state <Cell*> addAB muxAB match mul - select mul->type.in($mul) + select mul->type.in($mul, $__MUL16X16) select GetSize(mul->getPort(\A)) + GetSize(mul->getPort(\B)) > 10 select GetSize(mul->getPort(\Y)) > 10 endmatch match ffA select ffA->type.in($dff) - // select nusers(port(ffA, \Q)) == 2 - index <SigSpec> port(ffA, \Q) === port(mul, \A) + filter !port(mul, \A).remove_const().empty() + filter includes(port(ffA, \Q).to_sigbit_set(), port(mul, \A).remove_const().to_sigbit_set()) optional endmatch -code sigA clock clock_pol clock_vld +code sigA clock clock_pol sigA = port(mul, \A); if (ffA) { - sigA = port(ffA, \D); - clock = port(ffA, \CLK).as_bit(); clock_pol = param(ffA, \CLK_POLARITY).as_bool(); - clock_vld = true; + + sigA.replace(port(ffA, \Q), port(ffA, \D)); } endcode match ffB select ffB->type.in($dff) - // select nusers(port(ffB, \Q)) == 2 - index <SigSpec> port(ffB, \Q) === port(mul, \B) + filter !port(mul, \B).remove_const().empty() + filter includes(port(ffB, \Q).to_sigbit_set(), port(mul, \B).remove_const().to_sigbit_set()) optional endmatch -code sigB clock clock_pol clock_vld +code sigB clock clock_pol sigB = port(mul, \B); if (ffB) { - sigB = port(ffB, \D); SigBit c = port(ffB, \CLK).as_bit(); bool cp = param(ffB, \CLK_POLARITY).as_bool(); - if (clock_vld && (c != clock || cp != clock_pol)) + if (clock != SigBit() && (c != clock || cp != clock_pol)) reject; clock = c; clock_pol = cp; - clock_vld = true; + + sigB.replace(port(ffB, \Q), port(ffB, \D)); } endcode -match ffY - select ffY->type.in($dff) - select nusers(port(ffY, \D)) == 2 - index <SigSpec> port(ffY, \D) === port(mul, \Y) +match ffH + select ffH->type.in($dff) + select nusers(port(ffH, \D)) == 2 + index <SigSpec> port(ffH, \D) === port(mul, \Y) optional endmatch -code sigY clock clock_pol clock_vld - sigY = port(mul, \Y); +code sigH sigO clock clock_pol + sigH = port(mul, \Y); + sigO = sigH; - if (ffY) { - sigY = port(ffY, \Q); - SigBit c = port(ffY, \CLK).as_bit(); - bool cp = param(ffY, \CLK_POLARITY).as_bool(); + if (ffH) { + sigH = port(ffH, \Q); + sigO = sigH; - if (clock_vld && (c != clock || cp != clock_pol)) + SigBit c = port(ffH, \CLK).as_bit(); + bool cp = param(ffH, \CLK_POLARITY).as_bool(); + + if (clock != SigBit() && (c != clock || cp != clock_pol)) reject; clock = c; clock_pol = cp; - clock_vld = true; } endcode match addA select addA->type.in($add) select nusers(port(addA, \A)) == 2 - index <SigSpec> port(addA, \A) === sigY + index <SigSpec> port(addA, \A) === sigH optional endmatch @@ -89,74 +90,112 @@ match addB if !addA select addB->type.in($add, $sub) select nusers(port(addB, \B)) == 2 - index <SigSpec> port(addB, \B) === sigY + index <SigSpec> port(addB, \B) === sigH optional endmatch -code addAB sigS +code addAB sigCD sigCD_signed sigO if (addA) { addAB = addA; - sigS = port(addA, \B); + sigCD = port(addAB, \B); + sigCD_signed = param(addAB, \B_SIGNED).as_bool(); } if (addB) { addAB = addB; - sigS = port(addB, \A); + sigCD = port(addAB, \A); + sigCD_signed = param(addAB, \A_SIGNED).as_bool(); } if (addAB) { int natural_mul_width = GetSize(sigA) + GetSize(sigB); - int actual_mul_width = GetSize(sigY); - int actual_acc_width = GetSize(sigS); + int actual_mul_width = GetSize(sigH); + int actual_acc_width = GetSize(sigO); if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width)) reject; - if ((actual_acc_width != actual_mul_width) && (param(mul, \A_SIGNED).as_bool() != param(addAB, \A_SIGNED).as_bool())) + if ((actual_acc_width != actual_mul_width) && (param(mul, \A_SIGNED).as_bool() != param(addAB, \B_SIGNED).as_bool())) reject; + + sigO = port(addAB, \Y); } endcode match muxA - if addAB select muxA->type.in($mux) select nusers(port(muxA, \A)) == 2 - index <SigSpec> port(muxA, \A) === port(addAB, \Y) + index <SigSpec> port(muxA, \A) === sigO optional endmatch match muxB - if addAB if !muxA select muxB->type.in($mux) select nusers(port(muxB, \B)) == 2 - index <SigSpec> port(muxB, \B) === port(addAB, \Y) + index <SigSpec> port(muxB, \B) === sigO optional endmatch code muxAB - muxAB = addAB; if (muxA) muxAB = muxA; - if (muxB) + else if (muxB) muxAB = muxB; endcode -match ffS - if muxAB - select ffS->type.in($dff) - select nusers(port(ffS, \D)) == 2 - index <SigSpec> port(ffS, \D) === port(muxAB, \Y) - index <SigSpec> port(ffS, \Q) === sigS +match ffO_lo + select ffO_lo->type.in($dff) + filter nusers(sigO.extract(0,16)) == 2 + filter includes(port(ffO_lo, \D).to_sigbit_set(), sigO.extract(0,16).to_sigbit_set()) + optional endmatch -code clock clock_pol clock_vld - if (ffS) { - SigBit c = port(ffS, \CLK).as_bit(); - bool cp = param(ffS, \CLK_POLARITY).as_bool(); - - if (clock_vld && (c != clock || cp != clock_pol)) - reject; +match ffO_hi + select ffO_hi->type.in($dff) + filter nusers(sigO.extract(16,16)) == 2 + filter includes(port(ffO_hi, \D).to_sigbit_set(), sigO.extract(16,16).to_sigbit_set()) + optional +endmatch - clock = c; - clock_pol = cp; - clock_vld = true; +code clock clock_pol sigO sigCD sigCD_signed + if (ffO_lo || ffO_hi) { + if (ffO_lo) { + SigBit c = port(ffO_lo, \CLK).as_bit(); + bool cp = param(ffO_lo, \CLK_POLARITY).as_bool(); + + if (clock != SigBit() && (c != clock || cp != clock_pol)) + reject; + + clock = c; + clock_pol = cp; + + if (port(ffO_lo, \Q) != sigO.extract(0,16)) + sigO.replace(port(ffO_lo, \D), port(ffO_lo, \Q)); + } + + if (ffO_hi) { + SigBit c = port(ffO_hi, \CLK).as_bit(); + bool cp = param(ffO_hi, \CLK_POLARITY).as_bool(); + + if (clock != SigBit() && (c != clock || cp != clock_pol)) + reject; + + clock = c; + clock_pol = cp; + + if (port(ffO_hi, \Q) != sigO.extract(16,16)) + sigO.replace(port(ffO_hi, \D), port(ffO_hi, \Q)); + } + + // Loading value into output register is not + // supported unless using accumulator + if (muxAB) { + if (sigCD != sigO) + reject; + if (muxA) + sigCD = port(muxAB, \B); + else if (muxB) + sigCD = port(muxAB, \A); + else log_abort(); + sigCD_signed = addAB && param(addAB, \A_SIGNED).as_bool() && param(addAB, \B_SIGNED).as_bool(); + } } endcode |