latest changes 5/14 including generalize path report field and expose levelizObserver for dbsta

Signed-off-by: dsengupta0628 <dsengupta@precisioninno.com>
This commit is contained in:
dsengupta0628
2026-05-14 17:01:51 +00:00
19 changed files with 418 additions and 344 deletions

5
.gitignore vendored
View File

@@ -31,6 +31,5 @@ doc/messages.txt
# clangd turds
.cache/
# test artifacts
*/test/*.log
**/Testing/
# openroad ctest turds
cmake_test*

View File

@@ -0,0 +1,59 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2026, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software.
//
// Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// This notice may not be removed or altered from any source distribution.
#pragma once
namespace sta {
class Vertex;
class Search;
class GraphDelayCalc;
// Observer fired by Levelize during (re)levelization. Downstream consumers
// override the two hooks to invalidate caches that depend on vertex levels.
class LevelizeObserver
{
public:
virtual ~LevelizeObserver() = default;
virtual void levelsChangedBefore() = 0;
virtual void levelChangedBefore(Vertex *vertex) = 0;
};
// Default observer installed by Sta::makeObservers. Forwards level-change
// events to Search and GraphDelayCalc so their internal caches stay
// consistent. Subclass and override to extend (call the base methods first,
// then add your own invalidation).
class StaLevelizeObserver : public LevelizeObserver
{
public:
StaLevelizeObserver(Search *search, GraphDelayCalc *graph_delay_calc);
void levelsChangedBefore() override;
void levelChangedBefore(Vertex *vertex) override;
private:
Search *search_;
GraphDelayCalc *graph_delay_calc_;
};
} // namespace sta

View File

@@ -73,6 +73,7 @@ class ClkSkews;
class ReportField;
class EquivCells;
class StaSimObserver;
class LevelizeObserver;
class GraphLoop;
using ModeNameMap = std::map<std::string, Mode*, std::less<>>;
@@ -83,6 +84,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,16 +985,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,
bool report_orig_name);
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);
@@ -1327,6 +1330,10 @@ public:
// Ensure a network has been read, linked and liberty libraries exist.
Network *ensureLibLinked();
void ensureLevelized();
// Replace the Levelize observer. Takes ownership; deletes any prior
// observer. Subclass StaLevelizeObserver to extend the default behavior
// (Search + GraphDelayCalc forwarding) without re-implementing it.
void setLevelizeObserver(LevelizeObserver *observer);
// Ensure that the timing graph has been built.
Graph *ensureGraph();
void ensureClkArrivals();

View File

