Add variable length support to xilinx_srl

This commit is contained in:
Eddie Hung 2019-08-21 17:34:40 -07:00
parent 6d76ae4c65
commit 15188033da
3 changed files with 167 additions and 18 deletions

View File

@ -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;

View File

@ -76,7 +76,7 @@ match next
select !port(next, \D)[0].wire->get_bool_attribute(\keep)
select nusers(port(next, \Q)) == 2
index <IdString> next->type === first->type
index <SigSpec> port(next, \Q) === port(first, \D)
index <SigBit> 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 <IdString> next->type === chain.back()->type
index <SigSpec> port(next, \Q) === port(chain.back(), \D)
index <SigBit> 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 <int> shiftx_width
udata <int> minlen
udata <pool<SigBit>> output_bits
udata <vector<Cell*>> 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 <SigBit> 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 <IdString> next->type === chain.back()->type
index <SigBit> port(next, \Q) === port(chain.back(), \D)
index <SigBit> 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

View File

@ -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)