Fix multiple issues in wreduce FF handling, fixes #835
authorClifford Wolf <clifford@clifford.at>
Fri, 1 Mar 2019 01:24:46 +0000 (17:24 -0800)
committerClifford Wolf <clifford@clifford.at>
Fri, 1 Mar 2019 01:24:46 +0000 (17:24 -0800)
Signed-off-by: Clifford Wolf <clifford@clifford.at>
passes/opt/wreduce.cc

index 09983bc67405a8dcd83990a9e60e2ebb58e85ea9..1f7222e494b7c002a2ee7eb1be35069917554e53 100644 (file)
@@ -53,6 +53,7 @@ struct WreduceWorker
        std::set<Cell*, IdString::compare_ptr_by_name<Cell>> work_queue_cells;
        std::set<SigBit> work_queue_bits;
        pool<SigBit> keep_bits;
+       dict<SigBit, State> init_bits;
 
        WreduceWorker(WreduceConfig *config, Module *module) :
                        config(config), module(module), mi(module) { }
@@ -141,6 +142,7 @@ struct WreduceWorker
 
                SigSpec sig_d = mi.sigmap(cell->getPort("\\D"));
                SigSpec sig_q = mi.sigmap(cell->getPort("\\Q"));
+               Const initval;
 
                int width_before = GetSize(sig_q);
 
@@ -150,16 +152,24 @@ struct WreduceWorker
                bool zero_ext = sig_d[GetSize(sig_d)-1] == State::S0;
                bool sign_ext = !zero_ext;
 
+               for (int i = 0; i < GetSize(sig_q); i++) {
+                       SigBit bit = sig_q[i];
+                       if (init_bits.count(bit))
+                               initval.bits.push_back(init_bits.at(bit));
+                       else
+                               initval.bits.push_back(State::Sx);
+               }
+
                for (int i = GetSize(sig_q)-1; i >= 0; i--)
                {
-                       if (zero_ext && sig_d[i] == State::S0) {
+                       if (zero_ext && sig_d[i] == State::S0 && (initval[i] == State::S0 || initval[i] == State::Sx)) {
                                module->connect(sig_q[i], State::S0);
                                sig_d.remove(i);
                                sig_q.remove(i);
                                continue;
                        }
 
-                       if (sign_ext && i > 0 && sig_d[i] == sig_d[i-1]) {
+                       if (sign_ext && i > 0 && sig_d[i] == sig_d[i-1] && initval[i] == initval[i-1]) {
                                module->connect(sig_q[i], sig_q[i-1]);
                                sig_d.remove(i);
                                sig_q.remove(i);
@@ -167,7 +177,7 @@ struct WreduceWorker
                        }
 
                        auto info = mi.query(sig_q[i]);
-                       if (!info->is_output && GetSize(info->ports) <= 1 && !keep_bits.count(mi.sigmap(sig_q[i]))) {
+                       if (!info->is_output && GetSize(info->ports) == 1 && !keep_bits.count(mi.sigmap(sig_q[i]))) {
                                sig_d.remove(i);
                                sig_q.remove(i);
                                zero_ext = false;
@@ -183,10 +193,11 @@ struct WreduceWorker
 
                if (GetSize(sig_q) == 0) {
                        log("Removed cell %s.%s (%s).\n", log_id(module), log_id(cell), log_id(cell->type));
+                       module->remove(cell);
                        return;
                }
 
-               log("Removed top %d bits (of %d) from mux cell %s.%s (%s).\n", width_before - GetSize(sig_q), width_before,
+               log("Removed top %d bits (of %d) from FF cell %s.%s (%s).\n", width_before - GetSize(sig_q), width_before,
                                log_id(module), log_id(cell), log_id(cell->type));
 
                for (auto bit : sig_d)
@@ -376,10 +387,18 @@ struct WreduceWorker
 
        void run()
        {
-               for (auto w : module->wires())
+               for (auto w : module->wires()) {
                        if (w->get_bool_attribute("\\keep"))
                                for (auto bit : mi.sigmap(w))
                                        keep_bits.insert(bit);
+                       if (w->attributes.count("\\init")) {
+                               Const initval = w->attributes.at("\\init");
+                               SigSpec initsig = mi.sigmap(w);
+                               int width = std::min(GetSize(initval), GetSize(initsig));
+                               for (int i = 0; i < width; i++)
+                                       init_bits[initsig[i]] = initval[i];
+                       }
+               }
 
                for (auto c : module->selected_cells())
                        work_queue_cells.insert(c);