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 *