Merge pull request #1637 from YosysHQ/mwk/fix-1634
[yosys.git] / passes / pmgen / ice40_dsp.pmg
index 73e92031e6ff0e227aa0f5fe9b2f43bac2b566df..9d649cb98a2b0b3950a389fa0305b2a771af3867 100644 (file)
@@ -27,6 +27,19 @@ match mul
 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);
@@ -36,35 +49,23 @@ code sigA sigB sigH
        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) {
@@ -85,7 +86,7 @@ code argQ ffA ffAholdmux ffArstmux ffAholdpol ffArstpol sigA clock clock_pol
 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) {
@@ -105,10 +106,10 @@ code argQ ffB ffBholdmux ffBrstmux ffBholdpol ffBrstpol sigB clock clock_pol
        }
 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) {
@@ -139,17 +140,15 @@ code argD ffFJKG sigH sigO clock clock_pol
                        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) {
@@ -171,24 +170,25 @@ code argD ffH sigH sigO clock clock_pol
                        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
@@ -205,7 +205,7 @@ code sigCD sigO cd_signed
                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);
@@ -229,9 +229,9 @@ endcode
 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;
 
@@ -279,8 +279,8 @@ code argD ffO ffOholdmux ffOrstmux ffOholdpol ffOrstpol sigO sigCD clock clock_p
 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) {
@@ -312,11 +312,9 @@ code argQ ffCD ffCDholdmux ffCDholdpol ffCDrstpol sigCD clock clock_pol
                        clock = dffclock;
                        clock_pol = dffclock_pol;
                        sigCD = dffD;
-               }
-       }
 
-       if (0) {
-reject_ffCD: ;
+reject_ffCD:           ;
+               }
        }
 endcode
 
@@ -335,11 +333,16 @@ arg argD argQ clock clock_pol
 
 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
 
@@ -383,6 +386,8 @@ code argQ argD
 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
@@ -486,6 +491,8 @@ code argD argQ
 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