Added "shregmap" pass

This commit is contained in:
Clifford Wolf 2016-04-16 23:20:49 +02:00
parent fbdb8e7b3e
commit de647a390c
2 changed files with 262 additions and 0 deletions

View File

@ -26,6 +26,7 @@ OBJS += passes/techmap/tribuf.o
OBJS += passes/techmap/lut2mux.o
OBJS += passes/techmap/nlutmap.o
OBJS += passes/techmap/dffsr2dff.o
OBJS += passes/techmap/shregmap.o
endif
GENFILES += passes/techmap/techmap.inc

261
passes/techmap/shregmap.cc Normal file
View File

@ -0,0 +1,261 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct ShregmapOptions
{
std::string clkpol;
int minlen, maxlen;
int keep_before, keep_after;
ShregmapOptions()
{
clkpol = "any";
minlen = 2;
maxlen = 0;
keep_before = 0;
keep_after = 0;
}
};
struct ShregmapWorker
{
Module *module;
SigMap sigmap;
const ShregmapOptions &opts;
int dff_count, shreg_count;
// next is set to NULL for sigbits that drive non-DFFs
dict<SigBit, Cell*> sigbit_chain_next;
dict<SigBit, Cell*> sigbit_chain_prev;
pool<Cell*> 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 cell : module->cells())
{
if ((opts.clkpol != "pos" && cell->type == "$_DFF_N_") ||
(opts.clkpol != "neg" && cell->type == "$_DFF_P_"))
{
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;
}
for (auto conn : cell->connections())
if (cell->input(conn.first))
for (auto bit : sigmap(conn.second))
sigbit_chain_next[bit] = nullptr;
}
}
void find_chain_start_cells()
{
for (auto it : sigbit_chain_next)
{
if (it.second == nullptr)
continue;
if (sigbit_chain_prev.count(it.first) != 0)
{
Cell *c1 = sigbit_chain_prev.at(it.first);
Cell *c2 = it.second;
if (c1->type != c2->type)
goto start_cell;
if (sigmap(c1->getPort("\\C")) != c2->getPort("\\C"))
goto start_cell;
continue;
}
start_cell:
chain_start_cells.insert(it.second);
}
}
vector<Cell*> create_chain(Cell *start_cell)
{
vector<Cell*> chain;
Cell *c = start_cell;
while (c != nullptr)
{
chain.push_back(c);
SigBit q_bit = sigmap(c->getPort("\\Q").as_bit());
if (sigbit_chain_next.count(q_bit) == 0)
break;
c = sigbit_chain_next.at(q_bit);
if (chain_start_cells.count(c) != 0)
break;
}
return chain;
}
void process_chain(vector<Cell*> &chain)
{
if (GetSize(chain) < opts.keep_before + opts.minlen + opts.keep_after)
return;
int cursor = opts.keep_before;
while (cursor < GetSize(chain) - opts.keep_after)
{
int depth = GetSize(chain) - opts.keep_after - cursor;
if (opts.maxlen > 0)
depth = std::min(opts.maxlen, depth);
Cell *first_cell = chain[cursor], *last_cell = chain[cursor+depth-1];
if (depth < 2)
return;
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"));
first_cell->setParam("\\DEPTH", depth);
for (int i = 1; i < depth; i++)
module->remove(chain[cursor+i]);
cursor += depth;
}
}
ShregmapWorker(Module *module, const ShregmapOptions &opts) :
module(module), sigmap(module), opts(opts), dff_count(0), shreg_count(0)
{
make_sigbit_chain_next_prev();
find_chain_start_cells();
for (auto c : chain_start_cells) {
vector<Cell*> chain = create_chain(c);
process_chain(chain);
}
}
};
struct ShregmapPass : public Pass {
ShregmapPass() : Pass("shregmap", "map shift registers") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
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("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");
log("\n");
log(" -minlen N\n");
log(" minimum length of shift register (default = 2)\n");
log(" (this is the length after -keep_before and -keep_after)\n");
log("\n");
log(" -maxlen N\n");
log(" maximum length of shift register (default = no limit)\n");
log(" larger chains will be mapped to multiple shift register instances\n");
log("\n");
log(" -keep_before N\n");
log(" number of DFFs to keep before the shift register (default = 0)\n");
log("\n");
log(" -keep_after N\n");
log(" number of DFFs to keep after the shift register (default = 0)\n");
log("\n");
log(" -clkpol pos|neg|any\n");
log(" limit match to only positive or negative edge clocks. (default = any)\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
ShregmapOptions opts;
log_header("Executing SHREGMAP pass (map shift registers).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
if (args[argidx] == "-clkpol" && argidx+1 < args.size()) {
opts.clkpol = args[++argidx];
continue;
}
if (args[argidx] == "-minlen" && argidx+1 < args.size()) {
opts.minlen = atoi(args[++argidx].c_str());
continue;
}
if (args[argidx] == "-maxlen" && argidx+1 < args.size()) {
opts.maxlen = atoi(args[++argidx].c_str());
continue;
}
if (args[argidx] == "-keep_before" && argidx+1 < args.size()) {
opts.keep_before = atoi(args[++argidx].c_str());
continue;
}
if (args[argidx] == "-keep_after" && argidx+1 < args.size()) {
opts.keep_after = atoi(args[++argidx].c_str());
continue;
}
break;
}
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());
int dff_count = 0;
int shreg_count = 0;
for (auto module : design->selected_modules()) {
ShregmapWorker worker(module, opts);
dff_count += worker.dff_count;
shreg_count += worker.shreg_count;
}
log("Converted %d dff cells into %d shift registers.\n", dff_count, shreg_count);
}
} ShregmapPass;
PRIVATE_NAMESPACE_END