@@ -91,6 +91,9 @@ stringEqual(std::string_view s1,
std::pair<float, bool>
stringFloat(const std::string &str);
std::pair<long long, bool>
stringLong(const std::string &str,
int base = 10);
bool
isDigits(const char *str);

View File

@@ -62,7 +62,7 @@ sta::LibertyParse::error(const location_type &loc,
%define api.parser.class {LibertyParse}
%define api.value.type variant
%expect 2
%expect 0
%token <std::string> STRING KEYWORD
%token <float> FLOAT
@@ -75,8 +75,8 @@ sta::LibertyParse::error(const location_type &loc,
%type <void *> statement complex_attr simple_attr variable group file
%type <sta::LibertyAttrValueSeq *> attr_values
%type <sta::LibertyAttrValue *> attr_value
%type <std::string> string expr expr_term expr_term1 volt_expr
%type <char> expr_op volt_op
%type <std::string> string expr expr_term expr_term1
%type <char> expr_op
%start file
@@ -157,36 +157,8 @@ string:
;
attr_value:
FLOAT
{ $$ = reader->makeAttrValueFloat($1); }
| expr
expr
{ $$ = reader->makeAttrValueString(std::move($1)); }
| volt_expr
{ $$ = reader->makeAttrValueString(std::move($1)); }
;
/* Voltage expressions are ignored. */
/* Crafted to avoid conflicts with expr */
volt_expr:
FLOAT volt_op FLOAT
{ $$ = sta::format("{}{}{}", $1, $2, $3); }
| string volt_op FLOAT
{ $$ = sta::format("{}{}{}", $1, $2, $3); }
| FLOAT volt_op string
{ $$ = sta::format("{}{}{}", $1, $2, $3); }
| volt_expr volt_op FLOAT
{ $$ = sta::format("{}{}{}", $1, $2, $3); }
;
volt_op:
'+'
{ $$ = '+'; }
| '-'
{ $$ = '-'; }
| '*'
{ $$ = '*'; }
| '/'
{ $$ = '/'; }
;
expr:
@@ -197,6 +169,8 @@ expr:
expr_term:
string
| FLOAT
{ $$ = sta::format("{}", $1); }
| '0'
{ $$ = std::string("0"); }
| '1'
@@ -224,6 +198,10 @@ expr_op:
{ $$ = '&'; }
| '^'
{ $$ = '^'; }
| '-'
{ $$ = '-'; }
| '/'
{ $$ = '/'; }
;
semi_opt:

View File

@@ -513,6 +513,13 @@ LibertyGroup::findAttrInt(std::string_view attr_name,
exists = exists1;
return;
}
else {
const std::string &int_str = attr_value.stringValue();
auto [value1, valid1] = stringLong(int_str);
value = value1;
exists = valid1;
return;
}
}
exists = false;
}

View File

@@ -2344,16 +2344,13 @@ LibertyReader::readReceiverCapacitance(const LibertyGroup *timing_group,
std::string cap_group_name1 = sta::format("{}_{}", cap_group_name, rf->to_string());
const LibertyGroup *cap_group = timing_group->findSubgroup(cap_group_name1);
if (cap_group) {
const LibertySimpleAttr *segment_attr = cap_group->findSimpleAttr("segment");
if (segment_attr) {
// For receiver_capacitance groups with mulitiple segments this
// overrides the index passed in beginReceiverCapacitance1Rise/Fall.
int segment;
bool exists;
getAttrInt(segment_attr, segment, exists);
if (exists)
index = segment;
}
// For receiver_capacitance groups with mulitiple segments this
// overrides the index passed in beginReceiverCapacitance1Rise/Fall.
int segment;
bool exists;
cap_group->findAttrInt("segment", segment, exists);
if (exists)
index = segment;
TableModel *model = readTableModel(cap_group, rf, TableTemplateType::delay,
cap_scale_, ScaleFactorType::pin_cap);
if (ReceiverModel::checkAxes(model)) {
@@ -3224,24 +3221,6 @@ LibertyReader::makeFloatTable(const LibertyComplexAttr *values_attr,
////////////////////////////////////////////////////////////////
void
LibertyReader::getAttrInt(const LibertySimpleAttr *attr,
// Return values.
int &value,
bool &exists)
{
value = 0;
exists = false;
const LibertyAttrValue &attr_value = attr->value();
if (attr_value.isFloat()) {
auto [float_val, valid] = attr_value.floatValue();
value = static_cast<int>(float_val);
exists = true;
}
else
warn(1268, attr, "{} attribute is not an integer.", attr->name());
}
// Get two floats in a complex attribute.
// attr(float1, float2);
void

View File

@@ -418,10 +418,6 @@ protected:
StateInternalValues parseStateInternalValues(StringSeq &states,
const LibertySimpleAttr *attr);
void getAttrInt(const LibertySimpleAttr *attr,
// Return values.
int &value,
bool &exists);
void getAttrFloat2(const LibertyComplexAttr *attr,
// Return values.
float &value1,

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

@@ -30,11 +30,11 @@
#include "Graph.hh"
#include "StaState.hh"
#include "sta/LevelizeObserver.hh"
namespace sta {
class SearchPred;
class LevelizeObserver;
class GraphLoop;
using VertexEdgeIterPair = std::pair<Vertex*,VertexOutEdgeIterator*>;
@@ -133,12 +133,4 @@ private:
EdgeSeq *edges_;
};
class LevelizeObserver
{
public:
virtual ~LevelizeObserver() = default;
virtual void levelsChangedBefore() = 0;
virtual void levelChangedBefore(Vertex *vertex) = 0;
};
} // namespace sta

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,75 +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, 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_orig_name_;
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_orig_name_ = makeField("orig_name", "Orig Name", 36,
true, nullptr, false);
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;
@@ -216,34 +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,
bool report_orig_name)
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);
field_orig_name_->setEnabled(report_orig_name);
// 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
@@ -2464,8 +2477,8 @@ 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_,
time, false, early_late, rf, src_attr, orig_name, line_case);
reportLine(what, path, cap, slew, field_blank_, incr, field_blank_,
time, false, early_late, rf, src_attr, line_case);
}
void
@@ -2838,13 +2851,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,
orig_name, 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, "", "");
}
@@ -2857,7 +2870,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,
orig_name, line_case);
prev_time = time;
@@ -2882,27 +2895,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;
@@ -2930,9 +2943,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, "", "");
}
}
}
@@ -3124,8 +3137,8 @@ ReportPath::reportLine(std::string_view what,
Delay total,
const EarlyLate *early_late) const
{
reportLine(what, field_blank_, field_blank_, field_blank_, field_blank_,
field_blank_, total, false, early_late, nullptr, "", "", "");
reportLine(what, nullptr, field_blank_, field_blank_, field_blank_, field_blank_,
field_blank_, total, false, early_late, nullptr, "", "");
}
// Report negative total.
@@ -3134,7 +3147,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, "", "", "");
}
@@ -3146,8 +3159,8 @@ ReportPath::reportLine(std::string_view what,
const EarlyLate *early_late,
const RiseFall *rf) const
{
reportLine(what, field_blank_, field_blank_, field_blank_,
field_blank_, field_blank_, total, false, early_late, rf, "", "", "");
reportLine(what, nullptr, field_blank_, field_blank_, field_blank_,
field_blank_, field_blank_, total, false, early_late, rf, "", "");
}
// Report increment, and total.
@@ -3157,8 +3170,8 @@ ReportPath::reportLine(std::string_view what,
const Delay &total,
const EarlyLate *early_late) const
{
reportLine(what, field_blank_, field_blank_, field_blank_,
incr, field_blank_, total, false, early_late, nullptr, "", "", "");
reportLine(what, nullptr, field_blank_, field_blank_, field_blank_,
incr, field_blank_, total, false, early_late, nullptr, "", "");
}
// Report increment, total, and transition suffix.
@@ -3169,8 +3182,8 @@ ReportPath::reportLine(std::string_view what,
const EarlyLate *early_late,
const RiseFall *rf) const
{
reportLine(what, field_blank_, field_blank_, field_blank_,
incr, field_blank_, total, false, early_late, rf, "", "", "");
reportLine(what, nullptr, field_blank_, field_blank_, field_blank_,
incr, field_blank_, total, false, early_late, rf, "", "");
}
// Report slew, increment, and total.
@@ -3181,12 +3194,13 @@ ReportPath::reportLine(std::string_view what,
const Delay &total,
const EarlyLate *early_late) const
{
reportLine(what, field_blank_, slew, field_blank_,
incr, field_blank_, total, false, early_late, nullptr, "", "", "");
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,
@@ -3256,6 +3270,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,19 +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,
bool report_orig_name);
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;
@@ -166,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_; }
@@ -175,11 +220,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,
@@ -372,6 +417,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,
@@ -486,15 +532,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_;
@@ -511,41 +556,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,31 +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,
bool report_orig_name)
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,
report_orig_name);
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,45 +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 report_orig_name 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
} elseif { [string match "orig*" $field] } {
set report_orig_name 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 \
$report_orig_name
set_report_path_fields $fields
set_report_path_no_split [info exists path_options(-no_line_splits)]
}

