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..4f46ae8c 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/graph/Graph.i b/graph/Graph.i index 45fbeeeb..4fc6ec77 100644 --- a/graph/Graph.i +++ b/graph/Graph.i @@ -413,8 +413,8 @@ latch_d_to_q_en() { if (self->role() == TimingRole::latchDtoQ()) { Sta *sta = Sta::sta(); - const Network *network = sta->ensureLinked(); - const Graph *graph = sta->graph(); + const Network *network = sta->network(); + const Graph *graph = sta->ensureGraph(); Pin *from_pin = self->from(graph)->pin(); Instance *inst = network->instance(from_pin); LibertyCell *lib_cell = network->libertyCell(inst); diff --git a/include/sta/Sta.hh b/include/sta/Sta.hh index 13a57dfc..9f0503bb 100644 --- a/include/sta/Sta.hh +++ b/include/sta/Sta.hh @@ -112,6 +112,7 @@ public: bool infer_latches); bool setMinLibrary(const char *min_filename, const char *max_filename); + bool readVerilog(const char *filename); // Network readers call this to notify the Sta to delete any previously // linked network. void readNetlistBefore(); @@ -889,6 +890,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, @@ -1230,8 +1232,10 @@ public: void setTclInterp(Tcl_Interp *interp); Tcl_Interp *tclInterp(); - // Ensure a network has been read, linked and liberty libraries exist. + // Ensure a network has been read, and linked. Network *ensureLinked(); + // Ensure a network has been read, linked and liberty libraries exist. + Network *ensureLibLinked(); void ensureLevelized(); // Ensure that the timing graph has been built. Graph *ensureGraph(); diff --git a/network/Network.i b/network/Network.i index 2a7d7ee0..fcdb0034 100644 --- a/network/Network.i +++ b/network/Network.i @@ -618,13 +618,16 @@ void finish() { delete self; } } // LibraryIterator methods %extend Cell { -const char *name() { return Sta::sta()->ensureLinked()->name(self); } -Library *library() { return Sta::sta()->ensureLinked()->library(self); } -LibertyCell *liberty_cell() { return Sta::sta()->ensureLinked()->libertyCell(self); } -bool is_leaf() { return Sta::sta()->ensureLinked()->isLeaf(self); } +const char *name() { return Sta::sta()->cmdNetwork()->name(self); } +Library *library() { return Sta::sta()->cmdNetwork()->library(self); } +LibertyCell *liberty_cell() { return Sta::sta()->cmdNetwork()->libertyCell(self); } +bool is_leaf() { return Sta::sta()->cmdNetwork()->isLeaf(self); } CellPortIterator * -port_iterator() { return Sta::sta()->ensureLinked()->portIterator(self); } -string get_attribute(const char *key) { return Sta::sta()->ensureLinked()->getAttribute(self, key); } +port_iterator() { return Sta::sta()->cmdNetwork()->portIterator(self); } +string get_attribute(const char *key) +{ + return Sta::sta()->cmdNetwork()->getAttribute(self, key); +} Port * find_port(const char *name) @@ -654,7 +657,7 @@ void finish() { delete self; } %extend Port { const char *bus_name() { return Sta::sta()->ensureLinked()->busName(self); } Cell *cell() { return Sta::sta()->ensureLinked()->cell(self); } -LibertyPort *liberty_port() { return Sta::sta()->ensureLinked()->libertyPort(self); } +LibertyPort *liberty_port() { return Sta::sta()->ensureLibLinked()->libertyPort(self); } bool is_bus() { return Sta::sta()->ensureLinked()->isBus(self); } PortMemberIterator * member_iterator() { return Sta::sta()->ensureLinked()->memberIterator(self); } @@ -670,7 +673,7 @@ void finish() { delete self; } %extend Instance { Instance *parent() { return Sta::sta()->ensureLinked()->parent(self); } Cell *cell() { return Sta::sta()->ensureLinked()->cell(self); } -LibertyCell *liberty_cell() { return Sta::sta()->ensureLinked()->libertyCell(self); } +LibertyCell *liberty_cell() { return Sta::sta()->ensureLibLinked()->libertyCell(self); } bool is_leaf() { return Sta::sta()->ensureLinked()->isLeaf(self); } InstanceChildIterator * child_iterator() { return Sta::sta()->ensureLinked()->childIterator(self); } @@ -683,7 +686,10 @@ find_pin(const char *name) { return Sta::sta()->ensureLinked()->findPin(self, name); } -string get_attribute(const char *key) { return Sta::sta()->ensureLinked()->getAttribute(self, key); } +string get_attribute(const char *key) { + return Sta::sta()->ensureLinked()->getAttribute(self, key); +} + } // Instance methods %extend InstanceChildIterator { @@ -716,7 +722,7 @@ Instance *instance() { return Sta::sta()->ensureLinked()->instance(self); } Net *net() { return Sta::sta()->ensureLinked()->net(self); } Port *port() { return Sta::sta()->ensureLinked()->port(self); } Term *term() { return Sta::sta()->ensureLinked()->term(self); } -LibertyPort *liberty_port() { return Sta::sta()->ensureLinked()->libertyPort(self); } +LibertyPort *liberty_port() { return Sta::sta()->ensureLibLinked()->libertyPort(self); } bool is_driver() { return Sta::sta()->ensureLinked()->isDriver(self); } bool is_load() { return Sta::sta()->ensureLinked()->isLoad(self); } bool is_leaf() { return Sta::sta()->ensureLinked()->isLeaf(self); } @@ -768,7 +774,7 @@ capacitance(Corner *corner, const MinMax *min_max) { Sta *sta = Sta::sta(); - sta->ensureLinked(); + sta->ensureLibLinked(); float pin_cap, wire_cap; sta->connectedCap(self, corner, min_max, pin_cap, wire_cap); return pin_cap + wire_cap; @@ -779,7 +785,7 @@ pin_capacitance(Corner *corner, const MinMax *min_max) { Sta *sta = Sta::sta(); - sta->ensureLinked(); + sta->ensureLibLinked(); float pin_cap, wire_cap; sta->connectedCap(self, corner, min_max, pin_cap, wire_cap); return pin_cap; @@ -790,7 +796,7 @@ wire_capacitance(Corner *corner, const MinMax *min_max) { Sta *sta = Sta::sta(); - sta->ensureLinked(); + sta->ensureLibLinked(); float pin_cap, wire_cap; sta->connectedCap(self, corner, min_max, pin_cap, wire_cap); return wire_cap; diff --git a/power/Power.cc b/power/Power.cc index da8261ea..48554509 100644 --- a/power/Power.cc +++ b/power/Power.cc @@ -600,13 +600,16 @@ Power::evalBddActivity(DdNode *bdd, Cudd_RecursiveDeref(bdd_.cuddMgr(), diff); float var_act = var_activity.activity() * diff_duty; activity += var_act; - const Clock *clk = findClk(pin); - float clk_period = clk ? clk->period() : 1.0; - debugPrint(debug_, "power_activity", 3, "var %s %.3e * %.3f = %.3e", - port->name(), - var_activity.activity() / clk_period, - diff_duty, - var_act / clk_period); + if (debug_->check("power_activity", 3)) { + const Clock *clk = findClk(pin); + float clk_period = clk ? clk->period() : 1.0; + debugPrint(debug_, "power_activity", 3, "var %s%s %.3e * %.3f = %.3e", + port->name(), + clk ? "" : " (unclocked)", + var_activity.activity() / clk_period, + diff_duty, + var_act / clk_period); + } } } return activity; diff --git a/power/Power.i b/power/Power.i index ac3b6abc..016365fc 100644 --- a/power/Power.i +++ b/power/Power.i @@ -109,7 +109,7 @@ read_vcd_file(const char *filename, const char *scope) { Sta *sta = Sta::sta(); - sta->ensureLinked(); + sta->ensureLibLinked(); readVcdActivities(filename, scope, sta); } @@ -136,7 +136,7 @@ read_saif_file(const char *filename, const char *scope) { Sta *sta = Sta::sta(); - sta->ensureLinked(); + sta->ensureLibLinked(); return readSaif(filename, scope, sta); } diff --git a/power/Power.tcl b/power/Power.tcl index add027f7..a8fd9cef 100644 --- a/power/Power.tcl +++ b/power/Power.tcl @@ -271,6 +271,7 @@ proc set_power_activity { args } { ################################################################ +# Deprecated 9/2024 define_cmd_args "read_power_activities" { [-scope scope] -vcd filename } proc read_power_activities { args } { diff --git a/power/SaifReader.cc b/power/SaifReader.cc index 437c0be8..3dead669 100644 --- a/power/SaifReader.cc +++ b/power/SaifReader.cc @@ -89,6 +89,7 @@ SaifReader::read() // yyparse returns 0 on success. bool success = (::SaifParse_parse() == 0); gzclose(stream_); + report_->reportLine("Annotated %zu pin activities.", annotated_pins_.size()); return success; } else diff --git a/sdf/Sdf.i b/sdf/Sdf.i index dd3a0a2d..61e5dbac 100644 --- a/sdf/Sdf.i +++ b/sdf/Sdf.i @@ -51,7 +51,7 @@ read_sdf_file(const char *filename, MinMaxAllNull *cond_use) { Sta *sta = Sta::sta(); - sta->ensureLinked(); + sta->ensureLibLinked(); sta->ensureGraph(); if (stringEq(path, "")) path = NULL; @@ -72,7 +72,7 @@ report_annotated_delay_cmd(bool report_cells, bool report_constant_arcs) { Sta *sta = Sta::sta(); - sta->ensureLinked(); + sta->ensureLibLinked(); sta->ensureGraph(); reportAnnotatedDelay(report_cells, report_nets, report_in_ports, report_out_ports, @@ -95,7 +95,7 @@ report_annotated_check_cmd(bool report_setup, bool report_constant_arcs) { Sta *sta = Sta::sta(); - sta->ensureLinked(); + sta->ensureLibLinked(); sta->ensureGraph(); reportAnnotatedCheck(report_setup, report_hold, report_recovery, report_removal, @@ -116,7 +116,7 @@ write_sdf_cmd(char *filename, bool no_version) { Sta *sta = Sta::sta(); - sta->ensureLinked(); + sta->ensureLibLinked(); sta->writeSdf(filename, corner, divider, include_typ, digits, gzip, no_timestamp, no_version); } diff --git a/search/Property.cc b/search/Property.cc index 42f24e83..39562744 100644 --- a/search/Property.cc +++ b/search/Property.cc @@ -680,7 +680,7 @@ getProperty(const Library *lib, const char *property, Sta *sta) { - Network *network = sta->ensureLinked(); + Network *network = sta->cmdNetwork(); if (stringEqual(property, "name") || stringEqual(property, "full_name")) return PropertyValue(network->name(lib)); @@ -711,8 +711,8 @@ getProperty(const LibertyCell *cell, || stringEqual(property, "base_name")) return PropertyValue(cell->name()); else if (stringEqual(property, "full_name")) { - Network *network = sta->ensureLinked(); - auto lib = cell->libertyLibrary(); + Network *network = sta->cmdNetwork(); + LibertyLibrary *lib = cell->libertyLibrary(); string lib_name = lib->name(); string cell_name = cell->name(); string full_name = lib_name + network->pathDivider() + cell_name; @@ -741,7 +741,7 @@ getProperty(const Cell *cell, const char *property, Sta *sta) { - Network *network = sta->ensureLinked(); + Network *network = sta->cmdNetwork(); if (stringEqual(property, "name") || stringEqual(property, "base_name")) return PropertyValue(network->name(cell)); @@ -767,7 +767,7 @@ getProperty(const Port *port, const char *property, Sta *sta) { - Network *network = sta->ensureLinked(); + Network *network = sta->cmdNetwork(); if (stringEqual(property, "name") || stringEqual(property, "full_name")) return PropertyValue(network->name(port)); @@ -819,7 +819,7 @@ portSlewProperty(const Port *port, const MinMax *min_max, Sta *sta) { - Network *network = sta->ensureLinked(); + Network *network = sta->ensureLibLinked(); Instance *top_inst = network->topInstance(); Pin *pin = network->findPin(top_inst, port); return pinSlewProperty(pin, min_max, sta); @@ -831,7 +831,7 @@ portSlewProperty(const Port *port, const MinMax *min_max, Sta *sta) { - Network *network = sta->ensureLinked(); + Network *network = sta->ensureLibLinked(); Instance *top_inst = network->topInstance(); Pin *pin = network->findPin(top_inst, port); return pinSlewProperty(pin, rf, min_max, sta); @@ -842,7 +842,7 @@ portSlackProperty(const Port *port, const MinMax *min_max, Sta *sta) { - Network *network = sta->ensureLinked(); + Network *network = sta->ensureLibLinked(); Instance *top_inst = network->topInstance(); Pin *pin = network->findPin(top_inst, port); return pinSlackProperty(pin, min_max, sta); @@ -854,7 +854,7 @@ portSlackProperty(const Port *port, const MinMax *min_max, Sta *sta) { - Network *network = sta->ensureLinked(); + Network *network = sta->ensureLibLinked(); Instance *top_inst = network->topInstance(); Pin *pin = network->findPin(top_inst, port); return pinSlackProperty(pin, rf, min_max, sta); @@ -1075,7 +1075,7 @@ pinSlewProperty(const Pin *pin, const MinMax *min_max, Sta *sta) { - auto graph = sta->ensureGraph(); + Graph *graph = sta->ensureGraph(); Vertex *vertex, *bidirect_drvr_vertex; graph->pinVertices(pin, vertex, bidirect_drvr_vertex); Slew slew = min_max->initValue(); @@ -1098,7 +1098,7 @@ pinSlewProperty(const Pin *pin, const MinMax *min_max, Sta *sta) { - auto graph = sta->ensureGraph(); + Graph *graph = sta->ensureGraph(); Vertex *vertex, *bidirect_drvr_vertex; graph->pinVertices(pin, vertex, bidirect_drvr_vertex); Slew slew = min_max->initValue(); @@ -1139,7 +1139,7 @@ getProperty(Edge *edge, Sta *sta) { if (stringEqual(property, "full_name")) { - Network *network = sta->ensureLinked(); + Network *network = sta->cmdNetwork(); Graph *graph = sta->ensureGraph(); const char *from = edge->from(graph)->name(network); const char *to = edge->to(graph)->name(network); @@ -1177,7 +1177,7 @@ edgeDelayProperty(Edge *edge, for (TimingArc *arc : arc_set->arcs()) { RiseFall *to_rf = arc->toEdge()->asRiseFall(); if (to_rf == rf) { - for (auto corner : *sta->corners()) { + for (const Corner *corner : *sta->corners()) { DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max); ArcDelay arc_delay = sta->arcDelay(edge, arc, dcalc_ap); if (!delay_exists @@ -1204,9 +1204,9 @@ getProperty(TimingArcSet *arc_set, if (arc_set->isWire()) return PropertyValue("wire"); else { - auto from = arc_set->from()->name(); - auto to = arc_set->to()->name(); - auto cell_name = arc_set->libertyCell()->name(); + const char *from = arc_set->from()->name(); + const char *to = arc_set->to()->name(); + const char *cell_name = arc_set->libertyCell()->name(); string name; stringPrint(name, "%s %s -> %s", cell_name, from, to); return PropertyValue(name); @@ -1264,7 +1264,7 @@ getProperty(PathEnd *end, else if (stringEqual(property, "points")) { PathExpanded expanded(end->path(), sta); PathRefSeq paths; - for (auto i = expanded.startIndex(); i < expanded.size(); i++) { + for (size_t i = expanded.startIndex(); i < expanded.size(); i++) { const PathRef *path = expanded.path(i); paths.push_back(*path); } 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..5a231248 100644 --- a/search/Search.i +++ b/search/Search.i @@ -218,7 +218,7 @@ vertex_worst_arrival_path(Vertex *vertex, const MinMax *min_max) { Sta *sta = Sta::sta(); - sta->ensureLinked(); + sta->ensureLibLinked(); PathRef path = sta->vertexWorstArrivalPath(vertex, min_max); if (!path.isNull()) return new PathRef(path); @@ -232,7 +232,7 @@ vertex_worst_arrival_path_rf(Vertex *vertex, MinMax *min_max) { Sta *sta = Sta::sta(); - sta->ensureLinked(); + sta->ensureLibLinked(); PathRef path = sta->vertexWorstArrivalPath(vertex, rf, min_max); if (!path.isNull()) return new PathRef(path); @@ -245,7 +245,7 @@ vertex_worst_slack_path(Vertex *vertex, const MinMax *min_max) { Sta *sta = Sta::sta(); - sta->ensureLinked(); + sta->ensureLibLinked(); PathRef path = sta->vertexWorstSlackPath(vertex, min_max); if (!path.isNull()) return new PathRef(path); @@ -335,7 +335,7 @@ void report_loops() { Sta *sta = Sta::sta(); - Network *network = sta->ensureLinked(); + Network *network = sta->network(); Graph *graph = sta->ensureGraph(); Report *report = sta->report(); for (GraphLoop *loop : *sta->graphLoops()) { @@ -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, @@ -462,7 +464,7 @@ set_report_path_field_properties(const char *field_name, if (field) field->setProperties(title, width, left_justify); else - sta->report()->error(1575, "unknown report path field %s", field_name); + sta->report()->warn(1575, "unknown report path field %s", field_name); } void @@ -474,7 +476,7 @@ set_report_path_field_width(const char *field_name, if (field) field->setWidth(width); else - sta->report()->error(1576, "unknown report path field %s", field_name); + sta->report()->warn(1576, "unknown report path field %s", field_name); } void 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..cd56d3bf 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -723,6 +723,18 @@ Sta::setMinLibrary(const char *min_filename, return false; } +bool +Sta::readVerilog(const char *filename) +{ + NetworkReader *network = networkReader(); + if (network) { + readNetlistBefore(); + return readVerilogFile(filename, network); + } + else + return false; +} + void Sta::readNetlistBefore() { @@ -2109,7 +2121,7 @@ Sta::writeSdc(const char *filename, bool gzip, bool no_timestamp) { - ensureLinked(); + ensureLibLinked(); sta::writeSdc(network_->topInstance(), filename, "write_sdc", leaf, native, digits, gzip, no_timestamp, sdc_); } @@ -2481,14 +2493,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 * @@ -3310,7 +3324,7 @@ Sta::findDelays(Level level) void Sta::delayCalcPreamble() { - ensureLinked(); + ensureLibLinked(); ensureClkNetwork(); } @@ -3408,6 +3422,15 @@ Sta::vertexSlew(Vertex *vertex, // Throwing an error means the caller doesn't have to check the result. Network * Sta::ensureLinked() +{ + if (network_ == nullptr || !network_->isLinked()) + report_->error(1570, "No network has been linked."); + // Return cmd/sdc network. + return cmd_network_; +} + +Network * +Sta::ensureLibLinked() { if (network_ == nullptr || !network_->isLinked()) report_->error(1570, "No network has been linked."); @@ -3422,7 +3445,7 @@ Sta::ensureLinked() Graph * Sta::ensureGraph() { - ensureLinked(); + ensureLibLinked(); if (graph_ == nullptr && network_) { makeGraph(); // Update pointers to graph. @@ -3886,7 +3909,7 @@ Sta::readSpef(const char *filename, float coupling_cap_factor, bool reduce) { - ensureLinked(); + ensureLibLinked(); setParasiticAnalysisPts(corner != nullptr); const MinMax *ap_min_max = (min_max == MinMaxAll::all()) ? MinMax::max() @@ -3921,7 +3944,7 @@ void Sta::reportParasiticAnnotation(bool report_unannotated, const Corner *corner) { - ensureLinked(); + ensureLibLinked(); ensureGraph(); sta::reportParasiticAnnotation(report_unannotated, corner, this); } @@ -4768,7 +4791,7 @@ Sta::findRegisterOutputPins(ClockSet *clks, void Sta::findRegisterPreamble() { - ensureLinked(); + ensureLibLinked(); ensureGraph(); ensureGraphSdcAnnotated(); sim_->ensureConstantsPropagated(); @@ -5625,7 +5648,7 @@ Sta::writeTimingModel(const char *lib_name, const char *filename, const Corner *corner) { - ensureLinked(); + ensureLibLinked(); ensureGraph(); LibertyLibrary *library = makeTimingModel(lib_name, cell_name, filename, corner, this); @@ -5637,7 +5660,7 @@ Sta::writeTimingModel(const char *lib_name, void Sta::powerPreamble() { - ensureLinked(); + ensureLibLinked(); // Use arrivals to find clocking info. searchPreamble(); search_->findAllArrivals(); @@ -5685,7 +5708,7 @@ Sta::writePathSpice(PathRef *path, const char *gnd_name, CircuitSim ckt_sim) { - ensureLinked(); + ensureLibLinked(); sta::writePathSpice(path, spice_filename, subckt_filename, lib_subckt_filename, model_filename, power_name, gnd_name, ckt_sim, this); diff --git a/verilog/Verilog.i b/verilog/Verilog.i index e250545c..0101a2fe 100644 --- a/verilog/Verilog.i +++ b/verilog/Verilog.i @@ -32,14 +32,7 @@ using sta::readVerilogFile; bool read_verilog_cmd(const char *filename) { - Sta *sta = Sta::sta(); - NetworkReader *network = sta->networkReader(); - if (network) { - sta->readNetlistBefore(); - return readVerilogFile(filename, network); - } - else - return false; + return Sta::sta()->readVerilog(filename); } void @@ -54,9 +47,9 @@ write_verilog_cmd(const char *filename, bool include_pwr_gnd, CellSeq *remove_cells) { + Sta *sta = Sta::sta(); // This does NOT want the SDC (cmd) network because it wants // to see the sta internal names. - Sta *sta = Sta::sta(); Network *network = sta->network(); writeVerilog(filename, sort, include_pwr_gnd, remove_cells, network); delete remove_cells; diff --git a/verilog/VerilogReader.cc b/verilog/VerilogReader.cc index f5ff7615..4a4858ea 100644 --- a/verilog/VerilogReader.cc +++ b/verilog/VerilogReader.cc @@ -35,7 +35,7 @@ VerilogParse_parse(); namespace sta { VerilogReader *verilog_reader; -static const char *unconnected_net_name = reinterpret_cast(1); +const char *VerilogReader::unconnected_net_name_ = reinterpret_cast(1); static string verilogBusBitName(const char *bus_name, @@ -156,12 +156,8 @@ VerilogReader::~VerilogReader() void VerilogReader::deleteModules() { - StringSet filenames; - for (const auto [name, module] : module_map_) { - filenames.insert(module->filename()); + for (const auto [name, module] : module_map_) delete module; - } - deleteContents(&filenames); module_map_.clear(); } @@ -187,7 +183,8 @@ void VerilogReader::init(const char *filename) { // Statements point to verilog_filename, so copy it. - filename_ = stringCopy(filename); + filename_ = filename; + filenames_.push_back(filename); line_ = 1; library_ = network_->findLibrary("verilog"); @@ -267,12 +264,11 @@ VerilogReader::makeModule(const char *module_vname, VerilogModule *module = new VerilogModule(module_name.c_str(), ports, stmts, attribute_stmts, filename_, line, this); - cell = network_->makeCell(library_, module_name.c_str(), false, filename_); + cell = network_->makeCell(library_, module_name.c_str(), false, filename_.c_str()); for (VerilogAttributeStmt *stmt : *attribute_stmts) { - for (VerilogAttributeEntry *entry : *stmt->attribute_sequence()) { + for (VerilogAttributeEntry *entry : *stmt->attribute_sequence()) network_->setAttribute(cell, entry->key(), entry->value()); - } } module_map_[cell] = module; @@ -582,10 +578,10 @@ VerilogReader::makeModuleInst(const char *module_vname, int pin_index = lport->pinIndex(); const char *prev_net_name = net_names[pin_index]; if (prev_net_name - && prev_net_name !=unconnected_net_name) + && prev_net_name != unconnected_net_name_) // Repeated port reference. stringDelete(prev_net_name); - net_names[pin_index]=(net_name == nullptr) ? unconnected_net_name : net_name; + net_names[pin_index]=(net_name == nullptr) ? unconnected_net_name_ : net_name; delete vpin; net_port_ref_scalar_net_count_--; } @@ -841,7 +837,7 @@ VerilogModule::VerilogModule(const char *name, VerilogNetSeq *ports, VerilogStmtSeq *stmts, VerilogAttributeStmtSeq *attribute_stmts, - const char *filename, + string &filename, int line, VerilogReader *reader) : VerilogStmt(line), @@ -908,7 +904,7 @@ VerilogModule::parseDcl(VerilogDcl *dcl, dcl_map_[net_name] = dcl; else if (!dcl->direction()->isInternal()) { string net_vname = reader->netVerilogName(net_name); - reader->warn(1395, filename_, dcl->line(), + reader->warn(1395, filename_.c_str(), dcl->line(), "signal %s previously declared on line %d.", net_vname.c_str(), existing_dcl->line()); @@ -937,7 +933,7 @@ VerilogModule::checkInstanceName(VerilogInst *inst, replacement_name = stringPrint("%s_%d", inst_name, i++); } while (inst_names.findKey(replacement_name)); string inst_vname = reader->instanceVerilogName(inst_name); - reader->warn(1396, filename_, inst->line(), + reader->warn(1396, filename_.c_str(), inst->line(), "instance name %s duplicated - renamed to %s.", inst_vname.c_str(), replacement_name); @@ -1035,8 +1031,7 @@ VerilogLibertyInst::~VerilogLibertyInst() int port_count = cell_->portBitCount(); for (int i = 0; i < port_count; i++) { const char *net_name = net_names_[i]; - if (net_name - && net_name != unconnected_net_name) + if (net_name != VerilogReader::unconnected_net_name_) stringDelete(net_name); } delete [] net_names_; @@ -1937,7 +1932,7 @@ VerilogReader::makeModuleInstNetwork(VerilogModuleInst *mod_inst, cell = network_->cell(lib_cell); Instance *inst = network_->makeInstance(cell, mod_inst->instanceName(), parent); - VerilogAttributeStmtSeq *attribute_stmts = mod_inst->attribute_stmts(); + VerilogAttributeStmtSeq *attribute_stmts = mod_inst->attributeStmts(); for (VerilogAttributeStmt *stmt : *attribute_stmts) { for (VerilogAttributeEntry *entry : *stmt->attribute_sequence()) { network_->setAttribute(inst, entry->key(), entry->value()); @@ -2129,7 +2124,7 @@ VerilogReader::makeLibertyInst(VerilogLibertyInst *lib_inst, Cell *cell = reinterpret_cast(lib_cell); Instance *inst = network_->makeInstance(cell, lib_inst->instanceName(), parent); - VerilogAttributeStmtSeq *attribute_stmts = lib_inst->attribute_stmts(); + VerilogAttributeStmtSeq *attribute_stmts = lib_inst->attributeStmts(); for (VerilogAttributeStmt *stmt : *attribute_stmts) { for (VerilogAttributeEntry *entry : *stmt->attribute_sequence()) { network_->setAttribute(inst, entry->key(), entry->value()); @@ -2144,7 +2139,7 @@ VerilogReader::makeLibertyInst(VerilogLibertyInst *lib_inst, if (net_name) { Net *net = nullptr; // If the pin is unconnected (ie, .A()) make the pin but not the net. - if (net_name != unconnected_net_name) { + if (net_name != unconnected_net_name_) { VerilogDcl *dcl = parent_module->declaration(net_name); // Check for single bit bus reference .A(BUS) -> .A(BUS[LSB]). if (dcl && dcl->isBus()) { diff --git a/verilog/VerilogReaderPvt.hh b/verilog/VerilogReaderPvt.hh index ea9f857c..852f7fd1 100644 --- a/verilog/VerilogReaderPvt.hh +++ b/verilog/VerilogReaderPvt.hh @@ -33,6 +33,7 @@ VerilogParse_error(const char *msg); namespace sta { using std::string; +using std::vector; using std::set; class Debug; @@ -158,7 +159,7 @@ public: bool make_black_boxes, Report *report); int line() const { return line_; } - const char *filename() const { return filename_; } + const char *filename() const { return filename_.c_str(); } void incrLine(); Report *report() const { return report_; } void error(int id, @@ -181,6 +182,7 @@ public: instanceVerilogName(const char *inst_name); string netVerilogName(const char *net_name); + static const char *unconnected_net_name_; protected: void init(const char *filename); @@ -279,7 +281,8 @@ protected: Debug *debug_; NetworkReader *network_; - const char *filename_; + string filename_; + vector filenames_; int line_; gzFile stream_; @@ -340,13 +343,13 @@ public: VerilogNetSeq *ports, VerilogStmtSeq *stmts, VerilogAttributeStmtSeq *attribute_stmts, - const char *filename, + string &filename, int line, VerilogReader *reader); virtual ~VerilogModule(); const char *name() { return name_; } - const char *filename() { return filename_; } - VerilogAttributeStmtSeq *attribute_stmts() { return attribute_stmts_; } + const char *filename() { return filename_.c_str(); } + VerilogAttributeStmtSeq *attributeStmts() { return attribute_stmts_; } VerilogNetSeq *ports() { return ports_; } VerilogDcl *declaration(const char *net_name); VerilogStmtSeq *stmts() { return stmts_; } @@ -361,7 +364,7 @@ private: VerilogReader *reader); const char *name_; - const char *filename_; + string &filename_; VerilogNetSeq *ports_; VerilogStmtSeq *stmts_; VerilogDclMap dcl_map_; @@ -461,7 +464,7 @@ public: virtual ~VerilogInst(); virtual bool isInstance() const { return true; } const char *instanceName() const { return inst_name_; } - VerilogAttributeStmtSeq *attribute_stmts() const { return attribute_stmts_; } + VerilogAttributeStmtSeq *attributeStmts() const { return attribute_stmts_; } void setInstanceName(const char *inst_name); private: