make report field

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2026-05-12 11:24:24 -07:00
parent 30f862bf86
commit 4c8ef5b84a
7 changed files with 247 additions and 193 deletions

View File

@ -83,6 +83,8 @@ using CheckErrorSeq = std::vector<CheckError*>;
enum class CmdNamespace { sta, sdc };
using ParasiticsNameMap = std::map<std::string, Parasitics*, std::less<>>;
using GraphLoopSeq = std::vector<GraphLoop*>;
using ReportFieldGetValue = std::function<std::string (const Path *path,
const StaState *sta)>;
// Initialize sta functions that are not part of the Sta class.
void initSta();
@ -982,15 +984,16 @@ public:
bool clk_gating_hold);
void setReportPathFormat(ReportPathFormat format);
void setReportPathFieldOrder(const StringSeq &field_names);
void setReportPathFields(bool report_input_pin,
bool report_hier_pins,
bool report_net,
bool report_cap,
bool report_slew,
bool report_fanout,
bool report_variation,
bool report_src_attr);
void setReportPathFields(const StringSeq &fields);
ReportField *findReportPathField(std::string_view name);
ReportField *findReportPathFieldAbrev(std::string_view name);
void makeReportPathField(std::string_view name,
std::string_view name_abrev,
std::string_view title,
size_t width,
bool left_justify,
Unit *unit,
const ReportFieldGetValue &get_value);
void setReportPathDigits(int digits);
void setReportPathNoSplit(bool no_split);
void reportPathEnd(PathEnd *end);

View File

@ -655,6 +655,15 @@ get_attribute(const char *key)
return Sta::sta()->ensureLinked()->getAttribute(self, key);
}
void
set_attribute(const char *key,
const char *value)
{
sta::Sta *sta = Sta::sta();
sta->ensureLinked();
sta->networkReader()->setAttribute(self, key, value);
}
} // Instance methods
%extend InstanceChildIterator {
@ -813,4 +822,3 @@ bool has_next() { return self->hasNext(); }
const Pin *next() { return self->next(); }
void finish() { delete self; }
} // NetConnectedPinIterator methods

View File

@ -81,23 +81,22 @@ hierPinsThruEdge(const Edge *edge,
const Graph *graph);
ReportField::ReportField(std::string_view name,
std::string_view name_abrev,
std::string_view title,
size_t width,
bool left_justify,
Unit *unit,
bool enabled) :
ReportFieldGetValue get_value) :
name_(name),
name_abrev_(name_abrev),
title_(title),
left_justify_(left_justify),
unit_(unit),
enabled_(enabled)
get_value_(get_value)
{
setWidth(width);
}
ReportField::~ReportField()
= default;
void
ReportField::setProperties(std::string_view title,
size_t width,
@ -121,72 +120,85 @@ ReportField::setEnabled(bool enabled)
enabled_ = enabled;
}
std::string
ReportField::value(const Path *path,
const StaState *sta) const
{
return get_value_(path, sta);
}
////////////////////////////////////////////////////////////////
ReportPath::ReportPath(StaState *sta) :
StaState(sta)
{
makeFields();
setReportFields({"incr", "total", "edge", "description"});
setDigits(2);
setReportFields(false, false, false, false, false, false, false, false);
}
ReportPath::~ReportPath()
{
delete field_description_;
delete field_total_;
delete field_incr_;
delete field_capacitance_;
delete field_slew_;
delete field_fanout_;
delete field_variation_;
delete field_src_attr_;
delete field_edge_;
delete field_case_;
deleteContents(fields_);
}
void
ReportPath::makeFields()
{
// The order corresponds to the default field order.
field_fanout_ = makeField("fanout", "Fanout", 6, false, nullptr, true);
field_capacitance_ = makeField("capacitance", "Cap", 6, false,
units_->capacitanceUnit(), true);
field_slew_ = makeField("slew", "Slew", 6, false, units_->timeUnit(),
true);
field_incr_ = makeField("incr", "Delay", 6, false, units_->timeUnit(),
true);
field_variation_ = makeField("variation", "Variation", 6, false,
units_->timeUnit(), false);
field_total_ = makeField("total", "Time", 6, false, units_->timeUnit(),
true);
field_edge_ = makeField("edge", "", 1, false, nullptr, true);
field_case_ = makeField("case", "case", 11, false, nullptr, false);
field_description_ = makeField("description", "Description", 36,
true, nullptr, true);
field_src_attr_ = makeField("src_attr", "Src Attr", 40,
true, nullptr, true);
field_fanout_ = makeField("fanout", "fanout", "Fanout", 6, false, nullptr);
field_capacitance_ = makeField("capacitance", "cap", "Cap", 6, false,
units_->capacitanceUnit());
field_slew_ = makeField("slew", "slew", "Slew", 6, false, units_->timeUnit());
field_incr_ = makeField("incr", "incr", "Delay", 6, false, units_->timeUnit());
field_variation_ = makeField("variation", "var", "Variation", 6, false,
units_->timeUnit());
field_total_ = makeField("total", "total", "Time", 6, false, units_->timeUnit());
field_edge_ = makeField("edge", "edge", "", 1, false, nullptr);
field_case_ = makeField("case", "case", "case", 11, false, nullptr);
field_description_ = makeField("description", "desc", "Description", 36, true, nullptr);
field_src_attr_ = makeField("src_attr", "src", "Src Attr", 40, true, nullptr);
}
ReportField *
ReportPath::makeField(std::string_view name,
std::string_view name_abrev,
std::string_view title,
int width,
size_t width,
bool left_justify,
Unit *unit)
{
return makeField(name, name_abrev, title, width, left_justify, unit, nullptr);
}
ReportField *
ReportPath::makeField(std::string_view name,
std::string_view name_abrev,
std::string_view title,
size_t width,
bool left_justify,
Unit *unit,
bool enabled)
ReportFieldGetValue get_value)
{
ReportField *field = new ReportField(name, title, width, left_justify,
unit, enabled);
ReportField *field = new ReportField(name, name_abrev, title, width, left_justify,
unit, get_value);
fields_.push_back(field);
field_map_[std::string(name)] = field;
return field;
}
ReportField *
ReportPath::findField(std::string_view name) const
ReportPath::findField(std::string_view name)
{
return findKey(field_map_, std::string(name));
}
ReportField *
ReportPath::findFieldAbrev(std::string_view name)
{
for (ReportField *field : fields_) {
if (field->name() == name)
const std::string &name_abrev = field->nameAbrev();
if (name.substr(0, name_abrev.size()) == name_abrev)
return field;
}
return nullptr;
@ -213,32 +225,38 @@ ReportPath::setReportFieldOrder(const StringSeq &field_names)
next_fields.push_back(field);
}
fields_.clear();
for (ReportField *field : next_fields)
fields_.push_back(field);
fields_ = next_fields;
}
void
ReportPath::setReportFields(bool report_input_pin,
bool report_hier_pins,
bool report_net,
bool report_cap,
bool report_slew,
bool report_fanout,
bool report_variation,
bool report_src_attr)
ReportPath::setReportFields(const StringSeq &fields)
{
report_input_pin_ = report_input_pin;
report_hier_pins_ = report_hier_pins;
report_net_ = report_net;
for (ReportField *field : fields_)
field->setEnabled(false);
field_incr_->setEnabled(true);
field_total_->setEnabled(true);
field_description_->setEnabled(true);
field_edge_->setEnabled(true);
// These are not real fields; they are flags.
report_input_pin_ = false;
report_hier_pins_ = false;
report_net_ = false;
field_capacitance_->setEnabled(report_cap);
field_slew_->setEnabled(report_slew);
field_fanout_->setEnabled(report_fanout);
field_variation_->setEnabled(report_variation);
field_src_attr_->setEnabled(report_src_attr);
// for debug
field_case_->setEnabled(false);
for (const std::string &field_name : fields) {
if (field_name == "input_pin")
report_input_pin_ = true;
else if (field_name == "hierarchical_pin")
report_hier_pins_ = true;
else if (field_name == "net")
report_net_ = true;
else {
ReportField *field = findField(field_name);
if (field)
field->setEnabled(true);
else
report_->warn(2720, "unknown path reporting field {}.", field_name);
}
}
}
void
@ -2454,7 +2472,7 @@ ReportPath::reportPathLine(const Path *path,
// Don't show capacitance field for input pins.
if (is_driver && field_capacitance_->enabled())
cap = graph_delay_calc_->loadCap(pin, rf, scene, min_max);
reportLine(what, cap, slew, field_blank_, incr, field_blank_,
reportLine(what, path, cap, slew, field_blank_, incr, field_blank_,
time, false, early_late, rf, src_attr, line_case);
}
@ -2823,13 +2841,13 @@ ReportPath::reportPath6(const Path *path,
if (field_fanout_->enabled())
fanout = drvrFanout(vertex, scene, min_max);
const std::string what = descriptionField(vertex);
reportLine(what, cap, slew, fanout,
reportLine(what, path1, cap, slew, fanout,
incr, field_blank_, time, false, min_max, rf, src_attr,
line_case);
if (report_net_) {
const std::string what2 = descriptionNet(pin);
reportLine(what2, field_blank_, field_blank_, field_blank_,
reportLine(what2, path1, field_blank_, field_blank_, field_blank_,
field_blank_, field_blank_, field_blank_, false, min_max,
nullptr, src_attr, "");
}
@ -2842,7 +2860,7 @@ ReportPath::reportPath6(const Path *path,
|| (i == path_last_index)
|| is_clk_start) {
const std::string what = descriptionField(vertex);
reportLine(what, field_blank_, slew, field_blank_,
reportLine(what, path1, field_blank_, slew, field_blank_,
incr, field_blank_, time, false, min_max, rf, src_attr,
line_case);
prev_time = time;
@ -2867,27 +2885,27 @@ ReportPath::reportVariation(const Path *path) const
switch (variables_->pocvMode()) {
case PocvMode::normal: {
float std_dev = arc_delay.stdDev();
reportLine("sigma", field_blank_, field_blank_, field_blank_,
reportLine("sigma", path, field_blank_, field_blank_, field_blank_,
field_blank_, std_dev, field_blank_, true, min_max,
nullptr, "", "");
break;
}
case PocvMode::skew_normal: {
float mean = arc_delay.mean();
reportLine("mean", field_blank_, field_blank_, field_blank_,
reportLine("mean", path, field_blank_, field_blank_, field_blank_,
field_blank_, mean, field_blank_, true, min_max,
nullptr, "", "");
float mean_shift = arc_delay.meanShift();
reportLine("mean_shift", field_blank_, field_blank_, field_blank_,
reportLine("mean_shift", path, field_blank_, field_blank_, field_blank_,
field_blank_, mean_shift, field_blank_, true, min_max,
nullptr, "", "");
float std_dev = arc_delay.stdDev();
reportLine("std_dev", field_blank_, field_blank_, field_blank_,
reportLine("std_dev", path, field_blank_, field_blank_, field_blank_,
field_blank_, std_dev, field_blank_, true, min_max,
nullptr, "", "");
// skewness is dimensionless, so scale it to the field's time units.
float skewness = arc_delay.skewness() * units_->timeUnit()->scale();
reportLine("skewness", field_blank_, field_blank_, field_blank_,
reportLine("skewness", path, field_blank_, field_blank_, field_blank_,
field_blank_, skewness, field_blank_, true, min_max,
nullptr, "", "");
break;
@ -2915,9 +2933,9 @@ ReportPath::reportHierPinsThru(const Path *path) const
if (prev_edge && prev_edge->isWire()) {
for (const Pin *hpin : hierPinsThruEdge(prev_edge, network_, graph_)) {
const std::string what = descriptionField(hpin);
reportLine(what, field_blank_, field_blank_, field_blank_,
field_blank_, field_blank_, field_blank_, false, path->minMax(this),
nullptr, "", "");
reportLine(what, path, field_blank_, field_blank_, field_blank_,
field_blank_, field_blank_, field_blank_, false,
path->minMax(this), nullptr, "", "");
}
}
}
@ -3109,7 +3127,7 @@ ReportPath::reportLine(std::string_view what,
Delay total,
const EarlyLate *early_late) const
{
reportLine(what, field_blank_, field_blank_, field_blank_, field_blank_,
reportLine(what, nullptr, field_blank_, field_blank_, field_blank_, field_blank_,
field_blank_, total, false, early_late, nullptr, "", "");
}
@ -3119,7 +3137,7 @@ ReportPath::reportLineNegative(std::string_view what,
Delay total,
const EarlyLate *early_late) const
{
reportLine(what, field_blank_, field_blank_, field_blank_,
reportLine(what, nullptr, field_blank_, field_blank_, field_blank_,
field_blank_, field_blank_, total, true /* tota_with_minus */,
early_late, nullptr, "", "");
}
@ -3131,7 +3149,7 @@ ReportPath::reportLine(std::string_view what,
const EarlyLate *early_late,
const RiseFall *rf) const
{
reportLine(what, field_blank_, field_blank_, field_blank_,
reportLine(what, nullptr, field_blank_, field_blank_, field_blank_,
field_blank_, field_blank_, total, false, early_late, rf, "", "");
}
@ -3142,7 +3160,7 @@ ReportPath::reportLine(std::string_view what,
const Delay &total,
const EarlyLate *early_late) const
{
reportLine(what, field_blank_, field_blank_, field_blank_,
reportLine(what, nullptr, field_blank_, field_blank_, field_blank_,
incr, field_blank_, total, false, early_late, nullptr, "", "");
}
@ -3154,7 +3172,7 @@ ReportPath::reportLine(std::string_view what,
const EarlyLate *early_late,
const RiseFall *rf) const
{
reportLine(what, field_blank_, field_blank_, field_blank_,
reportLine(what, nullptr, field_blank_, field_blank_, field_blank_,
incr, field_blank_, total, false, early_late, rf, "", "");
}
@ -3166,12 +3184,13 @@ ReportPath::reportLine(std::string_view what,
const Delay &total,
const EarlyLate *early_late) const
{
reportLine(what, field_blank_, slew, field_blank_,
reportLine(what, nullptr, field_blank_, slew, field_blank_,
incr, field_blank_, total, false, early_late, nullptr, "", "");
}
void
ReportPath::reportLine(std::string_view what,
const Path *path,
float cap,
const Slew &slew,
float fanout,
@ -3234,6 +3253,8 @@ ReportPath::reportLine(std::string_view what,
}
else if (field == field_case_)
line += line_case;
else if (field->getValue())
line += field->value(path, this);
first_field = false;
}

View File

@ -25,6 +25,7 @@
#pragma once
#include <cstddef>
#include <map>
#include <string>
#include <string_view>
#include <vector>
@ -49,9 +50,51 @@ namespace sta {
class Scene;
class PathExpanded;
class ReportField;
using ReportFieldGetValue = std::function<std::string (const Path *path,
const StaState *sta)>;
class ReportField
{
public:
ReportField(std::string_view name,
std::string_view name_abrev,
std::string_view title,
size_t width,
bool left_justify,
Unit *unit,
ReportFieldGetValue get_value);
void setProperties(std::string_view title,
size_t width,
bool left_justify);
const std::string &name() const { return name_; }
const std::string &nameAbrev() const { return name_abrev_; }
const std::string &title() const { return title_; }
size_t width() const { return width_; }
void setWidth(size_t width);
bool leftJustify() const { return left_justify_; }
Unit *unit() const { return unit_; }
const std::string &blank() const { return blank_; }
void setEnabled(bool enabled);
bool enabled() const { return enabled_; }
std::string value(const Path *path,
const StaState *sta) const;
const ReportFieldGetValue &getValue() const { return get_value_; }
protected:
std::string name_;
std::string name_abrev_;
std::string title_;
size_t width_;
bool left_justify_;
Unit *unit_;
bool enabled_{false};
ReportFieldGetValue get_value_;
std::string blank_;
};
using ReportFieldSeq = std::vector<ReportField*>;
using ReportFieldMap = std::map<std::string, ReportField*, std::less<>>;
class ReportPath : public StaState
{
@ -61,18 +104,12 @@ public:
ReportPathFormat pathFormat() const { return format_; }
void setPathFormat(ReportPathFormat format);
void setReportFieldOrder(const StringSeq &field_names);
void setReportFields(bool report_input_pin,
bool report_hier_pins,
bool report_net,
bool report_cap,
bool report_slew,
bool report_fanout,
bool report_variation,
bool report_src_attr);
void setReportFields(const StringSeq &fields);
int digits() const { return digits_; }
void setDigits(int digits);
void setNoSplit(bool no_split);
ReportField *findField(std::string_view name) const;
ReportField *findField(std::string_view name);
ReportField *findFieldAbrev(std::string_view name);
// Header above reportPathEnd results.
void reportPathEndHeader() const;
@ -165,6 +202,15 @@ public:
float slack,
const Scene *scene,
const MinMax *min_max) const;
ReportField *makeField(std::string_view name,
std::string_view name_abrev,
std::string_view title,
size_t width,
bool left_justify,
// nullptr for string fields.
Unit *unit,
ReportFieldGetValue get_value);
ReportField *fieldSlew() const { return field_slew_; }
ReportField *fieldFanout() const { return field_fanout_; }
ReportField *fieldCapacitance() const { return field_capacitance_; }
@ -173,11 +219,11 @@ public:
protected:
void makeFields();
ReportField *makeField(std::string_view name,
std::string_view name_abrev,
std::string_view title,
int width,
size_t width,
bool left_justify,
Unit *unit,
bool enabled);
Unit *unit);
void reportEndpointHeader(const PathEnd *end,
const PathEnd *prev_end) const;
void reportShort(const PathEndUnconstrained *end,
@ -370,6 +416,7 @@ protected:
const Delay &total,
const EarlyLate *early_late) const;
void reportLine(std::string_view what,
const Path *path,
float cap,
const Slew &slew,
float fanout,
@ -483,15 +530,14 @@ protected:
// Path options.
ReportPathFormat format_{ReportPathFormat::full};
ReportFieldSeq fields_;
bool report_input_pin_;
bool report_hier_pins_;
bool report_net_;
bool no_split_{false};
int digits_;
size_t start_end_pt_width_{80};
ReportFieldMap field_map_;
ReportFieldSeq fields_;
ReportField *field_description_;
ReportField *field_total_;
ReportField *field_incr_;
@ -507,41 +553,9 @@ protected:
std::string minus_zero_;
int field_width_extra_{5};
size_t start_end_pt_width_{80};
static constexpr float field_blank_ = -1;
static const float field_skip_;
};
class ReportField
{
public:
ReportField(std::string_view name,
std::string_view title,
size_t width,
bool left_justify,
Unit *unit,
bool enabled);
~ReportField();
void setProperties(std::string_view title,
size_t width,
bool left_justify);
const std::string &name() const { return name_; }
const std::string &title() const { return title_; }
size_t width() const { return width_; }
void setWidth(size_t width);
bool leftJustify() const { return left_justify_; }
Unit *unit() const { return unit_; }
const std::string &blank() const { return blank_; }
void setEnabled(bool enabled);
bool enabled() const { return enabled_; }
protected:
std::string name_;
std::string title_;
size_t width_;
bool left_justify_;
Unit *unit_;
bool enabled_;
std::string blank_;
};
} // namespace sta

View File

@ -401,29 +401,46 @@ set_report_path_format(ReportPathFormat format)
}
void
set_report_path_field_order(const StringSeq &field_names)
set_report_path_field_order(StringSeq field_names)
{
Sta::sta()->setReportPathFieldOrder(field_names);
}
void
set_report_path_fields(bool report_input_pin,
bool report_hier_pins,
bool report_net,
bool report_cap,
bool report_slew,
bool report_fanout,
bool report_variation,
bool report_src_attr)
set_report_path_fields(StringSeq fields)
{
Sta::sta()->setReportPathFields(report_input_pin,
report_hier_pins,
report_net,
report_cap,
report_slew,
report_fanout,
report_variation,
report_src_attr);
Sta::sta()->setReportPathFields(fields);
}
void
make_report_path_attr_field(std::string attr_name,
int width)
{
Sta *sta = Sta::sta();
sta->makeReportPathField(attr_name, attr_name, attr_name, width, true,
nullptr,
[attr_name] (const Path *path,
const StaState *sta) -> std::string {
if (path) {
const Network *network = sta->network();
const Pin *pin = path->pin(sta);
const Instance *inst = network->instance(pin);
return network->getAttribute(inst, attr_name);
}
else
return "";
});
}
const char *
find_report_path_field_abrev(const char *name)
{
Sta *sta = Sta::sta();
ReportField *field = sta->findReportPathFieldAbrev(name);
if (field)
return field->name().c_str();
else
return "";
}
void

View File

@ -158,8 +158,6 @@ proc find_timing_paths_cmd { cmd args_var } {
sta_error 511 "$cmd command failed."
}
check_for_key_args $cmd args
if { [info exists flags(-unconstrained)] } {
set unconstrained 1
} elseif { [info exists sta_report_unconstrained_paths] } {
@ -230,7 +228,6 @@ proc find_timing_paths_cmd { cmd args_var } {
sta_error 515 "positional arguments not supported."
}
}
set path_ends [find_path_ends $from $thrus $to $unconstrained \
$scenes $min_max \
$group_path_count $endpoint_path_count \
@ -716,41 +713,26 @@ proc parse_report_path_options { cmd args_var default_format
set path_options(num_fmt) "%.${digits}f"
set_report_path_digits $digits
set report_input_pin 0
set report_hier_pins 0
set report_cap 0
set report_net 0
set report_slew 0
set report_fanout 0
set report_variation 0
set report_src_attr 0
set fields {}
if { [info exists path_options(-fields)] } {
foreach field $path_options(-fields) {
if { [string match "input*" $field] } {
set report_input_pin 1
lappend fields "input_pin"
} elseif { [string match "hier*" $field] } {
set report_hier_pins 1
} elseif { [string match "cap*" $field] } {
set report_cap 1
lappend fields "hierarchical_pin"
} elseif { [string match "net" $field] } {
set report_net 1
} elseif { [string match "slew" $field] } {
set report_slew 1
} elseif { [string match "fanout" $field] } {
set report_fanout 1
} elseif { [string match "variation" $field] } {
set report_variation 1
} elseif { [string match "src*" $field] } {
set report_src_attr 1
lappend fields "net"
} else {
sta_warn 168 "unknown field $field."
set field_name [find_report_path_field_abrev $field]
if { $field_name != "" } {
lappend fields $field_name
} else {
sta_warn 168 "unknown field $field."
}
}
}
}
set_report_path_fields $report_input_pin $report_hier_pins $report_net \
$report_cap $report_slew $report_fanout $report_variation $report_src_attr
set_report_path_fields $fields
set_report_path_no_split [info exists path_options(-no_line_splits)]
}

View File

@ -2816,18 +2816,9 @@ Sta::setReportPathFieldOrder(const StringSeq &field_names)
}
void
Sta::setReportPathFields(bool report_input_pin,
bool report_hier_pins,
bool report_net,
bool report_cap,
bool report_slew,
bool report_fanout,
bool report_variation,
bool report_src_attr)
Sta::setReportPathFields(const StringSeq &fields)
{
report_path_->setReportFields(report_input_pin, report_hier_pins, report_net,
report_cap, report_slew, report_fanout,
report_variation, report_src_attr);
report_path_->setReportFields(fields);
}
ReportField *
@ -2836,6 +2827,24 @@ Sta::findReportPathField(std::string_view name)
return report_path_->findField(name);
}
ReportField *
Sta::findReportPathFieldAbrev(std::string_view name)
{
return report_path_->findFieldAbrev(name);
}
void
Sta::makeReportPathField(std::string_view name,
std::string_view name_abrev,
std::string_view title,
size_t width,
bool left_justify,
Unit *unit,
const ReportFieldGetValue &get_value)
{
report_path_->makeField(name, name_abrev, title, width, left_justify, unit, get_value);
}
void
Sta::setReportPathDigits(int digits)
{