Improved opt_muxtree
authorClifford Wolf <clifford@clifford.at>
Sat, 17 Jan 2015 11:05:19 +0000 (12:05 +0100)
committerClifford Wolf <clifford@clifford.at>
Sat, 17 Jan 2015 11:05:19 +0000 (12:05 +0100)
passes/opt/opt_muxtree.cc

index 7bdc54afa0c63a1b79b5186142b6d1423e1616c5..fa91d4537b4412feda39c6085e7c57de4c9690b7 100644 (file)
@@ -256,7 +256,7 @@ struct OptMuxtreeWorker
                        list.push_back(value);
        }
 
-       std::vector<int> sig2bits(RTLIL::SigSpec sig)
+       std::vector<int> sig2bits(RTLIL::SigSpec sig, bool skip_non_wires = true)
        {
                std::vector<int> results;
                assign_map.apply(sig);
@@ -271,7 +271,8 @@ struct OptMuxtreeWorker
                                        bit2num[info.bit] = info.num;
                                }
                                results.push_back(bit2num[bit]);
-                       }
+                       } else if (!skip_non_wires)
+                               results.push_back(-1);
                return results;
        }
 
@@ -285,7 +286,7 @@ struct OptMuxtreeWorker
                // database of known active signals
                // the 2nd dimension is the list of or-ed signals. so we know that
                // for each i there is a j so that known_active[i][j] points to an
-               // inactive control signal.
+               // active control signal.
                std::vector<std::vector<int>> known_active;
 
                // this is just used to keep track of visited muxes in order to prohibit
@@ -331,10 +332,43 @@ struct OptMuxtreeWorker
                }
        }
 
+       void replace_known(knowledge_t &knowledge, muxinfo_t &muxinfo, IdString portname)
+       {
+               SigSpec sig = muxinfo.cell->getPort(portname);
+               bool did_something = false;
+
+               std::vector<int> bits = sig2bits(sig, false);
+               for (int i = 0; i < GetSize(bits); i++) {
+                       if (bits[i] < 0)
+                               continue;
+                       if (knowledge.known_inactive[bits[i]]) {
+                               sig[i] = State::S0;
+                               did_something = true;
+                       } else {
+                               for (auto &it : knowledge.known_active)
+                                       if (GetSize(it) == 1 && it.front() == bits[i]) {
+                                               sig[i] = State::S1;
+                                               did_something = true;
+                                               break;
+                                       }
+                       }
+               }
+
+               if (did_something) {
+                       log("    Replacing known input bits on port %s of cell %s: %s -> %s\n", log_id(portname),
+                                       log_id(muxinfo.cell), log_signal(muxinfo.cell->getPort(portname)), log_signal(sig));
+                       muxinfo.cell->setPort(portname, sig);
+               }
+       }
+
        void eval_mux(knowledge_t &knowledge, int mux_idx)
        {
                muxinfo_t &muxinfo = mux2info[mux_idx];
 
+               // set input ports to constants if we find known active or inactive signals
+               replace_known(knowledge, muxinfo, "\\A");
+               replace_known(knowledge, muxinfo, "\\B");
+
                // if there is a constant activated port we just use it
                for (size_t port_idx = 0; port_idx < muxinfo.ports.size()-1; port_idx++)
                {
@@ -360,7 +394,7 @@ struct OptMuxtreeWorker
                }
 
                // compare ports with known_inactive and known_active signals. If all control
-               // signals of the port are know_inactive or if the control signals of all other
+               // signals of the port are known_inactive or if the control signals of all other
                // ports are known_active this port can't be activated. this loop includes the
                // default port but no known_inactive match is performed on the default port.
                for (size_t port_idx = 0; port_idx < muxinfo.ports.size(); port_idx++)