From 15188033da68c89c409af0839f22e6acc573abb7 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 21 Aug 2019 17:34:40 -0700 Subject: [PATCH] Add variable length support to xilinx_srl --- passes/pmgen/xilinx_srl.cc | 112 ++++++++++++++++++++++++++++---- passes/pmgen/xilinx_srl.pmg | 66 ++++++++++++++++++- techlibs/xilinx/synth_xilinx.cc | 7 +- 3 files changed, 167 insertions(+), 18 deletions(-) diff --git a/passes/pmgen/xilinx_srl.cc b/passes/pmgen/xilinx_srl.cc index 029cb3235..ce77a3308 100644 --- a/passes/pmgen/xilinx_srl.cc +++ b/passes/pmgen/xilinx_srl.cc @@ -30,7 +30,7 @@ bool did_something; #include "passes/pmgen/ice40_dsp_pm.h" #include "passes/pmgen/peepopt_pm.h" -void fixed(xilinx_srl_pm &pm) +void run_fixed(xilinx_srl_pm &pm) { auto &st = pm.st_fixed; auto &ud = pm.ud_fixed; @@ -39,7 +39,7 @@ void fixed(xilinx_srl_pm &pm) return cell->parameters.at(param, def); }; - log("Found chain of length %d (%s):\n", GetSize(ud.longest_chain), log_id(st.first->type)); + log("Found fixed chain of length %d (%s):\n", GetSize(ud.longest_chain), log_id(st.first->type)); auto last_cell = ud.longest_chain.back(); @@ -97,6 +97,68 @@ void fixed(xilinx_srl_pm &pm) log(" -> %s (%s)\n", log_id(c), log_id(c->type)); } +void run_variable(xilinx_srl_pm &pm) +{ + auto &st = pm.st_variable; + auto &ud = pm.ud_variable; + + log("Found variable chain of length %d (%s):\n", GetSize(ud.chain), log_id(st.first->type)); + + auto last_cell = ud.chain.back(); + + SigSpec initval; + for (auto cell : ud.chain) { + log_debug(" %s\n", log_id(cell)); + if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) { + SigBit Q = cell->getPort(ID(Q)); + log_assert(Q.wire); + auto it = Q.wire->attributes.find(ID(init)); + if (it != Q.wire->attributes.end()) { + initval.append(it->second[Q.offset]); + } + else + initval.append(State::Sx); + } + else + log_abort(); + if (cell != last_cell) + pm.autoremove(cell); + } + pm.autoremove(st.shiftx); + + Cell *c = last_cell; + SigBit Q = st.first->getPort(ID(Q)); + c->setPort(ID(Q), Q); + + if (c->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) { + c->parameters.clear(); + c->setParam(ID(DEPTH), GetSize(ud.chain)); + c->setParam(ID(INIT), initval.as_const()); + if (c->type.in(ID($_DFF_P_), ID($_DFFE_PN_), ID($_DFFE_PP_))) + c->setParam(ID(CLKPOL), 1); + else if (c->type.in(ID($_DFF_N_), ID($DFFE_NN_), ID($_DFFE_NP_), ID(FDRE_1))) + c->setParam(ID(CLKPOL), 0); + else + log_abort(); + if (c->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_))) + c->setParam(ID(ENPOL), 1); + else if (c->type.in(ID($_DFFE_NN_), ID($_DFFE_PN_))) + c->setParam(ID(ENPOL), 0); + else + c->setParam(ID(ENPOL), 2); + if (c->type.in(ID($_DFF_N_), ID($_DFF_P_))) + c->setPort(ID(E), State::S1); + c->setPort(ID(L), st.shiftx->getPort(ID(B))); + c->setPort(ID(Q), st.shiftx->getPort(ID(Y))); + c->type = ID($__XILINX_SHREG_); + } + else + log_abort(); + + log(" -> %s (%s)\n", log_id(c), log_id(c->type)); + +} + struct XilinxSrlPass : public Pass { XilinxSrlPass() : Pass("xilinx_srl", "Xilinx shift register extraction") { } void help() YS_OVERRIDE @@ -113,6 +175,8 @@ struct XilinxSrlPass : public Pass { { log_header(design, "Executing XILINX_SRL pass (Xilinx shift register extraction).\n"); + bool fixed = false; + bool variable = false; int minlen = 3; size_t argidx; @@ -122,22 +186,46 @@ struct XilinxSrlPass : public Pass { minlen = atoi(args[++argidx].c_str()); continue; } + if (args[argidx] == "-fixed") { + fixed = true; + continue; + } + if (args[argidx] == "-variable") { + variable = true; + continue; + } break; } extra_args(args, argidx, design); + if (!fixed && !variable) + log_cmd_error("'-fixed' and/or '-variable' must be specified.\n"); + for (auto module : design->selected_modules()) { bool did_something = false; - do { - auto pm = xilinx_srl_pm(module, module->selected_cells()); - pm.ud_fixed.minlen = minlen; - // TODO: How to get these automatically? - pm.ud_fixed.default_params[std::make_pair(ID(FDRE),ID(INIT))] = State::S0; - pm.ud_fixed.default_params[std::make_pair(ID(FDRE),ID(IS_C_INVERTED))] = State::S0; - pm.ud_fixed.default_params[std::make_pair(ID(FDRE),ID(IS_D_INVERTED))] = State::S0; - pm.ud_fixed.default_params[std::make_pair(ID(FDRE),ID(IS_R_INVERTED))] = State::S0; - did_something = pm.run_fixed(fixed); - } while (did_something); + if (fixed) + do { + auto pm = xilinx_srl_pm(module, module->selected_cells()); + pm.ud_fixed.minlen = minlen; + // TODO: How to get these automatically? + pm.ud_fixed.default_params[std::make_pair(ID(FDRE),ID(INIT))] = State::S0; + pm.ud_fixed.default_params[std::make_pair(ID(FDRE),ID(IS_C_INVERTED))] = State::S0; + pm.ud_fixed.default_params[std::make_pair(ID(FDRE),ID(IS_D_INVERTED))] = State::S0; + pm.ud_fixed.default_params[std::make_pair(ID(FDRE),ID(IS_R_INVERTED))] = State::S0; + did_something = pm.run_fixed(run_fixed); + } while (did_something); + if (variable) + do { + auto pm = xilinx_srl_pm(module, module->selected_cells()); + pm.ud_variable.minlen = minlen; + for (auto p : module->ports) { + auto w = module->wire(p); + if (w->port_output) + for (auto b : pm.sigmap(w)) + pm.ud_variable.output_bits.insert(b); + } + did_something = pm.run_variable(run_variable); + } while (did_something); } } } XilinxSrlPass; diff --git a/passes/pmgen/xilinx_srl.pmg b/passes/pmgen/xilinx_srl.pmg index e7086c424..3f4efebe9 100644 --- a/passes/pmgen/xilinx_srl.pmg +++ b/passes/pmgen/xilinx_srl.pmg @@ -76,7 +76,7 @@ match next select !port(next, \D)[0].wire->get_bool_attribute(\keep) select nusers(port(next, \Q)) == 2 index next->type === first->type - index port(next, \Q) === port(first, \D) + index port(next, \Q) === port(first, \D) endmatch code @@ -109,7 +109,7 @@ match next select !port(next, \D)[0].wire->get_bool_attribute(\keep) select nusers(port(next, \Q)) == 2 index next->type === chain.back()->type - index port(next, \Q) === port(chain.back(), \D) + index port(next, \Q) === port(chain.back(), \D) //generate 10 // SigSpec A = module->addWire(NEW_ID); // SigSpec B = module->addWire(NEW_ID); @@ -145,3 +145,65 @@ finally if (next) chain.pop_back(); endcode + +// ----------- + +pattern variable + +state shiftx_width +udata minlen +udata > output_bits +udata > chain + +match shiftx + select shiftx->type.in($shiftx) + select !shiftx->has_keep_attr() + select param(shiftx, \Y_WIDTH) == 1 + filter param(shiftx, \A_WIDTH).as_int() >= minlen +endmatch + +code shiftx_width + shiftx_width = param(shiftx, \A_WIDTH).as_int(); +endcode + +match first + select first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_) + select nusers(port(first, \Q)) == 2 + index port(first, \Q) === port(shiftx, \A)[shiftx_width-1] + filter !output_bits.count(port(first, \Q)) +endmatch + +code + chain.push_back(first); + subpattern(tail); +finally + if (GetSize(chain) == param(shiftx, \A_WIDTH).as_int()) + accept; + chain.clear(); +endcode + +// ------------------------------------------------------------------ + +subpattern tail +arg shiftx +arg shiftx_width + +match next + semioptional + select next->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_) + select !next->has_keep_attr() + select !port(next, \D)[0].wire->get_bool_attribute(\keep) + select nusers(port(next, \Q)) == 3 + filter !output_bits.count(port(next, \Q)) + index next->type === chain.back()->type + index port(next, \Q) === port(chain.back(), \D) + index port(next, \Q) === port(shiftx, \A)[shiftx_width-1-GetSize(chain)] +endmatch + +code + if (next) { + chain.push_back(next); + if (GetSize(chain) < shiftx_width) + subpattern(tail); + } +endcode diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 2c5f2ec57..8bf43bf97 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -352,9 +352,8 @@ struct SynthXilinxPass : public ScriptPass if (!nosrl || help_mode) { // shregmap operates on bit-level flops, not word-level, // so break those down here - run("simplemap t:$dff t:$dffe", " (skip if '-nosrl')"); - // shregmap with '-tech xilinx' infers variable length shift regs - run("shregmap -tech xilinx -minlen 3", "(skip if '-nosrl')"); + run("simplemap t:$dff t:$dffe", " (skip if '-nosrl')"); + run("xilinx_srl -variable -minlen 3", "(skip if '-nosrl')"); } std::string techmap_args = " -map +/techmap.v"; @@ -414,7 +413,7 @@ struct SynthXilinxPass : public ScriptPass // This shregmap call infers fixed length shift registers after abc // has performed any necessary retiming if (!nosrl || help_mode) - run("xilinx_srl -minlen 3", "(skip if '-nosrl')"); + run("xilinx_srl -fixed -minlen 3", "(skip if '-nosrl')"); std::string techmap_args = "-map +/xilinx/lut_map.v -map +/xilinx/cells_map.v"; if (help_mode) -- 2.30.2