Add support for set-reset cell variants to opt_rmdff
authorClifford Wolf <clifford@clifford.at>
Wed, 9 Aug 2017 11:29:52 +0000 (13:29 +0200)
committerClifford Wolf <clifford@clifford.at>
Wed, 9 Aug 2017 11:29:52 +0000 (13:29 +0200)
passes/opt/opt_rmdff.cc

index 80217464c0edbc76191bbefce783730688ba001b..02f3e93f5a0ac02d99e12bc38592864c9e234621 100644 (file)
@@ -39,6 +39,175 @@ void remove_init_attr(SigSpec sig)
                                wbit.wire->attributes.at("\\init")[wbit.offset] = State::Sx;
 }
 
+bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell)
+{
+       SigSpec sig_set, sig_clr;
+       State pol_set, pol_clr;
+
+       if (cell->hasPort("\\S"))
+               sig_set = cell->getPort("\\S");
+
+       if (cell->hasPort("\\R"))
+               sig_clr = cell->getPort("\\R");
+
+       if (cell->hasPort("\\SET"))
+               sig_set = cell->getPort("\\SET");
+
+       if (cell->hasPort("\\CLR"))
+               sig_clr = cell->getPort("\\CLR");
+
+       log_assert(GetSize(sig_set) == GetSize(sig_clr));
+
+       if (cell->type.substr(0,8) == "$_DFFSR_") {
+               pol_set = cell->type[9] == 'P' ? State::S1 : State::S0;
+               pol_clr = cell->type[10] == 'P' ? State::S1 : State::S0;
+       } else
+       if (cell->type.substr(0,11) == "$_DLATCHSR_") {
+               pol_set = cell->type[12] == 'P' ? State::S1 : State::S0;
+               pol_clr = cell->type[13] == 'P' ? State::S1 : State::S0;
+       } else
+       if (cell->type == "$dffsr" || cell->type == "$dlatchsr") {
+               pol_set = cell->parameters["\\SET_POLARITY"].as_bool() ? State::S1 : State::S0;
+               pol_clr = cell->parameters["\\CLR_POLARITY"].as_bool() ? State::S1 : State::S0;
+       } else
+               log_abort();
+
+       State npol_set = pol_set == State::S0 ? State::S1 : State::S0;
+       State npol_clr = pol_clr == State::S0 ? State::S1 : State::S0;
+
+       SigSpec sig_d = cell->getPort("\\D");
+       SigSpec sig_q = cell->getPort("\\Q");
+
+       bool did_something = false;
+       bool proper_sr = false;
+       bool used_pol_set = false;
+       bool used_pol_clr = false;
+       bool hasreset = false;
+       Const reset_val;
+       SigSpec sig_reset;
+
+       for (int i = 0; i < GetSize(sig_set); i++)
+       {
+               SigBit s = sig_set[i], c = sig_clr[i];
+
+               if (s != npol_set || c != npol_clr)
+                       hasreset = true;
+
+               if (s == pol_set || c == pol_clr)
+               {
+                       log("Constantly %s Q bit %s for SR cell %s (%s) from module %s.\n",
+                                       s == pol_set ? "set" : "cleared", log_signal(sig_q[i]),
+                                       log_id(cell), log_id(cell->type), log_id(mod));
+
+                       remove_init_attr(sig_q[i]);
+                       mod->connect(sig_q[i], s == pol_set ? State::S1 : State::S0);
+                       sig_set.remove(i);
+                       sig_clr.remove(i);
+                       sig_d.remove(i);
+                       sig_q.remove(i--);
+                       did_something = true;
+                       continue;
+               }
+               if (sig_reset.empty() && s.wire != nullptr) sig_reset = s;
+               if (sig_reset.empty() && c.wire != nullptr) sig_reset = c;
+
+               if (s.wire != nullptr && s != sig_reset) proper_sr = true;
+               if (c.wire != nullptr && c != sig_reset) proper_sr = true;
+
+               if ((s.wire == nullptr) != (c.wire == nullptr)) {
+                       if (s.wire != nullptr) used_pol_set = true;
+                       if (c.wire != nullptr) used_pol_clr = true;
+                       reset_val.bits.push_back(c.wire == nullptr ? State::S1 : State::S0);
+               } else
+                       proper_sr = true;
+       }
+
+       if (!hasreset)
+               proper_sr = false;
+
+       if (GetSize(sig_set) == 0)
+       {
+               log("Removing %s (%s) from module %s.\n", log_id(cell), log_id(cell->type), log_id(mod));
+               mod->remove(cell);
+               return true;
+       }
+
+       if (cell->type == "$dffsr" || cell->type == "$dlatchsr")
+       {
+               cell->setParam("\\WIDTH", GetSize(sig_d));
+               cell->setPort("\\SET", sig_set);
+               cell->setPort("\\CLR", sig_clr);
+               cell->setPort("\\D", sig_d);
+               cell->setPort("\\Q", sig_q);
+       }
+       else
+       {
+               cell->setPort("\\S", sig_set);
+               cell->setPort("\\R", sig_clr);
+               cell->setPort("\\D", sig_d);
+               cell->setPort("\\Q", sig_q);
+       }
+
+       if (proper_sr)
+               return did_something;
+
+       if (used_pol_set && used_pol_clr && pol_set != pol_clr)
+               return did_something;
+
+       State unified_pol = used_pol_set ? pol_set : pol_clr;
+
+       if (cell->type == "$dffsr")
+       {
+               if (hasreset)
+               {
+                       log("Converting %s (%s) to %s in module %s.\n", log_id(cell), log_id(cell->type), "$adff", log_id(mod));
+
+                       cell->type = "$adff";
+                       cell->setParam("\\ARST_POLARITY", unified_pol);
+                       cell->setParam("\\ARST_VALUE", reset_val);
+                       cell->setPort("\\ARST", sig_reset);
+
+                       cell->unsetParam("\\SET_POLARITY");
+                       cell->unsetParam("\\CLR_POLARITY");
+                       cell->unsetPort("\\SET");
+                       cell->unsetPort("\\CLR");
+
+                       return true;
+               }
+               else
+               {
+                       log("Converting %s (%s) to %s in module %s.\n", log_id(cell), log_id(cell->type), "$dff", log_id(mod));
+
+                       cell->type = "$dff";
+                       cell->unsetParam("\\SET_POLARITY");
+                       cell->unsetParam("\\CLR_POLARITY");
+                       cell->unsetPort("\\SET");
+                       cell->unsetPort("\\CLR");
+
+                       return true;
+               }
+       }
+       else
+       {
+               IdString new_type;
+
+               if (cell->type.substr(0,8) == "$_DFFSR_")
+                       new_type = stringf("$_DFF_%c_", cell->type[8]);
+               else if (cell->type.substr(0,11) == "$_DLATCHSR_")
+                       new_type = stringf("$_DLATCH_%c_", cell->type[11]);
+               else
+                       log_abort();
+
+               log("Converting %s (%s) to %s in module %s.\n", log_id(cell), log_id(cell->type), log_id(new_type), log_id(mod));
+
+               cell->type = new_type;
+               cell->unsetPort("\\S");
+               cell->unsetPort("\\R");
+
+               return did_something;
+       }
+}
+
 bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch)
 {
        SigSpec sig_e;
@@ -287,6 +456,7 @@ struct OptRmdffPass : public Pass {
                        mux_drivers.clear();
 
                        std::vector<RTLIL::IdString> dff_list;
+                       std::vector<RTLIL::IdString> dffsr_list;
                        std::vector<RTLIL::IdString> dlatch_list;
                        for (auto cell : module->cells())
                        {
@@ -304,6 +474,12 @@ struct OptRmdffPass : public Pass {
                                if (!design->selected(module, cell))
                                        continue;
 
+                               if (cell->type.in("$_DFFSR_NNN_", "$_DFFSR_NNP_", "$_DFFSR_NPN_", "$_DFFSR_NPP_",
+                                               "$_DFFSR_PNN_", "$_DFFSR_PNP_", "$_DFFSR_PPN_", "$_DFFSR_PPP_", "$dffsr",
+                                               "$_DLATCHSR_NNN_", "$_DLATCHSR_NNP_", "$_DLATCHSR_NPN_", "$_DLATCHSR_NPP_",
+                                               "$_DLATCHSR_PNN_", "$_DLATCHSR_PNP_", "$_DLATCHSR_PPN_", "$_DLATCHSR_PPP_", "$dlatchsr"))
+                                       dffsr_list.push_back(cell->name);
+
                                if (cell->type.in("$_FF_", "$_DFF_N_", "$_DFF_P_",
                                                "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
                                                "$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_",
@@ -314,6 +490,12 @@ struct OptRmdffPass : public Pass {
                                        dlatch_list.push_back(cell->name);
                        }
 
+                       for (auto &id : dffsr_list) {
+                               if (module->cell(id) != nullptr &&
+                                               handle_dffsr(module, module->cells_[id]))
+                                       total_count++;
+                       }
+
                        for (auto &id : dff_list) {
                                if (module->cell(id) != nullptr &&
                                                handle_dff(module, module->cells_[id]))