Fix broken ice40_dsp
authorEddie Hung <eddie@fpgeh.com>
Fri, 6 Sep 2019 00:58:19 +0000 (17:58 -0700)
committerEddie Hung <eddie@fpgeh.com>
Fri, 6 Sep 2019 00:58:19 +0000 (17:58 -0700)
passes/pmgen/ice40_dsp.cc
passes/pmgen/ice40_dsp.pmg

index 31e11c7426c46ce73f614473b91868fef962b0f4..8f5191be7cc4a5b0499fce05ef8952ed62ee1963 100644 (file)
@@ -28,6 +28,7 @@ PRIVATE_NAMESPACE_BEGIN
 void create_ice40_dsp(ice40_dsp_pm &pm)
 {
        auto &st = pm.st_ice40_dsp;
+       Cell* ffO = st.ffO ? st.ffO : st.ffO_lo;
 
 #if 1
        log("\n");
@@ -37,8 +38,7 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
        log("ffFJKG: %s\n", log_id(st.ffFJKG, "--"));
        log("addAB:  %s\n", log_id(st.addAB, "--"));
        log("muxAB:  %s\n", log_id(st.muxAB, "--"));
-       log("ffO_lo: %s\n", log_id(st.ffO_lo, "--"));
-       log("ffO_hi: %s\n", log_id(st.ffO_hi, "--"));
+       log("ffO:    %s\n", log_id(ffO, "--"));
 #endif
 
        log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(st.mul));
@@ -118,10 +118,8 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
                if (st.ffFJKG)
                        log(" ffFJKG:%s", log_id(st.ffFJKG));
 
-               if (st.ffO_lo)
-                       log(" ffO_lo:%s", log_id(st.ffO_lo));
-               if (st.ffO_hi)
-                       log(" ffO_hi:%s", log_id(st.ffO_hi));
+               if (ffO)
+                       log(" ffO:%s", log_id(ffO));
 
                log("\n");
        }
