3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-08-20 10:10:23 +00:00

Merge pull request #5281 from suisseWalter/add_parameterised_cells_stat

STAT: Add parameterised cells
This commit is contained in:
KrystalDelusion 2025-08-18 09:21:45 +12:00 committed by GitHub
commit 6d55ca204b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 963 additions and 149 deletions

View file

@ -19,13 +19,14 @@
#include <iterator> #include <iterator>
#include "kernel/yosys.h"
#include "kernel/celltypes.h" #include "kernel/celltypes.h"
#include "passes/techmap/libparse.h"
#include "kernel/cost.h" #include "kernel/cost.h"
#include "kernel/gzip.h" #include "kernel/gzip.h"
#include "libs/json11/json11.hpp"
#include "kernel/log_help.h" #include "kernel/log_help.h"
#include "kernel/yosys.h"
#include "libs/json11/json11.hpp"
#include "passes/techmap/libparse.h"
#include <charconv>
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN PRIVATE_NAMESPACE_BEGIN
@ -33,24 +34,42 @@ 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 {
{ #define STAT_INT_MEMBERS \
#define STAT_INT_MEMBERS X(num_wires) X(num_wire_bits) X(num_pub_wires) X(num_pub_wire_bits) \ X(num_wires) \
X(num_ports) X(num_port_bits) X(num_memories) X(num_memory_bits) X(num_cells) \ X(num_wire_bits) \
X(num_processes) X(num_pub_wires) X(num_pub_wire_bits) X(num_ports) X(num_port_bits) X(num_memories) X(num_memory_bits) X(num_cells) X(num_processes)
#define STAT_NUMERIC_MEMBERS STAT_INT_MEMBERS X(area) X(sequential_area) #define STAT_NUMERIC_MEMBERS STAT_INT_MEMBERS X(area) X(sequential_area)
#define X(_name) unsigned int _name; #define X(_name) unsigned int _name;
STAT_INT_MEMBERS STAT_INT_MEMBERS
#undef X
#define X(_name) unsigned int local_##_name;
STAT_INT_MEMBERS
#undef X #undef X
double area = 0; double area = 0;
double sequential_area = 0; double sequential_area = 0;
double local_area = 0;
double local_sequential_area = 0;
double submodule_area = 0;
int num_submodules = 0;
std::map<RTLIL::IdString, unsigned int, RTLIL::sort_by_id_str> num_submodules_by_type;
std::map<RTLIL::IdString, double, RTLIL::sort_by_id_str> submodules_area_by_type;
std::map<RTLIL::IdString, unsigned int, RTLIL::sort_by_id_str> local_num_cells_by_type;
std::map<RTLIL::IdString, double, RTLIL::sort_by_id_str> local_area_cells_by_type;
std::map<RTLIL::IdString, double, RTLIL::sort_by_id_str> local_seq_area_cells_by_type;
string tech; string tech;
std::map<RTLIL::IdString, unsigned int, RTLIL::sort_by_id_str> num_cells_by_type; std::map<RTLIL::IdString, unsigned int, RTLIL::sort_by_id_str> num_cells_by_type;
std::map<RTLIL::IdString, double, RTLIL::sort_by_id_str> area_cells_by_type;
std::map<RTLIL::IdString, double, RTLIL::sort_by_id_str> seq_area_cells_by_type;
std::set<RTLIL::IdString> unknown_cell_area; std::set<RTLIL::IdString> unknown_cell_area;
statdata_t operator+(const statdata_t &other) const statdata_t operator+(const statdata_t &other) const
@ -63,7 +82,6 @@ struct statdata_t
sum.num_cells_by_type[it.first] += it.second; sum.num_cells_by_type[it.first] += it.second;
return sum; return sum;
} }
statdata_t operator*(unsigned int other) const statdata_t operator*(unsigned int other) const
{ {
statdata_t sum = *this; statdata_t sum = *this;
@ -74,6 +92,38 @@ struct statdata_t
it.second *= other; it.second *= other;
return sum; return sum;
} }
statdata_t add(const statdata_t &other)
{
#define X(_name) _name += other._name;
STAT_NUMERIC_MEMBERS
#undef X
for (auto &it : other.num_cells_by_type) {
if (num_cells_by_type.count(it.first))
num_cells_by_type[it.first] += it.second;
else
num_cells_by_type[it.first] = it.second;
}
for (auto &it : other.submodules_area_by_type) {
if (submodules_area_by_type.count(it.first))
submodules_area_by_type[it.first] += it.second;
else
submodules_area_by_type[it.first] = it.second;
}
for (auto &it : other.area_cells_by_type) {
if (area_cells_by_type.count(it.first))
area_cells_by_type[it.first] += it.second;
else
area_cells_by_type[it.first] = it.second;
}
for (auto &it : other.seq_area_cells_by_type) {
if (seq_area_cells_by_type.count(it.first))
seq_area_cells_by_type[it.first] += it.second;
else
seq_area_cells_by_type[it.first] = it.second;
}
unknown_cell_area.insert(other.unknown_cell_area.begin(), other.unknown_cell_area.end());
return *this;
}
statdata_t() statdata_t()
{ {
@ -82,90 +132,213 @@ struct statdata_t
#undef X #undef X
} }
statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode, const dict<IdString, cell_area_t> &cell_area, string techname) statdata_t(cell_area_t &cell_data, string techname)
{
tech = techname;
area = cell_data.area;
if (cell_data.is_sequential) {
sequential_area = cell_data.area;
}
}
statdata_t(const RTLIL::Design *design, const RTLIL::Module *mod, bool width_mode, dict<IdString, cell_area_t> &cell_area, string techname)
{ {
tech = techname; tech = techname;
#define X(_name) _name = 0; #define X(_name) _name = 0;
STAT_NUMERIC_MEMBERS STAT_NUMERIC_MEMBERS
#undef X #undef X
#define X(_name) local_##_name = 0;
STAT_NUMERIC_MEMBERS
#undef X
// additional_cell_area
for (auto wire : mod->selected_wires()) for (auto wire : mod->selected_wires()) {
{
if (wire->port_input || wire->port_output) { if (wire->port_input || wire->port_output) {
num_ports++; num_ports++;
local_num_ports++;
num_port_bits += wire->width; num_port_bits += wire->width;
local_num_port_bits += wire->width;
} }
if (wire->name.isPublic()) { if (wire->name.isPublic()) {
num_pub_wires++; num_pub_wires++;
local_num_pub_wires++;
num_pub_wire_bits += wire->width; num_pub_wire_bits += wire->width;
local_num_pub_wire_bits += wire->width;
} }
num_wires++; num_wires++;
local_num_wires++;
num_wire_bits += wire->width; num_wire_bits += wire->width;
local_num_wire_bits += wire->width;
} }
for (auto &it : mod->memories) { for (auto &it : mod->memories) {
if (!design->selected(mod, it.second)) if (!design->selected(mod, it.second))
continue; continue;
num_memories++; num_memories++;
local_num_memories++;
num_memory_bits += it.second->width * it.second->size; num_memory_bits += it.second->width * it.second->size;
local_num_memory_bits += it.second->width * it.second->size;
} }
for (auto cell : mod->selected_cells()) {
for (auto cell : mod->selected_cells())
{
RTLIL::IdString cell_type = cell->type; RTLIL::IdString cell_type = cell->type;
if (width_mode) {
if (width_mode) if (cell_type.in(ID($not), ID($pos), ID($neg), ID($logic_not), ID($logic_and), ID($logic_or), ID($reduce_and),
{ ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), ID($lut), ID($and), ID($or),
if (cell_type.in(ID($not), ID($pos), ID($neg), ID($xor), ID($xnor), ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx), ID($lt),
ID($logic_not), ID($logic_and), ID($logic_or), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt), ID($add), ID($sub), ID($mul),
ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow), ID($alu))) {
ID($lut), ID($and), ID($or), ID($xor), ID($xnor),
ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx),
ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt),
ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow), ID($alu))) {
int width_a = cell->hasPort(ID::A) ? GetSize(cell->getPort(ID::A)) : 0; 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_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_y = cell->hasPort(ID::Y) ? GetSize(cell->getPort(ID::Y)) : 0;
cell_type = stringf("%s_%d", cell_type.c_str(), max<int>({width_a, width_b, width_y})); cell_type = stringf("%s_%d", cell_type.c_str(), max<int>({width_a, width_b, width_y}));
} } else if (cell_type.in(ID($mux)))
else if (cell_type.in(ID($mux), ID($pmux)))
cell_type = stringf("%s_%d", cell_type.c_str(), GetSize(cell->getPort(ID::Y))); cell_type = stringf("%s_%d", cell_type.c_str(), GetSize(cell->getPort(ID::Y)));
else if (cell_type == ID($bmux)) else if (cell_type.in(ID($bmux), ID($pmux)))
cell_type = stringf("%s_%d_%d", cell_type.c_str(), GetSize(cell->getPort(ID::Y)), GetSize(cell->getPort(ID::S))); cell_type =
stringf("%s_%d_%d", cell_type.c_str(), GetSize(cell->getPort(ID::Y)), GetSize(cell->getPort(ID::S)));
else if (cell_type == ID($demux)) else if (cell_type == ID($demux))
cell_type = stringf("%s_%d_%d", cell_type.c_str(), GetSize(cell->getPort(ID::A)), GetSize(cell->getPort(ID::S))); cell_type =
else if (cell_type.in( stringf("%s_%d_%d", cell_type.c_str(), GetSize(cell->getPort(ID::A)), GetSize(cell->getPort(ID::S)));
ID($sr), ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre), else if (cell_type.in(ID($sr), ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre), ID($adff), ID($adffe),
ID($adff), ID($adffe), ID($sdff), ID($sdffe), ID($sdffce), ID($sdff), ID($sdffe), ID($sdffce), ID($aldff), ID($aldffe), ID($dlatch), ID($adlatch),
ID($aldff), ID($aldffe), ID($dlatch), ID($adlatch), ID($dlatchsr))) ID($dlatchsr)))
cell_type = stringf("%s_%d", cell_type.c_str(), GetSize(cell->getPort(ID::Q))); cell_type = stringf("%s_%d", cell_type.c_str(), GetSize(cell->getPort(ID::Q)));
} }
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 {
log_warning("too small single_parameter_area %s width: %d size: %d\n", cell_type.c_str(), max_width,
(int)cell_data.single_parameter_area.size());
cell_area.at(cell_type).area = cell_data.single_parameter_area.back();
cell_area.at(cell_type).is_sequential = cell_data.is_sequential;
}
}
vector<double> widths;
if (cell_data.parameter_names.size() > 0) {
for (auto &it : cell_data.parameter_names) {
RTLIL::IdString port_name;
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 {
log_warning("too small double_parameter_area %s, width_a: %d, width_b: %d, size_a: %d, size_b: %d\n", cell_type.c_str(),
width_a, width_b, (int)cell_data.double_parameter_area.size(),
(int)cell_data.double_parameter_area.at(width_a - 1).size());
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 {
log_error("double_parameter_area for %s has %d parameters, but only 2 are expected.\n", cell_type.c_str(),
(int)cell_data.double_parameter_area.size());
}
}
}
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);
if (cell_data.is_sequential) { if (cell_data.is_sequential) {
sequential_area += cell_data.area; sequential_area += cell_data.area;
local_sequential_area += cell_data.area;
} }
area += cell_data.area; area += cell_data.area;
}
else {
unknown_cell_area.insert(cell_type);
}
}
num_cells++; num_cells++;
num_cells_by_type[cell_type]++; num_cells_by_type[cell_type]++;
area_cells_by_type[cell_type] += cell_data.area;
seq_area_cells_by_type[cell_type] += cell_data.is_sequential ? cell_data.area : 0;
local_area_cells_by_type[cell_type] += cell_data.area;
local_seq_area_cells_by_type[cell_type] += cell_data.is_sequential ? cell_data.area : 0;
local_area += cell_data.area;
local_num_cells++;
local_num_cells_by_type[cell_type]++;
} else {
unknown_cell_area.insert(cell_type);
num_cells++;
num_cells_by_type[cell_type]++;
local_num_cells++;
local_num_cells_by_type[cell_type]++;
area_cells_by_type[cell_type] = 0;
seq_area_cells_by_type[cell_type] = 0;
local_area_cells_by_type[cell_type] = 0;
local_seq_area_cells_by_type[cell_type] = 0;
}
} else {
num_cells++;
num_cells_by_type[cell_type]++;
area_cells_by_type[cell_type] = 0;
seq_area_cells_by_type[cell_type] = 0;
local_num_cells++;
local_num_cells_by_type[cell_type]++;
local_area_cells_by_type[cell_type] = 0;
local_seq_area_cells_by_type[cell_type] = 0;
}
} }
for (auto &it : mod->processes) { for (auto &it : mod->processes) {
if (!design->selected(mod, it.second)) if (!design->selected(mod, it.second))
continue; continue;
num_processes++; num_processes++;
local_num_processes++;
} }
RTLIL::IdString cell_name = mod->name;
auto s = cell_name.str();
} }
unsigned int estimate_xilinx_lc() unsigned int estimate_xilinx_lc()
@ -238,22 +411,132 @@ struct statdata_t
return tran_cnt; return tran_cnt;
} }
void log_data(RTLIL::IdString mod_name, bool top_mod) /*
format a floating point value to a of 8 characters, with at most 7 digits or scientific notation
uses - to mark zero or very small values
*/
std::string f_val(double value)
{ {
log(" Number of wires: %6u\n", num_wires); if (std::abs(value) < 1e-12)
log(" Number of wire bits: %6u\n", num_wire_bits); return " -";
log(" Number of public wires: %6u\n", num_pub_wires);
log(" Number of public wire bits: %6u\n", num_pub_wire_bits);
log(" Number of ports: %6u\n", num_ports);
log(" Number of port bits: %6u\n", num_port_bits);
log(" Number of memories: %6u\n", num_memories);
log(" Number of memory bits: %6u\n", num_memory_bits);
log(" Number of processes: %6u\n", num_processes);
log(" Number of cells: %6u\n", num_cells);
for (auto &it : num_cells_by_type)
if (it.second)
log(" %-26s %6u\n", log_id(it.first), it.second);
char buf[16];
int len = snprintf(buf, sizeof(buf), "%.3f", value);
while (len > 0 && buf[len - 1] == '0')
--len;
if (len > 0 && buf[len - 1] == '.')
--len;
buf[len] = '\0';
if (len <= 7) {
return std::string(8 - len, ' ') + std::string(buf);
}
// use scientific notation, this should always fit in 8 characters
snprintf(buf, sizeof(buf), "%8.3G", value);
return std::string(buf);
}
void print_log_line(const std::string &name, unsigned int count_local, double area_local, unsigned int count_global, double area_global,
int spacer = 0, bool print_area = true, bool print_hierarchical = true, bool print_global_only = false)
{
const std::string indent(2 * spacer, ' ');
std::string count_local_str = f_val(static_cast<double>(count_local));
std::string count_global_str = f_val(static_cast<double>(count_global));
std::string area_local_str = f_val(area_local);
std::string area_global_str = f_val(area_global);
if (print_area) {
if (print_hierarchical) {
log(" %s %s %s %s %s%s\n", count_global_str.c_str(), area_global_str.c_str(), count_local_str.c_str(),
area_local_str.c_str(), indent.c_str(), name.c_str());
} else if (print_global_only) {
log(" %s %s %s%s\n", count_global_str.c_str(), area_global_str.c_str(), indent.c_str(), name.c_str());
} else {
if (count_local > 0)
log(" %s %s %s%s\n", count_local_str.c_str(), area_local_str.c_str(), indent.c_str(), name.c_str());
}
} else {
if (print_hierarchical) {
log(" %s %s %s%s\n", count_global_str.c_str(), count_local_str.c_str(), indent.c_str(), name.c_str());
} else if (print_global_only) {
log(" %s %s%s\n", count_global_str.c_str(), indent.c_str(), name.c_str());
} else {
if (count_local > 0)
log(" %s %s%s\n", count_local_str.c_str(), indent.c_str(), name.c_str());
}
}
}
void print_log_header(bool print_area = true, bool print_hierarchical = true, bool print_global_only = false)
{
if (print_area) {
if (print_hierarchical) {
log(" %8s-%8s-%8s-%8s-%s\n", "+", "--------", "--------", "--------", "Count including submodules.");
log(" %8s %8s-%8s-%8s-%s\n", "|", "+", "--------", "--------", "Area including submodules.");
log(" %8s %8s %8s-%8s-%s\n", "|", "|", "+", "--------", "Local count, excluding submodules.");
log(" %8s %8s %8s %8s-%s\n", "|", "|", "|", "+", "Local area, excluding submodules.");
log(" %8s %8s %8s %8s \n", "|", "|", "|", "|");
} else if (print_global_only) {
log(" %8s-%8s-%s\n", "+", "--------", "Count including submodules.");
log(" %8s %8s-%s\n", "|", "+", "Area including submodules.");
log(" %8s %8s \n", "|", "|");
} else {
log(" %8s-%8s-%s\n", "+", "--------", "Local Count, excluding submodules.");
log(" %8s %8s-%s\n", "|", "+", "Local Area, excluding submodules.");
log(" %8s %8s \n", "|", "|");
}
} else {
if (print_hierarchical) {
log(" %8s-%8s-%8s-%s\n", "+", "--------", "--------", "Count including submodules.");
log(" %8s %8s-%8s-%s\n", "|", "+", "--------", "Local count, excluding submodules.");
log(" %8s %8s \n", "|", "|");
} else if (print_global_only) {
log(" %8s-%8s-%s\n", "+", "--------", "Count including submodules.");
log(" %8s \n", "|");
} else {
log(" %8s-%8s-%s\n", "+", "--------", "Local Count, excluding submodules.");
log(" %8s \n", "|");
}
}
}
void log_data(RTLIL::IdString mod_name, bool top_mod, bool print_area = true, bool print_hierarchical = true, bool print_global_only = false)
{
print_log_header(print_area, print_hierarchical, print_global_only);
print_log_line("wires", local_num_wires, 0, num_wires, 0, 0, print_area, print_hierarchical, print_global_only);
print_log_line("wire bits", local_num_wire_bits, 0, num_wire_bits, 0, 0, print_area, print_hierarchical, print_global_only);
print_log_line("public wires", local_num_pub_wires, 0, num_pub_wires, 0, 0, print_area, print_hierarchical, print_global_only);
print_log_line("public wire bits", local_num_pub_wire_bits, 0, num_pub_wire_bits, 0, 0, print_area, print_hierarchical,
print_global_only);
print_log_line("ports", local_num_ports, 0, num_ports, 0, 0, print_area, print_hierarchical, print_global_only);
print_log_line("port bits", local_num_port_bits, 0, num_port_bits, 0, 0, print_area, print_hierarchical, print_global_only);
print_log_line("memories", local_num_memories, 0, num_memories, 0, 0, print_area, print_hierarchical, print_global_only);
print_log_line("memory bits", local_num_memory_bits, 0, num_memory_bits, 0, 0, print_area, print_hierarchical, print_global_only);
print_log_line("processes", local_num_processes, 0, num_processes, 0, 0, print_area, print_hierarchical, print_global_only);
print_log_line("cells", local_num_cells, local_area, num_cells, area, 0, print_area, print_hierarchical, print_global_only);
for (auto &it : num_cells_by_type)
if (it.second) {
auto name = string(log_id(it.first));
print_log_line(name, local_num_cells_by_type.count(it.first) ? local_num_cells_by_type.at(it.first) : 0,
local_area_cells_by_type.count(it.first) ? local_area_cells_by_type.at(it.first) : 0, it.second,
area_cells_by_type.at(it.first), 1, print_area, print_hierarchical, print_global_only);
}
if (num_submodules > 0) {
print_log_line("submodules", num_submodules, 0, num_submodules, submodule_area, 0, print_area, print_hierarchical,
print_global_only);
for (auto &it : num_submodules_by_type)
if (it.second)
print_log_line(string(log_id(it.first)), it.second, 0, it.second,
submodules_area_by_type.count(it.first) ? submodules_area_by_type.at(it.first) : 0, 1,
print_area, print_hierarchical, print_global_only);
}
if (!unknown_cell_area.empty()) { if (!unknown_cell_area.empty()) {
log("\n"); log("\n");
for (auto cell_type : unknown_cell_area) for (auto cell_type : unknown_cell_area)
@ -262,18 +545,28 @@ struct statdata_t
if (area != 0) { if (area != 0) {
log("\n"); log("\n");
if (print_hierarchical || print_global_only) {
log(" Chip area for %smodule '%s': %f\n", (top_mod) ? "top " : "", mod_name.c_str(), area); log(" Chip area for %smodule '%s': %f\n", (top_mod) ? "top " : "", mod_name.c_str(), area);
log(" of which used for sequential elements: %f (%.2f%%)\n", sequential_area, 100.0 * sequential_area / area); log(" of which used for sequential elements: %f (%.2f%%)\n", sequential_area, 100.0 * sequential_area / area);
} else {
double local_area = 0;
for (auto &it : local_area_cells_by_type)
local_area += it.second;
double local_sequential_area = 0;
for (auto &it : local_seq_area_cells_by_type)
local_sequential_area += it.second;
log(" Chip area for %smodule '%s': %f\n", (top_mod) ? "top " : "", mod_name.c_str(), local_area);
log(" of which used for sequential elements: %f (%.2f%%)\n", local_sequential_area,
100.0 * local_sequential_area / local_area);
}
} }
if (tech == "xilinx") if (tech == "xilinx") {
{
log("\n"); log("\n");
log(" Estimated number of LCs: %10u\n", estimate_xilinx_lc()); log(" Estimated number of LCs: %10u\n", estimate_xilinx_lc());
} }
if (tech == "cmos") if (tech == "cmos") {
{
bool tran_cnt_exact = true; bool tran_cnt_exact = true;
unsigned int tran_cnt = cmos_transistor_count(&tran_cnt_exact); unsigned int tran_cnt = cmos_transistor_count(&tran_cnt_exact);
@ -282,10 +575,71 @@ struct statdata_t
} }
} }
void log_data_json(const char *mod_name, bool first_module) string json_line(unsigned int count_local, double area_local, unsigned int count_global, double area_global)
{
return stringf("{ \"count\": \"%u\", \"area\": \"%f\", \"local_count\": \"%u\", \"local_area\": \"%f\" }", count_global, area_global,
count_local, area_local);
}
void log_data_json(const char *mod_name, bool first_module, bool hierarchical = false, bool global_only = false)
{ {
if (!first_module) if (!first_module)
log(",\n"); log(",\n");
if (hierarchical) {
log(" %s: {\n", json11::Json(mod_name).dump().c_str());
log(" \"num_wires\": %s,\n", json_line(local_num_wires, 0, num_wires, 0).c_str());
log(" \"num_wire_bits\": %s,\n", json_line(local_num_wire_bits, 0, num_wire_bits, 0).c_str());
log(" \"num_pub_wires\": %s,\n", json_line(local_num_pub_wires, 0, num_pub_wires, 0).c_str());
log(" \"num_pub_wire_bits\": %s,\n", json_line(local_num_pub_wire_bits, 0, num_pub_wire_bits, 0).c_str());
log(" \"num_ports\": %s,\n", json_line(local_num_ports, 0, num_ports, 0).c_str());
log(" \"num_port_bits\": %s,\n", json_line(local_num_port_bits, 0, num_port_bits, 0).c_str());
log(" \"num_memories\": %s,\n", json_line(local_num_memories, 0, num_memories, 0).c_str());
log(" \"num_memory_bits\": %s,\n", json_line(local_num_memory_bits, 0, num_memory_bits, 0).c_str());
log(" \"num_processes\": %s,\n", json_line(local_num_processes, 0, num_processes, 0).c_str());
log(" \"num_cells\": %s,\n", json_line(local_num_cells, local_area, num_cells, area).c_str());
log(" \"num_submodules\": %s,\n", json_line(0, 0, num_submodules, submodule_area).c_str());
log(" \"sequential_area\": %s,\n", json_line(0, local_sequential_area, 0, sequential_area).c_str());
log(" \"num_cells_by_type\": {\n");
bool first_line = true;
for (auto &it : num_cells_by_type)
if (it.second) {
if (!first_line)
log(",\n");
log(" %s: %s", json11::Json(log_id(it.first)).dump().c_str(),
json_line(local_num_cells_by_type.count(it.first) ? local_num_cells_by_type.at(it.first) : 0,
local_area_cells_by_type.count(it.first) ? local_area_cells_by_type.at(it.first) : 0, it.second,
area_cells_by_type.at(it.first))
.c_str());
first_line = false;
}
log("\n },\n");
log(" \"num_submodules_by_type\": {\n");
first_line = true;
for (auto &it : num_submodules_by_type)
if (it.second) {
if (!first_line)
log(",\n");
log(" %s: %s", json11::Json(log_id(it.first)).dump().c_str(),
json_line(0, 0, it.second,
submodules_area_by_type.count(it.first) ? submodules_area_by_type.at(it.first) : 0)
.c_str());
first_line = false;
}
log("\n }\n");
if (tech == "xilinx") {
log(" \"estimated_num_lc\": %u,\n", estimate_xilinx_lc());
}
if (tech == "cmos") {
bool tran_cnt_exact = true;
unsigned int tran_cnt = cmos_transistor_count(&tran_cnt_exact);
log(" \"estimated_num_transistors\": \"%u%s\"\n", tran_cnt, tran_cnt_exact ? "" : "+");
}
log(" }");
} else {
if (global_only) {
log(" %s: {\n", json11::Json(mod_name).dump().c_str()); log(" %s: {\n", json11::Json(mod_name).dump().c_str());
log(" \"num_wires\": %u,\n", num_wires); log(" \"num_wires\": %u,\n", num_wires);
log(" \"num_wire_bits\": %u,\n", num_wire_bits); log(" \"num_wire_bits\": %u,\n", num_wire_bits);
@ -297,8 +651,10 @@ struct statdata_t
log(" \"num_memory_bits\": %u,\n", num_memory_bits); log(" \"num_memory_bits\": %u,\n", num_memory_bits);
log(" \"num_processes\": %u,\n", num_processes); log(" \"num_processes\": %u,\n", num_processes);
log(" \"num_cells\": %u,\n", num_cells); log(" \"num_cells\": %u,\n", num_cells);
log(" \"num_submodules\": %u,\n", num_submodules);
if (area != 0) { if (area != 0) {
log(" \"area\": %f,\n", area); log(" \"area\": %f,\n", area);
log(" \"sequential_area\": %f,\n", sequential_area);
} }
log(" \"num_cells_by_type\": {\n"); log(" \"num_cells_by_type\": {\n");
bool first_line = true; bool first_line = true;
@ -309,15 +665,56 @@ struct statdata_t
log(" %s: %u", json11::Json(log_id(it.first)).dump().c_str(), it.second); log(" %s: %u", json11::Json(log_id(it.first)).dump().c_str(), it.second);
first_line = false; first_line = false;
} }
for (auto &it : num_submodules_by_type)
if (it.second) {
if (!first_line)
log(",\n");
log(" %s: %u", json11::Json(log_id(it.first)).dump().c_str(), it.second);
first_line = false;
}
log("\n"); log("\n");
log(" }"); log(" }");
if (tech == "xilinx") } else {
{ log(" %s: {\n", json11::Json(mod_name).dump().c_str());
log(" \"num_wires\": %u,\n", local_num_wires);
log(" \"num_wire_bits\": %u,\n", local_num_wire_bits);
log(" \"num_pub_wires\": %u,\n", local_num_pub_wires);
log(" \"num_pub_wire_bits\": %u,\n", local_num_pub_wire_bits);
log(" \"num_ports\": %u,\n", local_num_ports);
log(" \"num_port_bits\": %u,\n", local_num_port_bits);
log(" \"num_memories\": %u,\n", local_num_memories);
log(" \"num_memory_bits\": %u,\n", local_num_memory_bits);
log(" \"num_processes\": %u,\n", local_num_processes);
log(" \"num_cells\": %u,\n", local_num_cells);
log(" \"num_submodules\": %u,\n", num_submodules);
if (area != 0) {
log(" \"area\": %f,\n", area);
log(" \"sequential_area\": %f,\n", sequential_area);
}
log(" \"num_cells_by_type\": {\n");
bool first_line = true;
for (auto &it : local_num_cells_by_type)
if (it.second) {
if (!first_line)
log(",\n");
log(" %s: %u", json11::Json(log_id(it.first)).dump().c_str(), it.second);
first_line = false;
}
for (auto &it : num_submodules_by_type)
if (it.second) {
if (!first_line)
log(",\n");
log(" %s: %u", json11::Json(log_id(it.first)).dump().c_str(), it.second);
first_line = false;
}
log("\n");
log(" }");
}
if (tech == "xilinx") {
log(",\n"); log(",\n");
log(" \"estimated_num_lc\": %u", estimate_xilinx_lc()); log(" \"estimated_num_lc\": %u", estimate_xilinx_lc());
} }
if (tech == "cmos") if (tech == "cmos") {
{
bool tran_cnt_exact = true; bool tran_cnt_exact = true;
unsigned int tran_cnt = cmos_transistor_count(&tran_cnt_exact); unsigned int tran_cnt = cmos_transistor_count(&tran_cnt_exact);
log(",\n"); log(",\n");
@ -326,27 +723,80 @@ struct statdata_t
log("\n"); log("\n");
log(" }"); log(" }");
} }
}
}; };
statdata_t hierarchy_worker(std::map<RTLIL::IdString, statdata_t> &mod_stat, RTLIL::IdString mod, int level, bool quiet = false) statdata_t hierarchy_worker(std::map<RTLIL::IdString, statdata_t> &mod_stat, RTLIL::IdString mod, int level, bool quiet = false, bool has_area = true,
bool hierarchy_mode = true)
{ {
statdata_t mod_data = mod_stat.at(mod); statdata_t mod_data = mod_stat.at(mod);
std::map<RTLIL::IdString, unsigned int, RTLIL::sort_by_id_str> num_cells_by_type;
num_cells_by_type.swap(mod_data.num_cells_by_type);
for (auto &it : num_cells_by_type) for (auto &it : mod_data.num_submodules_by_type) {
if (mod_stat.count(it.first) > 0) { if (mod_stat.count(it.first) > 0) {
if (!quiet) if (!quiet)
log(" %*s%-*s %6u\n", 2*level, "", 26-2*level, log_id(it.first), it.second); mod_data.print_log_line(string(log_id(it.first)), mod_stat.at(it.first).local_num_cells,
mod_data = mod_data + hierarchy_worker(mod_stat, it.first, level+1, quiet) * it.second; mod_stat.at(it.first).local_area, mod_stat.at(it.first).num_cells, mod_stat.at(it.first).area,
mod_data.num_cells -= it.second; level, has_area, hierarchy_mode);
} else { hierarchy_worker(mod_stat, it.first, level + 1, quiet, has_area, hierarchy_mode) * it.second;
mod_data.num_cells_by_type[it.first] += it.second; }
} }
return mod_data; return mod_data;
} }
statdata_t hierarchy_builder(const RTLIL::Design *design, const RTLIL::Module *top_mod, std::map<RTLIL::IdString, statdata_t> &mod_stat,
bool width_mode, dict<IdString, cell_area_t> &cell_area, string techname)
{
if (top_mod == nullptr)
top_mod = design->top_module();
statdata_t mod_data(design, top_mod, width_mode, cell_area, techname);
for (auto cell : top_mod->selected_cells()) {
if (cell_area.count(cell->type) == 0) {
if (design->has(cell->type)) {
if (!(design->module(cell->type)->attributes.count(ID::blackbox))) {
// deal with modules
mod_data.add(
hierarchy_builder(design, design->module(cell->type), mod_stat, width_mode, cell_area, techname));
mod_data.num_submodules_by_type[cell->type]++;
mod_data.submodules_area_by_type[cell->type] += mod_stat.at(cell->type).area;
mod_data.submodule_area += mod_stat.at(cell->type).area;
mod_data.num_submodules++;
mod_data.unknown_cell_area.erase(cell->type);
mod_data.num_cells -=
(mod_data.num_cells_by_type.count(cell->type) != 0) ? mod_data.num_cells_by_type.at(cell->type) : 0;
mod_data.num_cells_by_type.erase(cell->type);
mod_data.local_num_cells -= (mod_data.local_num_cells_by_type.count(cell->type) != 0)
? mod_data.local_num_cells_by_type.at(cell->type)
: 0;
mod_data.local_num_cells_by_type.erase(cell->type);
mod_data.local_area_cells_by_type.erase(cell->type);
} else {
// deal with blackbox cells
if (design->module(cell->type)->attributes.count(ID::area) &&
design->module(cell->type)->attributes.at(ID::area).size() == 0) {
mod_data.num_submodules_by_type[cell->type]++;
mod_data.num_submodules++;
mod_data.submodules_area_by_type[cell->type] +=
double(design->module(cell->type)->attributes.at(ID::area).as_int());
mod_data.area += double(design->module(cell->type)->attributes.at(ID::area).as_int());
mod_data.unknown_cell_area.erase(cell->type);
mod_data.num_cells -=
(mod_data.num_cells_by_type.count(cell->type) != 0) ? mod_data.num_cells_by_type.at(cell->type) : 0;
mod_data.num_cells_by_type.erase(cell->type);
mod_data.local_num_cells -= (mod_data.local_num_cells_by_type.count(cell->type) != 0)
? mod_data.local_num_cells_by_type.at(cell->type)
: 0;
mod_data.local_num_cells_by_type.erase(cell->type);
mod_data.local_area_cells_by_type.erase(cell->type);
}
}
}
}
}
mod_stat[top_mod->name] = mod_data;
return mod_data;
}
void read_liberty_cellarea(dict<IdString, cell_area_t> &cell_area, string liberty_file) void read_liberty_cellarea(dict<IdString, cell_area_t> &cell_area, string liberty_file)
{ {
std::istream *f = uncompressed(liberty_file.c_str()); std::istream *f = uncompressed(liberty_file.c_str());
@ -354,21 +804,86 @@ void read_liberty_cellarea(dict<IdString, cell_area_t> &cell_area, string libert
LibertyParser libparser(*f, liberty_file); LibertyParser libparser(*f, liberty_file);
delete f; delete f;
for (auto cell : libparser.ast->children) for (auto cell : libparser.ast->children) {
{
if (cell->id != "cell" || cell->args.size() != 1) if (cell->id != "cell" || cell->args.size() != 1)
continue; continue;
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;
if (ar != nullptr && !ar->value.empty()) vector<double> single_parameter_area;
cell_area["\\" + cell->args[0]] = {/*area=*/atof(ar->value.c_str()), is_flip_flop}; 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) {
if (s.empty()) {
//catches trailing commas
continue;
}
try {
double value = std::stod(s);
single_parameter_area.push_back(value);
} catch (const std::exception &e) {
log_error("Failed to parse single parameter area value '%s': %s\n", s.c_str(), e.what());
}
}
if (single_parameter_area.size() == 0)
log_error("single parameter area has size 0: %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) {
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;
if (s.empty()) {
//catches trailing commas
continue;
}
try {
value = std::stod(s);
cast_sub_array.push_back(value);
} catch (const std::exception &e) {
log_error("Failed to parse double parameter area value for '%s': %s\n", s.c_str(), e.what());
}
}
double_parameter_area.push_back(cast_sub_array);
if (cast_sub_array.size() == 0)
log_error("double paramter array has size 0: %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()) {
string prefix = cell->args[0].substr(0, 1) == "$" ? "" : "\\";
cell_area[prefix + cell->args[0]] = {atof(ar->value.c_str()), is_flip_flop, single_parameter_area, double_parameter_area,
port_names};
}
} }
} }
struct StatPass : public Pass { struct StatPass : public Pass {
StatPass() : Pass("stat", "print some statistics") {} StatPass() : Pass("stat", "print some statistics") {}
bool formatted_help() override { bool formatted_help() override
{
auto *help = PrettyHelp::get_current(); auto *help = PrettyHelp::get_current();
help->set_group("passes/status"); help->set_group("passes/status");
return false; return false;
@ -381,6 +896,7 @@ struct StatPass : public Pass {
log("\n"); log("\n");
log("Print some statistics (number of objects) on the selected portion of the\n"); log("Print some statistics (number of objects) on the selected portion of the\n");
log("design.\n"); log("design.\n");
log("Extracts the area of cells from a liberty file, if provided.\n");
log("\n"); log("\n");
log(" -top <module>\n"); log(" -top <module>\n");
log(" print design hierarchy with this module as top. if the design is fully\n"); log(" print design hierarchy with this module as top. if the design is fully\n");
@ -402,18 +918,21 @@ struct StatPass : public Pass {
log(" output the statistics in a machine-readable JSON format.\n"); log(" output the statistics in a machine-readable JSON format.\n");
log(" this is output to the console; use \"tee\" to output to a file.\n"); log(" this is output to the console; use \"tee\" to output to a file.\n");
log("\n"); log("\n");
log(" -hierarchy\n");
log(" print hierarchical statistics, i.e. The area and number of cells include submodules.\n");
log(" this changes the format of the json output.\n");
log("\n");
} }
void execute(std::vector<std::string> args, RTLIL::Design *design) override void execute(std::vector<std::string> args, RTLIL::Design *design) override
{ {
bool width_mode = false, json_mode = false; bool width_mode = false, json_mode = false, hierarchy_mode = false;
RTLIL::Module *top_mod = nullptr; RTLIL::Module *top_mod = nullptr;
std::map<RTLIL::IdString, statdata_t> mod_stat; std::map<RTLIL::IdString, statdata_t> mod_stat;
dict<IdString, cell_area_t> cell_area; dict<IdString, cell_area_t> cell_area;
string techname; string techname;
size_t argidx; size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) for (argidx = 1; argidx < args.size(); argidx++) {
{
if (args[argidx] == "-width") { if (args[argidx] == "-width") {
width_mode = true; width_mode = true;
continue; continue;
@ -438,6 +957,10 @@ struct StatPass : public Pass {
json_mode = true; json_mode = true;
continue; continue;
} }
if (args[argidx] == "-hierarchy") {
hierarchy_mode = true;
continue;
}
break; break;
} }
extra_args(args, argidx, design); extra_args(args, argidx, design);
@ -457,24 +980,38 @@ struct StatPass : public Pass {
log(" \"modules\": {\n"); log(" \"modules\": {\n");
} }
if (top_mod != nullptr) {
hierarchy_builder(design, top_mod, mod_stat, width_mode, cell_area, techname);
} else {
for (auto mod : design->selected_modules()) {
if (mod_stat.count(mod->name) == 0) {
hierarchy_builder(design, mod, mod_stat, width_mode, cell_area, techname);
}
}
}
bool first_module = true; bool first_module = true;
for (auto mod : design->selected_modules()) // determine if anything has a area.
{ bool has_area = false;
for (auto &it : mod_stat) {
if (it.second.area > 0 || it.second.sequential_area > 0) {
has_area = true;
break;
}
}
for (auto mod : design->selected_modules()) {
if (!top_mod && design->full_selection()) if (!top_mod && design->full_selection())
if (mod->get_bool_attribute(ID::top)) if (mod->get_bool_attribute(ID::top))
top_mod = mod; top_mod = mod;
statdata_t data = mod_stat.at(mod->name);
statdata_t data(design, mod, width_mode, cell_area, techname);
mod_stat[mod->name] = data;
if (json_mode) { if (json_mode) {
data.log_data_json(mod->name.c_str(), first_module); data.log_data_json(mod->name.c_str(), first_module, hierarchy_mode);
first_module = false; first_module = false;
} else { } else {
log("\n"); log("\n");
log("=== %s%s ===\n", log_id(mod->name), mod->is_selected_whole() ? "" : " (partially selected)"); log("=== %s%s ===\n", log_id(mod->name), mod->is_selected_whole() ? "" : " (partially selected)");
log("\n"); log("\n");
data.log_data(mod->name, false); data.log_data(mod->name, false, has_area, hierarchy_mode);
} }
} }
@ -483,22 +1020,24 @@ struct StatPass : public Pass {
log(top_mod == nullptr ? " }\n" : " },\n"); log(top_mod == nullptr ? " }\n" : " },\n");
} }
if (top_mod != nullptr) if (top_mod != nullptr) {
{
if (!json_mode && GetSize(mod_stat) > 1) { if (!json_mode && GetSize(mod_stat) > 1) {
log("\n"); log("\n");
log("=== design hierarchy ===\n"); log("=== design hierarchy ===\n");
log("\n"); log("\n");
log(" %-28s %6d\n", log_id(top_mod->name), 1); mod_stat[top_mod->name].print_log_header(has_area, hierarchy_mode, true);
mod_stat[top_mod->name].print_log_line(log_id(top_mod->name), mod_stat[top_mod->name].local_num_cells,
mod_stat[top_mod->name].local_area, mod_stat[top_mod->name].num_cells,
mod_stat[top_mod->name].area, 0, has_area, hierarchy_mode, true);
} }
statdata_t data = hierarchy_worker(mod_stat, top_mod->name, 0, /*quiet=*/json_mode); statdata_t data = hierarchy_worker(mod_stat, top_mod->name, 0, /*quiet=*/json_mode, has_area, hierarchy_mode);
if (json_mode) if (json_mode)
data.log_data_json("design", true); data.log_data_json("design", true, hierarchy_mode, true);
else if (GetSize(mod_stat) > 1) { else if (GetSize(mod_stat) > 1) {
log("\n"); log("\n");
data.log_data(top_mod->name, true); data.log_data(top_mod->name, true, has_area, hierarchy_mode, true);
} }
design->scratchpad_set_int("stat.num_wires", data.num_wires); design->scratchpad_set_int("stat.num_wires", data.num_wires);

View file

@ -11,6 +11,8 @@ end
EOT EOT
logger -expect log "Chip area for module '\\top': 9.072000" 1 logger -expect log "Chip area for module '\\top': 9.072000" 1
logger -expect-no-warnings logger -expect-no-warnings
logger -expect log " 1 9.072 cells" 1
logger -expect log " 1 9.072 sg13g2_and2_1" 1
stat -liberty ../../tests/liberty/foundry_data/sg13g2_stdcell_typ_1p20V_25C.lib.filtered.gz stat -liberty ../../tests/liberty/foundry_data/sg13g2_stdcell_typ_1p20V_25C.lib.filtered.gz
@ -70,5 +72,8 @@ end
EOT EOT
logger -expect log "Chip area for top module '\\top': 112.492800" 1 logger -expect log "Chip area for top module '\\top': 112.492800" 1
logger -expect log "of which used for sequential elements: 94.348800" 1 logger -expect log "of which used for sequential elements: 94.348800" 1
logger -expect log "2 18.144 cells" 1
logger -expect log "4 112.493 cells" 1
logger -expect log "2 94.349 sg13g2_dfrbp_1" 1
logger -expect-no-warnings logger -expect-no-warnings
stat -liberty ../../tests/liberty/foundry_data/sg13g2_stdcell_typ_1p20V_25C.lib.filtered.gz -top \top stat -liberty ../../tests/liberty/foundry_data/sg13g2_stdcell_typ_1p20V_25C.lib.filtered.gz -top \top

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,62 @@
read_rtlil << EOT
module \top
wire input 1 \A
wire output 2 \Y
wire output 3 \N
cell \sg13g2_and2_1 \sub1
connect \A \A
connect \B 1'0
connect \Y \Y
end
cell \child \sequential
connect \A \A
connect \B 1'0
connect \R 1'0
connect \Y \Y
connect \N \N
end
cell \child \sequential1
connect \A \A
connect \B 1'0
connect \R 1'0
connect \Y \Y
connect \N \N
end
cell \sg13g2_and2_1 \sub2
connect \A \A
connect \B 1'0
connect \Y \Y
end
end
module \child
wire input 1 \A
wire input 2 \B
wire input 3 \R
wire output 4 \Y
wire output 5 \N
cell \sg13g2_dfrbp_1 \sequential_ff
connect \CLK \A
connect \D \B
connect \Q \Y
connect \Q_N \N
connect \RESET_B \R
end
end
EOT
logger -expect log "4 112.493 2 18.144 cells" 2
logger -expect log "2 18.144 2 18.144 sg13g2_and2_1" 2
logger -expect log "2 94.349 - - sg13g2_dfrbp_1" 2
logger -expect log "2 94.349 2 - submodules" 2
logger -expect-no-warnings
stat -liberty ../../tests/liberty/foundry_data/sg13g2_stdcell_typ_1p20V_25C.lib.filtered.gz -top \top -hierarchy

View file

@ -0,0 +1,92 @@
read_rtlil << EOT
module \top
wire input 1 \A
wire output 2 \Y
wire output 3 \N
cell $and \sub1
parameter \A_SIGNED 0
parameter \A_WIDTH 1
parameter \B_SIGNED 0
parameter \B_WIDTH 1
parameter \Y_WIDTH 1
connect \A \A
connect \B 1'0
connect \Y \Y
end
cell \child \sequential
connect \A \A
connect \B 1'0
connect \R 1'0
connect \Y \Y
connect \N \N
end
cell \child \sequential1
connect \A \A
connect \B 1'0
connect \R 1'0
connect \Y \Y
connect \N \N
end
cell $xor \sub2
parameter \A_SIGNED 0
parameter \A_WIDTH 1
parameter \B_SIGNED 0
parameter \B_WIDTH 1
parameter \Y_WIDTH 1
connect \A \A
connect \B 1'0
connect \Y \Y
end
end
module \child
wire input 1 \A
wire input 2 \B
wire input 3 \R
wire output 4 \Y
wire output 5 \N
wire \Y1
wire \Y2
cell \sg13g2_dfrbp_1 \sequential_ff
connect \CLK \A
connect \D \Y2
connect \Q \Y
connect \Q_N \N
connect \RESET_B \R
end
cell $xor \sub2
parameter \A_SIGNED 0
parameter \A_WIDTH 1
parameter \B_SIGNED 0
parameter \B_WIDTH 1
parameter \Y_WIDTH 1
connect \A \B
connect \B 1'0
connect \Y \Y1
end
cell $reduce_xor \sub3
parameter \A_SIGNED 0
parameter \A_WIDTH 10
parameter \Y_WIDTH 1
connect \A 10'0000000000
connect \Y \Y2
end
end
EOT
logger -expect log "Chip area for top module '\\top': 66.000000" 1
logger -expect log "3 30.5 3 30.5 cells" 1
logger -expect log "2 51 - - \$reduce_xor" 2
logger -expect log "8 66 2 5 cells" 2
logger -expect-no-warnings
stat -liberty ./stat_area_by_width.lib -top \top -hierarchy

View file

@ -0,0 +1,91 @@
read_rtlil << EOT
module \top
wire input 1 \A
wire output 2 \Y
wire output 3 \N
cell $and \sub1
parameter \A_SIGNED 0
parameter \A_WIDTH 1
parameter \B_SIGNED 0
parameter \B_WIDTH 1
parameter \Y_WIDTH 1
connect \A \A
connect \B 1'0
connect \Y \Y
end
cell \child \sequential
connect \A \A
connect \B 1'0
connect \R 1'0
connect \Y \Y
connect \N \N
end
cell \child \sequential1
connect \A \A
connect \B 1'0
connect \R 1'0
connect \Y \Y
connect \N \N
end
cell $xor \sub2
parameter \A_SIGNED 0
parameter \A_WIDTH 1
parameter \B_SIGNED 0
parameter \B_WIDTH 1
parameter \Y_WIDTH 1
connect \A \A
connect \B 1'0
connect \Y \Y
end
end
module \child
wire input 1 \A
wire input 2 \B
wire input 3 \R
wire output 4 \Y
wire output 5 \N
wire \Y1
wire \Y2
wire width 2 \A2
cell \sg13g2_dfrbp_1 \sequential_ff
connect \CLK \A
connect \D \Y2
connect \Q \Y
connect \Q_N \N
connect \RESET_B \R
end
cell $bmux \bmux1
parameter \WIDTH 2
parameter \S_WIDTH 2
connect \A 8'00000000
connect \S 2'00
connect \Y \A2
end
cell $reduce_xor \sub3
parameter \A_SIGNED 0
parameter \A_WIDTH 10
parameter \Y_WIDTH 1
connect \A 10'0000000000
connect \Y \Y2
end
end
EOT
logger -expect log "Chip area for top module '\\top': 80.000000" 1
logger -expect log "1 12 1 12 \$bmux" 1
logger -expect log "3 37.5 3 37.5 cells" 1
logger -expect log "8 80 2 5 cells" 2
logger -expect-no-warnings
stat -liberty ./stat_area_by_width.lib -top \top -hierarchy