From ce7c980ec755c481182de9bd078e190bd8d9ff51 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sun, 17 Apr 2016 15:37:22 +0200 Subject: [PATCH] Improvements in "shregmap" --- passes/techmap/shregmap.cc | 170 ++++++++++++++++++++++++++++++------- 1 file changed, 140 insertions(+), 30 deletions(-) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index ad5c50cd6..d9c725573 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -25,13 +25,12 @@ PRIVATE_NAMESPACE_BEGIN struct ShregmapOptions { - std::string clkpol; int minlen, maxlen; int keep_before, keep_after; + dict> ffcells; ShregmapOptions() { - clkpol = "any"; minlen = 2; maxlen = 0; keep_before = 0; @@ -46,41 +45,59 @@ struct ShregmapWorker const ShregmapOptions &opts; int dff_count, shreg_count; + pool remove_cells; - // next is set to NULL for sigbits that drive non-DFFs + dict sigbit_init; dict sigbit_chain_next; dict sigbit_chain_prev; + pool sigbit_with_non_chain_users; pool chain_start_cells; void make_sigbit_chain_next_prev() { - for (auto wire : module->wires()) { - if (!wire->port_output) - continue; - for (auto bit : sigmap(wire)) - sigbit_chain_next[bit] = nullptr; + for (auto wire : module->wires()) + { + if (wire->port_output) { + for (auto bit : sigmap(wire)) + sigbit_with_non_chain_users.insert(bit); + } + + if (wire->attributes.count("\\init")) { + SigSpec initsig = sigmap(wire); + Const initval = wire->attributes.at("\\init"); + for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++) + if (initval[i] == State::S0) + sigbit_init[initsig[i]] = false; + else if (initval[i] == State::S1) + sigbit_init[initsig[i]] = true; + } } for (auto cell : module->cells()) { - if ((opts.clkpol != "pos" && cell->type == "$_DFF_N_") || - (opts.clkpol != "neg" && cell->type == "$_DFF_P_")) + if (opts.ffcells.count(cell->type)) { - SigBit d_bit = sigmap(cell->getPort("\\D").as_bit()); - if (sigbit_chain_next.count(d_bit)) - sigbit_chain_next[d_bit] = nullptr; - else - sigbit_chain_next[d_bit] = cell; - - SigBit q_bit = sigmap(cell->getPort("\\Q").as_bit()); - sigbit_chain_prev[q_bit] = cell; - continue; + IdString d_port = opts.ffcells.at(cell->type).first; + IdString q_port = opts.ffcells.at(cell->type).second; + + SigBit d_bit = sigmap(cell->getPort(d_port).as_bit()); + SigBit q_bit = sigmap(cell->getPort(q_port).as_bit()); + + if (sigbit_init.count(q_bit) == 0) { + if (sigbit_chain_next.count(d_bit)) { + sigbit_with_non_chain_users.insert(d_bit); + } else + sigbit_chain_next[d_bit] = cell; + + sigbit_chain_prev[q_bit] = cell; + continue; + } } for (auto conn : cell->connections()) if (cell->input(conn.first)) for (auto bit : sigmap(conn.second)) - sigbit_chain_next[bit] = nullptr; + sigbit_with_non_chain_users.insert(bit); } } @@ -88,7 +105,7 @@ struct ShregmapWorker { for (auto it : sigbit_chain_next) { - if (it.second == nullptr) + if (sigbit_with_non_chain_users.count(it.first)) continue; if (sigbit_chain_prev.count(it.first) != 0) @@ -99,7 +116,22 @@ struct ShregmapWorker if (c1->type != c2->type) goto start_cell; - if (sigmap(c1->getPort("\\C")) != c2->getPort("\\C")) + if (c1->parameters != c2->parameters) + goto start_cell; + + IdString d_port = opts.ffcells.at(c1->type).first; + IdString q_port = opts.ffcells.at(c1->type).second; + + auto c1_conn = c1->connections(); + auto c2_conn = c1->connections(); + + c1_conn.erase(d_port); + c1_conn.erase(q_port); + + c2_conn.erase(d_port); + c2_conn.erase(q_port); + + if (c1_conn != c2_conn) goto start_cell; continue; @@ -119,7 +151,8 @@ struct ShregmapWorker { chain.push_back(c); - SigBit q_bit = sigmap(c->getPort("\\Q").as_bit()); + IdString q_port = opts.ffcells.at(c->type).second; + SigBit q_bit = sigmap(c->getPort(q_port).as_bit()); if (sigbit_chain_next.count(q_bit) == 0) break; @@ -153,16 +186,36 @@ struct ShregmapWorker log("Converting %s.%s ... %s.%s to a shift register with depth %d.\n", log_id(module), log_id(first_cell), log_id(module), log_id(last_cell), depth); - first_cell->type = "$__DFF_SHREG_" + first_cell->type.substr(6); - first_cell->setPort("\\Q", last_cell->getPort("\\Q")); + dff_count += depth; + shreg_count += 1; + + string shreg_cell_type_str = "$__SHREG"; + if (first_cell->type[1] != '_') + shreg_cell_type_str += "_"; + shreg_cell_type_str += first_cell->type.substr(1); + + IdString q_port = opts.ffcells.at(first_cell->type).second; + first_cell->type = shreg_cell_type_str; + first_cell->setPort(q_port, last_cell->getPort(q_port)); first_cell->setParam("\\DEPTH", depth); for (int i = 1; i < depth; i++) - module->remove(chain[cursor+i]); + remove_cells.insert(chain[cursor+i]); cursor += depth; } } + void cleanup() + { + for (auto cell : remove_cells) + module->remove(cell); + + remove_cells.clear(); + sigbit_chain_next.clear(); + sigbit_chain_prev.clear(); + chain_start_cells.clear(); + } + ShregmapWorker(Module *module, const ShregmapOptions &opts) : module(module), sigmap(module), opts(opts), dff_count(0), shreg_count(0) { @@ -174,6 +227,8 @@ struct ShregmapWorker vector chain = create_chain(c); process_chain(chain); } + + cleanup(); } }; @@ -186,7 +241,7 @@ struct ShregmapPass : public Pass { log(" shregmap [options] [selection]\n"); log("\n"); log("This pass converts chains of $_DFF_[NP]_ gates to target specific shift register.\n"); - log("primitives. The generated shift register will be of type $__DFF_SHREG_[NP]_ and\n"); + log("primitives. The generated shift register will be of type $__SHREG_DFF_[NP]_ and\n"); log("will use the same interface as the original $_DFF_*_ cells. The cell parameter\n"); log("'DEPTH' will contain the depth of the shift register. Use a target-specific\n"); log("'techmap' map file to convert those cells to the actual target cells.\n"); @@ -208,10 +263,20 @@ struct ShregmapPass : public Pass { log(" -clkpol pos|neg|any\n"); log(" limit match to only positive or negative edge clocks. (default = any)\n"); log("\n"); + log(" -enpol pos|neg|none|any_or_none|any\n"); + log(" limit match to FFs with the specified enable polarity. (default = none)\n"); + log("\n"); + log(" -match [::]\n"); + log(" match the specified cells instead of $_DFF_N_ and $_DFF_P_. If\n"); + log(" '::' is omitted then 'D' and 'Q' is used\n"); + log(" by default. E.g. the option '-clkpol pos' is just an alias for\n"); + log(" '-match $_DFF_P_', which is an alias for '-match $_DFF_P_:D:Q'.\n"); + log("\n"); } virtual void execute(std::vector args, RTLIL::Design *design) { ShregmapOptions opts; + string clkpol, enpol; log_header("Executing SHREGMAP pass (map shift registers).\n"); @@ -219,7 +284,23 @@ struct ShregmapPass : public Pass { for (argidx = 1; argidx < args.size(); argidx++) { if (args[argidx] == "-clkpol" && argidx+1 < args.size()) { - opts.clkpol = args[++argidx]; + clkpol = args[++argidx]; + continue; + } + if (args[argidx] == "-enpol" && argidx+1 < args.size()) { + enpol = args[++argidx]; + continue; + } + if (args[argidx] == "-match" && argidx+1 < args.size()) { + vector match_args = split_tokens(args[++argidx], ":"); + if (GetSize(match_args) < 2) + match_args.push_back("D"); + if (GetSize(match_args) < 3) + match_args.push_back("Q"); + IdString id_cell_type(RTLIL::escape_id(match_args[0])); + IdString id_d_port_name(RTLIL::escape_id(match_args[1])); + IdString id_q_port_name(RTLIL::escape_id(match_args[2])); + opts.ffcells[id_cell_type] = make_pair(id_d_port_name, id_q_port_name); continue; } if (args[argidx] == "-minlen" && argidx+1 < args.size()) { @@ -242,8 +323,37 @@ struct ShregmapPass : public Pass { } extra_args(args, argidx, design); - if (opts.clkpol != "pos" && opts.clkpol != "neg" && opts.clkpol != "any") - log_cmd_error("Invalid value for -clkpol: %s\n", opts.clkpol.c_str()); + if (opts.ffcells.empty()) + { + bool clk_pos = clkpol == "" || clkpol == "pos" || clkpol == "any"; + bool clk_neg = clkpol == "" || clkpol == "neg" || clkpol == "any"; + + bool en_none = enpol == "" || enpol == "none" || enpol == "any_or_none"; + bool en_pos = enpol == "pos" || enpol == "any" || enpol == "any_or_none"; + bool en_neg = enpol == "neg" || enpol == "any" || enpol == "any_or_none"; + + if (clk_pos && en_none) + opts.ffcells["$_DFF_P_"] = make_pair(IdString("\\D"), IdString("\\Q")); + if (clk_neg && en_none) + opts.ffcells["$_DFF_N_"] = make_pair(IdString("\\D"), IdString("\\Q")); + + if (clk_pos && en_pos) + opts.ffcells["$_DFFE_PP_"] = make_pair(IdString("\\D"), IdString("\\Q")); + if (clk_pos && en_neg) + opts.ffcells["$_DFFE_PN_"] = make_pair(IdString("\\D"), IdString("\\Q")); + + if (clk_neg && en_pos) + opts.ffcells["$_DFFE_NP_"] = make_pair(IdString("\\D"), IdString("\\Q")); + if (clk_neg && en_neg) + opts.ffcells["$_DFFE_NN_"] = make_pair(IdString("\\D"), IdString("\\Q")); + } + else + { + if (!clkpol.empty()) + log_cmd_error("Options -clkpol and -match are exclusive!\n"); + if (!enpol.empty()) + log_cmd_error("Options -enpol and -match are exclusive!\n"); + } int dff_count = 0; int shreg_count = 0; -- 2.30.2