@@ -167,9 +165,9 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
        bool accum = false;
        if (st.addAB) {
                if (st.addA)
-                       accum = (st.ffO_lo && st.ffO_hi && st.addAB->getPort("\\B") == st.sigO);
+                       accum = (ffO && st.addAB->getPort("\\B") == st.sigO);
                else if (st.addB)
-                       accum = (st.ffO_lo && st.ffO_hi && st.addAB->getPort("\\A") == st.sigO);
+                       accum = (ffO && st.addAB->getPort("\\A") == st.sigO);
                else log_abort();
                if (accum)
                        log("  accumulator %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type));
@@ -207,12 +205,10 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
        cell->setParam("\\PIPELINE_16x16_MULT_REG1", st.ffFJKG ? State::S1 : State::S0);
        cell->setParam("\\PIPELINE_16x16_MULT_REG2", State::S0);
 
-       cell->setParam("\\TOPOUTPUT_SELECT", Const(st.ffO_hi ? 1 : (st.addAB ? 0 : 3), 2));
        cell->setParam("\\TOPADDSUB_LOWERINPUT", Const(2, 2));
        cell->setParam("\\TOPADDSUB_UPPERINPUT", accum ? State::S0 : State::S1);
        cell->setParam("\\TOPADDSUB_CARRYSELECT", Const(3, 2));
 
-       cell->setParam("\\BOTOUTPUT_SELECT", Const(st.ffO_lo ? 1 : (st.addAB ? 0 : 3), 2));
        cell->setParam("\\BOTADDSUB_LOWERINPUT", Const(2, 2));
        cell->setParam("\\BOTADDSUB_UPPERINPUT", accum ? State::S0 : State::S1);
        cell->setParam("\\BOTADDSUB_CARRYSELECT", Const(0, 2));
@@ -221,20 +217,26 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
        cell->setParam("\\A_SIGNED", st.mul->getParam("\\A_SIGNED").as_bool());
        cell->setParam("\\B_SIGNED", st.mul->getParam("\\B_SIGNED").as_bool());
 
+       if (ffO) {
+               if (st.ffO)
+                       cell->setParam("\\TOPOUTPUT_SELECT", Const(1, 2));
+               else
+                       cell->setParam("\\TOPOUTPUT_SELECT", Const(st.addAB ? 0 : 3, 2));
+
+               ffO->connections_.at("\\Q").replace(O, pm.module->addWire(NEW_ID, GetSize(O)));
+               cell->setParam("\\BOTOUTPUT_SELECT", Const(1, 2));
+       }
+       else {
+               cell->setParam("\\TOPOUTPUT_SELECT", Const(st.addAB ? 0 : 3, 2));
+               cell->setParam("\\BOTOUTPUT_SELECT", Const(st.addAB ? 0 : 3, 2));
+       }
+
        if (cell != st.mul)
                pm.autoremove(st.mul);
        else
                pm.blacklist(st.mul);
        pm.autoremove(st.ffFJKG);
        pm.autoremove(st.addAB);
-       if (st.ffO_lo) {
-                       SigSpec O = st.sigO.extract(0,std::min(16,st.ffO_lo->getParam("\\WIDTH").as_int()));
-                       st.ffO_lo->connections_.at("\\Q").replace(O, pm.module->addWire(NEW_ID, GetSize(O)));
-       }
-       if (st.ffO_hi) {
-                       SigSpec O = st.sigO.extract_end(16);
-                       st.ffO_hi->connections_.at("\\Q").replace(O, pm.module->addWire(NEW_ID, GetSize(O)));
-       }
 }
 
 struct Ice40DspPass : public Pass {
index 8221cdb69c94eb78bb7535d5061a7c97ec39cf4e..4baea8aefc69349c5865a39d15614d8e296df961 100644 (file)
@@ -1,7 +1,7 @@
 pattern ice40_dsp
 
 state <SigBit> clock
-state <bool> clock_pol
+state <bool> clock_pol cd_signed
 state <std::set<SigBit>> sigAset sigBset
 state <SigSpec> sigA sigB sigCD sigH sigO sigOused
 state <Cell*> addAB muxAB
@@ -21,13 +21,22 @@ code sigAset sigBset
 endcode
 
 code sigH
+       SigSpec O;
        if (mul->type == $mul)
-               sigH = mul->getPort(\Y);
+               O = mul->getPort(\Y);
        else if (mul->type == \SB_MAC16)
-               sigH = mul->getPort(\O);
+               O = mul->getPort(\O);
        else log_abort();
-       if (GetSize(sigH) <= 10)
+       if (GetSize(O) <= 10)
                reject;
+       // 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]);
+       }
+       log_assert(nusers(O.extract_end(i)) <= 1);
 endcode
 
 match ffA
@@ -136,17 +145,16 @@ match addB
        optional
 endmatch
 
-code addAB sigCD sigO
-       bool CD_SIGNED = false;
+code addAB sigCD sigO cd_signed
        if (addA) {
                addAB = addA;
                sigCD = port(addAB, \B);
-               CD_SIGNED = param(addAB, \B_SIGNED).as_bool();
+               cd_signed = param(addAB, \B_SIGNED).as_bool();
        }
-       if (addB) {
+       else if (addB) {
                addAB = addB;
                sigCD = port(addAB, \A);
-               CD_SIGNED = param(addAB, \A_SIGNED).as_bool();
+               cd_signed = param(addAB, \A_SIGNED).as_bool();
        }
        if (addAB) {
                if (mul->type == \SB_MAC16) {
@@ -167,7 +175,6 @@ code addAB sigCD sigO
                        reject;
 
                sigO = port(addAB, \Y);
-               sigCD.extend_u0(32, CD_SIGNED);
        }
 endcode
 
@@ -186,105 +193,63 @@ match muxB
        optional
 endmatch
 
-code muxAB
+code muxAB sigO
        if (muxA)
                muxAB = muxA;
        else if (muxB)
                muxAB = muxB;
+       if (muxAB)
+               sigO = port(muxAB, \Y);
 endcode
 
-// Extract the bits of P that actually have a consumer
-// (as opposed to being a dummy)
-code sigOused
-       for (int i = 0; i < GetSize(sigO); i++)
-               if (!sigO[i].wire || nusers(sigO[i]) == 1)
-                       sigOused.append(State::Sx);
-               else
-                       sigOused.append(sigO[i]);
-endcode
-
-match ffO_lo
-       if nusers(sigOused.extract(0,std::min(16,GetSize(sigOused)))) == 2
-       select ffO_lo->type.in($dff)
+match ffO
+       // 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
+       select ffO->type.in($dff)
+       filter GetSize(port(ffO, \D)) >= GetSize(sigO)
+       slice offset GetSize(port(ffO, \D))
+       filter offset+GetSize(sigO) <= GetSize(port(ffO, \D)) && port(ffO, \D).extract(offset, GetSize(sigO)) == sigO
        optional
 endmatch
 
-code
-       if (ffO_lo) {
-               SigSpec O = sigOused.extract(0,std::min(16,param(ffO_lo, \WIDTH).as_int()));
-               O.remove_const();
-               auto ffO_loSet = port(ffO_lo, \D).to_sigbit_set();
-               auto Oset = O.to_sigbit_set();
-               if (!std::includes(ffO_loSet.begin(), ffO_loSet.end(), Oset.begin(), Oset.end()))
-                       reject;
-       }
-endcode
-
-match ffO_hi
-       if GetSize(sigOused) > 16
-       if nusers(sigOused.extract_end(16)) == 2
-       select ffO_hi->type.in($dff)
+match ffO_lo
+       if !ffO && GetSize(sigO) > 16
+       // 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)
        optional
 endmatch
 
-code
-       if (ffO_hi) {
-               SigSpec O = sigOused.extract_end(16);
-               O.remove_const();
-               auto ffO_hiSet = port(ffO_hi, \D).to_sigbit_set();
-               auto Oset = O.to_sigbit_set();
-               if (!std::includes(ffO_hiSet.begin(), ffO_hiSet.end(), Oset.begin(), Oset.end()))
-                       reject;
-       }
-endcode
-
-code clock clock_pol sigO sigCD
-       if (ffO_lo || ffO_hi) {
-               if (mul->type == \SB_MAC16) {
-                       // Ensure that register is not already used
-                       if (param(mul, \TOPOUTPUT_SELECT).as_int() == 1 ||
-                                       param(mul, \BOTOUTPUT_SELECT).as_int() == 1)
-                               reject;
-
-                       // Ensure that OLOADTOP/OLOADBOT is unused or zero
-                       if ((mul->hasPort(\OLOADTOP) && !port(mul, \OLOADTOP).is_fully_zero())
-                               || (mul->hasPort(\OLOADBOT) && !port(mul, \OLOADBOT).is_fully_zero()))
-                               reject;
-               }
-
-               if (ffO_lo) {
-                       for (auto b : port(ffO_lo, \Q))
-                               if (b.wire->get_bool_attribute(\keep))
-                                       reject;
-
-                       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))
+code clock clock_pol sigO sigCD cd_signed
+       Cell* ff = nullptr;
+       if (ffO)
+               ff = ffO;
+       else if (ffO_lo)
+               ff = ffO_lo;
+       if (ff) {
+               for (auto b : port(ff, \Q))
+                       if (b.wire->get_bool_attribute(\keep))
                                reject;
 
-                       clock = c;
-                       clock_pol = cp;
-
-                       sigO.replace(port(ffO_lo, \D), port(ffO_lo, \Q));
-               }
-
-               if (ffO_hi) {
-                       for (auto b : port(ffO_hi, \Q))
-                               if (b.wire->get_bool_attribute(\keep))
-                                       reject;
-
-                       SigBit c = port(ffO_hi, \CLK).as_bit();
-                       bool cp = param(ffO_hi, \CLK_POLARITY).as_bool();
+               SigBit c = port(ff, \CLK).as_bit();
+               bool cp = param(ff, \CLK_POLARITY).as_bool();
 
-                       if (clock != SigBit() && (c != clock || cp != clock_pol))
-                               reject;
+               if (clock != SigBit() && (c != clock || cp != clock_pol))
+                       reject;
 
-                       clock = c;
-                       clock_pol = cp;
+               clock = c;
+               clock_pol = cp;
 
-                       sigO.replace(port(ffO_hi, \D), port(ffO_hi, \Q));
-               }
+               sigO.replace(port(ff, \D), port(ff, \Q));
 
                // Loading value into output register is not
                //   supported unless using accumulator
@@ -296,8 +261,13 @@ code clock clock_pol sigO sigCD
                        else if (muxB)
                                sigCD = port(muxAB, \A);
                        else log_abort();
-                       sigCD.extend_u0(32, addAB && param(addAB, \A_SIGNED).as_bool() && param(addAB, \B_SIGNED).as_bool());
+
+                       cd_signed = addAB && param(addAB, \A_SIGNED).as_bool() && param(addAB, \B_SIGNED).as_bool();
                }
        }
+       sigCD.extend_u0(32, cd_signed);
+endcode
+
+code
        accept;
 endcode