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:
|