diff --git a/include/sta/Liberty.hh b/include/sta/Liberty.hh index b98af125..7ebdc882 100644 --- a/include/sta/Liberty.hh +++ b/include/sta/Liberty.hh @@ -47,8 +47,9 @@ class InternalPowerAttrs; class LibertyPgPort; class StaState; class Corner; +class Corners; +class DcalcAnalysisPt; -typedef Set LibrarySet; typedef Map TableTemplateMap; typedef Vector TableTemplateSeq; typedef Map BusDclMap; @@ -295,6 +296,10 @@ public: bool link, int ap_index, Report *report); + static void + checkCorners(LibertyCell *cell, + Corners *corners, + Report *report); protected: float degradeWireSlew(const LibertyCell *cell, @@ -446,8 +451,8 @@ public: bool isDisabledConstraint() const { return is_disabled_constraint_; } LibertyCell *cornerCell(const Corner *corner, const MinMax *min_max); - const LibertyCell *cornerCell(const Corner *corner, - const MinMax *min_max) const; + LibertyCell *cornerCell(const DcalcAnalysisPt *dcalc_ap); + LibertyCell *cornerCell(int ap_index); // AOCV float ocvArcDepth() const; @@ -493,6 +498,9 @@ public: void bufferPorts(// Return values. LibertyPort *&input, LibertyPort *&output) const; + // Check all liberty cells to make sure they exist + // for all the defined corners. + static void checkLibertyCorners(); protected: void addPort(ConcretePort *port); @@ -519,6 +527,8 @@ protected: const LibertyPort *output) const; bool hasInverterFunc(const LibertyPort *input, const LibertyPort *output) const; + bool checkCornerCell(const Corner *corner, + const MinMax *min_max) const; LibertyLibrary *liberty_library_; float area_; @@ -720,6 +730,10 @@ public: const MinMax *min_max); const LibertyPort *cornerPort(const Corner *corner, const MinMax *min_max) const; + LibertyPort *cornerPort(const DcalcAnalysisPt *dcalc_ap); + const LibertyPort *cornerPort(const DcalcAnalysisPt *dcalc_ap) const; + LibertyPort *cornerPort(int ap_index); + const LibertyPort *cornerPort(int ap_index) const; void setCornerPort(LibertyPort *corner_port, int ap_index); const char *relatedGroundPin() const { return related_ground_pin_; } diff --git a/include/sta/Network.hh b/include/sta/Network.hh index e209f898..ec399403 100644 --- a/include/sta/Network.hh +++ b/include/sta/Network.hh @@ -127,6 +127,11 @@ public: // This corresponds to a link_path of '*'. LibertyLibrary *defaultLibertyLibrary() const; void setDefaultLibertyLibrary(LibertyLibrary *library); + // Check liberty cells used by the network to make sure they exist + // for all the defined corners. + void checkNetworkLibertyCorners(); + // Check liberty cells to make sure they exist for all the defined corners. + void checkLibertyCorners(); //////////////////////////////////////////////////////////////// // Cell functions. @@ -514,7 +519,6 @@ public: virtual void mergeInto(Net *net, Net *into_net) = 0; virtual Net *mergedInto(Net *net) = 0; - }; // Network API to support the Parallax readers. diff --git a/liberty/Liberty.cc b/liberty/Liberty.cc index e8de116e..e87ba253 100644 --- a/liberty/Liberty.cc +++ b/liberty/Liberty.cc @@ -37,11 +37,10 @@ #include "Network.hh" #include "PortDirection.hh" #include "Corner.hh" +#include "DcalcAnalysisPt.hh" namespace sta { -typedef Set TimingModelSet; -typedef Set FuncExprSet; typedef Set LatchEnableSet; void @@ -783,6 +782,23 @@ LibertyLibrary::makeCornerMap(LibertyCell *cell1, } } +void +LibertyLibrary::checkCorners(LibertyCell *cell, + Corners *corners, + Report *report) +{ + for (const Corner *corner : *corners) { + for (auto min_max : MinMax::range()) { + if (!cell->checkCornerCell(corner, min_max)) + report->error(705, "Liberty cell %s/%s for corner %s/%s not found", + cell->libertyLibrary()->name(), + cell->name(), + corner->name(), + min_max->asString()); + } + } +} + //////////////////////////////////////////////////////////////// float @@ -1502,25 +1518,34 @@ LibertyCell * LibertyCell::cornerCell(const Corner *corner, const MinMax *min_max) { - if (corner_cells_.empty()) - return this; - else { - int ap_index = corner->libertyIndex(min_max); - return corner_cells_[ap_index]; - } + return cornerCell(corner->libertyIndex(min_max)); } -const LibertyCell * -LibertyCell::cornerCell(const Corner *corner, - const MinMax *min_max) const +LibertyCell * +LibertyCell::cornerCell(const DcalcAnalysisPt *dcalc_ap) +{ + return cornerCell(dcalc_ap->libertyIndex()); +} + +LibertyCell * +LibertyCell::cornerCell(int ap_index) { if (corner_cells_.empty()) return this; - else { - int ap_index = corner->libertyIndex(min_max); + else if (ap_index < static_cast(corner_cells_.size())) return corner_cells_[ap_index]; - } + else + return nullptr; +} +bool +LibertyCell::checkCornerCell(const Corner *corner, + const MinMax *min_max) const +{ + int lib_index = corner->libertyIndex(min_max); + return corner_cells_.empty() + || (lib_index <= static_cast(corner_cells_.size()) + && corner_cells_[lib_index]); } void @@ -2344,24 +2369,48 @@ LibertyPort * LibertyPort::cornerPort(const Corner *corner, const MinMax *min_max) { - if (corner_ports_.empty()) - return this; - else { - int ap_index = corner->libertyIndex(min_max); - return corner_ports_[ap_index]; - } + return cornerPort(corner->libertyIndex(min_max)); } const LibertyPort * LibertyPort::cornerPort(const Corner *corner, const MinMax *min_max) const +{ + return cornerPort(corner->libertyIndex(min_max)); +} + +LibertyPort * +LibertyPort::cornerPort(const DcalcAnalysisPt *dcalc_ap) +{ + return cornerPort(dcalc_ap->libertyIndex()); +} + +const LibertyPort * +LibertyPort::cornerPort(const DcalcAnalysisPt *dcalc_ap) const +{ + return cornerPort(dcalc_ap->libertyIndex()); +} + +LibertyPort * +LibertyPort::cornerPort(int ap_index) { if (corner_ports_.empty()) return this; - else { - int ap_index = corner->libertyIndex(min_max); + else if (ap_index < static_cast(corner_ports_.size())) return corner_ports_[ap_index]; - } + else + return nullptr; +} + +const LibertyPort * +LibertyPort::cornerPort(int ap_index) const +{ + if (corner_ports_.empty()) + return this; + else if (ap_index < static_cast(corner_ports_.size())) + return corner_ports_[ap_index]; + else + return nullptr; } void diff --git a/network/ConcreteNetwork.cc b/network/ConcreteNetwork.cc index a5b4e276..825f322d 100644 --- a/network/ConcreteNetwork.cc +++ b/network/ConcreteNetwork.cc @@ -1849,6 +1849,8 @@ ConcreteNetwork::linkNetwork(const char *top_cell_name, clearConstantNets(); deleteTopInstance(); top_instance_ = link_func_(top_cell_name, make_black_boxes, report, this); + if (top_instance_) + checkNetworkLibertyCorners(); return top_instance_ != nullptr; } else { diff --git a/network/Network.cc b/network/Network.cc index 07753312..da692e11 100644 --- a/network/Network.cc +++ b/network/Network.cc @@ -21,6 +21,7 @@ #include "PatternMatch.hh" #include "Liberty.hh" #include "PortDirection.hh" +#include "Corner.hh" namespace sta { @@ -94,6 +95,47 @@ Network::setDefaultLibertyLibrary(LibertyLibrary *library) default_liberty_ = library; } +void +Network::checkLibertyCorners() +{ + if (corners_->count() > 1) { + LibertyLibraryIterator *lib_iter = libertyLibraryIterator(); + LibertyCellSet cells; + while (lib_iter->hasNext()) { + LibertyLibrary *lib = lib_iter->next(); + LibertyCellIterator cell_iter(lib); + while (cell_iter.hasNext()) { + LibertyCell *cell = cell_iter.next(); + LibertyCell *link_cell = findLibertyCell(cell->name()); + cells.insert(link_cell); + } + } + delete lib_iter; + + for (LibertyCell *cell : cells) + LibertyLibrary::checkCorners(cell, corners_, report_); + } +} + +void +Network::checkNetworkLibertyCorners() +{ + if (corners_->count() > 1) { + LibertyCellSet network_cells; + LeafInstanceIterator *leaf_iter = network_->leafInstanceIterator(); + while (leaf_iter->hasNext()) { + const Instance *inst = leaf_iter->next(); + LibertyCell *cell = libertyCell(inst); + if (cell) + network_cells.insert(cell); + } + delete leaf_iter; + + for (LibertyCell *cell : network_cells) + LibertyLibrary::checkCorners(cell, corners_, report_); + } +} + // Only used by Sta::setMinLibrary so linear search is acceptable. LibertyLibrary * Network::findLibertyFilename(const char *filename) diff --git a/search/Power.cc b/search/Power.cc index feae79d7..ea4e91ef 100644 --- a/search/Power.cc +++ b/search/Power.cc @@ -784,9 +784,8 @@ Power::findOutputInternalPower(const Pin *to_pin, cell->name()); const DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(MinMax::max()); const Pvt *pvt = dcalc_ap->operatingConditions(); - const MinMax *min_max = MinMax::max(); - LibertyCell *corner_cell = cell->cornerCell(corner, min_max); - const LibertyPort *to_corner_port = to_port->cornerPort(corner, min_max); + LibertyCell *corner_cell = cell->cornerCell(dcalc_ap); + const LibertyPort *to_corner_port = to_port->cornerPort(dcalc_ap); debugPrint(debug_, "power", 2, " cap = %s", units_->capacitanceUnit()->asString(load_cap)); FuncExpr *func = to_port->function(); @@ -999,7 +998,7 @@ Power::findSwitchingPower(LibertyCell *cell, { MinMax *mm = MinMax::max(); const DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(mm); - LibertyCell *corner_cell = cell->cornerCell(corner, MinMax::max()); + LibertyCell *corner_cell = cell->cornerCell(dcalc_ap); float volt = portVoltage(corner_cell, to_port, dcalc_ap); float switching = .5 * load_cap * volt * volt * activity.activity(); debugPrint(debug_, "power", 2, "switching %s/%s activity = %.2e volt = %.2f %.3e",