View File

@@ -217,19 +217,6 @@ StaSimObserver::fanoutEdgesChangeAfter(const Pin *pin)
////////////////////////////////////////////////////////////////
class StaLevelizeObserver : public LevelizeObserver
{
public:
StaLevelizeObserver(Search *search,
GraphDelayCalc *graph_delay_calc);
void levelsChangedBefore() override;
void levelChangedBefore(Vertex *vertex) override;
private:
Search *search_;
GraphDelayCalc *graph_delay_calc_;
};
StaLevelizeObserver::StaLevelizeObserver(Search *search,
GraphDelayCalc *graph_delay_calc) :
search_(search),
@@ -2816,20 +2803,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,
bool report_orig_name)
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_orig_name);
report_path_->setReportFields(fields);
}
ReportField *
@@ -2838,6 +2814,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)
{
@@ -3773,6 +3767,12 @@ Sta::ensureLevelized()
levelize_->ensureLevelized();
}
void
Sta::setLevelizeObserver(LevelizeObserver *observer)
{
levelize_->setObserver(observer);
}
void
Sta::updateGeneratedClks()
{

View File

@@ -265,45 +265,6 @@ using namespace sta;
%}
////////////////////////////////////////////////////////////////
%inline %{
inline bool
is_object(const char *obj)
{
// _hexaddress_p_type
const std::string s(obj);
if (s.empty() || s[0] != '_')
return false;
const size_t hex_digits = sizeof(void *) * 2;
if (s.size() < 1 + hex_digits + 3)
return false;
for (size_t i = 1; i < 1 + hex_digits; i++) {
if (!std::isxdigit(static_cast<unsigned char>(s[i])))
return false;
}
if (s.compare(1 + hex_digits, 3, "_p_") != 0)
return false;
for (size_t i = 1 + hex_digits + 3; i < s.size(); i++) {
char ch = s[i];
if (!(std::isalnum(ch) || ch == '_'))
return false;
}
return true;
}
// Assumes is_object is true.
inline const char *
object_type(const char *obj)
{
if (is_object(obj))
return &obj[1 + sizeof(void*) * 2 + 3];
return "";
}
%}
////////////////////////////////////////////////////////////////
//
// SWIG type definitions.

