X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=passes%2Ftechmap%2Fshregmap.cc;h=3868bbb8948b0acc12eaa4732c1f9623aaa24d09;hb=935df3569b4677ac38041ff01a2f67185681f4e3;hp=a541b33bef692bf9b277eda3437526519c91cbd5;hpb=4df4a97ffa77ad75013a0b616f25a2be4fc77e34;p=yosys.git diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index a541b33be..3868bbb89 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -28,8 +28,9 @@ struct ShregmapTech virtual ~ShregmapTech() { } virtual void init(const Module * /*module*/, const SigMap &/*sigmap*/) {} virtual void non_chain_user(const SigBit &/*bit*/, const Cell* /*cell*/, IdString /*port*/) {} + virtual bool analyze_first(const Cell* /*first_cell*/, const SigMap &/*sigmap*/) { return true; } virtual bool analyze(vector &taps, const vector &qbits) = 0; - virtual bool fixup(Cell *cell, dict &taps) = 0; + virtual Cell* fixup(Cell *cell, const vector &taps, const vector &qbits) = 0; }; struct ShregmapOptions @@ -56,7 +57,7 @@ struct ShregmapOptions struct ShregmapTechGreenpak4 : ShregmapTech { - bool analyze(vector &taps, const vector &/*qbits*/) + virtual bool analyze(vector &taps, const vector &/*qbits*/) override { if (GetSize(taps) > 2 && taps[0] == 0 && taps[2] < 17) { taps.clear(); @@ -71,7 +72,7 @@ struct ShregmapTechGreenpak4 : ShregmapTech return true; } - bool fixup(Cell *cell, dict &taps) + virtual Cell* fixup(Cell *cell, const vector &taps, const vector &qbits) override { auto D = cell->getPort("\\D"); auto C = cell->getPort("\\C"); @@ -83,22 +84,148 @@ struct ShregmapTechGreenpak4 : ShregmapTech int i = 0; for (auto tap : taps) { - newcell->setPort(i ? "\\OUTB" : "\\OUTA", tap.second); - newcell->setParam(i ? "\\OUTB_TAP" : "\\OUTA_TAP", tap.first + 1); + newcell->setPort(i ? "\\OUTB" : "\\OUTA", qbits[tap]); + newcell->setParam(i ? "\\OUTB_TAP" : "\\OUTA_TAP", tap + 1); i++; } cell->setParam("\\OUTA_INVERT", 0); - return false; + return newcell; } }; -struct ShregmapTechXilinx7 : ShregmapTech +struct ShregmapTechXilinx7Static : ShregmapTech { - dict> sigbit_to_shiftx_offset; + dict sigbit_to_cell; const ShregmapOptions &opts; - ShregmapTechXilinx7(const ShregmapOptions &opts) : opts(opts) {} + virtual void init(const Module* module, const SigMap &sigmap) override + { + for (const auto &i : module->cells_) { + auto cell = i.second; + if (!cell->type.in("\\FDRE", "\\FDRE_1","\\FDSE", "\\FDSE_1", + "\\FDCE", "\\FDCE_1", "\\FDPE", "\\FDPE_1")) + continue; + + sigbit_to_cell[sigmap(cell->getPort("\\Q"))] = cell; + } + } + + ShregmapTechXilinx7Static(const ShregmapOptions &opts) : opts(opts) {} + + virtual bool analyze_first(const Cell* first_cell, const SigMap &sigmap) override + { + if (first_cell->type.in("\\FDRE", "\\FDRE_1")) { + bool is_R_inverted = false; + if (first_cell->hasParam("\\IS_R_INVERTED")) + is_R_inverted = first_cell->getParam("\\IS_R_INVERTED").as_bool(); + SigBit R = sigmap(first_cell->getPort("\\R")); + if (R != RTLIL::S0 && R != RTLIL::S1) + return false; + if ((!is_R_inverted && R != RTLIL::S0) || (is_R_inverted && R != RTLIL::S1)) + return false; + return true; + } + if (first_cell->type.in("\\FDSE", "\\FDSE_1")) { + bool is_S_inverted = false; + if (first_cell->hasParam("\\IS_S_INVERTED")) + is_S_inverted = first_cell->getParam("\\IS_S_INVERTED").as_bool(); + SigBit S = sigmap(first_cell->getPort("\\S")); + if (S != RTLIL::S0 && S != RTLIL::S1) + return false; + if ((!is_S_inverted && S != RTLIL::S0) || (is_S_inverted && S != RTLIL::S1)) + return false; + return true; + } + if (first_cell->type.in("\\FDCE", "\\FDCE_1")) { + bool is_CLR_inverted = false; + if (first_cell->hasParam("\\IS_CLR_INVERTED")) + is_CLR_inverted = first_cell->getParam("\\IS_CLR_INVERTED").as_bool(); + SigBit CLR = sigmap(first_cell->getPort("\\CLR")); + if (CLR != RTLIL::S0 && CLR != RTLIL::S1) + return false; + if ((!is_CLR_inverted && CLR != RTLIL::S0) || (is_CLR_inverted && CLR != RTLIL::S1)) + return false; + return true; + } + if (first_cell->type.in("\\FDPE", "\\FDPE_1")) { + bool is_PRE_inverted = false; + if (first_cell->hasParam("\\IS_PRE_INVERTED")) + is_PRE_inverted = first_cell->getParam("\\IS_PRE_INVERTED").as_bool(); + SigBit PRE = sigmap(first_cell->getPort("\\PRE")); + if (PRE != RTLIL::S0 && PRE != RTLIL::S1) + return false; + if ((!is_PRE_inverted && PRE != RTLIL::S0) || (is_PRE_inverted && PRE != RTLIL::S1)) + return false; + return true; + } + return true; + } + + virtual bool analyze(vector &taps, const vector &/*qbits*/) override + { + return GetSize(taps) == 1 && taps[0] >= opts.minlen-1; + } + + virtual Cell* fixup(Cell *cell, const vector &/*taps*/, const vector &qbits) override + { + auto newcell = cell->module->addCell(NEW_ID, "$__SHREG_"); + newcell->set_src_attribute(cell->get_src_attribute()); + newcell->setParam("\\DEPTH", cell->getParam("\\DEPTH")); + + if (cell->type.in("$__SHREG_DFF_N_", "$__SHREG_DFF_P_", + "$__SHREG_DFFE_NN_", "$__SHREG_DFFE_NP_", "$__SHREG_DFFE_PN_", "$__SHREG_DFFE_PP_")) { + int param_clkpol = -1; + int param_enpol = 2; + if (cell->type == "$__SHREG_DFF_N_") param_clkpol = 0; + else if (cell->type == "$__SHREG_DFF_P_") param_clkpol = 1; + else if (cell->type == "$__SHREG_DFFE_NN_") param_clkpol = 0, param_enpol = 0; + else if (cell->type == "$__SHREG_DFFE_NP_") param_clkpol = 0, param_enpol = 1; + else if (cell->type == "$__SHREG_DFFE_PN_") param_clkpol = 1, param_enpol = 0; + else if (cell->type == "$__SHREG_DFFE_PP_") param_clkpol = 1, param_enpol = 1; + else log_abort(); + + log_assert(param_clkpol >= 0); + newcell->setParam("\\CLKPOL", param_clkpol); + newcell->setParam("\\ENPOL", param_enpol); + newcell->setParam("\\INIT", cell->getParam("\\INIT")); + + if (cell->hasPort("\\E")) + newcell->setPort("\\E", cell->getPort("\\E")); + } + else if (cell->type.in("$__SHREG_FDRE", "$__SHREG_FDRE_1","$__SHREG_FDSE", "$__SHREG_FDSE_1", + "$__SHREG_FDCE", "$__SHREG_FDCE_1", "$__SHREG_FDPE", "$__SHREG_FDPE_1")) { + int param_clkpol = 1; + if (cell->hasParam("\\IS_C_INVERTED") && cell->getParam("\\IS_C_INVERTED").as_bool()) + param_clkpol = 0; + newcell->setParam("\\CLKPOL", param_clkpol); + newcell->setParam("\\ENPOL", 1); + log_assert(cell->getParam("\\INIT").is_fully_undef()); + SigSpec INIT; + for (auto q : qbits) { + Cell* reg = sigbit_to_cell.at(q); + INIT.append(SigBit(reg->getParam("\\INIT").as_bool())); + } + + newcell->setPort("\\E", cell->getPort("\\CE")); + } + else log_abort(); + + newcell->setParam("\\ENPOL", 1); + + newcell->setPort("\\C", cell->getPort("\\C")); + newcell->setPort("\\D", cell->getPort("\\D")); + newcell->setPort("\\Q", cell->getPort("\\Q")); + + return newcell; + } +}; + +struct ShregmapTechXilinx7Dynamic : ShregmapTechXilinx7Static +{ + dict> sigbit_to_shiftx_offset; + + ShregmapTechXilinx7Dynamic(const ShregmapOptions &opts) : ShregmapTechXilinx7Static(opts) {} virtual void init(const Module* module, const SigMap &sigmap) override { @@ -147,13 +274,14 @@ struct ShregmapTechXilinx7 : ShregmapTech Cell *shiftx = nullptr; int group = 0; for (int i = 0; i < GetSize(taps); ++i) { + // Check taps are sequential + if (i != taps[i]) + return false; + auto it = sigbit_to_shiftx_offset.find(qbits[i]); if (it == sigbit_to_shiftx_offset.end()) return false; - // Check taps are sequential - if (i != taps[i]) - return false; // Check taps are not connected to a shift register, // or sequential to the same shift register if (i == 0) { @@ -178,7 +306,17 @@ struct ShregmapTechXilinx7 : ShregmapTech // Only map if $shiftx exclusively covers the shift register if (shiftx->type == "$shiftx") { - if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int()) + if (GetSize(taps) > shiftx->getParam("\\A_WIDTH").as_int()) + return false; + // Due to padding the most significant bits of A may be 1'bx, + // and if so, discount them + if (GetSize(taps) < shiftx->getParam("\\A_WIDTH").as_int()) { + const SigSpec A = shiftx->getPort("\\A"); + const int A_width = shiftx->getParam("\\A_WIDTH").as_int(); + for (int i = GetSize(taps); i < A_width; ++i) + if (A[i] != RTLIL::Sx) return false; + } + else if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int()) return false; } else if (shiftx->type == "$mux") { @@ -190,44 +328,31 @@ struct ShregmapTechXilinx7 : ShregmapTech return true; } - virtual bool fixup(Cell *cell, dict &taps) override + virtual Cell* fixup(Cell *cell, const vector &taps, const vector &qbits) override { - const auto &tap = *taps.begin(); - auto bit = tap.second; + auto bit = qbits[taps.front()]; auto it = sigbit_to_shiftx_offset.find(bit); log_assert(it != sigbit_to_shiftx_offset.end()); - auto newcell = cell->module->addCell(NEW_ID, "$__XILINX_SHREG_"); - newcell->set_src_attribute(cell->get_src_attribute()); - newcell->setParam("\\DEPTH", cell->getParam("\\DEPTH")); - newcell->setParam("\\INIT", cell->getParam("\\INIT")); - newcell->setParam("\\CLKPOL", cell->getParam("\\CLKPOL")); - newcell->setParam("\\ENPOL", cell->getParam("\\ENPOL")); - - newcell->setPort("\\C", cell->getPort("\\C")); - newcell->setPort("\\D", cell->getPort("\\D")); - if (cell->hasPort("\\E")) - newcell->setPort("\\E", cell->getPort("\\E")); + Cell* newcell = ShregmapTechXilinx7Static::fixup(cell, taps, qbits); + log_assert(newcell); + log_assert(newcell->type == "$__SHREG_"); + newcell->type = "$__XILINX_SHREG_"; Cell* shiftx = std::get<0>(it->second); - RTLIL::SigSpec l_wire, q_wire; - if (shiftx->type == "$shiftx") { + RTLIL::SigSpec l_wire; + if (shiftx->type == "$shiftx") l_wire = shiftx->getPort("\\B"); - q_wire = shiftx->getPort("\\Y"); - shiftx->setPort("\\Y", cell->module->addWire(NEW_ID)); - } - else if (shiftx->type == "$mux") { + else if (shiftx->type == "$mux") l_wire = shiftx->getPort("\\S"); - q_wire = shiftx->getPort("\\Y"); - shiftx->setPort("\\Y", cell->module->addWire(NEW_ID)); - } else log_abort(); - newcell->setPort("\\Q", q_wire); newcell->setPort("\\L", l_wire); + newcell->setPort("\\Q", shiftx->getPort("\\Y")); + shiftx->setPort("\\Y", cell->module->addWire(NEW_ID)); - return false; + return newcell; } }; @@ -381,12 +506,15 @@ struct ShregmapWorker Cell *first_cell = chain[cursor]; IdString q_port = opts.ffcells.at(first_cell->type).second; - dict taps_dict; + vector qbits; + vector taps; if (opts.tech) { - vector qbits; - vector taps; + if (!opts.tech->analyze_first(first_cell, sigmap)) { + cursor += depth; + continue; + } for (int i = 0; i < depth; i++) { @@ -412,7 +540,6 @@ struct ShregmapWorker depth = 0; for (auto tap : taps) { - taps_dict[tap] = qbits.at(tap); log_assert(depth < tap+1); depth = tap+1; } @@ -483,7 +610,7 @@ struct ShregmapWorker first_cell->setPort(q_port, last_cell->getPort(q_port)); first_cell->setParam("\\DEPTH", depth); - if (opts.tech != nullptr && !opts.tech->fixup(first_cell, taps_dict)) + if (opts.tech != nullptr && opts.tech->fixup(first_cell, taps, qbits)) remove_cells.insert(first_cell); for (int i = 1; i < depth; i++) @@ -650,11 +777,26 @@ struct ShregmapPass : public Pass { opts.zinit = true; opts.tech = new ShregmapTechGreenpak4; } - else if (tech == "xilinx") { + else if (tech == "xilinx_static" || tech == "xilinx_dynamic") { opts.init = true; - opts.params = true; - enpol = "any_or_none"; - opts.tech = new ShregmapTechXilinx7(opts); + opts.ffcells["$_DFF_P_"] = make_pair(IdString("\\D"), IdString("\\Q")); + opts.ffcells["$_DFF_N_"] = make_pair(IdString("\\D"), IdString("\\Q")); + opts.ffcells["$_DFFE_PP_"] = make_pair(IdString("\\D"), IdString("\\Q")); + opts.ffcells["$_DFFE_PN_"] = make_pair(IdString("\\D"), IdString("\\Q")); + opts.ffcells["$_DFFE_NP_"] = make_pair(IdString("\\D"), IdString("\\Q")); + opts.ffcells["$_DFFE_NN_"] = make_pair(IdString("\\D"), IdString("\\Q")); + opts.ffcells["\\FDRE"] = make_pair(IdString("\\D"), IdString("\\Q")); + opts.ffcells["\\FDRE_1"] = make_pair(IdString("\\D"), IdString("\\Q")); + opts.ffcells["\\FDSE"] = make_pair(IdString("\\D"), IdString("\\Q")); + opts.ffcells["\\FDSE_1"] = make_pair(IdString("\\D"), IdString("\\Q")); + opts.ffcells["\\FDCE"] = make_pair(IdString("\\D"), IdString("\\Q")); + opts.ffcells["\\FDCE_1"] = make_pair(IdString("\\D"), IdString("\\Q")); + opts.ffcells["\\FDPE"] = make_pair(IdString("\\D"), IdString("\\Q")); + opts.ffcells["\\FDPE_1"] = make_pair(IdString("\\D"), IdString("\\Q")); + if (tech == "xilinx_static") + opts.tech = new ShregmapTechXilinx7Static(opts); + else if (tech == "xilinx_dynamic") + opts.tech = new ShregmapTechXilinx7Dynamic(opts); } else { argidx--; break;