diff --git a/doc/ChangeLog.txt b/doc/ChangeLog.txt
index f4b323a7..11c91663 100644
--- a/doc/ChangeLog.txt
+++ b/doc/ChangeLog.txt
@@ -33,6 +33,9 @@ is now supported by the the read_saif command.
The report_checks -group_count option has been renamed to -group_path_count.
The report_checks -endpoing_count option has been renamed to -endpoint_path_count.
+The report_checks -field hierarchical_pins field reports hierarical pins between
+a driver and a load in the path report.
+
Release 2.5.0 2024/01/17
-------------------------
diff --git a/doc/OpenSTA.odt b/doc/OpenSTA.odt
index 99fdb8ae..59d6b997 100644
Binary files a/doc/OpenSTA.odt and b/doc/OpenSTA.odt differ
diff --git a/doc/OpenSTA.pdf b/doc/OpenSTA.pdf
index 733d32d0..b4f81586 100644
Binary files a/doc/OpenSTA.pdf and b/doc/OpenSTA.pdf differ
diff --git a/include/sta/Sta.hh b/include/sta/Sta.hh
index 13a57dfc..2ffee382 100644
--- a/include/sta/Sta.hh
+++ b/include/sta/Sta.hh
@@ -889,6 +889,7 @@ public:
void setReportPathFormat(ReportPathFormat format);
void setReportPathFieldOrder(StringSeq *field_names);
void setReportPathFields(bool report_input_pin,
+ bool report_hier_pins,
bool report_net,
bool report_cap,
bool report_slew,
diff --git a/search/ReportPath.cc b/search/ReportPath.cc
index 1eec5327..5b2617a2 100644
--- a/search/ReportPath.cc
+++ b/search/ReportPath.cc
@@ -14,6 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
+#include // reverse
+
#include "ReportPath.hh"
#include "Report.hh"
@@ -53,6 +55,11 @@
namespace sta {
+static PinSeq
+hierPinsThruEdge(const Edge *edge,
+ const Network *network,
+ const Graph *graph);
+
ReportField::ReportField(const char *name,
const char *title,
int width,
@@ -122,7 +129,7 @@ ReportPath::ReportPath(StaState *sta) :
{
setDigits(2);
makeFields();
- setReportFields(false, false, false, false, false, false);
+ setReportFields(false, false, false, false, false, false, false);
}
ReportPath::~ReportPath()
@@ -225,6 +232,7 @@ ReportPath::setReportFieldOrder(StringSeq *field_names)
void
ReportPath::setReportFields(bool report_input_pin,
+ bool report_hier_pins,
bool report_net,
bool report_cap,
bool report_slew,
@@ -232,6 +240,7 @@ ReportPath::setReportFields(bool report_input_pin,
bool report_src_attr)
{
report_input_pin_ = report_input_pin;
+ report_hier_pins_ = report_hier_pins;
report_net_ = report_net;
field_capacitance_->setEnabled(report_cap);
@@ -2402,7 +2411,7 @@ ReportPath::reportPathLine(const Path *path,
{
Vertex *vertex = path->vertex(this);
Pin *pin = vertex->pin();
- auto what = descriptionField(vertex);
+ const string what = descriptionField(vertex);
const RiseFall *rf = path->transition(this);
bool is_driver = network_->isDriver(pin);
PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
@@ -2761,52 +2770,39 @@ ReportPath::reportPath5(const Path *path,
incr = delayIncr(time, prev_time, min_max);
line_case = "normal";
}
- if (report_input_pin_
- || (i == path_last_index)
- || is_clk_start
- || (prev_arc == nullptr)
- // Filter wire edges from report unless reporting
- // input pins.
- || (prev_arc
- && !prev_arc->role()->isWire())) {
- bool is_driver = network_->isDriver(pin);
- float cap = field_blank_;
+
+ if (vertex->isDriver(network_)) {
+ float cap = field_blank_;
float fanout = field_blank_;
- // Don't show capacitance field for input pins.
- if (is_driver && field_capacitance_->enabled())
+ if (field_capacitance_->enabled())
cap = graph_delay_calc_->loadCap(pin, rf, dcalc_ap);
- // Don't show fanout field for input pins.
- if (is_driver && field_fanout_->enabled())
- fanout = drvrFanout(vertex, dcalc_ap->corner(), min_max);
- auto what = descriptionField(vertex);
- if (report_net_ && is_driver) {
- reportLine(what.c_str(), cap, slew, fanout,
- incr, time, false, min_max, rf,
- src_attr, line_case);
- string what2;
- if (network_->isTopLevelPort(pin)) {
- const char *pin_name = cmd_network_->pathName(pin);
- what2 = stdstrPrint("%s (net)", pin_name);
- }
- else {
- Net *net = network_->net(pin);
- if (net) {
- Net *highest_net = network_->highestNetAbove(net);
- const char *net_name = cmd_network_->pathName(highest_net);
- what2 = stdstrPrint("%s (net)", net_name);
- }
- else
- what2 = "(unconnected)";
- }
- reportLine(what2.c_str(), field_blank_, field_blank_, field_blank_,
- field_blank_, field_blank_, false, min_max,
- nullptr, src_attr, line_case);
- }
- else
- reportLine(what.c_str(), cap, slew, fanout,
- incr, time, false, min_max, rf, src_attr,
- line_case);
- prev_time = time;
+ if (field_fanout_->enabled())
+ fanout = drvrFanout(vertex, dcalc_ap->corner(), min_max);
+ const string what = descriptionField(vertex);
+ reportLine(what.c_str(), cap, slew, fanout,
+ incr, time, false, min_max, rf, src_attr,
+ line_case);
+
+ if (report_net_) {
+ const string what2 = descriptionNet(pin);
+ reportLine(what2.c_str(), field_blank_, field_blank_, field_blank_,
+ field_blank_, field_blank_, false, min_max,
+ nullptr, src_attr, "");
+ }
+ prev_time = time;
+ }
+ else {
+ reportHierPinsThru(path1, prev_arc);
+ if (report_input_pin_
+ || (i == 0)
+ || (i == path_last_index)
+ || is_clk_start) {
+ const string what = descriptionField(vertex);
+ reportLine(what.c_str(), field_blank_, slew, field_blank_,
+ incr, time, false, min_max, rf, src_attr,
+ line_case);
+ prev_time = time;
+ }
}
}
else
@@ -2814,6 +2810,23 @@ ReportPath::reportPath5(const Path *path,
}
}
+void
+ReportPath::reportHierPinsThru(const Path *path,
+ const TimingArc *prev_arc)
+{
+ if (report_hier_pins_) {
+ const Edge *prev_edge = path->prevEdge(prev_arc, this);
+ if (prev_edge && prev_edge->isWire()) {
+ for (const Pin *hpin : hierPinsThruEdge(prev_edge, network_, graph_)) {
+ const string what = descriptionField(hpin);
+ reportLine(what.c_str(), field_blank_, field_blank_, field_blank_,
+ field_blank_, field_blank_, false, path->minMax(this),
+ nullptr, "", "");
+ }
+ }
+ }
+}
+
Delay
ReportPath::delayIncr(Delay time,
Delay prev,
@@ -2839,7 +2852,12 @@ ReportPath::nextArcAnnotated(const PathRef *next_path,
string
ReportPath::descriptionField(Vertex *vertex)
{
- Pin *pin = vertex->pin();
+ return descriptionField(vertex->pin());
+}
+
+string
+ReportPath::descriptionField(const Pin *pin)
+{
const char *pin_name = cmd_network_->pathName(pin);
const char *name2;
if (network_->isTopLevelPort(pin)) {
@@ -2863,6 +2881,25 @@ ReportPath::descriptionField(Vertex *vertex)
return stdstrPrint("%s (%s)", pin_name, name2);
}
+string
+ReportPath::descriptionNet(const Pin *pin)
+{
+ if (network_->isTopLevelPort(pin)) {
+ const char *pin_name = cmd_network_->pathName(pin);
+ return stdstrPrint("%s (net)", pin_name);
+ }
+ else {
+ Net *net = network_->net(pin);
+ if (net) {
+ Net *highest_net = network_->highestNetAbove(net);
+ const char *net_name = cmd_network_->pathName(highest_net);
+ return stdstrPrint("%s (net)", net_name);
+ }
+ else
+ return "(unconnected)";
+ }
+}
+
float
ReportPath::drvrFanout(Vertex *drvr,
const Corner *corner,
@@ -3442,4 +3479,85 @@ ReportPath::latchDesc(const RiseFall *clk_rf) const
: "negative level-sensitive latch";
}
+////////////////////////////////////////////////////////////////
+
+static void
+hierPinsAbove(const Net *net,
+ const Network *network,
+ PinSeq &pins_above);
+static void
+hierPinsAbove(const Pin *pin,
+ const Network *network,
+ PinSeq &pins_above);
+
+static PinSeq
+hierPinsThruEdge(const Edge *edge,
+ const Network *network,
+ const Graph *graph)
+{
+ const Pin *drvr_pin = edge->from(graph)->pin();
+ const Pin *load_pin = edge->to(graph)->pin();
+ PinSeq drvr_hpins;
+ PinSeq load_hpins;
+ hierPinsAbove(drvr_pin, network, drvr_hpins);
+ hierPinsAbove(load_pin, network, load_hpins);
+ if (drvr_hpins.empty()) {
+ std::reverse(load_hpins.begin(), load_hpins.end());
+ return load_hpins;
+ }
+ if (load_hpins.empty())
+ return drvr_hpins;
+ for (size_t l1 = 0; l1 < load_hpins.size(); l1++) {
+ const Pin *load_hpin = load_hpins[l1];
+ const Net *load_net = network->net(load_hpin);
+ for (size_t d1 = 0; d1 < drvr_hpins.size(); d1++) {
+ const Pin *drvr_hpin = drvr_hpins[d1];
+ const Net *drvr_net = network->net(drvr_hpin);
+ if (load_net == drvr_net) {
+ PinSeq hpins_thru;
+ for (size_t d2 = 0; d2 < d1; d2++) {
+ const Pin *drvr_hpin2 = drvr_hpins[d2];
+ hpins_thru.push_back(drvr_hpin2);
+ }
+ hpins_thru.push_back(drvr_hpin);
+ hpins_thru.push_back(load_hpin);
+ for (size_t l2 = 0; l2 < l1; l2++) {
+ const Pin *load_hpin2 = load_hpins[l2];
+ hpins_thru.push_back(load_hpin2);
+ }
+ return hpins_thru;
+ }
+ }
+ }
+ return PinSeq();
+}
+
+static void
+hierPinsAbove(const Pin *pin,
+ const Network *network,
+ PinSeq &pins_above)
+{
+ const Net *net = network->net(pin);
+ hierPinsAbove(net, network, pins_above);
+}
+
+static void
+hierPinsAbove(const Net *net,
+ const Network *network,
+ PinSeq &pins_above)
+{
+ if (net) {
+ NetTermIterator *term_iter = network->termIterator(net);
+ while (term_iter->hasNext()) {
+ const Term *term = term_iter->next();
+ const Pin *net_pin = network->pin(term);
+ if (network->isHierarchical(net_pin))
+ pins_above.push_back(net_pin);
+ const Net *hpin_net = network->net(net_pin);
+ if (hpin_net)
+ hierPinsAbove(hpin_net, network, pins_above);
+ }
+ }
+}
+
} // namespace
diff --git a/search/ReportPath.hh b/search/ReportPath.hh
index e86b7e2a..964a3e30 100644
--- a/search/ReportPath.hh
+++ b/search/ReportPath.hh
@@ -41,6 +41,7 @@ public:
void setPathFormat(ReportPathFormat format);
void setReportFieldOrder(StringSeq *field_names);
void setReportFields(bool report_input_pin,
+ bool report_hier_pins,
bool report_net,
bool report_cap,
bool report_slew,
@@ -316,6 +317,8 @@ protected:
bool report_clk_path,
Arrival prev_time,
float time_offset);
+ void reportHierPinsThru(const Path *path,
+ const TimingArc *prev_arc);
void reportInputExternalDelay(const Path *path,
float time_offset);
void reportLine(const char *what,
@@ -401,6 +404,8 @@ protected:
void reportDashLine(int line_width);
void reportBlankLine();
string descriptionField(Vertex *vertex);
+ string descriptionField(const Pin *pin);
+ string descriptionNet(const Pin *pin);
bool reportClkPath() const;
string clkName(const Clock *clk,
bool inverted);
@@ -455,6 +460,7 @@ protected:
ReportPathFormat format_;
ReportFieldSeq fields_;
bool report_input_pin_;
+ bool report_hier_pins_;
bool report_net_;
bool no_split_;
int digits_;
diff --git a/search/Search.i b/search/Search.i
index 8895848a..96384b2f 100644
--- a/search/Search.i
+++ b/search/Search.i
@@ -437,6 +437,7 @@ set_report_path_field_order(StringSeq *field_names)
void
set_report_path_fields(bool report_input_pin,
+ bool report_hier_pins,
bool report_net,
bool report_cap,
bool report_slew,
@@ -444,6 +445,7 @@ set_report_path_fields(bool report_input_pin,
bool report_src_attr)
{
Sta::sta()->setReportPathFields(report_input_pin,
+ report_hier_pins,
report_net,
report_cap,
report_slew,
diff --git a/search/Search.tcl b/search/Search.tcl
index 8e2db458..fa1e5138 100644
--- a/search/Search.tcl
+++ b/search/Search.tcl
@@ -907,23 +907,35 @@ proc parse_report_path_options { cmd args_var default_format
set_report_path_field_width $field $field_width
}
+ 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_src_attr 0
if { [info exists path_options(-fields)] } {
- set fields $path_options(-fields)
- set report_input_pin [expr [lsearch $fields "input*"] != -1]
- set report_cap [expr [lsearch $fields "cap*"] != -1]
- set report_net [expr [lsearch $fields "net*"] != -1]
- set report_slew [expr [lsearch $fields "slew*"] != -1]
- set report_fanout [expr [lsearch $fields "fanout*"] != -1]
- set report_src_attr [expr [lsearch $fields "src_attr*"] != -1]
- } else {
- set report_input_pin 0
- set report_cap 0
- set report_net 0
- set report_slew 0
- set report_fanout 0
- set report_src_attr 0
+ foreach field $path_options(-fields) {
+ if { [string match "input*" $field] } {
+ set report_input_pin 1
+ } elseif { [string match "hier*" $field] } {
+ set report_hier_pins 1
+ } elseif { [string match "cap*" $field] } {
+ set report_cap 1
+ } 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 "src*" $field] } {
+ set report_src_attr 1
+ } else {
+ sta_warn 166 "unknown field $field."
+ }
+ }
}
- set_report_path_fields $report_input_pin $report_net \
+ set_report_path_fields $report_input_pin $report_hier_pins $report_net \
$report_cap $report_slew $report_fanout $report_src_attr
set_report_path_no_split [info exists path_options(-no_line_splits)]
diff --git a/search/Sta.cc b/search/Sta.cc
index c0c40fa6..4369b258 100644
--- a/search/Sta.cc
+++ b/search/Sta.cc
@@ -2481,14 +2481,16 @@ Sta::setReportPathFieldOrder(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_src_attr)
{
- report_path_->setReportFields(report_input_pin, report_net, report_cap,
- report_slew, report_fanout, report_src_attr);
+ report_path_->setReportFields(report_input_pin, report_hier_pins, report_net,
+ report_cap, report_slew, report_fanout,
+ report_src_attr);
}
ReportField *