diff options
Diffstat (limited to 'passes/opt/opt_rmdff.cc')
-rw-r--r-- | passes/opt/opt_rmdff.cc | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/passes/opt/opt_rmdff.cc b/passes/opt/opt_rmdff.cc index 80217464c..02f3e93f5 100644 --- a/passes/opt/opt_rmdff.cc +++ b/passes/opt/opt_rmdff.cc @@ -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])) |