mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-24 01:25:33 +00:00
Update Yosys
This commit is contained in:
commit
c0af4604bc
47 changed files with 5093 additions and 97 deletions
195
kernel/cost.cc
Normal file
195
kernel/cost.cc
Normal file
|
@ -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;
|
||||
}
|
|
@ -26,7 +26,17 @@ YOSYS_NAMESPACE_BEGIN
|
|||
|
||||
struct CellCosts
|
||||
{
|
||||
|
||||
private:
|
||||
dict<RTLIL::IdString, int> mod_cost_cache_;
|
||||
Design *design_ = nullptr;
|
||||
|
||||
public:
|
||||
CellCosts(RTLIL::Design *design) : design_(design) { }
|
||||
|
||||
static const dict<RTLIL::IdString, int>& default_gate_cost() {
|
||||
// Default size heuristics for several common PDK standard cells
|
||||
// used by abc and stat
|
||||
static const dict<RTLIL::IdString, int> db = {
|
||||
{ ID($_BUF_), 1 },
|
||||
{ ID($_NOT_), 2 },
|
||||
|
@ -43,12 +53,14 @@ struct CellCosts
|
|||
{ ID($_AOI4_), 7 },
|
||||
{ ID($_OAI4_), 7 },
|
||||
{ ID($_MUX_), 4 },
|
||||
{ ID($_NMUX_), 4 }
|
||||
{ ID($_NMUX_), 4 },
|
||||
};
|
||||
return db;
|
||||
}
|
||||
|
||||
static const dict<RTLIL::IdString, int>& cmos_gate_cost() {
|
||||
// Estimated CMOS transistor counts for several common PDK standard cells
|
||||
// used by stat and optionally by abc
|
||||
static const dict<RTLIL::IdString, int> db = {
|
||||
{ ID($_BUF_), 1 },
|
||||
{ ID($_NOT_), 2 },
|
||||
|
@ -65,50 +77,21 @@ 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;
|
||||
}
|
||||
|
||||
log_warning("Can't determine cost of %s cell (%d parameters).\n", log_id(cell->type), GetSize(cell->parameters));
|
||||
return 1;
|
||||
}
|
||||
// Get the cell cost for a cell based on its parameters.
|
||||
// This cost is an *approximate* upper bound for the number of gates that
|
||||
// the cell will get mapped to with "opt -fast; techmap"
|
||||
// The intended usage is for flattening heuristics and similar situations
|
||||
unsigned int get(RTLIL::Cell *cell);
|
||||
// Sum up the cell costs of all cells in the module
|
||||
// and all its submodules recursively
|
||||
unsigned int get(RTLIL::Module *mod);
|
||||
};
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
|
|
@ -188,6 +188,7 @@ inline unsigned int mkhash(const T &v) {
|
|||
|
||||
inline int hashtable_size(int min_size)
|
||||
{
|
||||
// Primes as generated by https://oeis.org/A175953
|
||||
static std::vector<int> zero_and_some_primes = {
|
||||
0, 23, 29, 37, 47, 59, 79, 101, 127, 163, 211, 269, 337, 431, 541, 677,
|
||||
853, 1069, 1361, 1709, 2137, 2677, 3347, 4201, 5261, 6577, 8231, 10289,
|
||||
|
@ -196,7 +197,9 @@ inline int hashtable_size(int min_size)
|
|||
897133, 1121423, 1401791, 1752239, 2190299, 2737937, 3422429, 4278037,
|
||||
5347553, 6684443, 8355563, 10444457, 13055587, 16319519, 20399411,
|
||||
25499291, 31874149, 39842687, 49803361, 62254207, 77817767, 97272239,
|
||||
121590311, 151987889, 189984863, 237481091, 296851369, 371064217
|
||||
121590311, 151987889, 189984863, 237481091, 296851369, 371064217,
|
||||
463830313, 579787991, 724735009, 905918777, 1132398479, 1415498113,
|
||||
1769372713
|
||||
};
|
||||
|
||||
for (auto p : zero_and_some_primes)
|
||||
|
@ -1129,6 +1132,11 @@ public:
|
|||
const_iterator end() const { return const_iterator(*this, offset + size()); }
|
||||
};
|
||||
|
||||
/**
|
||||
* Union-find data structure with a promotion method
|
||||
* mfp stands for "merge, find, promote"
|
||||
* i-prefixed methods operate on indices in parents
|
||||
*/
|
||||
template<typename K, typename OPS>
|
||||
class mfp
|
||||
{
|
||||
|
@ -1142,13 +1150,18 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
// Finds a given element's index. If it isn't in the data structure,
|
||||
// it is added as its own set
|
||||
int operator()(const K &key) const
|
||||
{
|
||||
int i = database(key);
|
||||
// If the lookup caused the database to grow,
|
||||
// also add a corresponding entry in parents initialized to -1 (no parent)
|
||||
parents.resize(database.size(), -1);
|
||||
return i;
|
||||
}
|
||||
|
||||
// Finds an element at given index
|
||||
const K &operator[](int index) const
|
||||
{
|
||||
return database[index];
|
||||
|
@ -1161,6 +1174,11 @@ public:
|
|||
while (parents[p] != -1)
|
||||
p = parents[p];
|
||||
|
||||
// p is now the representative of i
|
||||
// Now we traverse from i up to the representative again
|
||||
// and make p the parent of all the nodes along the way.
|
||||
// This is a side effect and doesn't affect the return value.
|
||||
// It speeds up future find operations
|
||||
while (k != p) {
|
||||
int next_k = parents[k];
|
||||
parents[k] = p;
|
||||
|
@ -1170,6 +1188,7 @@ public:
|
|||
return p;
|
||||
}
|
||||
|
||||
// Merge sets if the given indices belong to different sets
|
||||
void imerge(int i, int j)
|
||||
{
|
||||
i = ifind(i);
|
||||
|
|
|
@ -229,6 +229,13 @@ using sort_by_name_id_guard = typename std::enable_if<std::is_same<T,RTLIL::Cell
|
|||
template<typename T>
|
||||
class SigSet<T, sort_by_name_id_guard<T>> : public SigSet<T, RTLIL::sort_by_name_id<typename std::remove_pointer<T>::type>> {};
|
||||
|
||||
/**
|
||||
* SigMap wraps a union-find "database"
|
||||
* to map SigBits of a module to canonical representative SigBits.
|
||||
* SigBits that are connected share a set in the underlying database.
|
||||
* If a SigBit has a const state (impl: bit.wire is nullptr),
|
||||
* it's promoted to a representative.
|
||||
*/
|
||||
struct SigMap
|
||||
{
|
||||
mfp<SigBit> database;
|
||||
|
@ -249,6 +256,7 @@ struct SigMap
|
|||
database.clear();
|
||||
}
|
||||
|
||||
// Rebuild SigMap for all connections in module
|
||||
void set(RTLIL::Module *module)
|
||||
{
|
||||
int bitcount = 0;
|
||||
|
@ -262,6 +270,7 @@ struct SigMap
|
|||
add(it.first, it.second);
|
||||
}
|
||||
|
||||
// Add connections from "from" to "to", bit-by-bit
|
||||
void add(const RTLIL::SigSpec& from, const RTLIL::SigSpec& to)
|
||||
{
|
||||
log_assert(GetSize(from) == GetSize(to));
|
||||
|
@ -287,6 +296,7 @@ struct SigMap
|
|||
}
|
||||
}
|
||||
|
||||
// Add sig as disconnected from anything
|
||||
void add(const RTLIL::SigBit &bit)
|
||||
{
|
||||
const auto &b = database.find(bit);
|
||||
|
@ -302,6 +312,7 @@ struct SigMap
|
|||
|
||||
inline void add(Wire *wire) { return add(RTLIL::SigSpec(wire)); }
|
||||
|
||||
// Modify bit to its representative
|
||||
void apply(RTLIL::SigBit &bit) const
|
||||
{
|
||||
bit = database.find(bit);
|
||||
|
@ -332,6 +343,7 @@ struct SigMap
|
|||
return sig;
|
||||
}
|
||||
|
||||
// All non-const bits
|
||||
RTLIL::SigSpec allbits() const
|
||||
{
|
||||
RTLIL::SigSpec sig;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue