From 77cd9e1edca9765b3cc77656a88ee365547e8464 Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Sun, 28 Jun 2026 20:28:23 -0700 Subject: [PATCH] stat bugfix --- passes/cmds/stat.cc | 12 +++++--- tests/various/stat_blackbox_area.ys | 44 +++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 tests/various/stat_blackbox_area.ys diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index de767b96a..836c2531b 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -772,13 +772,17 @@ statdata_t hierarchy_builder(const RTLIL::Design *design, const RTLIL::Module *t mod_data.local_area_cells_by_type.erase(cell->type); } else { // deal with blackbox cells + // The read_liberty/read_liberty2json frontends store the cell + // area as a string attribute, so parse it as a floating point + // value rather than reinterpreting the raw attribute bits. if (design->module(cell->type)->attributes.count(ID::area) && - design->module(cell->type)->attributes.at(ID::area).size() == 0) { + design->module(cell->type)->attributes.at(ID::area).size() != 0) { + double blackbox_area = + atof(design->module(cell->type)->attributes.at(ID::area).decode_string().c_str()); 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.submodules_area_by_type[cell->type] += blackbox_area; + mod_data.area += blackbox_area; 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; diff --git a/tests/various/stat_blackbox_area.ys b/tests/various/stat_blackbox_area.ys new file mode 100644 index 000000000..f74ce5ae8 --- /dev/null +++ b/tests/various/stat_blackbox_area.ys @@ -0,0 +1,44 @@ +# Regression test: `stat` must account for the area of blackbox cells whose +# area comes from the module's `area` attribute (rather than from a `-liberty` +# file passed to `stat` itself). +# +# Both the `read_liberty` (-lib) and `read_liberty2json` frontends attach the +# cell area to the blackbox module as a STRING attribute: +# frontends/liberty/liberty.cc: module->attributes[ID::area] = area->value; // raw liberty string, e.g. "1.500000" +# passes/silimate/l2j_frontend.cc: set_string_attribute(ID(area), std::to_string(area)); // e.g. "1.500000" +# +# The blackbox-area branch in stat.cc's hierarchy_builder() previously guarded +# on `attributes.at(ID::area).size() == 0` and read the value with `.as_int()`. +# A string-valued area Const has size() != 0, so the branch never ran, and even +# if it had, `.as_int()` reinterprets the raw bits instead of parsing "1.5". +# The fix guards on size() != 0 and parses the string area as a double. +# +# This test recreates exactly what the frontends produce (a blackbox module +# with a string `area` attribute) and checks that stat counts it. `-hierarchy` +# is used because the blackbox-area branch accounts the cell as a submodule, +# and only the hierarchical view reports submodule area. + +read_rtlil << EOT +attribute \blackbox 1 +attribute \area "1.500000" +module \blackbox_cell + wire input 1 \A + wire output 2 \Y +end + +module \top + wire input 1 \A + wire output 2 \Y + cell \blackbox_cell \inst + connect \A \A + connect \Y \Y + end +end +EOT + +# The single blackbox instance has area 1.5, so the top module's hierarchical +# chip area must be 1.5, reported as one submodule. +logger -expect log "Chip area for module '\\top': 1.500000" 1 +logger -expect log "1.5.*blackbox_cell" 1 +logger -expect-no-warnings +stat -hierarchy