View File

@@ -66,9 +66,11 @@ proc setup {} {
set valgrind_shared_lib_failure 0
if { ![file exists $app_path] } {
error "$app_path not found."
puts "$app_path not found."
exit 1
} elseif { ![file executable $app_path] } {
error "$app_path is not executable."
puts "$app_path is not executable."
exit 1
}
}

View File

@@ -78,6 +78,32 @@ stringFloat(const std::string &str)
#endif
}
std::pair<long long, bool>
stringLong(const std::string &str,
int base)
{
long long value;
#if defined(__cpp_lib_to_chars) && __cpp_lib_to_chars >= 201611L
auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), value, base);
// Check for success and that we consumed the entire string
if (ec == std::errc() && ptr == str.data() + str.size())
return {value, true};
else
return {0LL, false};
#else
char *ptr;
errno = 0;
// strtoll handles "long long" specifically
value = std::strtoll(str.data(), &ptr, base);
if (errno == ERANGE || *ptr != '\0' || ptr == str.data())
return {0LL, false};
else
return {value, true};
#endif
}
void
trimRight(std::string &str)
{

View File

@@ -504,4 +504,39 @@ fuzzy_equal(float value1,
return fuzzyEqual(value1, value2);
}
////////////////////////////////////////////////////////////////
bool
is_object(const char *obj)
{
// _hexaddress_p_type
const std::string s(obj);
if (s.empty() || s[0] != '_')
return false;
const size_t hex_digits = sizeof(void *) * 2;
if (s.size() < 1 + hex_digits + 3)
return false;
for (size_t i = 1; i < 1 + hex_digits; i++) {
if (!std::isxdigit(static_cast<unsigned char>(s[i])))
return false;
}
if (s.compare(1 + hex_digits, 3, "_p_") != 0)
return false;
for (size_t i = 1 + hex_digits + 3; i < s.size(); i++) {
char ch = s[i];
if (!(std::isalnum(ch) || ch == '_'))
return false;
}
return true;
}
// Assumes is_object is true.
const char *
object_type(const char *obj)
{
if (is_object(obj))
return &obj[1 + sizeof(void*) * 2 + 3];
return "";
}
%} // inline