mirror of
https://github.com/YosysHQ/yosys
synced 2025-08-18 17:22:17 +00:00
Improve STAT
This commit is contained in:
parent
8c71226d00
commit
a0dde68487
1 changed files with 472 additions and 145 deletions
|
@ -19,13 +19,14 @@
|
|||
|
||||
#include <iterator>
|
||||
|
||||
#include "kernel/yosys.h"
|
||||
#include "kernel/celltypes.h"
|
||||
#include "passes/techmap/libparse.h"
|
||||
#include "kernel/cost.h"
|
||||
#include "kernel/gzip.h"
|
||||
#include "kernel/yosys.h"
|
||||
#include "libs/json11/json11.hpp"
|
||||
#include "kernel/log_help.h"
|
||||
#include "passes/techmap/libparse.h"
|
||||
#include <charconv>
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
@ -35,137 +36,225 @@ struct cell_area_t {
|
|||
bool is_sequential;
|
||||
};
|
||||
|
||||
struct statdata_t
|
||||
{
|
||||
#define STAT_INT_MEMBERS X(num_wires) X(num_wire_bits) 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)
|
||||
struct statdata_t {
|
||||
#define STAT_INT_MEMBERS \
|
||||
X(num_wires) \
|
||||
X(num_wire_bits) \
|
||||
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
|
||||
#undef X
|
||||
#undef X
|
||||
#define X(_name) unsigned int local_##_name;
|
||||
STAT_INT_MEMBERS
|
||||
#undef X
|
||||
double 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;
|
||||
|
||||
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;
|
||||
|
||||
statdata_t operator+(const statdata_t &other) const
|
||||
{
|
||||
statdata_t sum = other;
|
||||
#define X(_name) sum._name += _name;
|
||||
#define X(_name) sum._name += _name;
|
||||
STAT_NUMERIC_MEMBERS
|
||||
#undef X
|
||||
#undef X
|
||||
for (auto &it : num_cells_by_type)
|
||||
sum.num_cells_by_type[it.first] += it.second;
|
||||
return sum;
|
||||
}
|
||||
|
||||
statdata_t operator*(unsigned int other) const
|
||||
{
|
||||
statdata_t sum = *this;
|
||||
#define X(_name) sum._name *= other;
|
||||
#define X(_name) sum._name *= other;
|
||||
STAT_NUMERIC_MEMBERS
|
||||
#undef X
|
||||
#undef X
|
||||
for (auto &it : sum.num_cells_by_type)
|
||||
it.second *= other;
|
||||
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()
|
||||
{
|
||||
#define X(_name) _name = 0;
|
||||
#define X(_name) _name = 0;
|
||||
STAT_NUMERIC_MEMBERS
|
||||
#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;
|
||||
|
||||
#define X(_name) _name = 0;
|
||||
#define X(_name) _name = 0;
|
||||
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) {
|
||||
num_ports++;
|
||||
local_num_ports++;
|
||||
num_port_bits += wire->width;
|
||||
local_num_port_bits += wire->width;
|
||||
}
|
||||
|
||||
if (wire->name.isPublic()) {
|
||||
num_pub_wires++;
|
||||
local_num_pub_wires++;
|
||||
num_pub_wire_bits += wire->width;
|
||||
local_num_pub_wire_bits += wire->width;
|
||||
}
|
||||
|
||||
num_wires++;
|
||||
local_num_wires++;
|
||||
num_wire_bits += wire->width;
|
||||
local_num_wire_bits += wire->width;
|
||||
}
|
||||
|
||||
for (auto &it : mod->memories) {
|
||||
if (!design->selected(mod, it.second))
|
||||
continue;
|
||||
num_memories++;
|
||||
local_num_memories++;
|
||||
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;
|
||||
|
||||
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), 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))) {
|
||||
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),
|
||||
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_b = cell->hasPort(ID::B) ? GetSize(cell->getPort(ID::B)) : 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}));
|
||||
}
|
||||
else if (cell_type.in(ID($mux), ID($pmux)))
|
||||
} else if (cell_type.in(ID($mux)))
|
||||
cell_type = stringf("%s_%d", cell_type.c_str(), GetSize(cell->getPort(ID::Y)));
|
||||
else if (cell_type == ID($bmux))
|
||||
cell_type = stringf("%s_%d_%d", cell_type.c_str(), GetSize(cell->getPort(ID::Y)), GetSize(cell->getPort(ID::S)));
|
||||
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)));
|
||||
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)));
|
||||
else if (cell_type.in(
|
||||
ID($sr), ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre),
|
||||
ID($adff), ID($adffe), ID($sdff), ID($sdffe), ID($sdffce),
|
||||
ID($aldff), ID($aldffe), ID($dlatch), ID($adlatch), ID($dlatchsr)))
|
||||
cell_type =
|
||||
stringf("%s_%d_%d", cell_type.c_str(), GetSize(cell->getPort(ID::A)), GetSize(cell->getPort(ID::S)));
|
||||
else if (cell_type.in(ID($sr), ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre), ID($adff), ID($adffe),
|
||||
ID($sdff), ID($sdffe), ID($sdffce), ID($aldff), ID($aldffe), ID($dlatch), ID($adlatch),
|
||||
ID($dlatchsr)))
|
||||
cell_type = stringf("%s_%d", cell_type.c_str(), GetSize(cell->getPort(ID::Q)));
|
||||
}
|
||||
|
||||
if (!cell_area.empty()) {
|
||||
|
||||
if (cell_area.count(cell_type)) {
|
||||
cell_area_t cell_data = cell_area.at(cell_type);
|
||||
if (cell_data.is_sequential) {
|
||||
sequential_area += cell_data.area;
|
||||
local_sequential_area += cell_data.area;
|
||||
}
|
||||
area += cell_data.area;
|
||||
}
|
||||
else {
|
||||
unknown_cell_area.insert(cell_type);
|
||||
}
|
||||
}
|
||||
num_cells++;
|
||||
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]++;
|
||||
|
||||
num_cells++;
|
||||
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) {
|
||||
if (!design->selected(mod, it.second))
|
||||
continue;
|
||||
num_processes++;
|
||||
local_num_processes++;
|
||||
}
|
||||
RTLIL::IdString cell_name = mod->name;
|
||||
auto s = cell_name.str();
|
||||
}
|
||||
|
||||
unsigned int estimate_xilinx_lc()
|
||||
|
@ -238,22 +327,119 @@ struct statdata_t
|
|||
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);
|
||||
log(" Number of wire bits: %6u\n", num_wire_bits);
|
||||
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);
|
||||
if (std::abs(value) < 1e-12)
|
||||
return " -";
|
||||
|
||||
char buf[16];
|
||||
|
||||
int len = std::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
|
||||
std::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)
|
||||
{
|
||||
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 (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 (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)
|
||||
{
|
||||
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 {
|
||||
log(" %8s-%8s-%s\n", "+", "--------", "Local Count including submodules.");
|
||||
log(" %8s %8s-%s\n", "|", "+", "Local Area including 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 {
|
||||
log(" %8s-%8s-%s\n", "+", "--------", "Local Count including submodules.");
|
||||
log(" %8s \n", "|");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void log_data(RTLIL::IdString mod_name, bool top_mod, bool print_area = true, bool print_hierarchical = true)
|
||||
{
|
||||
|
||||
print_log_header(print_area, print_hierarchical);
|
||||
|
||||
print_log_line("wires", local_num_wires, 0, num_wires, 0, 0, print_area, print_hierarchical);
|
||||
print_log_line("wire bits", local_num_wire_bits, 0, num_wire_bits, 0, 0, print_area, print_hierarchical);
|
||||
print_log_line("public wires", local_num_pub_wires, 0, num_pub_wires, 0, 0, print_area, print_hierarchical);
|
||||
print_log_line("public wire bits", local_num_pub_wire_bits, 0, num_pub_wire_bits, 0, 0, print_area, print_hierarchical);
|
||||
print_log_line("ports", local_num_ports, 0, num_ports, 0, 0, print_area, print_hierarchical);
|
||||
print_log_line("port bits", local_num_port_bits, 0, num_port_bits, 0, 0, print_area, print_hierarchical);
|
||||
print_log_line("memories", local_num_memories, 0, num_memories, 0, 0, print_area, print_hierarchical);
|
||||
print_log_line("memory bits", local_num_memory_bits, 0, num_memory_bits, 0, 0, print_area, print_hierarchical);
|
||||
print_log_line("processes", local_num_processes, 0, num_processes, 0, 0, print_area, print_hierarchical);
|
||||
print_log_line("cells", local_num_cells, local_area, num_cells, area, 0, print_area, print_hierarchical);
|
||||
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);
|
||||
}
|
||||
if (num_submodules > 0) {
|
||||
print_log_line("submodules", num_submodules, 0, num_submodules, submodule_area, 0, print_area, print_hierarchical);
|
||||
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);
|
||||
}
|
||||
if (!unknown_cell_area.empty()) {
|
||||
log("\n");
|
||||
for (auto cell_type : unknown_cell_area)
|
||||
|
@ -263,17 +449,15 @@ struct statdata_t
|
|||
if (area != 0) {
|
||||
log("\n");
|
||||
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);
|
||||
}
|
||||
|
||||
if (tech == "xilinx")
|
||||
{
|
||||
if (tech == "xilinx") {
|
||||
log("\n");
|
||||
log(" Estimated number of LCs: %10u\n", estimate_xilinx_lc());
|
||||
}
|
||||
|
||||
if (tech == "cmos")
|
||||
{
|
||||
if (tech == "cmos") {
|
||||
bool tran_cnt_exact = true;
|
||||
unsigned int tran_cnt = cmos_transistor_count(&tran_cnt_exact);
|
||||
|
||||
|
@ -282,87 +466,203 @@ 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)
|
||||
{
|
||||
if (!first_module)
|
||||
log(",\n");
|
||||
log(" %s: {\n", json11::Json(mod_name).dump().c_str());
|
||||
log(" \"num_wires\": %u,\n", num_wires);
|
||||
log(" \"num_wire_bits\": %u,\n", num_wire_bits);
|
||||
log(" \"num_pub_wires\": %u,\n", num_pub_wires);
|
||||
log(" \"num_pub_wire_bits\": %u,\n", num_pub_wire_bits);
|
||||
log(" \"num_ports\": %u,\n", num_ports);
|
||||
log(" \"num_port_bits\": %u,\n", num_port_bits);
|
||||
log(" \"num_memories\": %u,\n", num_memories);
|
||||
log(" \"num_memory_bits\": %u,\n", num_memory_bits);
|
||||
log(" \"num_processes\": %u,\n", num_processes);
|
||||
log(" \"num_cells\": %u,\n", num_cells);
|
||||
if (area != 0) {
|
||||
log(" \"area\": %f,\n", area);
|
||||
}
|
||||
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: %u", json11::Json(log_id(it.first)).dump().c_str(), it.second);
|
||||
first_line = false;
|
||||
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());
|
||||
}
|
||||
log("\n");
|
||||
log(" }");
|
||||
if (tech == "xilinx")
|
||||
{
|
||||
log(",\n");
|
||||
log(" \"estimated_num_lc\": %u", 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 {
|
||||
|
||||
log(" %s: {\n", json11::Json(mod_name).dump().c_str());
|
||||
log(" \"num_wires\": %u,\n", num_wires);
|
||||
log(" \"num_wire_bits\": %u,\n", num_wire_bits);
|
||||
log(" \"num_pub_wires\": %u,\n", num_pub_wires);
|
||||
log(" \"num_pub_wire_bits\": %u,\n", num_pub_wire_bits);
|
||||
log(" \"num_ports\": %u,\n", num_ports);
|
||||
log(" \"num_port_bits\": %u,\n", num_port_bits);
|
||||
log(" \"num_memories\": %u,\n", num_memories);
|
||||
log(" \"num_memory_bits\": %u,\n", num_memory_bits);
|
||||
log(" \"num_processes\": %u,\n", 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(" \"estimated_num_lc\": %u", estimate_xilinx_lc());
|
||||
}
|
||||
if (tech == "cmos") {
|
||||
bool tran_cnt_exact = true;
|
||||
unsigned int tran_cnt = cmos_transistor_count(&tran_cnt_exact);
|
||||
log(",\n");
|
||||
log(" \"estimated_num_transistors\": \"%u%s\"", tran_cnt, tran_cnt_exact ? "" : "+");
|
||||
}
|
||||
log("\n");
|
||||
log(" }");
|
||||
}
|
||||
if (tech == "cmos")
|
||||
{
|
||||
bool tran_cnt_exact = true;
|
||||
unsigned int tran_cnt = cmos_transistor_count(&tran_cnt_exact);
|
||||
log(",\n");
|
||||
log(" \"estimated_num_transistors\": \"%u%s\"", tran_cnt, tran_cnt_exact ? "" : "+");
|
||||
}
|
||||
log("\n");
|
||||
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);
|
||||
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 (!quiet)
|
||||
log(" %*s%-*s %6u\n", 2*level, "", 26-2*level, log_id(it.first), it.second);
|
||||
mod_data = mod_data + hierarchy_worker(mod_stat, it.first, level+1, quiet) * it.second;
|
||||
mod_data.num_cells -= it.second;
|
||||
} else {
|
||||
mod_data.num_cells_by_type[it.first] += it.second;
|
||||
mod_data.print_log_line(string(log_id(it.first)), mod_stat.at(it.first).local_num_cells,
|
||||
mod_stat.at(it.first).local_area, mod_stat.at(it.first).num_cells, mod_stat.at(it.first).area,
|
||||
level, has_area, hierarchy_mode);
|
||||
hierarchy_worker(mod_stat, it.first, level + 1, quiet, has_area, hierarchy_mode) * it.second;
|
||||
}
|
||||
}
|
||||
|
||||
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.erase(cell->type);
|
||||
mod_data.area_cells_by_type.erase(cell->type);
|
||||
mod_data.local_num_cells -= 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);
|
||||
} else {
|
||||
mod_data.unknown_cell_area.insert(cell->type);
|
||||
mod_data.num_submodules++;
|
||||
mod_data.num_submodules_by_type[cell->type]++;
|
||||
mod_data.submodules_area_by_type[cell->type] = 0;
|
||||
mod_data.seq_area_cells_by_type[cell->type] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mod_stat[top_mod->name] = mod_data;
|
||||
return mod_data;
|
||||
}
|
||||
|
||||
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());
|
||||
yosys_input_files.insert(liberty_file);
|
||||
LibertyParser libparser(*f, liberty_file);
|
||||
delete f;
|
||||
|
||||
for (auto cell : libparser.ast->children)
|
||||
{
|
||||
for (auto cell : libparser.ast->children) {
|
||||
if (cell->id != "cell" || cell->args.size() != 1)
|
||||
continue;
|
||||
|
||||
const LibertyAst *ar = cell->find("area");
|
||||
bool is_flip_flop = cell->find("ff") != nullptr;
|
||||
if (ar != nullptr && !ar->value.empty())
|
||||
cell_area["\\" + cell->args[0]] = {/*area=*/atof(ar->value.c_str()), is_flip_flop};
|
||||
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};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -381,6 +681,7 @@ struct StatPass : public Pass {
|
|||
log("\n");
|
||||
log("Print some statistics (number of objects) on the selected portion of the\n");
|
||||
log("design.\n");
|
||||
log("Extracts the area of cells from a liberty file, if provided.\n");
|
||||
log("\n");
|
||||
log(" -top <module>\n");
|
||||
log(" print design hierarchy with this module as top. if the design is fully\n");
|
||||
|
@ -402,35 +703,38 @@ struct StatPass : public Pass {
|
|||
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("\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
|
||||
{
|
||||
bool width_mode = false, json_mode = false;
|
||||
bool width_mode = false, json_mode = false, hierarchy_mode = false;
|
||||
RTLIL::Module *top_mod = nullptr;
|
||||
std::map<RTLIL::IdString, statdata_t> mod_stat;
|
||||
dict<IdString, cell_area_t> cell_area;
|
||||
string techname;
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
{
|
||||
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||
if (args[argidx] == "-width") {
|
||||
width_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-liberty" && argidx+1 < args.size()) {
|
||||
if (args[argidx] == "-liberty" && argidx + 1 < args.size()) {
|
||||
string liberty_file = args[++argidx];
|
||||
rewrite_filename(liberty_file);
|
||||
read_liberty_cellarea(cell_area, liberty_file);
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-tech" && argidx+1 < args.size()) {
|
||||
if (args[argidx] == "-tech" && argidx + 1 < args.size()) {
|
||||
techname = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-top" && argidx+1 < args.size()) {
|
||||
if (design->module(RTLIL::escape_id(args[argidx+1])) == nullptr)
|
||||
log_cmd_error("Can't find module %s.\n", args[argidx+1].c_str());
|
||||
if (args[argidx] == "-top" && argidx + 1 < args.size()) {
|
||||
if (design->module(RTLIL::escape_id(args[argidx + 1])) == nullptr)
|
||||
log_cmd_error("Can't find module %s.\n", args[argidx + 1].c_str());
|
||||
top_mod = design->module(RTLIL::escape_id(args[++argidx]));
|
||||
continue;
|
||||
}
|
||||
|
@ -438,11 +742,15 @@ struct StatPass : public Pass {
|
|||
json_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-hierarchy") {
|
||||
hierarchy_mode = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
||||
if(!json_mode)
|
||||
if (!json_mode)
|
||||
log_header(design, "Printing statistics.\n");
|
||||
|
||||
if (techname != "" && techname != "xilinx" && techname != "cmos" && !json_mode)
|
||||
|
@ -457,24 +765,40 @@ struct StatPass : public Pass {
|
|||
log(" \"modules\": {\n");
|
||||
}
|
||||
|
||||
printf("building cell area\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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("built hierarchy\n");
|
||||
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 (mod->get_bool_attribute(ID::top))
|
||||
top_mod = mod;
|
||||
|
||||
statdata_t data(design, mod, width_mode, cell_area, techname);
|
||||
mod_stat[mod->name] = data;
|
||||
|
||||
statdata_t data = mod_stat.at(mod->name);
|
||||
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;
|
||||
} else {
|
||||
log("\n");
|
||||
log("=== %s%s ===\n", log_id(mod->name), mod->is_selected_whole() ? "" : " (partially selected)");
|
||||
log("\n");
|
||||
data.log_data(mod->name, false);
|
||||
data.log_data(mod->name, false, has_area, hierarchy_mode);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -483,22 +807,24 @@ struct StatPass : public Pass {
|
|||
log(top_mod == nullptr ? " }\n" : " },\n");
|
||||
}
|
||||
|
||||
if (top_mod != nullptr)
|
||||
{
|
||||
if (top_mod != nullptr) {
|
||||
if (!json_mode && GetSize(mod_stat) > 1) {
|
||||
log("\n");
|
||||
log("=== design hierarchy ===\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);
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
data.log_data_json("design", true);
|
||||
data.log_data_json("design", true, true);
|
||||
else if (GetSize(mod_stat) > 1) {
|
||||
log("\n");
|
||||
data.log_data(top_mod->name, true);
|
||||
data.log_data(top_mod->name, true, has_area, hierarchy_mode);
|
||||
}
|
||||
|
||||
design->scratchpad_set_int("stat.num_wires", data.num_wires);
|
||||
|
@ -520,6 +846,7 @@ struct StatPass : public Pass {
|
|||
}
|
||||
|
||||
log("\n");
|
||||
printf("processed statistics\n");
|
||||
}
|
||||
} StatPass;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue