diff --git a/doc/OpenSTA.odt b/doc/OpenSTA.odt index 32579683..ada6d878 100644 Binary files a/doc/OpenSTA.odt and b/doc/OpenSTA.odt differ diff --git a/liberty/EquivCells.cc b/liberty/EquivCells.cc index 7b392f60..43f9730c 100644 --- a/liberty/EquivCells.cc +++ b/liberty/EquivCells.cc @@ -43,13 +43,25 @@ hashPort(const LibertyPort *port); static unsigned hashString(const char *str); -class CellDriveResistanceLess +static float +cellDriveResistance(const LibertyCell *cell) +{ + LibertyCellPortBitIterator port_iter(cell); + while (port_iter.hasNext()) { + auto port = port_iter.next(); + if (port->direction()->isOutput()) + return port->driveResistance(); + } + return 0.0; +} + +class CellDriveResistanceGreater { public: bool operator()(const LibertyCell *cell1, const LibertyCell *cell2) const { - return cell1->driveResistance() > cell2->driveResistance(); + return cellDriveResistance(cell1) > cellDriveResistance(cell2); } }; @@ -62,7 +74,7 @@ EquivCells::EquivCells(LibertyLibrarySeq *equiv_libs, // Sort the equiv sets by drive resistance. for (auto cell : unique_equiv_cells_) { auto equivs = equiv_cells_.findKey(cell); - sort(equivs, CellDriveResistanceLess()); + sort(equivs, CellDriveResistanceGreater()); } if (map_libs) { for (auto lib : *map_libs) diff --git a/liberty/Liberty.cc b/liberty/Liberty.cc index a28d4ab5..fb1dcb09 100644 --- a/liberty/Liberty.cc +++ b/liberty/Liberty.cc @@ -1440,42 +1440,6 @@ LibertyCell::setCornerCell(LibertyCell *corner_cell, //////////////////////////////////////////////////////////////// -// Use the min/max "drive" for all the timing arcs in the cell. -float -LibertyCell::driveResistance(const TransRiseFall *tr, - const MinMax *min_max) const -{ - float max_drive = min_max->initValue(); - LibertyCellTimingArcSetIterator set_iter(this); - while (set_iter.hasNext()) { - TimingArcSet *set = set_iter.next(); - if (!set->role()->isTimingCheck()) { - TimingArcSetArcIterator arc_iter(set); - while (arc_iter.hasNext()) { - TimingArc *arc = arc_iter.next(); - if (tr == nullptr - || arc->toTrans()->asRiseFall() == tr) { - GateTimingModel *model = dynamic_cast(arc->model()); - if (model) { - float drive = model->driveResistance(this, nullptr); - if (min_max->compare(drive, max_drive)) - max_drive = drive; - } - } - } - } - } - return max_drive; -} - -float -LibertyCell::driveResistance() const -{ - return driveResistance(nullptr, MinMax::max()); -} - -//////////////////////////////////////////////////////////////// - float LibertyCell::ocvArcDepth() const { @@ -1953,6 +1917,47 @@ LibertyPort::capacitanceIsOneValue() const return capacitance_.isOneValue(); } +//////////////////////////////////////////////////////////////// + +// Use the min/max "drive" for all the timing arcs in the cell. +float +LibertyPort::driveResistance(const TransRiseFall *tr, + const MinMax *min_max) const +{ + float max_drive = min_max->initValue(); + bool found_drive = false; + LibertyCellTimingArcSetIterator set_iter(liberty_cell_, nullptr, this); + while (set_iter.hasNext()) { + TimingArcSet *set = set_iter.next(); + if (!set->role()->isTimingCheck()) { + TimingArcSetArcIterator arc_iter(set); + while (arc_iter.hasNext()) { + TimingArc *arc = arc_iter.next(); + if (tr == nullptr + || arc->toTrans()->asRiseFall() == tr) { + GateTimingModel *model = dynamic_cast(arc->model()); + if (model) { + float drive = model->driveResistance(liberty_cell_, nullptr); + if (min_max->compare(drive, max_drive)) + max_drive = drive; + found_drive = true; + } + } + } + } + } + if (found_drive) + return max_drive; + else + return 0.0; +} + +float +LibertyPort::driveResistance() const +{ + return driveResistance(nullptr, MinMax::max()); +} + void LibertyPort::setFunction(FuncExpr *func) { diff --git a/liberty/Liberty.hh b/liberty/Liberty.hh index f82fa793..806ffa7a 100644 --- a/liberty/Liberty.hh +++ b/liberty/Liberty.hh @@ -411,7 +411,7 @@ public: bool isClockGateOther() const; bool isClockGate() const; void setClockGateType(ClockGateType type); - // Internal to LibertyCellTimingArcSetIterator. + // from or to may be nullptr to wildcard. TimingArcSetSeq *timingArcSets(const LibertyPort *from, const LibertyPort *to) const; size_t timingArcSetCount() const; @@ -490,10 +490,6 @@ public: virtual void finish(bool infer_latches, Report *report, Debug *debug); - float driveResistance(const TransRiseFall *tr, - const MinMax *min_max) const; - // Max of rise/fall. - float driveResistance() const; bool isBuffer() const; // Only valid when isBuffer() returns true. void bufferPorts(// Return values. @@ -607,6 +603,7 @@ class LibertyCellTimingArcSetIterator : public TimingArcSetSeq::ConstIterator { public: LibertyCellTimingArcSetIterator(const LibertyCell *cell); + // from or to may be nullptr to wildcard. LibertyCellTimingArcSetIterator(const LibertyCell *cell, const LibertyPort *from, const LibertyPort *to); @@ -659,6 +656,10 @@ public: void setCapacitance(const TransRiseFall *tr, const MinMax *min_max, float cap); + float driveResistance(const TransRiseFall *tr, + const MinMax *min_max) const; + // Max of rise/fall. + float driveResistance() const; FuncExpr *function() const { return function_; } void setFunction(FuncExpr *func); FuncExpr *&functionRef() { return function_; } diff --git a/sdc/WriteSdc.cc b/sdc/WriteSdc.cc index df039e02..e0d4a4e6 100644 --- a/sdc/WriteSdc.cc +++ b/sdc/WriteSdc.cc @@ -918,7 +918,7 @@ WriteSdc::writeClockSense(PinClockPair &pin_clk, flag = "-negative"; else if (sense == ClockSense::stop) flag = "-stop_propagation"; - fprintf(stream_, "set_clock_sense %s ", flag); + fprintf(stream_, "set_sense -type clock %s ", flag); const Clock *clk = pin_clk.second; if (clk) { fprintf(stream_, "-clock "); diff --git a/search/Property.cc b/search/Property.cc index c7121ee2..1b41c4c3 100644 --- a/search/Property.cc +++ b/search/Property.cc @@ -527,18 +527,6 @@ getProperty(const LibertyCell *cell, return PropertyValue(cell->filename()); else if (stringEqual(property, "library")) return PropertyValue(cell->libertyLibrary()); - else if (stringEqual(property, "drive_resistance_rise_min")) - return PropertyValue(cell->driveResistance(TransRiseFall::rise(), - MinMax::min())); - else if (stringEqual(property, "drive_resistance_rise_max")) - return PropertyValue(cell->driveResistance(TransRiseFall::rise(), - MinMax::max())); - else if (stringEqual(property, "drive_resistance_fall_min")) - return PropertyValue(cell->driveResistance(TransRiseFall::fall(), - MinMax::min())); - else if (stringEqual(property, "drive_resistance_fall_max")) - return PropertyValue(cell->driveResistance(TransRiseFall::fall(), - MinMax::max())); else if (stringEqual(property, "is_buffer")) return PropertyValue(cell->isBuffer()); else if (stringEqual(property, "dont_use")) @@ -656,6 +644,18 @@ getProperty(const LibertyPort *port, float cap = port->capacitance(TransRiseFall::rise(), MinMax::max()); return PropertyValue(sta->units()->capacitanceUnit()->asString(cap, 6)); } + else if (stringEqual(property, "drive_resistance_rise_min")) + return PropertyValue(port->driveResistance(TransRiseFall::rise(), + MinMax::min())); + else if (stringEqual(property, "drive_resistance_rise_max")) + return PropertyValue(port->driveResistance(TransRiseFall::rise(), + MinMax::max())); + else if (stringEqual(property, "drive_resistance_fall_min")) + return PropertyValue(port->driveResistance(TransRiseFall::fall(), + MinMax::min())); + else if (stringEqual(property, "drive_resistance_fall_max")) + return PropertyValue(port->driveResistance(TransRiseFall::fall(), + MinMax::max())); else throw PropertyUnknown("liberty port", property); } diff --git a/search/Search.cc b/search/Search.cc index 0413ba37..72a2e887 100644 --- a/search/Search.cc +++ b/search/Search.cc @@ -192,16 +192,6 @@ SearchThru::searchThru(Edge *edge) && loopEnabled(edge, sdc, graph, search); } -class ClkArrivalSearchPred : public EvalPred -{ -public: - ClkArrivalSearchPred(const StaState *sta); - virtual bool searchThru(Edge *edge); - -private: - DISALLOW_COPY_AND_ASSIGN(ClkArrivalSearchPred); -}; - ClkArrivalSearchPred::ClkArrivalSearchPred(const StaState *sta) : EvalPred(sta) { diff --git a/search/Search.hh b/search/Search.hh index 4d39f102..daa06935 100644 --- a/search/Search.hh +++ b/search/Search.hh @@ -346,6 +346,7 @@ public: VisitPathEnds *visitPathEnds() { return visit_path_ends_; } GatedClk *gatedClk() { return gated_clk_; } Genclks *genclks() { return genclks_; } + void findClkVertexPins(PinSet &clk_pins); protected: void init(StaState *sta); @@ -376,7 +377,6 @@ protected: const PathAnalysisPt *path_ap, Arrival insertion, TagGroupBldr *tag_bldr); - void findClkVertexPins(PinSet &clk_pins); Tag *clkDataTag(const Pin *pin, Clock *clk, const TransRiseFall *tr, @@ -624,6 +624,16 @@ protected: bool search_thru_latches_; }; +class ClkArrivalSearchPred : public EvalPred +{ +public: + ClkArrivalSearchPred(const StaState *sta); + virtual bool searchThru(Edge *edge); + +private: + DISALLOW_COPY_AND_ASSIGN(ClkArrivalSearchPred); +}; + // Class for visiting fanin/fanout paths of a vertex. // This used by forward/backward search to find arrival/required path times. class PathVisitor : public VertexVisitor diff --git a/tcl/Sdc.tcl b/tcl/Sdc.tcl index 4625f2b7..eb2096df 100644 --- a/tcl/Sdc.tcl +++ b/tcl/Sdc.tcl @@ -1434,15 +1434,41 @@ proc set_clock_latency { args } { ################################################################ +define_cmd_args "set_sense" \ + {[-type clock|data] [-positive] [-negative] [-pulse pulse_type]\ + [-stop_propagation] [-clocks clocks] pins} + +proc set_sense { args } { + parse_key_args "set_clock_sense" args keys {-type} flags {} 0 + + set type "clock" + if { [info exists keys(-type)] } { + set type $keys(-type) + if { $type == "data" } { + sdc_warn "set_sense -type data not supported." + } elseif { $type == "clock" } { + set_clock_sense_cmd1 "set_sense" $args + } else { + sdc_error "set_sense -type clock|data" + } + } +} + +# deprecated in SDC 2.1 define_cmd_args "set_clock_sense" \ {[-positive] [-negative] [-pulse pulse_type] [-stop_propagation] \ [-clock clocks] pins} proc set_clock_sense { args } { + sdc_warn "set_clock_sense is deprecated as of SDC 2.1. Use set_sense -type clock." + set_clock_sense_cmd1 "set_clock_sense" $args +} + +proc set_clock_sense_cmd1 { cmd cmd_args } { # SDC uses -clock, OT, OC use -clocks - parse_key_args "set_clock_sense" args keys {-clock -clocks -pulse} \ - flags {-positive -negative -stop_propagation} - check_argc_eq1 "set_clock_sense" $args + parse_key_args $cmd cmd_args keys {-clock -clocks -pulse} \ + flags {-positive -negative -stop_propagation} 0 + check_argc_eq1 "set_clock_sense" $cmd_args set pulse [info exists keys(-pulse)] if { $pulse } { @@ -1458,7 +1484,7 @@ proc set_clock_sense { args } { sta_warn "-positive, -negative, -stop_propagation and -pulse are mutually exclusive." } - set pins [get_port_pins_error "pins" [lindex $args 0]] + set pins [get_port_pins_error "pins" [lindex $cmd_args 0]] set clks {} if {[info exists keys(-clock)]} { set clks [get_clocks_warn "clock" $keys(-clock)]