2015-09-18 14:57:34 -05:00
|
|
|
/*
|
|
|
|
* 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 NlutmapConfig
|
|
|
|
{
|
|
|
|
vector<int> luts;
|
2016-06-09 04:47:41 -05:00
|
|
|
bool assert_mode = false;
|
2015-09-18 14:57:34 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
struct NlutmapWorker
|
|
|
|
{
|
|
|
|
const NlutmapConfig &config;
|
|
|
|
pool<Cell*> mapped_cells;
|
|
|
|
Module *module;
|
|
|
|
|
|
|
|
NlutmapWorker(const NlutmapConfig &config, Module *module) :
|
|
|
|
config(config), module(module)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
RTLIL::Selection get_selection()
|
|
|
|
{
|
|
|
|
RTLIL::Selection sel(false);
|
|
|
|
for (auto cell : module->cells())
|
|
|
|
if (!mapped_cells.count(cell))
|
|
|
|
sel.select(module, cell);
|
|
|
|
return sel;
|
|
|
|
}
|
|
|
|
|
|
|
|
void run_abc(int lut_size)
|
|
|
|
{
|
|
|
|
Pass::call_on_selection(module->design, get_selection(), "lut2mux");
|
|
|
|
|
|
|
|
if (lut_size > 0)
|
|
|
|
Pass::call_on_selection(module->design, get_selection(), stringf("abc -lut 1:%d", lut_size));
|
|
|
|
else
|
|
|
|
Pass::call_on_selection(module->design, get_selection(), "abc");
|
|
|
|
|
|
|
|
Pass::call_on_module(module->design, module, "opt_clean");
|
|
|
|
}
|
|
|
|
|
|
|
|
void run()
|
|
|
|
{
|
|
|
|
vector<int> available_luts = config.luts;
|
|
|
|
|
2016-03-23 02:56:08 -05:00
|
|
|
while (GetSize(available_luts) > 1)
|
2015-09-18 14:57:34 -05:00
|
|
|
{
|
|
|
|
int n_luts = available_luts.back();
|
|
|
|
int lut_size = GetSize(available_luts);
|
|
|
|
available_luts.pop_back();
|
|
|
|
|
|
|
|
if (n_luts == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
run_abc(lut_size);
|
|
|
|
|
|
|
|
SigMap sigmap(module);
|
|
|
|
dict<Cell*, int> candidate_ratings;
|
|
|
|
dict<SigBit, int> bit_lut_count;
|
|
|
|
|
|
|
|
for (auto cell : module->cells())
|
|
|
|
{
|
2019-08-15 12:05:08 -05:00
|
|
|
if (cell->type != ID($lut) || mapped_cells.count(cell))
|
2015-09-18 14:57:34 -05:00
|
|
|
continue;
|
|
|
|
|
2019-08-15 12:25:54 -05:00
|
|
|
if (GetSize(cell->getPort(ID(A))) == lut_size || lut_size == 2)
|
2015-09-18 14:57:34 -05:00
|
|
|
candidate_ratings[cell] = 0;
|
|
|
|
|
|
|
|
for (auto &conn : cell->connections())
|
|
|
|
for (auto bit : sigmap(conn.second))
|
|
|
|
bit_lut_count[bit]++;
|
|
|
|
}
|
2017-04-08 22:54:31 -05:00
|
|
|
|
2015-09-18 14:57:34 -05:00
|
|
|
for (auto &cand : candidate_ratings)
|
|
|
|
{
|
|
|
|
for (auto &conn : cand.first->connections())
|
|
|
|
for (auto bit : sigmap(conn.second))
|
|
|
|
cand.second -= bit_lut_count[bit];
|
|
|
|
}
|
|
|
|
|
|
|
|
vector<pair<int, IdString>> rated_candidates;
|
|
|
|
|
|
|
|
for (auto &cand : candidate_ratings)
|
|
|
|
rated_candidates.push_back(pair<int, IdString>(cand.second, cand.first->name));
|
|
|
|
|
|
|
|
std::sort(rated_candidates.begin(), rated_candidates.end());
|
|
|
|
|
|
|
|
while (n_luts > 0 && !rated_candidates.empty()) {
|
|
|
|
mapped_cells.insert(module->cell(rated_candidates.back().second));
|
|
|
|
rated_candidates.pop_back();
|
|
|
|
n_luts--;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!available_luts.empty())
|
|
|
|
available_luts.back() += n_luts;
|
|
|
|
}
|
|
|
|
|
2016-06-09 04:47:41 -05:00
|
|
|
if (config.assert_mode) {
|
|
|
|
for (auto cell : module->cells())
|
2019-08-15 12:05:08 -05:00
|
|
|
if (cell->type == ID($lut) && !mapped_cells.count(cell))
|
2016-06-09 04:47:41 -05:00
|
|
|
log_error("Insufficient number of LUTs to map all logic cells!\n");
|
|
|
|
}
|
|
|
|
|
2015-09-18 14:57:34 -05:00
|
|
|
run_abc(0);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct NlutmapPass : public Pass {
|
|
|
|
NlutmapPass() : Pass("nlutmap", "map to LUTs of different sizes") { }
|
2018-07-21 01:41:18 -05:00
|
|
|
void help() YS_OVERRIDE
|
2015-09-18 14:57:34 -05:00
|
|
|
{
|
|
|
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
|
|
|
log("\n");
|
|
|
|
log(" nlutmap [options] [selection]\n");
|
|
|
|
log("\n");
|
|
|
|
log("This pass uses successive calls to 'abc' to map to an architecture. That\n");
|
|
|
|
log("provides a small number of differently sized LUTs.\n");
|
|
|
|
log("\n");
|
|
|
|
log(" -luts N_1,N_2,N_3,...\n");
|
|
|
|
log(" The number of LUTs with 1, 2, 3, ... inputs that are\n");
|
|
|
|
log(" available in the target architecture.\n");
|
|
|
|
log("\n");
|
2016-06-09 04:47:41 -05:00
|
|
|
log(" -assert\n");
|
|
|
|
log(" Create an error if not all logic can be mapped\n");
|
|
|
|
log("\n");
|
2015-09-18 14:57:34 -05:00
|
|
|
log("Excess logic that does not fit into the specified LUTs is mapped back\n");
|
|
|
|
log("to generic logic gates ($_AND_, etc.).\n");
|
|
|
|
log("\n");
|
|
|
|
}
|
2018-07-21 01:41:18 -05:00
|
|
|
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
2015-09-18 14:57:34 -05:00
|
|
|
{
|
|
|
|
NlutmapConfig config;
|
|
|
|
|
2016-04-21 16:28:37 -05:00
|
|
|
log_header(design, "Executing NLUTMAP pass (mapping to constant drivers).\n");
|
2015-09-18 14:57:34 -05:00
|
|
|
log_push();
|
|
|
|
|
|
|
|
size_t argidx;
|
|
|
|
for (argidx = 1; argidx < args.size(); argidx++)
|
|
|
|
{
|
|
|
|
if (args[argidx] == "-luts" && argidx+1 < args.size()) {
|
|
|
|
vector<string> tokens = split_tokens(args[++argidx], ",");
|
|
|
|
config.luts.clear();
|
|
|
|
for (auto &token : tokens)
|
|
|
|
config.luts.push_back(atoi(token.c_str()));
|
|
|
|
continue;
|
|
|
|
}
|
2016-06-09 04:47:41 -05:00
|
|
|
if (args[argidx] == "-assert") {
|
|
|
|
config.assert_mode = true;
|
|
|
|
continue;
|
|
|
|
}
|
2015-09-18 14:57:34 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
extra_args(args, argidx, design);
|
|
|
|
|
|
|
|
for (auto module : design->selected_whole_modules_warn())
|
|
|
|
{
|
|
|
|
NlutmapWorker worker(config, module);
|
|
|
|
worker.run();
|
|
|
|
}
|
|
|
|
|
|
|
|
log_pop();
|
|
|
|
}
|
|
|
|
} NlutmapPass;
|
|
|
|
|
|
|
|
PRIVATE_NAMESPACE_END
|