mirror of https://github.com/YosysHQ/yosys.git
This commit is contained in:
commit
b2c36f6136
|
@ -25,13 +25,12 @@ PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
struct ShregmapOptions
|
struct ShregmapOptions
|
||||||
{
|
{
|
||||||
std::string clkpol;
|
|
||||||
int minlen, maxlen;
|
int minlen, maxlen;
|
||||||
int keep_before, keep_after;
|
int keep_before, keep_after;
|
||||||
|
dict<IdString, pair<IdString, IdString>> ffcells;
|
||||||
|
|
||||||
ShregmapOptions()
|
ShregmapOptions()
|
||||||
{
|
{
|
||||||
clkpol = "any";
|
|
||||||
minlen = 2;
|
minlen = 2;
|
||||||
maxlen = 0;
|
maxlen = 0;
|
||||||
keep_before = 0;
|
keep_before = 0;
|
||||||
|
@ -46,41 +45,59 @@ struct ShregmapWorker
|
||||||
|
|
||||||
const ShregmapOptions &opts;
|
const ShregmapOptions &opts;
|
||||||
int dff_count, shreg_count;
|
int dff_count, shreg_count;
|
||||||
|
pool<Cell*> remove_cells;
|
||||||
|
|
||||||
// next is set to NULL for sigbits that drive non-DFFs
|
dict<SigBit, bool> sigbit_init;
|
||||||
dict<SigBit, Cell*> sigbit_chain_next;
|
dict<SigBit, Cell*> sigbit_chain_next;
|
||||||
dict<SigBit, Cell*> sigbit_chain_prev;
|
dict<SigBit, Cell*> sigbit_chain_prev;
|
||||||
|
pool<SigBit> sigbit_with_non_chain_users;
|
||||||
pool<Cell*> chain_start_cells;
|
pool<Cell*> chain_start_cells;
|
||||||
|
|
||||||
void make_sigbit_chain_next_prev()
|
void make_sigbit_chain_next_prev()
|
||||||
{
|
{
|
||||||
for (auto wire : module->wires()) {
|
for (auto wire : module->wires())
|
||||||
if (!wire->port_output)
|
{
|
||||||
continue;
|
if (wire->port_output) {
|
||||||
for (auto bit : sigmap(wire))
|
for (auto bit : sigmap(wire))
|
||||||
sigbit_chain_next[bit] = nullptr;
|
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())
|
for (auto cell : module->cells())
|
||||||
{
|
{
|
||||||
if ((opts.clkpol != "pos" && cell->type == "$_DFF_N_") ||
|
if (opts.ffcells.count(cell->type))
|
||||||
(opts.clkpol != "neg" && cell->type == "$_DFF_P_"))
|
|
||||||
{
|
{
|
||||||
SigBit d_bit = sigmap(cell->getPort("\\D").as_bit());
|
IdString d_port = opts.ffcells.at(cell->type).first;
|
||||||
if (sigbit_chain_next.count(d_bit))
|
IdString q_port = opts.ffcells.at(cell->type).second;
|
||||||
sigbit_chain_next[d_bit] = nullptr;
|
|
||||||
else
|
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_next[d_bit] = cell;
|
||||||
|
|
||||||
SigBit q_bit = sigmap(cell->getPort("\\Q").as_bit());
|
|
||||||
sigbit_chain_prev[q_bit] = cell;
|
sigbit_chain_prev[q_bit] = cell;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (auto conn : cell->connections())
|
for (auto conn : cell->connections())
|
||||||
if (cell->input(conn.first))
|
if (cell->input(conn.first))
|
||||||
for (auto bit : sigmap(conn.second))
|
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)
|
for (auto it : sigbit_chain_next)
|
||||||
{
|
{
|
||||||
if (it.second == nullptr)
|
if (sigbit_with_non_chain_users.count(it.first))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (sigbit_chain_prev.count(it.first) != 0)
|
if (sigbit_chain_prev.count(it.first) != 0)
|
||||||
|
@ -99,7 +116,22 @@ struct ShregmapWorker
|
||||||
if (c1->type != c2->type)
|
if (c1->type != c2->type)
|
||||||
goto start_cell;
|
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;
|
goto start_cell;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
@ -119,7 +151,8 @@ struct ShregmapWorker
|
||||||
{
|
{
|
||||||
chain.push_back(c);
|
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)
|
if (sigbit_chain_next.count(q_bit) == 0)
|
||||||
break;
|
break;
|
||||||
|
@ -153,16 +186,36 @@ struct ShregmapWorker
|
||||||
log("Converting %s.%s ... %s.%s to a shift register with depth %d.\n",
|
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);
|
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);
|
dff_count += depth;
|
||||||
first_cell->setPort("\\Q", last_cell->getPort("\\Q"));
|
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);
|
first_cell->setParam("\\DEPTH", depth);
|
||||||
|
|
||||||
for (int i = 1; i < depth; i++)
|
for (int i = 1; i < depth; i++)
|
||||||
module->remove(chain[cursor+i]);
|
remove_cells.insert(chain[cursor+i]);
|
||||||
cursor += depth;
|
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) :
|
ShregmapWorker(Module *module, const ShregmapOptions &opts) :
|
||||||
module(module), sigmap(module), opts(opts), dff_count(0), shreg_count(0)
|
module(module), sigmap(module), opts(opts), dff_count(0), shreg_count(0)
|
||||||
{
|
{
|
||||||
|
@ -174,6 +227,8 @@ struct ShregmapWorker
|
||||||
vector<Cell*> chain = create_chain(c);
|
vector<Cell*> chain = create_chain(c);
|
||||||
process_chain(chain);
|
process_chain(chain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cleanup();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -186,7 +241,7 @@ struct ShregmapPass : public Pass {
|
||||||
log(" shregmap [options] [selection]\n");
|
log(" shregmap [options] [selection]\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("This pass converts chains of $_DFF_[NP]_ gates to target specific shift register.\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("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("'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");
|
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(" -clkpol pos|neg|any\n");
|
||||||
log(" limit match to only positive or negative edge clocks. (default = any)\n");
|
log(" limit match to only positive or negative edge clocks. (default = any)\n");
|
||||||
log("\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 <cell_type>[:<d_port_name>:<q_port_name>]\n");
|
||||||
|
log(" match the specified cells instead of $_DFF_N_ and $_DFF_P_. If\n");
|
||||||
|
log(" ':<d_port_name>:<q_port_name>' 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<std::string> args, RTLIL::Design *design)
|
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
|
||||||
{
|
{
|
||||||
ShregmapOptions opts;
|
ShregmapOptions opts;
|
||||||
|
string clkpol, enpol;
|
||||||
|
|
||||||
log_header("Executing SHREGMAP pass (map shift registers).\n");
|
log_header("Executing SHREGMAP pass (map shift registers).\n");
|
||||||
|
|
||||||
|
@ -219,7 +284,23 @@ struct ShregmapPass : public Pass {
|
||||||
for (argidx = 1; argidx < args.size(); argidx++)
|
for (argidx = 1; argidx < args.size(); argidx++)
|
||||||
{
|
{
|
||||||
if (args[argidx] == "-clkpol" && argidx+1 < args.size()) {
|
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<string> 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;
|
continue;
|
||||||
}
|
}
|
||||||
if (args[argidx] == "-minlen" && argidx+1 < args.size()) {
|
if (args[argidx] == "-minlen" && argidx+1 < args.size()) {
|
||||||
|
@ -242,8 +323,37 @@ struct ShregmapPass : public Pass {
|
||||||
}
|
}
|
||||||
extra_args(args, argidx, design);
|
extra_args(args, argidx, design);
|
||||||
|
|
||||||
if (opts.clkpol != "pos" && opts.clkpol != "neg" && opts.clkpol != "any")
|
if (opts.ffcells.empty())
|
||||||
log_cmd_error("Invalid value for -clkpol: %s\n", opts.clkpol.c_str());
|
{
|
||||||
|
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 dff_count = 0;
|
||||||
int shreg_count = 0;
|
int shreg_count = 0;
|
||||||
|
|
Loading…
Reference in New Issue