-
Notifications
You must be signed in to change notification settings - Fork 902
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4344 from widlarizer/emil/keep_hierarchy
cost: add keep_hierarchy pass with min_cost argument
- Loading branch information
Showing
7 changed files
with
383 additions
and
64 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
#include "kernel/cost.h" | ||
|
||
USING_YOSYS_NAMESPACE | ||
|
||
unsigned int CellCosts::get(RTLIL::Module *mod) | ||
{ | ||
if (mod_cost_cache_.count(mod->name)) | ||
return mod_cost_cache_.at(mod->name); | ||
|
||
unsigned int module_cost = 1; | ||
for (auto c : mod->cells()) { | ||
unsigned int new_cost = module_cost + get(c); | ||
module_cost = new_cost >= module_cost ? new_cost : INT_MAX; | ||
} | ||
|
||
mod_cost_cache_[mod->name] = module_cost; | ||
return module_cost; | ||
} | ||
|
||
static unsigned int y_coef(RTLIL::IdString type) | ||
{ | ||
if ( | ||
// equality | ||
type.in(ID($bweqx), ID($nex), ID($eqx)) || | ||
// basic logic | ||
type.in(ID($and), ID($or), ID($xor), ID($xnor), ID($not)) || | ||
// mux | ||
type.in(ID($bwmux), ID($mux)) || | ||
// others | ||
type == ID($tribuf)) { | ||
return 1; | ||
} else if (type == ID($neg)) { | ||
return 4; | ||
} else if (type == ID($demux)) { | ||
return 2; | ||
} else if (type == ID($fa)) { | ||
return 5; | ||
} else if (type.in(ID($add), ID($sub), ID($alu))) { | ||
// multi-bit adders | ||
return 8; | ||
} else if (type.in(ID($shl), ID($sshl))) { | ||
// left shift | ||
return 10; | ||
} | ||
return 0; | ||
} | ||
|
||
static unsigned int max_inp_coef(RTLIL::IdString type) | ||
{ | ||
if ( | ||
// binop reduce | ||
type.in(ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool)) || | ||
// others | ||
type.in(ID($logic_not), ID($pmux), ID($bmux))) { | ||
return 1; | ||
} else if ( | ||
// equality | ||
type.in(ID($eq), ID($ne)) || | ||
// logic | ||
type.in(ID($logic_and), ID($logic_or))) { | ||
return 2; | ||
} else if (type == ID($lcu)) { | ||
return 5; | ||
} else if (type.in(ID($lt), ID($le), ID($ge), ID($gt))) { | ||
// comparison | ||
return 7; | ||
} | ||
return 0; | ||
} | ||
|
||
static unsigned int sum_coef(RTLIL::IdString type) | ||
{ | ||
if (type.in(ID($shr), ID($sshr))) { | ||
// right shift | ||
return 4; | ||
} else if (type.in(ID($shift), ID($shiftx))) { | ||
// shift | ||
return 8; | ||
} | ||
return 0; | ||
} | ||
|
||
static unsigned int is_div_mod(RTLIL::IdString type) | ||
{ | ||
return (type == ID($div) || type == ID($divfloor) || type == ID($mod) || type == ID($modfloor)); | ||
} | ||
|
||
static bool is_free(RTLIL::IdString type) | ||
{ | ||
return ( | ||
// tags | ||
type.in(ID($overwrite_tag), ID($set_tag), ID($original_tag), ID($get_tag)) || | ||
// formal | ||
type.in(ID($check), ID($equiv), ID($initstate), ID($assert), ID($assume), ID($live), ID($cover), ID($fair)) || | ||
type.in(ID($allseq), ID($allconst), ID($anyseq), ID($anyconst), ID($anyinit)) || | ||
// utilities | ||
type.in(ID($scopeinfo), ID($print)) || | ||
// real but free | ||
type.in(ID($concat), ID($slice), ID($pos)) || | ||
// specify | ||
type.in(ID($specrule), ID($specify2), ID($specify3))); | ||
} | ||
|
||
unsigned int max_inp_width(RTLIL::Cell *cell) | ||
{ | ||
unsigned int max = 0; | ||
RTLIL::IdString input_width_params[] = { | ||
ID::WIDTH, | ||
ID::A_WIDTH, | ||
ID::B_WIDTH, | ||
ID::S_WIDTH, | ||
}; | ||
|
||
if (cell->type == ID($bmux)) | ||
return cell->getParam(ID::WIDTH).as_int() << cell->getParam(ID::S_WIDTH).as_int(); | ||
|
||
for (RTLIL::IdString param : input_width_params) | ||
if (cell->hasParam(param)) | ||
max = std::max(max, (unsigned int)cell->getParam(param).as_int()); | ||
return max; | ||
} | ||
|
||
unsigned int port_width_sum(RTLIL::Cell *cell) | ||
{ | ||
unsigned int sum = 0; | ||
RTLIL::IdString port_width_params[] = { | ||
ID::WIDTH, ID::A_WIDTH, ID::B_WIDTH, ID::S_WIDTH, ID::Y_WIDTH, | ||
}; | ||
|
||
for (auto param : port_width_params) | ||
if (cell->hasParam(param)) | ||
sum += cell->getParam(param).as_int(); | ||
|
||
return sum; | ||
} | ||
|
||
unsigned int CellCosts::get(RTLIL::Cell *cell) | ||
{ | ||
|
||
// simple 1-bit cells | ||
if (cmos_gate_cost().count(cell->type)) | ||
return 1; | ||
|
||
if (design_ && design_->module(cell->type) && cell->parameters.empty()) { | ||
log_debug("%s is a module, recurse\n", cell->name.c_str()); | ||
return get(design_->module(cell->type)); | ||
} else if (RTLIL::builtin_ff_cell_types().count(cell->type)) { | ||
log_assert(cell->hasPort(ID::Q) && "Weird flip flop"); | ||
log_debug("%s is ff\n", cell->name.c_str()); | ||
return cell->getParam(ID::WIDTH).as_int(); | ||
} else if (y_coef(cell->type)) { | ||
// linear with Y_WIDTH or WIDTH | ||
log_assert((cell->hasParam(ID::Y_WIDTH) || cell->hasParam(ID::WIDTH)) && "Unknown width"); | ||
auto param = cell->hasParam(ID::Y_WIDTH) ? ID::Y_WIDTH : ID::WIDTH; | ||
int width = cell->getParam(param).as_int(); | ||
if (cell->type == ID($demux)) | ||
width <<= cell->getParam(ID::S_WIDTH).as_int(); | ||
log_debug("%s Y*coef %d * %d\n", cell->name.c_str(), width, y_coef(cell->type)); | ||
return width * y_coef(cell->type); | ||
} else if (sum_coef(cell->type)) { | ||
// linear with sum of port widths | ||
unsigned int sum = port_width_sum(cell); | ||
log_debug("%s sum*coef %d * %d\n", cell->name.c_str(), sum, sum_coef(cell->type)); | ||
return sum * sum_coef(cell->type); | ||
} else if (max_inp_coef(cell->type)) { | ||
// linear with largest input width | ||
unsigned int max = max_inp_width(cell); | ||
log_debug("%s max*coef %d * %d\n", cell->name.c_str(), max, max_inp_coef(cell->type)); | ||
return max * max_inp_coef(cell->type); | ||
} else if (is_div_mod(cell->type) || cell->type == ID($mul)) { | ||
// quadratic with sum of port widths | ||
unsigned int sum = port_width_sum(cell); | ||
unsigned int coef = cell->type == ID($mul) ? 3 : 5; | ||
log_debug("%s coef*(sum**2) %d * %d\n", cell->name.c_str(), coef, sum * sum); | ||
return coef * sum * sum; | ||
} else if (cell->type == ID($lut)) { | ||
int width = cell->getParam(ID::WIDTH).as_int(); | ||
unsigned int cost = 1U << (unsigned int)width; | ||
log_debug("%s is 2**%d\n", cell->name.c_str(), width); | ||
return cost; | ||
} else if (cell->type == ID($sop)) { | ||
int width = cell->getParam(ID::WIDTH).as_int(); | ||
int depth = cell->getParam(ID::DEPTH).as_int(); | ||
log_debug("%s is (2*%d + 1)*%d\n", cell->name.c_str(), width, depth); | ||
return (2 * width + 1) * depth; | ||
} else if (is_free(cell->type)) { | ||
log_debug("%s is free\n", cell->name.c_str()); | ||
return 0; | ||
} | ||
// TODO: $fsm $mem.* $macc | ||
// ignored: $pow | ||
|
||
log_warning("Can't determine cost of %s cell (%d parameters).\n", log_id(cell->type), GetSize(cell->parameters)); | ||
return 1; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
/* | ||
* yosys -- Yosys Open SYnthesis Suite | ||
* | ||
* Copyright (C) 2012 Claire Xenia Wolf <[email protected]> | ||
* | ||
* 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/cost.h" | ||
|
||
USING_YOSYS_NAMESPACE | ||
PRIVATE_NAMESPACE_BEGIN | ||
|
||
struct KeepHierarchyPass : public Pass { | ||
KeepHierarchyPass() : Pass("keep_hierarchy", "add the keep_hierarchy attribute") {} | ||
void help() override | ||
{ | ||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| | ||
log("\n"); | ||
log(" keep_hierarchy [options]\n"); | ||
log("\n"); | ||
log("Add the keep_hierarchy attribute.\n"); | ||
log("\n"); | ||
log(" -min_cost <min_cost>\n"); | ||
log(" only add the attribute to modules estimated to have more\n"); | ||
log(" than <min_cost> gates after simple techmapping. Intended\n"); | ||
log(" for tuning trade-offs between quality and yosys runtime.\n"); | ||
} | ||
void execute(std::vector<std::string> args, RTLIL::Design *design) override | ||
{ | ||
unsigned int min_cost = 0; | ||
|
||
log_header(design, "Executing KEEP_HIERARCHY pass.\n"); | ||
|
||
size_t argidx; | ||
for (argidx = 1; argidx < args.size(); argidx++) { | ||
if (args[argidx] == "-min_cost" && argidx+1 < args.size()) { | ||
min_cost = std::stoi(args[++argidx].c_str()); | ||
continue; | ||
} | ||
break; | ||
} | ||
extra_args(args, argidx, design); | ||
|
||
CellCosts costs(design); | ||
|
||
for (auto module : design->selected_modules()) { | ||
if (min_cost) { | ||
unsigned int cost = costs.get(module); | ||
if (cost > min_cost) { | ||
log("Marking %s (module too big: %d > %d).\n", log_id(module), cost, min_cost); | ||
module->set_bool_attribute(ID::keep_hierarchy); | ||
} | ||
} else { | ||
log("Marking %s.\n", log_id(module)); | ||
module->set_bool_attribute(ID::keep_hierarchy); | ||
} | ||
} | ||
} | ||
} KeepHierarchyPass; | ||
|
||
PRIVATE_NAMESPACE_END |
Oops, something went wrong.