mirror of https://github.com/YosysHQ/yosys.git
Add variable length support to xilinx_srl
This commit is contained in:
parent
6d76ae4c65
commit
15188033da
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue