mirror of
https://github.com/YosysHQ/yosys
synced 2025-08-18 09:12:18 +00:00
add functionality to be able to use parameterised cells.
cells can have their area as a function of the input port width.
This commit is contained in:
parent
d8fb4da437
commit
5fc0e77c3d
1 changed files with 142 additions and 1 deletions
|
@ -34,6 +34,9 @@ PRIVATE_NAMESPACE_BEGIN
|
||||||
struct cell_area_t {
|
struct cell_area_t {
|
||||||
double area;
|
double area;
|
||||||
bool is_sequential;
|
bool is_sequential;
|
||||||
|
vector<double> single_parameter_area;
|
||||||
|
vector<vector<double>> double_parameter_area;
|
||||||
|
vector<string> parameter_names;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct statdata_t {
|
struct statdata_t {
|
||||||
|
@ -206,6 +209,89 @@ struct statdata_t {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cell_area.empty()) {
|
if (!cell_area.empty()) {
|
||||||
|
// check if cell_area provides a area calculator
|
||||||
|
if (cell_area.count(cell->type)) {
|
||||||
|
cell_area_t cell_data = cell_area.at(cell->type);
|
||||||
|
if (cell_data.single_parameter_area.size() > 0) {
|
||||||
|
// assume that we just take the max of the A,B,Y ports
|
||||||
|
|
||||||
|
int width_a = cell->hasPort(ID::A) ? GetSize(cell->getPort(ID::A)) : 0;
|
||||||
|
int width_b = cell->hasPort(ID::B) ? GetSize(cell->getPort(ID::B)) : 0;
|
||||||
|
int width_y = cell->hasPort(ID::Y) ? GetSize(cell->getPort(ID::Y)) : 0;
|
||||||
|
int width_q = cell->hasPort(ID::Q) ? GetSize(cell->getPort(ID::Q)) : 0;
|
||||||
|
int max_width = max<int>({width_a, width_b, width_y, width_q});
|
||||||
|
if (!cell_area.count(cell_type)) {
|
||||||
|
cell_area[cell_type] = cell_data;
|
||||||
|
}
|
||||||
|
if (cell_data.single_parameter_area.size() > max_width - 1u) {
|
||||||
|
cell_area.at(cell_type).area = cell_data.single_parameter_area.at(max_width - 1);
|
||||||
|
cell_area.at(cell_type).is_sequential = cell_data.is_sequential;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
printf("too small single_parameter_area %s %d %f\n", cell_type.c_str(), max_width,
|
||||||
|
cell_data.single_parameter_area.back());
|
||||||
|
cell_area.at(cell_type).area = cell_data.single_parameter_area.back();
|
||||||
|
cell_area.at(cell_type).is_sequential = cell_data.is_sequential;
|
||||||
|
}
|
||||||
|
// printf("single_paramter_extraction %s %d %f\n", cell_type.c_str(), max_width,
|
||||||
|
// cell_area.at(cell_type).area);
|
||||||
|
}
|
||||||
|
vector<double> widths;
|
||||||
|
if (cell_data.parameter_names.size() > 0) {
|
||||||
|
for (auto &it : cell_data.parameter_names) {
|
||||||
|
RTLIL::IdString port_name;
|
||||||
|
// TODO: there has to be a better way to do this
|
||||||
|
if (it == "A") {
|
||||||
|
port_name = ID::A;
|
||||||
|
} else if (it == "B") {
|
||||||
|
port_name = ID::B;
|
||||||
|
} else if (it == "Y") {
|
||||||
|
port_name = ID::Y;
|
||||||
|
} else if (it == "Q") {
|
||||||
|
port_name = ID::Q;
|
||||||
|
} else if (it == "S") {
|
||||||
|
port_name = ID::S;
|
||||||
|
} else {
|
||||||
|
port_name = ID(it);
|
||||||
|
}
|
||||||
|
if (cell->hasPort(port_name)) {
|
||||||
|
int width = GetSize(cell->getPort(port_name));
|
||||||
|
widths.push_back(width);
|
||||||
|
} else {
|
||||||
|
widths.push_back(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cell_data.double_parameter_area.size() > 0) {
|
||||||
|
if (!cell_area.count(cell_type)) {
|
||||||
|
cell_area[cell_type] = cell_data;
|
||||||
|
}
|
||||||
|
if (widths.size() == 2) {
|
||||||
|
unsigned int width_a = widths.at(0);
|
||||||
|
unsigned int width_b = widths.at(1);
|
||||||
|
if (width_a > 0 && width_b > 0) {
|
||||||
|
if (cell_data.double_parameter_area.size() > width_a - 1 &&
|
||||||
|
cell_data.double_parameter_area.at(width_a - 1).size() > width_b - 1) {
|
||||||
|
cell_area.at(cell_type).area =
|
||||||
|
cell_data.double_parameter_area.at(width_a - 1).at(width_b - 1);
|
||||||
|
cell_area.at(cell_type).is_sequential = cell_data.is_sequential;
|
||||||
|
} else {
|
||||||
|
printf("too small double_parameter_area %s %d %d %f\n", cell_type.c_str(),
|
||||||
|
width_a, width_b, cell_data.double_parameter_area.back().back());
|
||||||
|
cell_area.at(cell_type).area = cell_data.double_parameter_area.back().back();
|
||||||
|
cell_area.at(cell_type).is_sequential = cell_data.is_sequential;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cell_area.at(cell_type).area = cell_data.area;
|
||||||
|
cell_area.at(cell_type).is_sequential = cell_data.is_sequential;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("double_paramter_extraction %s %zu %f\n", cell_type.c_str(), widths.size(),
|
||||||
|
cell_area.at(cell_type).area);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (cell_area.count(cell_type)) {
|
if (cell_area.count(cell_type)) {
|
||||||
cell_area_t cell_data = cell_area.at(cell_type);
|
cell_area_t cell_data = cell_area.at(cell_type);
|
||||||
|
@ -726,9 +812,64 @@ void read_liberty_cellarea(dict<IdString, cell_area_t> &cell_area, string libert
|
||||||
|
|
||||||
const LibertyAst *ar = cell->find("area");
|
const LibertyAst *ar = cell->find("area");
|
||||||
bool is_flip_flop = cell->find("ff") != nullptr;
|
bool is_flip_flop = cell->find("ff") != nullptr;
|
||||||
|
vector<double> single_parameter_area;
|
||||||
|
vector<vector<double>> double_parameter_area;
|
||||||
|
vector<string> port_names;
|
||||||
|
const LibertyAst *sar = cell->find("single_area_parameterised");
|
||||||
|
if (sar != nullptr) {
|
||||||
|
for (const auto &s : sar->args) {
|
||||||
|
double value = 0;
|
||||||
|
auto [ptr, ec] = std::from_chars(s.data(), s.data() + s.size(), value);
|
||||||
|
// ec != std::errc() means parse error, or ptr didn't consume entire string
|
||||||
|
if (ec != std::errc() || ptr != s.data() + s.size())
|
||||||
|
break;
|
||||||
|
single_parameter_area.push_back(value);
|
||||||
|
}
|
||||||
|
if (single_parameter_area.size() == 0)
|
||||||
|
printf("error: %s\n", sar->args[single_parameter_area.size() - 1].c_str());
|
||||||
|
// check if it is a double parameterised area
|
||||||
|
}
|
||||||
|
const LibertyAst *dar = cell->find("double_area_parameterised");
|
||||||
|
if (dar != nullptr) {
|
||||||
|
for (const auto &s : dar->args) {
|
||||||
|
|
||||||
|
// printf("value: %s\n",sar->value.c_str());
|
||||||
|
// printf("args1: %s\n",dar->args[0].c_str());
|
||||||
|
|
||||||
|
vector<string> sub_array;
|
||||||
|
std::string::size_type start = 0;
|
||||||
|
std::string::size_type end = s.find_first_of(",", start);
|
||||||
|
while (end != std::string::npos) {
|
||||||
|
sub_array.push_back(s.substr(start, end - start));
|
||||||
|
start = end + 1;
|
||||||
|
end = s.find_first_of(",", start);
|
||||||
|
}
|
||||||
|
sub_array.push_back(s.substr(start, end));
|
||||||
|
|
||||||
|
vector<double> cast_sub_array;
|
||||||
|
for (const auto &s : sub_array) {
|
||||||
|
double value = 0;
|
||||||
|
auto [ptr, ec] = std::from_chars(s.data() + 1, s.data() + s.size(), value);
|
||||||
|
if (ec != std::errc() || ptr != s.data() + s.size())
|
||||||
|
break;
|
||||||
|
cast_sub_array.push_back(value);
|
||||||
|
}
|
||||||
|
double_parameter_area.push_back(cast_sub_array);
|
||||||
|
if (cast_sub_array.size() == 0)
|
||||||
|
printf("error: %s\n", s.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const LibertyAst *par = cell->find("port_names");
|
||||||
|
if (par != nullptr) {
|
||||||
|
for (const auto &s : par->args) {
|
||||||
|
port_names.push_back(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ar != nullptr && !ar->value.empty()) {
|
if (ar != nullptr && !ar->value.empty()) {
|
||||||
string prefix = cell->args[0].substr(0, 1) == "$" ? "" : "\\";
|
string prefix = cell->args[0].substr(0, 1) == "$" ? "" : "\\";
|
||||||
cell_area[prefix + cell->args[0]] = {atof(ar->value.c_str()), is_flip_flop};
|
cell_area[prefix + cell->args[0]] = {atof(ar->value.c_str()), is_flip_flop, single_parameter_area, double_parameter_area,
|
||||||
|
port_names};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue