1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 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;
}
|