diff options
Diffstat (limited to 'passes/opt/opt_rmdff.cc')
-rw-r--r-- | passes/opt/opt_rmdff.cc | 246 |
1 files changed, 238 insertions, 8 deletions
diff --git a/passes/opt/opt_rmdff.cc b/passes/opt/opt_rmdff.cc index 922f086f..5880254c 100644 --- a/passes/opt/opt_rmdff.cc +++ b/passes/opt/opt_rmdff.cc @@ -39,11 +39,201 @@ 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; + + if (cell->type == "$dlatchsr") + 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 = dlatch->getPort("\\EN"); + SigSpec sig_e; + State on_state, off_state; + + if (dlatch->type == "$dlatch") { + sig_e = assign_map(dlatch->getPort("\\EN")); + on_state = dlatch->getParam("\\EN_POLARITY").as_bool() ? State::S1 : State::S0; + off_state = dlatch->getParam("\\EN_POLARITY").as_bool() ? State::S0 : State::S1; + } else + if (dlatch->type == "$_DLATCH_P_") { + sig_e = assign_map(dlatch->getPort("\\E")); + on_state = State::S1; + off_state = State::S0; + } else + if (dlatch->type == "$_DLATCH_N_") { + sig_e = assign_map(dlatch->getPort("\\E")); + on_state = State::S0; + off_state = State::S1; + } else + log_abort(); - if (sig_e == State::S0) + if (sig_e == off_state) { RTLIL::Const val_init; for (auto bit : dff_init_map(dlatch->getPort("\\Q"))) @@ -52,7 +242,7 @@ bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch) goto delete_dlatch; } - if (sig_e == State::S1) + if (sig_e == on_state) { mod->connect(dlatch->getPort("\\Q"), dlatch->getPort("\\D")); goto delete_dlatch; @@ -168,7 +358,7 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff) goto delete_dff; } - if (sig_d == sig_q && (!sig_r.size() || !has_init || val_init == val_rv)) { + if (sig_d == sig_q && (sig_r.empty() || !has_init || val_init == val_rv)) { if (sig_r.size()) mod->connect(sig_q, val_rv); if (has_init) @@ -176,6 +366,28 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff) goto delete_dff; } + if (!sig_r.empty() && sig_r.is_fully_const()) + { + if (sig_r == val_rp || sig_r.is_fully_undef()) { + mod->connect(sig_q, val_rv); + goto delete_dff; + } + + log("Removing unused reset from %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod)); + + if (dff->type == "$adff") { + dff->type = "$dff"; + dff->unsetPort("\\ARST"); + dff->unsetParam("\\ARST_POLARITY"); + dff->unsetParam("\\ARST_VALUE"); + return true; + } + + log_assert(dff->type.substr(0,6) == "$_DFF_"); + dff->type = stringf("$_DFF_%c_", + dff->type[6]); + dff->unsetPort("\\R"); + } + return false; delete_dff: @@ -187,7 +399,7 @@ delete_dff: struct OptRmdffPass : public Pass { OptRmdffPass() : Pass("opt_rmdff", "remove DFFs with constant inputs") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -197,7 +409,7 @@ struct OptRmdffPass : public Pass { log("a constant driver.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { int total_count = 0, total_initdrv = 0; log_header(design, "Executing OPT_RMDFF pass (remove dff with constant values).\n"); @@ -221,12 +433,16 @@ struct OptRmdffPass : public Pass { assign_map.set(module); dff_init_map.set(module); + mux_drivers.clear(); + init_attributes.clear(); for (auto wire : module->wires()) { if (wire->attributes.count("\\init") != 0) { Const initval = wire->attributes.at("\\init"); - dff_init_map.add(wire, initval); + for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++) + if (initval[i] == State::S0 || initval[i] == State::S1) + dff_init_map.add(SigBit(wire, i), initval[i]); for (int i = 0; i < GetSize(wire); i++) { SigBit wire_bit(wire, i), mapped_bit = assign_map(wire_bit); if (mapped_bit.wire) { @@ -245,6 +461,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()) { @@ -262,16 +479,28 @@ 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_", "$ff", "$dff", "$adff")) dff_list.push_back(cell->name); - if (cell->type == "$dlatch") + if (cell->type.in("$dlatch", "$_DLATCH_P_", "$_DLATCH_N_")) 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])) @@ -310,6 +539,7 @@ struct OptRmdffPass : public Pass { assign_map.clear(); mux_drivers.clear(); + init_attributes.clear(); if (total_count || total_initdrv) design->scratchpad_set_bool("opt.did_something", true); |