Improved handling of reg init in opt_share and opt_rmdff
authorClifford Wolf <clifford@clifford.at>
Tue, 4 Feb 2014 11:02:47 +0000 (12:02 +0100)
committerClifford Wolf <clifford@clifford.at>
Tue, 4 Feb 2014 11:02:47 +0000 (12:02 +0100)
passes/opt/opt_rmdff.cc
passes/opt/opt_share.cc

index a8e2c4121895297701f67075853d296c61f59351..02b7f77e71610a6090b587a689edb22cddd8514d 100644 (file)
@@ -24,7 +24,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 
-static SigMap assign_map;
+static SigMap assign_map, dff_init_map;
 static SigSet<RTLIL::Cell*> mux_drivers;
 
 static bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
@@ -73,6 +73,14 @@ static bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
        assign_map.apply(sig_c);
        assign_map.apply(sig_r);
 
+       bool has_init;
+       RTLIL::Const val_init;
+       for (auto bit : dff_init_map(sig_q).to_sigbit_vector()) {
+               if (bit.wire == NULL)
+                       has_init = true;
+               val_init.bits.push_back(bit.wire == NULL ? bit.data : RTLIL::State::Sx);
+       }
+
        if (dff->type == "$dff" && mux_drivers.has(sig_d)) {
                std::set<RTLIL::Cell*> muxes;
                mux_drivers.find(sig_d, muxes);
@@ -92,31 +100,41 @@ static bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
                }
        }
 
-       if (sig_c.is_fully_const()) {
+       if (sig_c.is_fully_const() && (!sig_r.width || !has_init)) {
                if (val_rv.bits.size() == 0)
-                       val_rv = RTLIL::Const(RTLIL::State::Sx, sig_q.width);
+                       val_rv = val_init;
                RTLIL::SigSig conn(sig_q, val_rv);
                mod->connections.push_back(conn);
                goto delete_dff;
        }
 
-       if (sig_d.is_fully_undef() && sig_d.width == int(val_rv.bits.size())) {
+       if (sig_d.is_fully_undef() && sig_r.width && !has_init) {
                RTLIL::SigSig conn(sig_q, val_rv);
                mod->connections.push_back(conn);
                goto delete_dff;
        }
 
-       if (sig_d.is_fully_const() && sig_r.width == 0) {
+       if (sig_d.is_fully_undef() && !sig_r.width && has_init) {
+               RTLIL::SigSig conn(sig_q, val_init);
+               mod->connections.push_back(conn);
+               goto delete_dff;
+       }
+
+       if (sig_d.is_fully_const() && !sig_r.width && !has_init) {
                RTLIL::SigSig conn(sig_q, sig_d);
                mod->connections.push_back(conn);
                goto delete_dff;
        }
 
-       if (sig_d == sig_q) {
-               if (sig_r.width > 0) {
+       if (sig_d == sig_q && !(sig_r.width && has_init)) {
+               if (sig_r.width) {
                        RTLIL::SigSig conn(sig_q, val_rv);
                        mod->connections.push_back(conn);
                }
+               if (has_init) {
+                       RTLIL::SigSig conn(sig_q, val_init);
+                       mod->connections.push_back(conn);
+               }
                goto delete_dff;
        }
 
@@ -155,6 +173,10 @@ struct OptRmdffPass : public Pass {
                                continue;
 
                        assign_map.set(mod_it.second);
+                       dff_init_map.set(mod_it.second);
+                       for (auto &it : mod_it.second->wires)
+                               if (it.second->attributes.count("\\init") != 0)
+                                       dff_init_map.add(it.second, it.second->attributes.at("\\init"));
                        mux_drivers.clear();
 
                        std::vector<std::string> dff_list;
index 43d1a57e1635dd544bce681d8662bde21e1a9854..eb639d8ab928c277e423bc6fb0cad45738fae9bb 100644 (file)
@@ -35,6 +35,7 @@ struct OptShareWorker
        RTLIL::Design *design;
        RTLIL::Module *module;
        SigMap assign_map;
+       SigMap dff_init_map;
 
        CellTypes ct;
        int total_count;
@@ -178,6 +179,16 @@ struct OptShareWorker
                        return true;
                }
 
+               if (cell1->type.substr(0, 1) == "$" && conn1.count("\\Q") != 0) {
+                       std::vector<RTLIL::SigBit> q1 = dff_init_map(cell1->connections.at("\\Q")).to_sigbit_vector();
+                       std::vector<RTLIL::SigBit> q2 = dff_init_map(cell2->connections.at("\\Q")).to_sigbit_vector();
+                       for (size_t i = 0; i < q1.size(); i++)
+                               if ((q1.at(i).wire == NULL || q2.at(i).wire == NULL) && q1.at(i) != q2.at(i)) {
+                                       lt = q1.at(i) < q2.at(i);
+                                       return true;
+                               }
+               }
+
                return false;
        }
 
@@ -189,6 +200,9 @@ struct OptShareWorker
                if (!ct.cell_known(cell1->type))
                        return cell1 < cell2;
 
+               if (cell1->get_bool_attribute("\\keep") || cell2->get_bool_attribute("\\keep"))
+                       return cell1 < cell2;
+
                bool lt;
                if (compare_cell_parameters_and_connections(cell1, cell2, lt))
                        return lt;
@@ -222,6 +236,11 @@ struct OptShareWorker
                log("Finding identical cells in module `%s'.\n", module->name.c_str());
                assign_map.set(module);
 
+               dff_init_map.set(module);
+               for (auto &it : module->wires)
+                       if (it.second->attributes.count("\\init") != 0)
+                               dff_init_map.add(it.second, it.second->attributes.at("\\init"));
+
                bool did_something = true;
                while (did_something)
                {