Skip to content

Commit

Permalink
cost: add keep_hierarchy pass with max_cost argument
Browse files Browse the repository at this point in the history
  • Loading branch information
Emil Tywoniak authored and Emil Tywoniak committed Apr 18, 2024
1 parent bc14999 commit 978d8fd
Show file tree
Hide file tree
Showing 8 changed files with 339 additions and 74 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,7 @@ $(eval $(call add_include_file,backends/rtlil/rtlil_backend.h))

OBJS += kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/calc.o kernel/yosys.o
OBJS += kernel/binding.o
OBJS += kernel/cellaigs.o kernel/celledges.o kernel/satgen.o kernel/scopeinfo.o kernel/qcsat.o kernel/mem.o kernel/ffmerge.o kernel/ff.o kernel/yw.o kernel/json.o kernel/fmt.o
OBJS += kernel/cellaigs.o kernel/celledges.o kernel/cost.o kernel/satgen.o kernel/scopeinfo.o kernel/qcsat.o kernel/mem.o kernel/ffmerge.o kernel/ff.o kernel/yw.o kernel/json.o kernel/fmt.o
ifeq ($(ENABLE_ZLIB),1)
OBJS += kernel/fstdata.o
endif
Expand Down
1 change: 1 addition & 0 deletions kernel/constids.inc
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ X(CO)
X(COLLISION_X_MASK)
X(CONFIG)
X(CONFIG_WIDTH)
X(cost)
X(CTRL_IN)
X(CTRL_IN_WIDTH)
X(CTRL_OUT)
Expand Down
203 changes: 203 additions & 0 deletions kernel/cost.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
#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)
{
// clang-format off
if (// equality
type == ID($bweqx) ||
type == ID($nex) ||
type == ID($eqx) ||
// basic logic
type == ID($and) ||
type == ID($or) ||
type == ID($xor) ||
type == ID($xnor) ||
type == ID($not) ||
// mux
type == ID($bwmux) ||
type == ID($mux) ||
type == ID($demux) ||
// others
type == ID($tribuf)) {
return 1;
} else if (type == ID($neg)) {
return 4;
} else if (type == ID($fa)) {
return 5;
} else if (// multi-bit adders
type == ID($add) ||
type == ID($sub) ||
type == ID($alu)) {
return 8;
} else if (// left shift
type == ID($shl) ||
type == ID($sshl)) {
return 10;
}
// clang-format on
return 0;
}

static unsigned int max_inp_coef(RTLIL::IdString type)
{
// clang-format off
if (// binop reduce
type == ID($reduce_and) ||
type == ID($reduce_or) ||
type == ID($reduce_xor) ||
type == ID($reduce_xnor) ||
type == ID($reduce_bool) ||
// others
type == ID($logic_not) ||
type == ID($pmux) ||
type == ID($bmux)) {
return 1;
} else if (// equality
type == ID($eq) ||
type == ID($ne) ||
// logic
type == ID($logic_and) ||
type == ID($logic_or)) {
return 2;
} else if (type == ID($lcu)) {
return 5;
} else if (// comparison
type == ID($lt) ||
type == ID($le) ||
type == ID($ge) ||
type == ID($gt) ||
// others
type == ID($sop)) {
return 6;
}
// clang-format on
return 0;
}
static unsigned int sum_coef(RTLIL::IdString type)
{
// clang-format off
if (// right shift
type == ID($shr) ||
type == ID($sshr)) {
return 4;
} else if (// shift
type == ID($shift) ||
type == ID($shiftx)) {
return 8;
}
// clang-format on
return 0;
}

static bool is_free(RTLIL::IdString type)
{
// clang-format off
return (// tags
type == ID($overwrite_tag) ||
type == ID($set_tag) ||
type == ID($original_tag) ||
type == ID($get_tag) ||
// formal
type == ID($check) ||
type == ID($equiv) ||
type == ID($initstate) ||
type == ID($assert) ||
type == ID($assume) ||
type == ID($live) ||
type == ID($cover) ||
type == ID($allseq) ||
type == ID($allconst) ||
type == ID($anyseq) ||
type == ID($anyinit) ||
type == ID($anyconst) ||
type == ID($fair) ||
// utilities
type == ID($scopeinfo) ||
type == ID($print) ||
// real but free
type == ID($concat) ||
type == ID($slice) ||
type == ID($pos) ||
// specify
type == ID($specrule) ||
type == ID($specify2) ||
type == ID($specify3));
// clang-format on
}

unsigned int CellCosts::get(RTLIL::Cell *cell)
{

if (gate_type_cost().count(cell->type))
return gate_type_cost().at(cell->type);

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();
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 = 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();

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 = 0;
RTLIL::IdString input_width_params[] = {
ID::WIDTH,
ID::A_WIDTH,
ID::B_WIDTH,
ID::S_WIDTH,
};

for (RTLIL::IdString param : input_width_params)
if (cell->hasParam(param))
max = std::max(max, (unsigned int)cell->getParam(param).as_int());

log_debug("%s max*coef %d * %d\n", cell->name.c_str(), max, max_inp_coef(cell->type));
return max;
} else if (is_free(cell->type)) {
log_debug("%s is free\n", cell->name.c_str());
return 0;
}
// TODO: $fsm $mem.*
// ignored: $pow

log_warning("Can't determine cost of %s cell (%d parameters).\n", log_id(cell->type), GetSize(cell->parameters));
return 1;
}
81 changes: 33 additions & 48 deletions kernel/cost.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,22 @@ YOSYS_NAMESPACE_BEGIN

struct CellCosts
{
static const dict<RTLIL::IdString, int>& default_gate_cost() {
static const dict<RTLIL::IdString, int> db = {

enum CostKind {
DEFAULT,
CMOS,
};

private:
dict<RTLIL::IdString, int> mod_cost_cache_;
CostKind kind_;
Design *design_ = nullptr;

public:
CellCosts(CellCosts::CostKind kind, RTLIL::Design *design) : kind_(kind), design_(design) { }

const dict<RTLIL::IdString, int>& gate_type_cost() {
static const dict<RTLIL::IdString, int> default_gate_db = {
{ ID($_BUF_), 1 },
{ ID($_NOT_), 2 },
{ ID($_AND_), 4 },
Expand All @@ -43,13 +57,12 @@ struct CellCosts
{ ID($_AOI4_), 7 },
{ ID($_OAI4_), 7 },
{ ID($_MUX_), 4 },
{ ID($_NMUX_), 4 }
{ ID($_NMUX_), 4 },
{ ID($_DFF_P_), 1 },
{ ID($_DFF_N_), 1 },
};
return db;
}

static const dict<RTLIL::IdString, int>& cmos_gate_cost() {
static const dict<RTLIL::IdString, int> db = {
static const dict<RTLIL::IdString, int> cmos_transistors_db = {
{ ID($_BUF_), 1 },
{ ID($_NOT_), 2 },
{ ID($_AND_), 6 },
Expand All @@ -65,50 +78,22 @@ struct CellCosts
{ ID($_AOI4_), 8 },
{ ID($_OAI4_), 8 },
{ ID($_MUX_), 12 },
{ ID($_NMUX_), 10 }
{ ID($_NMUX_), 10 },
{ ID($_DFF_P_), 16 },
{ ID($_DFF_N_), 16 },
};
return db;
}

dict<RTLIL::IdString, int> mod_cost_cache;
const dict<RTLIL::IdString, int> *gate_cost = nullptr;
Design *design = nullptr;

int get(RTLIL::IdString type) const
{
if (gate_cost && gate_cost->count(type))
return gate_cost->at(type);

log_warning("Can't determine cost of %s cell.\n", log_id(type));
return 1;
}

int get(RTLIL::Cell *cell)
{
if (gate_cost && gate_cost->count(cell->type))
return gate_cost->at(cell->type);

if (design && design->module(cell->type) && cell->parameters.empty())
{
RTLIL::Module *mod = design->module(cell->type);

if (mod->attributes.count(ID(cost)))
return mod->attributes.at(ID(cost)).as_int();

if (mod_cost_cache.count(mod->name))
return mod_cost_cache.at(mod->name);

int module_cost = 1;
for (auto c : mod->cells())
module_cost += get(c);

mod_cost_cache[mod->name] = module_cost;
return module_cost;
switch (kind_) {
case DEFAULT:
return default_gate_db;
case CMOS:
return cmos_transistors_db;
default:
log_assert(false && "Unreachable: Invalid cell cost kind\n");
}

log_warning("Can't determine cost of %s cell (%d parameters).\n", log_id(cell->type), GetSize(cell->parameters));
return 1;
}

unsigned int get(RTLIL::Module *mod);
unsigned int get(RTLIL::Cell *cell);
};

YOSYS_NAMESPACE_END
Expand Down
10 changes: 5 additions & 5 deletions passes/cmds/stat.cc
Original file line number Diff line number Diff line change
Expand Up @@ -222,16 +222,16 @@ struct statdata_t
unsigned int cmos_transistor_count(bool *tran_cnt_exact)
{
unsigned int tran_cnt = 0;
auto &gate_costs = CellCosts::cmos_gate_cost();
auto cost_kind = CellCosts::CMOS;
CellCosts costs(cost_kind, nullptr);
auto cell_type_cost = costs.gate_type_cost();

for (auto it : num_cells_by_type) {
auto ctype = it.first;
auto cnum = it.second;

if (gate_costs.count(ctype))
tran_cnt += cnum * gate_costs.at(ctype);
else if (ctype.in(ID($_DFF_P_), ID($_DFF_N_)))
tran_cnt += cnum * 16;
if (cell_type_cost.count(ctype))
tran_cnt += cnum * cell_type_cost.at(ctype);
else
*tran_cnt_exact = false;
}
Expand Down
1 change: 1 addition & 0 deletions passes/hierarchy/Makefile.inc
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
OBJS += passes/hierarchy/hierarchy.o
OBJS += passes/hierarchy/uniquify.o
OBJS += passes/hierarchy/submod.o
OBJS += passes/hierarchy/keep_hierarchy.o

Loading

0 comments on commit 978d8fd

Please sign in to comment.