diff --git a/CMakeLists.txt b/CMakeLists.txt index d2f6f380..b123b788 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ cmake_minimum_required (VERSION 3.9) -project(STA VERSION 2.0.12) +project(STA VERSION 2.0.13) set(CMAKE_VERBOSE_MAKEFILE ON) set(CMAKE_CXX_STANDARD 11) diff --git a/dcalc/DcalcAnalysisPt.cc b/dcalc/DcalcAnalysisPt.cc index 40cb59c3..ab6e7f43 100644 --- a/dcalc/DcalcAnalysisPt.cc +++ b/dcalc/DcalcAnalysisPt.cc @@ -16,6 +16,7 @@ #include "Machine.hh" #include "StringUtil.hh" +#include "Corner.hh" #include "DcalcAnalysisPt.hh" namespace sta { @@ -23,19 +24,13 @@ namespace sta { DcalcAnalysisPt::DcalcAnalysisPt(Corner *corner, DcalcAPIndex index, const OperatingConditions *op_cond, - const MinMax *cnst_min_max, - const MinMax *delay_min_max, - const MinMax *slew_min_max, - const MinMax *check_clk_slew_min_max, - const ParasiticAnalysisPt *parasitic_ap) : + const MinMax *min_max, + const MinMax *check_clk_slew_min_max) : corner_(corner), index_(index), op_cond_(op_cond), - cnst_min_max_(cnst_min_max), - delay_min_max_(delay_min_max), - slew_min_max_(slew_min_max), - check_clk_slew_min_max_(check_clk_slew_min_max), - parasitic_ap_(parasitic_ap) + min_max_(min_max), + check_clk_slew_min_max_(check_clk_slew_min_max) { } @@ -45,11 +40,10 @@ DcalcAnalysisPt::setOperatingConditions(const OperatingConditions *op_cond) op_cond_ = op_cond; } -void -DcalcAnalysisPt:: -setParasiticAnalysisPt(const ParasiticAnalysisPt *parasitic_ap) +ParasiticAnalysisPt * +DcalcAnalysisPt::parasiticAnalysisPt() const { - parasitic_ap_ = parasitic_ap; + return corner_->findParasiticAnalysisPt(min_max_); } void diff --git a/dcalc/DcalcAnalysisPt.hh b/dcalc/DcalcAnalysisPt.hh index 907550c7..90046dd0 100644 --- a/dcalc/DcalcAnalysisPt.hh +++ b/dcalc/DcalcAnalysisPt.hh @@ -39,11 +39,8 @@ public: DcalcAnalysisPt(Corner *corner, DcalcAPIndex index, const OperatingConditions *op_cond, - const MinMax *cnst_min_max, - const MinMax *delay_min_max, - const MinMax *slew_min_max, - const MinMax *check_clk_slew_min_max, - const ParasiticAnalysisPt *parasitic_ap); + const MinMax *min_max, + const MinMax *check_clk_slew_min_max); Corner *corner() const { return corner_; } // Which of the delay_count results this analysis point corresponds to. DcalcAPIndex index() const { return index_; } @@ -54,16 +51,15 @@ public: // Slew min/max of timing check clock. const MinMax *checkClkSlewMinMax() const { return check_clk_slew_min_max_; } // Constraint min/max values to use. - const MinMax *constraintMinMax() const { return cnst_min_max_; } + const MinMax *constraintMinMax() const { return min_max_; } // Constraints::operatingCondition(cnst_min_max_) const OperatingConditions *operatingConditions() const { return op_cond_; } void setOperatingConditions(const OperatingConditions *op_cond); // Delay merging min/max operator (for wires). - const MinMax *delayMinMax() const { return delay_min_max_; } + const MinMax *delayMinMax() const { return min_max_; } // Merge min/max slews across timing arcs. - const MinMax *slewMinMax() const { return slew_min_max_; } - const ParasiticAnalysisPt *parasiticAnalysisPt()const{return parasitic_ap_;} - void setParasiticAnalysisPt(const ParasiticAnalysisPt *parasitic_ap); + const MinMax *slewMinMax() const { return min_max_; } + ParasiticAnalysisPt *parasiticAnalysisPt() const; void setCheckClkSlewIndex(DcalcAPIndex index); int libertyIndex() const; @@ -74,11 +70,8 @@ private: DcalcAPIndex index_; DcalcAPIndex check_clk_slew_index_; const OperatingConditions *op_cond_; - const MinMax *cnst_min_max_; - const MinMax *delay_min_max_; - const MinMax *slew_min_max_; + const MinMax *min_max_; const MinMax *check_clk_slew_min_max_; - const ParasiticAnalysisPt *parasitic_ap_; }; } // namespace diff --git a/liberty/Liberty.cc b/liberty/Liberty.cc index 8e564fc7..808e58c4 100644 --- a/liberty/Liberty.cc +++ b/liberty/Liberty.cc @@ -848,7 +848,8 @@ LibertyCell::LibertyCell(LibertyLibrary *library, ocv_arc_depth_(0.0), ocv_derate_(nullptr), is_disabled_constraint_(false), - leakage_power_(0.0) + leakage_power_(0.0), + leakage_power_exists_(false) { } @@ -1081,6 +1082,16 @@ void LibertyCell::setLeakagePower(float leakage) { leakage_power_ = leakage; + leakage_power_exists_ = true; +} + +void +LibertyCell::leakagePower(// Return values. + float &leakage, + bool &exists) const +{ + leakage = leakage_power_; + exists = leakage_power_exists_; } void diff --git a/liberty/Liberty.hh b/liberty/Liberty.hh index a1f49caf..b2f9808c 100644 --- a/liberty/Liberty.hh +++ b/liberty/Liberty.hh @@ -429,7 +429,10 @@ public: bool hasTimingArcs(LibertyPort *port) const; InternalPowerSeq *internalPowers() { return &internal_powers_; } LeakagePowerSeq *leakagePowers() { return &leakage_powers_; } - float leakagePower() const { return leakage_power_; } + void leakagePower(// Return values. + float &leakage, + bool &exists) const; + bool leakagePowerEx() const { return leakage_power_exists_; } bool hasSequentials() const; void makeSequential(int size, bool is_register, @@ -537,6 +540,7 @@ protected: bool is_disabled_constraint_; Vector corner_cells_; float leakage_power_; + bool leakage_power_exists_; LibertyPgPortMap pg_port_map_; private: diff --git a/parasitics/EstimateParasitics.cc b/parasitics/EstimateParasitics.cc index 17e6bfdf..e9931d7f 100644 --- a/parasitics/EstimateParasitics.cc +++ b/parasitics/EstimateParasitics.cc @@ -193,9 +193,17 @@ EstimateParasitics::estimatePiElmoreBalanced(const Pin *drvr_pin, } delete load_iter; - c1 = static_cast(y2 * y2 / y3); - c2 = static_cast(y1 - y2 * y2 / y3); - rpi = static_cast(-y3 * y3 / (y2 * y2 * y2)); + if (y3 == 0) { + // No loads. + c1 = 0.0; + c2 = 0.0; + rpi = 0.0; + } + else { + c1 = static_cast(y2 * y2 / y3); + c2 = static_cast(y1 - y2 * y2 / y3); + rpi = static_cast(-y3 * y3 / (y2 * y2 * y2)); + } elmore_res = static_cast(res_fanout); elmore_cap = static_cast(cap_fanout); elmore_use_load_cap = true; diff --git a/sdc/DisabledPorts.cc b/sdc/DisabledPorts.cc index 6dfa1278..1fcfaff8 100644 --- a/sdc/DisabledPorts.cc +++ b/sdc/DisabledPorts.cc @@ -253,7 +253,8 @@ LibertyPortPairNameLess::operator()(const LibertyPortPair *pair1, } void -sortLibertyPortPairSet(LibertyPortPairSet *sets, LibertyPortPairSeq &pairs) +sortLibertyPortPairSet(LibertyPortPairSet *sets, + LibertyPortPairSeq &pairs) { LibertyPortPairSet::Iterator pair_iter(sets); while (pair_iter.hasNext()) diff --git a/sdc/DisabledPorts.hh b/sdc/DisabledPorts.hh index d75d8063..c1b7734b 100644 --- a/sdc/DisabledPorts.hh +++ b/sdc/DisabledPorts.hh @@ -105,7 +105,8 @@ sortDisabledInstancePortsMap(DisabledInstancePortsMap *inst_map, Network *network, DisabledInstancePortsSeq &disables); void -sortLibertyPortPairSet(LibertyPortPairSet *sets, LibertyPortPairSeq &pairs); +sortLibertyPortPairSet(LibertyPortPairSet *sets, + LibertyPortPairSeq &pairs); } // namespace #endif diff --git a/search/Corner.cc b/search/Corner.cc index 1ecf5306..3907168b 100644 --- a/search/Corner.cc +++ b/search/Corner.cc @@ -24,24 +24,23 @@ namespace sta { Corners::Corners(StaState *sta) : - StaState(sta), - default_corner_(nullptr) + StaState(sta) { } Corners::~Corners() { clear(); - parasitic_analysis_pts_.deleteContentsClear(); } void Corners::clear() { corners_.deleteContentsClear(); + corner_map_.clear(); dcalc_analysis_pts_.deleteContentsClear(); path_analysis_pts_.deleteContentsClear(); - default_corner_ = nullptr; + parasitic_analysis_pts_.deleteContentsClear(); } int @@ -59,13 +58,13 @@ Corners::multiCorner() const Corner * Corners::findCorner(const char *corner_name) { - return corners_.findKey(corner_name); + return corner_map_.findKey(corner_name); } Corner * -Corners::defaultCorner() +Corners::findCorner(int corner_index) { - return default_corner_; + return corners_[corner_index]; } void @@ -96,10 +95,9 @@ Corners::makeCorners(StringSet *corner_names) while (name_iter.hasNext()) { const char *name = name_iter.next(); Corner *corner = new Corner(name, index); + corners_.push_back(corner); // Use the copied name in the map. - corners_[corner->name()] = corner; - if (default_corner_ == nullptr) - default_corner_ = corner; + corner_map_[corner->name()] = corner; index++; } updateCornerParasiticAnalysisPts(); @@ -142,11 +140,11 @@ Corners::makeParasiticAnalysisPtsMinMax() void Corners::updateCornerParasiticAnalysisPts() { - CornerMap::Iterator corner_iter(corners_); + CornerSeq::Iterator corner_iter(corners_); while (corner_iter.hasNext()) { Corner *corner = corner_iter.next(); corner->setParasiticAnalysisPtcount(parasitic_analysis_pts_.size()); - ParasiticAnalysisPtIterator ap_iter(this); + ParasiticAnalysisPtSeq::Iterator ap_iter(parasitic_analysis_pts_); while (ap_iter.hasNext()) { ParasiticAnalysisPt *ap = ap_iter.next(); corner->addParasiticAP(ap); @@ -160,7 +158,7 @@ Corners::makeAnalysisPts() dcalc_analysis_pts_.deleteContentsClear(); path_analysis_pts_.deleteContentsClear(); - CornerMap::Iterator corner_iter(corners_); + CornerSeq::Iterator corner_iter(corners_); while (corner_iter.hasNext()) { Corner *corner = corner_iter.next(); makeDcalcAnalysisPts(corner); @@ -200,13 +198,10 @@ Corners::makeDcalcAnalysisPt(Corner *corner, const MinMax *check_clk_slew_min_max) { OperatingConditions *op_cond = sdc_->operatingConditions(min_max); - ParasiticAnalysisPt *parasitic_ap = corner->findParasiticAnalysisPt(min_max); DcalcAnalysisPt *dcalc_ap = new DcalcAnalysisPt(corner, dcalc_analysis_pts_.size(), op_cond, min_max, - min_max, min_max, - check_clk_slew_min_max, - parasitic_ap); + check_clk_slew_min_max); dcalc_analysis_pts_.push_back(dcalc_ap); corner->addDcalcAP(dcalc_ap); return dcalc_ap; diff --git a/search/Corner.hh b/search/Corner.hh index b1607cb4..540ba442 100644 --- a/search/Corner.hh +++ b/search/Corner.hh @@ -34,6 +34,7 @@ class Corner; class Corners; class LibertyLibrary; +typedef Vector CornerSeq; typedef Map CornerMap; typedef Vector ParasiticAnalysisPtSeq; typedef Vector DcalcAnalysisPtSeq; @@ -49,7 +50,7 @@ public: int count() const; bool multiCorner() const; Corner *findCorner(const char *corner); - Corner *defaultCorner(); + Corner *findCorner(int corner_index); void makeCorners(StringSet *corner_names); void analysisTypeChanged(); void operatingConditionsChanged(); @@ -80,11 +81,11 @@ protected: bool swap_clk_min_max, DcalcAnalysisPt *dcalc_ap_min, DcalcAnalysisPt *dcalc_ap_max); - CornerMap &corners() { return corners_; } + CornerSeq &corners() { return corners_; } private: - CornerMap corners_; - Corner *default_corner_; + CornerMap corner_map_; + CornerSeq corners_; ParasiticAnalysisPtSeq parasitic_analysis_pts_; DcalcAnalysisPtSeq dcalc_analysis_pts_; PathAnalysisPtSeq path_analysis_pts_; @@ -137,7 +138,7 @@ public: virtual Corner *next(); protected: - CornerMap::ConstIterator iter_; + CornerSeq::ConstIterator iter_; private: DISALLOW_COPY_AND_ASSIGN(CornerIterator); diff --git a/search/Power.cc b/search/Power.cc index 6d6a08f0..88e48618 100644 --- a/search/Power.cc +++ b/search/Power.cc @@ -252,29 +252,59 @@ Power::loadCap(const Pin *to_pin, } void -Power::findLeakagePower(const Instance *inst, +Power::findLeakagePower(const Instance *, LibertyCell *cell, // Return values. PowerResult &result) { - float leakage = cell->leakagePower(); + float cond_leakage = 0.0; + bool found_cond = false; + float default_leakage = 0.0; + bool found_default = false; LibertyCellLeakagePowerIterator pwr_iter(cell); while (pwr_iter.hasNext()) { LeakagePower *leak = pwr_iter.next(); FuncExpr *when = leak->when(); if (when) { - LogicValue when_value = sim_->evalExpr(when, inst); - switch (when_value) { - case LogicValue::zero: - case LogicValue::one: - leakage = max(leakage, leak->power()); - break; - case LogicValue::unknown: - default: - break; + FuncExprPortIterator port_iter(when); + float duty = 1.0; + while (port_iter.hasNext()) { + auto port = port_iter.next(); + if (port->direction()->isAnyInput()) + duty *= .5; } + debugPrint4(debug_, "power", 2, "leakage %s %s %.3e * %.2f\n", + cell->name(), + when->asString(), + leak->power(), + duty); + cond_leakage += leak->power() * duty; + found_cond = true; + } + else { + debugPrint2(debug_, "power", 2, "leakage default %s %.3e\n", + cell->name(), + leak->power()); + default_leakage += leak->power(); + found_default = true; } } + float leakage = 0.0; + float leak; + bool exists; + cell->leakagePower(leak, exists); + if (exists) { + // Prefer cell_leakage_power until propagated activities exist. + debugPrint2(debug_, "power", 2, "leakage %s cell %.3e\n", + cell->name(), + leak); + leakage = leak; + } + // Ignore default leakages unless there are no conditional leakage groups. + else if (found_cond) + leakage = cond_leakage; + else if (found_default) + leakage = default_leakage; result.setLeakage(leakage); } @@ -292,6 +322,15 @@ Power::findSwitchingPower(LibertyCell *cell, result.setSwitching(switching); } +float +Power::activity(const Pin *pin) +{ + float activity1; + bool is_clk; + activity(pin, activity1, is_clk); + return activity1; +} + void Power::activity(const Pin *pin, // Return values. diff --git a/search/Power.hh b/search/Power.hh index 6f253448..071b88c7 100644 --- a/search/Power.hh +++ b/search/Power.hh @@ -78,6 +78,7 @@ protected: // Return values. float &activity, bool &is_clk); + float activity(const Pin *pin); float voltage(LibertyCell *cell, const LibertyPort *port, const DcalcAnalysisPt *dcalc_ap); diff --git a/search/Sta.cc b/search/Sta.cc index 58d11153..942ae15f 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -301,9 +301,8 @@ Sta::makeComponents() updateComponentsState(); makeObservers(); - + // This must follow updateComponentsState. corners_->makeParasiticAnalysisPtsSingle(); - makeDefaultCorners(); setThreadCount(defaultThreadCount()); } @@ -667,8 +666,7 @@ Sta::setMinLibrary(const char *min_filename, { LibertyLibrary *max_lib = network_->findLibertyFilename(max_filename); if (max_lib) { - LibertyLibrary *min_lib = readLibertyFile(min_filename, - corners_->defaultCorner(), + LibertyLibrary *min_lib = readLibertyFile(min_filename, cmd_corner_, MinMaxAll::min(), false, report_, debug_, network_); return min_lib != nullptr; @@ -2339,12 +2337,6 @@ Sta::setClkThruTristateEnabled(bool enable) //////////////////////////////////////////////////////////////// -Corner * -Sta::defaultCorner() -{ - return corners_->defaultCorner(); -} - Corner * Sta::findCorner(const char *corner_name) { @@ -2357,24 +2349,33 @@ Sta::multiCorner() return corners_->multiCorner(); } +// Init one corner named "default". void Sta::makeCorners() { corners_ = new Corners(this); + StringSet corner_names; + corner_names.insert("default"); + makeCorners(&corner_names); } void Sta::makeCorners(StringSet *corner_names) { corners_->makeCorners(corner_names); + cmd_corner_ = corners_->findCorner(0); +} + +Corner * +Sta::cmdCorner() const +{ + return cmd_corner_; } void -Sta::makeDefaultCorners() +Sta::setCmdCorner(Corner *corner) { - StringSet corner_names; - corner_names.insert("default"); - corners_->makeCorners(&corner_names); + cmd_corner_ = corner; } void @@ -3344,7 +3345,7 @@ Sta::setPortExtWireCap(Port *port, const MinMaxAll *min_max, float cap) { - Corner *corner = corners_->defaultCorner(); + Corner *corner = cmd_corner_; TransRiseFallIterator tr_iter(tr); while (tr_iter.hasNext()) { TransRiseFall *tr1 = tr_iter.next(); @@ -3489,7 +3490,7 @@ Sta::readSpef(const char *filename, bool save, bool quiet) { - Corner *corner = corners_->defaultCorner(); + Corner *corner = cmd_corner_; const MinMax *cnst_min_max; ParasiticAnalysisPt *ap; if (min_max == MinMaxAll::all()) { @@ -3510,27 +3511,9 @@ Sta::readSpef(const char *filename, reduce_to, delete_after_reduce, op_cond, corner, cnst_min_max, save, quiet, report_, network_, parasitics_); - parasiticsChangedAfter(); - return success; -} - -void -Sta::parasiticsChangedAfter() -{ - // Update the delay calculation analysis points to use the parasitics. - CornerIterator corner_iter(sta_); - while (corner_iter.hasNext()) { - Corner *corner = corner_iter.next(); - MinMaxIterator mm_iter; - while (mm_iter.hasNext()) { - MinMax *min_max = mm_iter.next(); - ParasiticAnalysisPt *ap = corner->findParasiticAnalysisPt(min_max); - DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max); - dcalc_ap->setParasiticAnalysisPt(ap); - } - } graph_delay_calc_->delaysInvalid(); search_->arrivalsInvalid(); + return success; } void @@ -3542,7 +3525,7 @@ Sta::findPiElmore(Pin *drvr_pin, float &c1, bool &exists) const { - Corner *corner = corners_->defaultCorner(); + Corner *corner = cmd_corner_; const ParasiticAnalysisPt *ap = corner->findParasiticAnalysisPt(min_max); if (parasitics_->hasPiElmore(drvr_pin, tr, ap)) { Parasitic *pi_elmore = parasitics_->findPiElmore(drvr_pin, tr, ap); @@ -3561,7 +3544,7 @@ Sta::makePiElmore(Pin *drvr_pin, float rpi, float c1) { - Corner *corner = corners_->defaultCorner(); + Corner *corner = cmd_corner_; MinMaxIterator mm_iter(min_max); while (mm_iter.hasNext()) { MinMax *mm = mm_iter.next(); @@ -3579,7 +3562,7 @@ Sta::findElmore(Pin *drvr_pin, float &elmore, bool &exists) const { - Corner *corner = corners_->defaultCorner(); + Corner *corner = cmd_corner_; const ParasiticAnalysisPt *ap = corner->findParasiticAnalysisPt(min_max); if (parasitics_->hasPiElmore(drvr_pin, tr, ap)) { Parasitic *pi_elmore = parasitics_->findPiElmore(drvr_pin, tr, ap); @@ -3597,7 +3580,7 @@ Sta::setElmore(Pin *drvr_pin, const MinMaxAll *min_max, float elmore) { - Corner *corner = corners_->defaultCorner(); + Corner *corner = cmd_corner_; MinMaxIterator mm_iter(min_max); while (mm_iter.hasNext()) { MinMax *mm = mm_iter.next(); diff --git a/search/Sta.hh b/search/Sta.hh index 74d9b92a..a31e1b73 100644 --- a/search/Sta.hh +++ b/search/Sta.hh @@ -1133,7 +1133,8 @@ public: Tcl_Interp *tclInterp(); // Ensure that the timing graph has been built. Graph *ensureGraph(); - Corner *defaultCorner(); + Corner *cmdCorner() const; + void setCmdCorner(Corner *corner); Corner *findCorner(const char *corner_name); bool multiCorner(); void makeCorners(StringSet *corner_names); @@ -1292,17 +1293,16 @@ protected: void findRegisterPreamble(); bool crossesHierarchy(Edge *edge) const; void deleteLeafInstanceBefore(Instance *inst); - void makeDefaultCorners(); void readLibertyAfter(LibertyLibrary *liberty, Corner *corner, const MinMax *min_max); - void parasiticsChangedAfter(); void powerPreamble(); void disableFanoutCrprPruning(Vertex *vertex, int &fanou); CmdNamespace cmd_namespace_; Instance *current_instance_; + Corner *cmd_corner_; CheckTiming *check_timing_; CheckSlewLimits *check_slew_limits_; CheckMinPulseWidths *check_min_pulse_widths_; diff --git a/tcl/Cmds.tcl b/tcl/Cmds.tcl index 9fa26f4b..932b8ae3 100644 --- a/tcl/Cmds.tcl +++ b/tcl/Cmds.tcl @@ -1255,7 +1255,7 @@ proc parse_corner { keys_var } { } elseif { [multi_corner] } { sta_error "-corner keyword required with multi-corner analysis." } else { - return [default_corner] + return [cmd_corner] } } @@ -1289,7 +1289,7 @@ proc parse_corner_or_default { keys_var } { return $corner } } else { - return [default_corner] + return [cmd_corner] } } diff --git a/tcl/StaTcl.i b/tcl/StaTcl.i index 426ea1a5..3a1d099f 100644 --- a/tcl/StaTcl.i +++ b/tcl/StaTcl.i @@ -1988,6 +1988,13 @@ private: ~OperatingConditions(); }; +class Corner +{ +private: + Corner(); + ~Corner(); +}; + //////////////////////////////////////////////////////////////// // // C++ functions visible as TCL functions. @@ -2735,10 +2742,24 @@ leaf_instance_iterator() //////////////////////////////////////////////////////////////// -Corner * -default_corner() +void +define_corners_cmd(StringSet *corner_names) { - return Sta::sta()->defaultCorner(); + Sta *sta = Sta::sta(); + sta->makeCorners(corner_names); + delete corner_names; +} + +Corner * +cmd_corner() +{ + return Sta::sta()->cmdCorner(); +} + +void +set_cmd_corner(Corner *corner) +{ + Sta::sta()->setCmdCorner(corner); } Corner * @@ -5169,14 +5190,6 @@ arrivals_invalid() sta->arrivalsInvalid(); } -void -define_corners_cmd(StringSet *corner_names) -{ - Sta *sta = Sta::sta(); - sta->makeCorners(corner_names); - delete corner_names; -} - %} // inline //////////////////////////////////////////////////////////////// @@ -6133,6 +6146,10 @@ finish() } +%extend Corner { +const char *name() { return self->name(); } +} + // Local Variables: // mode:c++ // End: