From a0dde68487da600c569c0b61b684dc845fd5c554 Mon Sep 17 00:00:00 2001 From: clemens Date: Tue, 15 Apr 2025 09:39:49 +0200 Subject: [PATCH 01/14] Improve STAT --- passes/cmds/stat.cc | 617 +++++++++++++++++++++++++++++++++----------- 1 file changed, 472 insertions(+), 145 deletions(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index af7023bdd..0d19849c3 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -19,13 +19,14 @@ #include -#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 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 num_submodules_by_type; + std::map submodules_area_by_type; + + std::map local_num_cells_by_type; + std::map local_area_cells_by_type; + std::map local_seq_area_cells_by_type; string tech; std::map num_cells_by_type; + std::map area_cells_by_type; + std::map seq_area_cells_by_type; std::set 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 &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 &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({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(count_local)); + std::string count_global_str = f_val(static_cast(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 &mod_stat, RTLIL::IdString mod, int level, bool quiet = false) +statdata_t hierarchy_worker(std::map &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 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 &mod_stat, + bool width_mode, dict &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 &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 \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 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 mod_stat; dict 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; From 2a97987cf208d353ff76f6c3964ea2ee689c0955 Mon Sep 17 00:00:00 2001 From: clemens Date: Tue, 12 Aug 2025 09:16:05 +0200 Subject: [PATCH 02/14] formatting and remove debug statements --- passes/cmds/stat.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 0d19849c3..24b21d674 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -22,9 +22,9 @@ #include "kernel/celltypes.h" #include "kernel/cost.h" #include "kernel/gzip.h" +#include "kernel/log_help.h" #include "kernel/yosys.h" #include "libs/json11/json11.hpp" -#include "kernel/log_help.h" #include "passes/techmap/libparse.h" #include @@ -667,8 +667,9 @@ void read_liberty_cellarea(dict &cell_area, string libert } struct StatPass : public Pass { - StatPass() : Pass("stat", "print some statistics") { } - bool formatted_help() override { + StatPass() : Pass("stat", "print some statistics") {} + bool formatted_help() override + { auto *help = PrettyHelp::get_current(); help->set_group("passes/status"); return false; @@ -765,7 +766,6 @@ 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 { @@ -776,7 +776,6 @@ struct StatPass : public Pass { } } - printf("built hierarchy\n"); bool first_module = true; // determine if anything has a area. bool has_area = false; From 1eb8844e38ce0dd88f797e26661cfd31007a1597 Mon Sep 17 00:00:00 2001 From: clemens Date: Wed, 13 Aug 2025 08:36:26 +0200 Subject: [PATCH 03/14] fix labeling in report fix design hierarchy containing wrong values. remove left over debug print. --- passes/cmds/stat.cc | 62 +++++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 24b21d674..8ed4e5b93 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -338,7 +338,7 @@ struct statdata_t { char buf[16]; - int len = std::snprintf(buf, sizeof(buf), "%.3f", value); + int len = snprintf(buf, sizeof(buf), "%.3f", value); while (len > 0 && buf[len - 1] == '0') --len; @@ -351,13 +351,13 @@ struct statdata_t { } // use scientific notation, this should always fit in 8 characters - std::snprintf(buf, sizeof(buf), "%8.3G", value); + 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) + int spacer = 0, bool print_area = true, bool print_hierarchical = true, bool print_global_only = false) { const std::string indent(2 * spacer, ' '); @@ -370,6 +370,8 @@ struct statdata_t { 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()); @@ -377,6 +379,8 @@ struct statdata_t { } 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()); @@ -384,7 +388,7 @@ struct statdata_t { } } - void print_log_header(bool print_area = true, bool print_hierarchical = true) + void print_log_header(bool print_area = true, bool print_hierarchical = true, bool print_global_only = false) { if (print_area) { if (print_hierarchical) { @@ -393,9 +397,13 @@ struct statdata_t { 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 including submodules."); - log(" %8s %8s-%s\n", "|", "+", "Local Area including submodules."); + log(" %8s-%8s-%s\n", "+", "--------", "Local Count, excluding submodules."); + log(" %8s %8s-%s\n", "|", "+", "Local Area, excluding submodules."); log(" %8s %8s \n", "|", "|"); } } else { @@ -403,42 +411,47 @@ struct statdata_t { 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 %8s \n", "|", "|"); } else { - log(" %8s-%8s-%s\n", "+", "--------", "Local Count including submodules."); + 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) + 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_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_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); + 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); + 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_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_area, print_hierarchical, print_global_only); } if (!unknown_cell_area.empty()) { log("\n"); @@ -811,7 +824,7 @@ struct StatPass : public Pass { log("\n"); log("=== design hierarchy ===\n"); log("\n"); - mod_stat[top_mod->name].print_log_header(has_area, hierarchy_mode); + 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); @@ -823,7 +836,7 @@ struct StatPass : public Pass { data.log_data_json("design", true, true); else if (GetSize(mod_stat) > 1) { log("\n"); - data.log_data(top_mod->name, true, has_area, hierarchy_mode); + data.log_data(top_mod->name, true, has_area, hierarchy_mode, true); } design->scratchpad_set_int("stat.num_wires", data.num_wires); @@ -845,7 +858,6 @@ struct StatPass : public Pass { } log("\n"); - printf("processed statistics\n"); } } StatPass; From 383d11c2ac9254836f8107e4a2fa6901b7bccd09 Mon Sep 17 00:00:00 2001 From: clemens Date: Wed, 13 Aug 2025 10:09:02 +0200 Subject: [PATCH 04/14] fix design overview in json. Fix some unknown cells apearing twice. --- passes/cmds/stat.cc | 118 ++++++++++++++++++++++++++++---------------- 1 file changed, 76 insertions(+), 42 deletions(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 8ed4e5b93..ea9dfcd3c 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -486,7 +486,7 @@ struct statdata_t { count_local, area_local); } - void log_data_json(const char *mod_name, bool first_module, bool hierarchical = false) + void log_data_json(const char *mod_name, bool first_module, bool hierarchical = false, bool global_only = false) { if (!first_module) log(",\n"); @@ -543,41 +543,77 @@ struct statdata_t { 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); + if (global_only) { + 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); + 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 : 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(" }"); + } 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(" }"); } - 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()); @@ -644,12 +680,10 @@ statdata_t hierarchy_builder(const RTLIL::Design *design, const RTLIL::Module *t 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_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); } } } @@ -833,7 +867,7 @@ struct StatPass : public Pass { 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, true); + data.log_data_json("design", true, hierarchy_mode, true); else if (GetSize(mod_stat) > 1) { log("\n"); data.log_data(top_mod->name, true, has_area, hierarchy_mode, true); From 71307b4a519dbbe81fff5988987f69eec290e737 Mon Sep 17 00:00:00 2001 From: clemens Date: Wed, 13 Aug 2025 14:46:01 +0200 Subject: [PATCH 05/14] add Testcases Fix existing testcases Fix edgecase where modules where counted as cells. --- passes/cmds/stat.cc | 16 +++++---- tests/various/stat.ys | 7 +++- tests/various/stat_hierarchy.ys | 62 +++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 8 deletions(-) create mode 100644 tests/various/stat_hierarchy.ys diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index ea9dfcd3c..5cb223ba8 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -666,9 +666,10 @@ statdata_t hierarchy_builder(const RTLIL::Design *design, const RTLIL::Module *t 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.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 @@ -680,9 +681,10 @@ statdata_t hierarchy_builder(const RTLIL::Design *design, const RTLIL::Module *t 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.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.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); } } @@ -861,7 +863,7 @@ struct StatPass : public Pass { 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); + 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, has_area, hierarchy_mode); diff --git a/tests/various/stat.ys b/tests/various/stat.ys index cf084a986..50e1a35d8 100644 --- a/tests/various/stat.ys +++ b/tests/various/stat.ys @@ -11,6 +11,8 @@ end EOT logger -expect log "Chip area for module '\\top': 9.072000" 1 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 @@ -69,6 +71,9 @@ module \child end EOT 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" 2 +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 stat -liberty ../../tests/liberty/foundry_data/sg13g2_stdcell_typ_1p20V_25C.lib.filtered.gz -top \top diff --git a/tests/various/stat_hierarchy.ys b/tests/various/stat_hierarchy.ys new file mode 100644 index 000000000..f41165629 --- /dev/null +++ b/tests/various/stat_hierarchy.ys @@ -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 + + From f5b219f59eb02fb0d8a4a9fad731cf0cc96368ab Mon Sep 17 00:00:00 2001 From: suisseWalter <42143099+suisseWalter@users.noreply.github.com> Date: Sat, 16 Aug 2025 08:36:06 +0200 Subject: [PATCH 06/14] Update passes/cmds/stat.cc Co-authored-by: KrystalDelusion <93062060+KrystalDelusion@users.noreply.github.com> --- passes/cmds/stat.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 5cb223ba8..6d8d3105f 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -413,7 +413,7 @@ struct statdata_t { log(" %8s %8s \n", "|", "|"); } else if (print_global_only) { log(" %8s-%8s-%s\n", "+", "--------", "Count including submodules."); - log(" %8s %8s \n", "|", "|"); + log(" %8s \n", "|"); } else { log(" %8s-%8s-%s\n", "+", "--------", "Local Count, excluding submodules."); log(" %8s \n", "|"); From a6e0ab5ea5b6938f3ff67e5b36ecdf8797ce852c Mon Sep 17 00:00:00 2001 From: clemens Date: Sat, 16 Aug 2025 09:09:57 +0200 Subject: [PATCH 07/14] Update (sequential) area to be only local without -hierarchy --- passes/cmds/stat.cc | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 6d8d3105f..c41b8831f 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -461,8 +461,20 @@ 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); + if (print_hierarchical || print_global_only) { + 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); + } 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") { @@ -666,9 +678,12 @@ statdata_t hierarchy_builder(const RTLIL::Design *design, const RTLIL::Module *t 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 -= + (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 -= (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 { @@ -681,9 +696,12 @@ statdata_t hierarchy_builder(const RTLIL::Design *design, const RTLIL::Module *t 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 -= + (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 -= (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); } From d8fb4da437b9fc1b4e818f8bfac10ded3a1cee15 Mon Sep 17 00:00:00 2001 From: clemens Date: Sat, 16 Aug 2025 09:32:08 +0200 Subject: [PATCH 08/14] updated testcase --- tests/various/stat.ys | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/various/stat.ys b/tests/various/stat.ys index 50e1a35d8..1644f63e3 100644 --- a/tests/various/stat.ys +++ b/tests/various/stat.ys @@ -71,7 +71,7 @@ module \child end EOT logger -expect log "Chip area for top module '\\top': 112.492800" 1 -logger -expect log "of which used for sequential elements: 94.348800" 2 +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 From 5fc0e77c3d8d954594ef933d6270b5864f410661 Mon Sep 17 00:00:00 2001 From: clemens Date: Tue, 12 Aug 2025 08:56:05 +0200 Subject: [PATCH 09/14] add functionality to be able to use parameterised cells. cells can have their area as a function of the input port width. --- passes/cmds/stat.cc | 143 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 142 insertions(+), 1 deletion(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index c41b8831f..827ee0f05 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -34,6 +34,9 @@ PRIVATE_NAMESPACE_BEGIN struct cell_area_t { double area; bool is_sequential; + vector single_parameter_area; + vector> double_parameter_area; + vector parameter_names; }; struct statdata_t { @@ -206,6 +209,89 @@ struct statdata_t { } 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({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 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)) { cell_area_t cell_data = cell_area.at(cell_type); @@ -726,9 +812,64 @@ void read_liberty_cellarea(dict &cell_area, string libert const LibertyAst *ar = cell->find("area"); bool is_flip_flop = cell->find("ff") != nullptr; + vector single_parameter_area; + vector> double_parameter_area; + vector 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 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 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()) { 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}; } } } From 50fe9dd7f26615c8e90d01bb443644096e9f6185 Mon Sep 17 00:00:00 2001 From: clemens Date: Tue, 12 Aug 2025 09:37:55 +0200 Subject: [PATCH 10/14] clean parsing code --- passes/cmds/stat.cc | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 827ee0f05..a036b1930 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -818,12 +818,12 @@ void read_liberty_cellarea(dict &cell_area, string libert 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); + 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) printf("error: %s\n", sar->args[single_parameter_area.size() - 1].c_str()); @@ -849,10 +849,12 @@ void read_liberty_cellarea(dict &cell_area, string libert vector 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); + 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 '%s': %s\n", s.c_str(), e.what()); + } } double_parameter_area.push_back(cast_sub_array); if (cast_sub_array.size() == 0) From 8b1f77ebd297ab312af81be0661f44f09b0edb43 Mon Sep 17 00:00:00 2001 From: clemens Date: Wed, 13 Aug 2025 15:16:15 +0200 Subject: [PATCH 11/14] cleanup. printf to errors or warnings --- passes/cmds/stat.cc | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index a036b1930..4d01b8535 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -228,19 +228,16 @@ struct statdata_t { 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()); + 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; } - // printf("single_paramter_extraction %s %d %f\n", cell_type.c_str(), max_width, - // cell_area.at(cell_type).area); } vector 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") { @@ -277,8 +274,9 @@ struct statdata_t { 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()); + 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(), + (int)width_a, width_b, 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; } @@ -287,8 +285,8 @@ struct statdata_t { 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); + 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()); } } } @@ -826,15 +824,13 @@ void read_liberty_cellarea(dict &cell_area, string libert } } if (single_parameter_area.size() == 0) - printf("error: %s\n", sar->args[single_parameter_area.size() - 1].c_str()); + 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) { - // printf("value: %s\n",sar->value.c_str()); - // printf("args1: %s\n",dar->args[0].c_str()); vector sub_array; std::string::size_type start = 0; @@ -858,7 +854,7 @@ void read_liberty_cellarea(dict &cell_area, string libert } double_parameter_area.push_back(cast_sub_array); if (cast_sub_array.size() == 0) - printf("error: %s\n", s.c_str()); + log_error("double paramter array has size 0: %s\n", s.c_str()); } } const LibertyAst *par = cell->find("port_names"); From 73d1177665815012981f439138f97937c4a90373 Mon Sep 17 00:00:00 2001 From: clemens Date: Thu, 14 Aug 2025 09:57:44 +0200 Subject: [PATCH 12/14] testcases one testcase for single parameter cells. one testcase for double parameter cells. --- tests/various/stat_area_by_width.lib | 42 +++++++++++++ tests/various/stat_high_level.ys | 92 ++++++++++++++++++++++++++++ tests/various/stat_high_level2.ys | 91 +++++++++++++++++++++++++++ 3 files changed, 225 insertions(+) create mode 100644 tests/various/stat_area_by_width.lib create mode 100644 tests/various/stat_high_level.ys create mode 100644 tests/various/stat_high_level2.ys diff --git a/tests/various/stat_area_by_width.lib b/tests/various/stat_area_by_width.lib new file mode 100644 index 000000000..73e266472 --- /dev/null +++ b/tests/various/stat_area_by_width.lib @@ -0,0 +1,42 @@ + +/************************************************************************ + + Copyright 2025 Clemens Walter, + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +************************************************************************/ +//Mock library for Yosys pre techmap +library (mock) { +cell ( "$reduce_xor" ) { + area : 3.0 ; + delay : 2.5 ; + single_area_parameterised ( 3.0, 5.5, 8.0, 10.5, 13.0, 15.5, 18.0, 20.5, 23.0, 25.5, 28.0, 30.5, 33.0, 35.5, 38.0, 40.5, 43.0, 45.5, 48.0, 50.5, 53.0, 55.5, 58.0, 60.5, 63.0, 65.5, 68.0, 70.5, 73.0, 75.5, 78.0, 80.5, 83.0, 85.5, 88.0, 90.5, 93.0, 95.5, 98.0, 100.5, 103.0, 105.5, 108.0, 110.5, 113.0, 115.5, 118.0, 120.5, ) ; + +} + +cell ( "$xor" ) { + area : 5.0 ; + delay : 2.0 ; + single_area_parameterised ( 5.0, 7.5, 10.0, 12.5, 15.0, 17.5, 20.0, 22.5, 25.0, 27.5, 30.0, 32.5, 35.0, 37.5, 40.0, 42.5, 45.0, 47.5, 50.0, 52.5, 55.0, ) ; + +} + +cell ( "$bmux" ) { + area : 3.0 ; + delay : 2.0 ; + port_names ( "Y", "S" ) ; + double_area_parameterised ( " 3.0, 6.0, 9.0, 12.0, 15.0, 18.0, 21.0, 24.0, 27.0, 30.0, 33.0, 36.0, 39.0, 42.0, 45.0, 48.0, 51.0, 54.0, 57.0, 60.0, 63.0, 66.0, 69.0, 72.0, 75.0, 78.0, 81.0, 84.0, 87.0, 90.0, 93.0, 96.0, 99.0, 102.0, 105.0, 108.0, 111.0, 114.0, 117.0, 120.0, 123.0, 126.0, 129.0, 132.0, 135.0, 138.0, 141.0, 144.0, 147.0, 150.0, 153.0, 156.0, 159.0, 162.0, 165.0, 168.0, 171.0, 174.0, 177.0, 180.0, 183.0, 186.0, 189.0, 192.0, 195.0, 198.0, 201.0, 204.0, 207.0, 210.0, 213.0, 216.0, 219.0, 222.0, 225.0, 228.0, 231.0, 234.0, 237.0, 240.0, 243.0, 246.0, 249.0, 252.0, 255.0, 258.0, 261.0, 264.0, 267.0, 270.0, 273.0, 276.0, 279.0, 282.0, 285.0, 288.0, 291.0, 294.0, 297.0, 300.0, 303.0, 306.0, 309.0, 312.0, 315.0, 318.0, 321.0, 324.0, 327.0, 330.0, 333.0, 336.0, 339.0, 342.0, 345.0, 348.0, 351.0, 354.0, 357.0, 360.0, 363.0, 366.0, 369.0, 372.0, 375.0, 378.0, 381.0, 384.0,", " 6.0, 12.0, 18.0, 24.0, 30.0, 36.0, 42.0, 48.0, 54.0, 60.0, 66.0, 72.0, 78.0, 84.0, 90.0, 96.0, 102.0, 108.0, 114.0, 120.0, 126.0, 132.0, 138.0, 144.0, 150.0, 156.0, 162.0, 168.0, 174.0, 180.0, 186.0, 192.0, 198.0, 204.0, 210.0, 216.0, 222.0, 228.0, 234.0, 240.0, 246.0, 252.0, 258.0, 264.0, 270.0, 276.0, 282.0, 288.0, 294.0, 300.0, 306.0, 312.0, 318.0, 324.0, 330.0, 336.0, 342.0, 348.0, 354.0, 360.0, 366.0, 372.0, 378.0, 384.0, 390.0, 396.0, 402.0, 408.0, 414.0, 420.0, 426.0, 432.0, 438.0, 444.0, 450.0, 456.0, 462.0, 468.0, 474.0, 480.0, 486.0, 492.0, 498.0, 504.0, 510.0, 516.0, 522.0, 528.0, 534.0, 540.0, 546.0, 552.0, 558.0, 564.0, 570.0, 576.0, 582.0, 588.0, 594.0, 600.0, 606.0, 612.0, 618.0, 624.0, 630.0, 636.0, 642.0, 648.0, 654.0, 660.0, 666.0, 672.0, 678.0, 684.0, 690.0, 696.0, 702.0, 708.0, 714.0, 720.0, 726.0, 732.0, 738.0, 744.0, 750.0, 756.0, 762.0, 768.0,", " 9.0, 18.0, 27.0, 36.0, 45.0, 54.0, 63.0, 72.0, 81.0, 90.0, 99.0, 108.0, 117.0, 126.0, 135.0, 144.0, 153.0, 162.0, 171.0, 180.0, 189.0, 198.0, 207.0, 216.0, 225.0, 234.0, 243.0, 252.0, 261.0, 270.0, 279.0, 288.0, 297.0, 306.0, 315.0, 324.0, 333.0, 342.0, 351.0, 360.0, 369.0, 378.0, 387.0, 396.0, 405.0, 414.0, 423.0, 432.0, 441.0, 450.0, 459.0, 468.0, 477.0, 486.0, 495.0, 504.0, 513.0, 522.0, 531.0, 540.0, 549.0, 558.0, 567.0, 576.0, 585.0, 594.0, 603.0, 612.0, 621.0, 630.0, 639.0, 648.0, 657.0, 666.0, 675.0, 684.0, 693.0, 702.0, 711.0, 720.0, 729.0, 738.0, 747.0, 756.0, 765.0, 774.0, 783.0, 792.0, 801.0, 810.0, 819.0, 828.0, 837.0, 846.0, 855.0, 864.0, 873.0, 882.0, 891.0, 900.0, 909.0, 918.0, 927.0, 936.0, 945.0, 954.0, 963.0, 972.0, 981.0, 990.0, 999.0, 1008.0, 1017.0, 1026.0, 1035.0, 1044.0, 1053.0, 1062.0, 1071.0, 1080.0, 1089.0, 1098.0, 1107.0, 1116.0, 1125.0, 1134.0, 1143.0, 1152.0,", " 12.0, 24.0, 36.0, 48.0, 60.0, 72.0, 84.0, 96.0, 108.0, 120.0, 132.0, 144.0, 156.0, 168.0, 180.0, 192.0, 204.0, 216.0, 228.0, 240.0, 252.0, 264.0, 276.0, 288.0, 300.0, 312.0, 324.0, 336.0, 348.0, 360.0, 372.0, 384.0, 396.0, 408.0, 420.0, 432.0, 444.0, 456.0, 468.0, 480.0, 492.0, 504.0, 516.0, 528.0, 540.0, 552.0, 564.0, 576.0, 588.0, 600.0, 612.0, 624.0, 636.0, 648.0, 660.0, 672.0, 684.0, 696.0, 708.0, 720.0, 732.0, 744.0, 756.0, 768.0, 780.0, 792.0, 804.0, 816.0, 828.0, 840.0, 852.0, 864.0, 876.0, 888.0, 900.0, 912.0, 924.0, 936.0, 948.0, 960.0, 972.0, 984.0, 996.0, 1008.0, 1020.0, 1032.0, 1044.0, 1056.0, 1068.0, 1080.0, 1092.0, 1104.0, 1116.0, 1128.0, 1140.0, 1152.0, 1164.0, 1176.0, 1188.0, 1200.0, 1212.0, 1224.0, 1236.0, 1248.0, 1260.0, 1272.0, 1284.0, 1296.0, 1308.0, 1320.0, 1332.0, 1344.0, 1356.0, 1368.0, 1380.0, 1392.0, 1404.0, 1416.0, 1428.0, 1440.0, 1452.0, 1464.0, 1476.0, 1488.0, 1500.0, 1512.0, 1524.0, 1536.0,", " 15.0, 30.0, 45.0, 60.0, 75.0, 90.0, 105.0, 120.0, 135.0, 150.0, 165.0, 180.0, 195.0, 210.0, 225.0, 240.0, 255.0, 270.0, 285.0, 300.0, 315.0, 330.0, 345.0, 360.0, 375.0, 390.0, 405.0, 420.0, 435.0, 450.0, 465.0, 480.0, 495.0, 510.0, 525.0, 540.0, 555.0, 570.0, 585.0, 600.0, 615.0, 630.0, 645.0, 660.0, 675.0, 690.0, 705.0, 720.0, 735.0, 750.0, 765.0, 780.0, 795.0, 810.0, 825.0, 840.0, 855.0, 870.0, 885.0, 900.0, 915.0, 930.0, 945.0, 960.0, 975.0, 990.0, 1005.0, 1020.0, 1035.0, 1050.0, 1065.0, 1080.0, 1095.0, 1110.0, 1125.0, 1140.0, 1155.0, 1170.0, 1185.0, 1200.0, 1215.0, 1230.0, 1245.0, 1260.0, 1275.0, 1290.0, 1305.0, 1320.0, 1335.0, 1350.0, 1365.0, 1380.0, 1395.0, 1410.0, 1425.0, 1440.0, 1455.0, 1470.0, 1485.0, 1500.0, 1515.0, 1530.0, 1545.0, 1560.0, 1575.0, 1590.0, 1605.0, 1620.0, 1635.0, 1650.0, 1665.0, 1680.0, 1695.0, 1710.0, 1725.0, 1740.0, 1755.0, 1770.0, 1785.0, 1800.0, 1815.0, 1830.0, 1845.0, 1860.0, 1875.0, 1890.0, 1905.0, 1920.0,", " 18.0, 36.0, 54.0, 72.0, 90.0, 108.0, 126.0, 144.0, 162.0, 180.0, 198.0, 216.0, 234.0, 252.0, 270.0, 288.0, 306.0, 324.0, 342.0, 360.0, 378.0, 396.0, 414.0, 432.0, 450.0, 468.0, 486.0, 504.0, 522.0, 540.0, 558.0, 576.0, 594.0, 612.0, 630.0, 648.0, 666.0, 684.0, 702.0, 720.0, 738.0, 756.0, 774.0, 792.0, 810.0, 828.0, 846.0, 864.0, 882.0, 900.0, 918.0, 936.0, 954.0, 972.0, 990.0, 1008.0, 1026.0, 1044.0, 1062.0, 1080.0, 1098.0, 1116.0, 1134.0, 1152.0, 1170.0, 1188.0, 1206.0, 1224.0, 1242.0, 1260.0, 1278.0, 1296.0, 1314.0, 1332.0, 1350.0, 1368.0, 1386.0, 1404.0, 1422.0, 1440.0, 1458.0, 1476.0, 1494.0, 1512.0, 1530.0, 1548.0, 1566.0, 1584.0, 1602.0, 1620.0, 1638.0, 1656.0, 1674.0, 1692.0, 1710.0, 1728.0, 1746.0, 1764.0, 1782.0, 1800.0, 1818.0, 1836.0, 1854.0, 1872.0, 1890.0, 1908.0, 1926.0, 1944.0, 1962.0, 1980.0, 1998.0, 2016.0, 2034.0, 2052.0, 2070.0, 2088.0, 2106.0, 2124.0, 2142.0, 2160.0, 2178.0, 2196.0, 2214.0, 2232.0, 2250.0, 2268.0, 2286.0, 2304.0,", " 21.0, 42.0, 63.0, 84.0, 105.0, 126.0, 147.0, 168.0, 189.0, 210.0, 231.0, 252.0, 273.0, 294.0, 315.0, 336.0, 357.0, 378.0, 399.0, 420.0, 441.0, 462.0, 483.0, 504.0, 525.0, 546.0, 567.0, 588.0, 609.0, 630.0, 651.0, 672.0, 693.0, 714.0, 735.0, 756.0, 777.0, 798.0, 819.0, 840.0, 861.0, 882.0, 903.0, 924.0, 945.0, 966.0, 987.0, 1008.0, 1029.0, 1050.0, 1071.0, 1092.0, 1113.0, 1134.0, 1155.0, 1176.0, 1197.0, 1218.0, 1239.0, 1260.0, 1281.0, 1302.0, 1323.0, 1344.0, 1365.0, 1386.0, 1407.0, 1428.0, 1449.0, 1470.0, 1491.0, 1512.0, 1533.0, 1554.0, 1575.0, 1596.0, 1617.0, 1638.0, 1659.0, 1680.0, 1701.0, 1722.0, 1743.0, 1764.0, 1785.0, 1806.0, 1827.0, 1848.0, 1869.0, 1890.0, 1911.0, 1932.0, 1953.0, 1974.0, 1995.0, 2016.0, 2037.0, 2058.0, 2079.0, 2100.0, 2121.0, 2142.0, 2163.0, 2184.0, 2205.0, 2226.0, 2247.0, 2268.0, 2289.0, 2310.0, 2331.0, 2352.0, 2373.0, 2394.0, 2415.0, 2436.0, 2457.0, 2478.0, 2499.0, 2520.0, 2541.0, 2562.0, 2583.0, 2604.0, 2625.0, 2646.0, 2667.0, 2688.0,", " 24.0, 48.0, 72.0, 96.0, 120.0, 144.0, 168.0, 192.0, 216.0, 240.0, 264.0, 288.0, 312.0, 336.0, 360.0, 384.0, 408.0, 432.0, 456.0, 480.0, 504.0, 528.0, 552.0, 576.0, 600.0, 624.0, 648.0, 672.0, 696.0, 720.0, 744.0, 768.0, 792.0, 816.0, 840.0, 864.0, 888.0, 912.0, 936.0, 960.0, 984.0, 1008.0, 1032.0, 1056.0, 1080.0, 1104.0, 1128.0, 1152.0, 1176.0, 1200.0, 1224.0, 1248.0, 1272.0, 1296.0, 1320.0, 1344.0, 1368.0, 1392.0, 1416.0, 1440.0, 1464.0, 1488.0, 1512.0, 1536.0, 1560.0, 1584.0, 1608.0, 1632.0, 1656.0, 1680.0, 1704.0, 1728.0, 1752.0, 1776.0, 1800.0, 1824.0, 1848.0, 1872.0, 1896.0, 1920.0, 1944.0, 1968.0, 1992.0, 2016.0, 2040.0, 2064.0, 2088.0, 2112.0, 2136.0, 2160.0, 2184.0, 2208.0, 2232.0, 2256.0, 2280.0, 2304.0, 2328.0, 2352.0, 2376.0, 2400.0, 2424.0, 2448.0, 2472.0, 2496.0, 2520.0, 2544.0, 2568.0, 2592.0, 2616.0, 2640.0, 2664.0, 2688.0, 2712.0, 2736.0, 2760.0, 2784.0, 2808.0, 2832.0, 2856.0, 2880.0, 2904.0, 2928.0, 2952.0, 2976.0, 3000.0, 3024.0, 3048.0, 3072.0,", " 27.0, 54.0, 81.0, 108.0, 135.0, 162.0, 189.0, 216.0, 243.0, 270.0, 297.0, 324.0, 351.0, 378.0, 405.0, 432.0, 459.0, 486.0, 513.0, 540.0, 567.0, 594.0, 621.0, 648.0, 675.0, 702.0, 729.0, 756.0, 783.0, 810.0, 837.0, 864.0, 891.0, 918.0, 945.0, 972.0, 999.0, 1026.0, 1053.0, 1080.0, 1107.0, 1134.0, 1161.0, 1188.0, 1215.0, 1242.0, 1269.0, 1296.0, 1323.0, 1350.0, 1377.0, 1404.0, 1431.0, 1458.0, 1485.0, 1512.0, 1539.0, 1566.0, 1593.0, 1620.0, 1647.0, 1674.0, 1701.0, 1728.0, 1755.0, 1782.0, 1809.0, 1836.0, 1863.0, 1890.0, 1917.0, 1944.0, 1971.0, 1998.0, 2025.0, 2052.0, 2079.0, 2106.0, 2133.0, 2160.0, 2187.0, 2214.0, 2241.0, 2268.0, 2295.0, 2322.0, 2349.0, 2376.0, 2403.0, 2430.0, 2457.0, 2484.0, 2511.0, 2538.0, 2565.0, 2592.0, 2619.0, 2646.0, 2673.0, 2700.0, 2727.0, 2754.0, 2781.0, 2808.0, 2835.0, 2862.0, 2889.0, 2916.0, 2943.0, 2970.0, 2997.0, 3024.0, 3051.0, 3078.0, 3105.0, 3132.0, 3159.0, 3186.0, 3213.0, 3240.0, 3267.0, 3294.0, 3321.0, 3348.0, 3375.0, 3402.0, 3429.0, 3456.0,", " 30.0, 60.0, 90.0, 120.0, 150.0, 180.0, 210.0, 240.0, 270.0, 300.0, 330.0, 360.0, 390.0, 420.0, 450.0, 480.0, 510.0, 540.0, 570.0, 600.0, 630.0, 660.0, 690.0, 720.0, 750.0, 780.0, 810.0, 840.0, 870.0, 900.0, 930.0, 960.0, 990.0, 1020.0, 1050.0, 1080.0, 1110.0, 1140.0, 1170.0, 1200.0, 1230.0, 1260.0, 1290.0, 1320.0, 1350.0, 1380.0, 1410.0, 1440.0, 1470.0, 1500.0, 1530.0, 1560.0, 1590.0, 1620.0, 1650.0, 1680.0, 1710.0, 1740.0, 1770.0, 1800.0, 1830.0, 1860.0, 1890.0, 1920.0, 1950.0, 1980.0, 2010.0, 2040.0, 2070.0, 2100.0, 2130.0, 2160.0, 2190.0, 2220.0, 2250.0, 2280.0, 2310.0, 2340.0, 2370.0, 2400.0, 2430.0, 2460.0, 2490.0, 2520.0, 2550.0, 2580.0, 2610.0, 2640.0, 2670.0, 2700.0, 2730.0, 2760.0, 2790.0, 2820.0, 2850.0, 2880.0, 2910.0, 2940.0, 2970.0, 3000.0, 3030.0, 3060.0, 3090.0, 3120.0, 3150.0, 3180.0, 3210.0, 3240.0, 3270.0, 3300.0, 3330.0, 3360.0, 3390.0, 3420.0, 3450.0, 3480.0, 3510.0, 3540.0, 3570.0, 3600.0, 3630.0, 3660.0, 3690.0, 3720.0, 3750.0, 3780.0, 3810.0, 3840.0,", " 33.0, 66.0, 99.0, 132.0, 165.0, 198.0, 231.0, 264.0, 297.0, 330.0, 363.0, 396.0, 429.0, 462.0, 495.0, 528.0, 561.0, 594.0, 627.0, 660.0, 693.0, 726.0, 759.0, 792.0, 825.0, 858.0, 891.0, 924.0, 957.0, 990.0, 1023.0, 1056.0, 1089.0, 1122.0, 1155.0, 1188.0, 1221.0, 1254.0, 1287.0, 1320.0, 1353.0, 1386.0, 1419.0, 1452.0, 1485.0, 1518.0, 1551.0, 1584.0, 1617.0, 1650.0, 1683.0, 1716.0, 1749.0, 1782.0, 1815.0, 1848.0, 1881.0, 1914.0, 1947.0, 1980.0, 2013.0, 2046.0, 2079.0, 2112.0, 2145.0, 2178.0, 2211.0, 2244.0, 2277.0, 2310.0, 2343.0, 2376.0, 2409.0, 2442.0, 2475.0, 2508.0, 2541.0, 2574.0, 2607.0, 2640.0, 2673.0, 2706.0, 2739.0, 2772.0, 2805.0, 2838.0, 2871.0, 2904.0, 2937.0, 2970.0, 3003.0, 3036.0, 3069.0, 3102.0, 3135.0, 3168.0, 3201.0, 3234.0, 3267.0, 3300.0, 3333.0, 3366.0, 3399.0, 3432.0, 3465.0, 3498.0, 3531.0, 3564.0, 3597.0, 3630.0, 3663.0, 3696.0, 3729.0, 3762.0, 3795.0, 3828.0, 3861.0, 3894.0, 3927.0, 3960.0, 3993.0, 4026.0, 4059.0, 4092.0, 4125.0, 4158.0, 4191.0, 4224.0,", " 36.0, 72.0, 108.0, 144.0, 180.0, 216.0, 252.0, 288.0, 324.0, 360.0, 396.0, 432.0, 468.0, 504.0, 540.0, 576.0, 612.0, 648.0, 684.0, 720.0, 756.0, 792.0, 828.0, 864.0, 900.0, 936.0, 972.0, 1008.0, 1044.0, 1080.0, 1116.0, 1152.0, 1188.0, 1224.0, 1260.0, 1296.0, 1332.0, 1368.0, 1404.0, 1440.0, 1476.0, 1512.0, 1548.0, 1584.0, 1620.0, 1656.0, 1692.0, 1728.0, 1764.0, 1800.0, 1836.0, 1872.0, 1908.0, 1944.0, 1980.0, 2016.0, 2052.0, 2088.0, 2124.0, 2160.0, 2196.0, 2232.0, 2268.0, 2304.0, 2340.0, 2376.0, 2412.0, 2448.0, 2484.0, 2520.0, 2556.0, 2592.0, 2628.0, 2664.0, 2700.0, 2736.0, 2772.0, 2808.0, 2844.0, 2880.0, 2916.0, 2952.0, 2988.0, 3024.0, 3060.0, 3096.0, 3132.0, 3168.0, 3204.0, 3240.0, 3276.0, 3312.0, 3348.0, 3384.0, 3420.0, 3456.0, 3492.0, 3528.0, 3564.0, 3600.0, 3636.0, 3672.0, 3708.0, 3744.0, 3780.0, 3816.0, 3852.0, 3888.0, 3924.0, 3960.0, 3996.0, 4032.0, 4068.0, 4104.0, 4140.0, 4176.0, 4212.0, 4248.0, 4284.0, 4320.0, 4356.0, 4392.0, 4428.0, 4464.0, 4500.0, 4536.0, 4572.0, 4608.0,", " 39.0, 78.0, 117.0, 156.0, 195.0, 234.0, 273.0, 312.0, 351.0, 390.0, 429.0, 468.0, 507.0, 546.0, 585.0, 624.0, 663.0, 702.0, 741.0, 780.0, 819.0, 858.0, 897.0, 936.0, 975.0, 1014.0, 1053.0, 1092.0, 1131.0, 1170.0, 1209.0, 1248.0, 1287.0, 1326.0, 1365.0, 1404.0, 1443.0, 1482.0, 1521.0, 1560.0, 1599.0, 1638.0, 1677.0, 1716.0, 1755.0, 1794.0, 1833.0, 1872.0, 1911.0, 1950.0, 1989.0, 2028.0, 2067.0, 2106.0, 2145.0, 2184.0, 2223.0, 2262.0, 2301.0, 2340.0, 2379.0, 2418.0, 2457.0, 2496.0, 2535.0, 2574.0, 2613.0, 2652.0, 2691.0, 2730.0, 2769.0, 2808.0, 2847.0, 2886.0, 2925.0, 2964.0, 3003.0, 3042.0, 3081.0, 3120.0, 3159.0, 3198.0, 3237.0, 3276.0, 3315.0, 3354.0, 3393.0, 3432.0, 3471.0, 3510.0, 3549.0, 3588.0, 3627.0, 3666.0, 3705.0, 3744.0, 3783.0, 3822.0, 3861.0, 3900.0, 3939.0, 3978.0, 4017.0, 4056.0, 4095.0, 4134.0, 4173.0, 4212.0, 4251.0, 4290.0, 4329.0, 4368.0, 4407.0, 4446.0, 4485.0, 4524.0, 4563.0, 4602.0, 4641.0, 4680.0, 4719.0, 4758.0, 4797.0, 4836.0, 4875.0, 4914.0, 4953.0, 4992.0,", ) ; + +} +} \ No newline at end of file diff --git a/tests/various/stat_high_level.ys b/tests/various/stat_high_level.ys new file mode 100644 index 000000000..03e5e957e --- /dev/null +++ b/tests/various/stat_high_level.ys @@ -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 + + diff --git a/tests/various/stat_high_level2.ys b/tests/various/stat_high_level2.ys new file mode 100644 index 000000000..63d59da95 --- /dev/null +++ b/tests/various/stat_high_level2.ys @@ -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 + + From 4e45b5e1bb26a7c742b7abab7c4f78d80be0c052 Mon Sep 17 00:00:00 2001 From: clemens Date: Thu, 14 Aug 2025 11:13:40 +0200 Subject: [PATCH 13/14] permit trailing comma --- passes/cmds/stat.cc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 4d01b8535..07b1e5228 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -275,7 +275,7 @@ struct statdata_t { 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(), - (int)width_a, width_b, cell_data.double_parameter_area.size(), + 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; @@ -816,6 +816,10 @@ void read_liberty_cellarea(dict &cell_area, string libert 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); @@ -845,11 +849,15 @@ void read_liberty_cellarea(dict &cell_area, string libert vector 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 '%s': %s\n", s.c_str(), e.what()); + 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); From 9278bed853e0e391d42a646bb1633da9ae5f7597 Mon Sep 17 00:00:00 2001 From: clemens Date: Thu, 14 Aug 2025 16:33:59 +0200 Subject: [PATCH 14/14] removed copyright notice on lib file. Should be covered by the yosys license not anything else. --- tests/various/stat_area_by_width.lib | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/tests/various/stat_area_by_width.lib b/tests/various/stat_area_by_width.lib index 73e266472..1e98aa488 100644 --- a/tests/various/stat_area_by_width.lib +++ b/tests/various/stat_area_by_width.lib @@ -1,22 +1,5 @@ -/************************************************************************ - - Copyright 2025 Clemens Walter, - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -************************************************************************/ -//Mock library for Yosys pre techmap +//library for testcases, can also be used as a template for new libraries library (mock) { cell ( "$reduce_xor" ) { area : 3.0 ;