From e1059eac1255e19c36c38faf0127692408b800ae Mon Sep 17 00:00:00 2001 From: James Cherry Date: Thu, 20 Dec 2018 22:41:54 -0800 Subject: [PATCH] find_timing_paths --- README | 2 +- liberty/Liberty.cc | 21 +++++ liberty/Liberty.hh | 5 ++ liberty/LibertyReader.cc | 34 ++++++++ liberty/LibertyReaderPvt.hh | 1 + search/Path.cc | 14 +++ search/Path.hh | 4 + search/ReportPath.cc | 170 ++++++++++++++++++------------------ search/ReportPath.hh | 12 ++- search/SearchClass.hh | 2 +- search/Sta.cc | 25 ++++++ search/Sta.hh | 10 +++ tcl/Cmds.tcl | 20 +++++ tcl/Search.tcl | 10 +++ tcl/Sta.tcl | 58 ++++++++---- tcl/StaTcl.i | 117 +++++++++++++++---------- 16 files changed, 353 insertions(+), 152 deletions(-) diff --git a/README b/README index 1ecd713b..23f679da 100644 --- a/README +++ b/README @@ -15,7 +15,7 @@ # along with this program. If not, see . Parallax Gate Level Static Timing Analyzer - See INSTALL for build instructions. +See INSTALL for installation and build instructions. Standard file formats Verilog diff --git a/liberty/Liberty.cc b/liberty/Liberty.cc index 68dba11c..7c835111 100644 --- a/liberty/Liberty.cc +++ b/liberty/Liberty.cc @@ -135,6 +135,14 @@ LibertyLibrary::~LibertyLibrary() deleteEquivCellMap(equiv_cell_map_); delete units_; ocv_derate_map_.deleteContents(); + + SupplyVoltageMap::Iterator supply_iter(supply_voltage_map_); + while (supply_iter.hasNext()) { + const char *supply_name; + float voltage; + supply_iter.next(supply_name, voltage); + stringDelete(supply_name); + } } LibertyCell * @@ -762,6 +770,19 @@ LibertyLibrary::addOcvDerate(OcvDerate *derate) ocv_derate_map_[derate->name()] = derate; } +void +LibertyLibrary::addSupplyVoltage(const char *supply_name, + float voltage) +{ + supply_voltage_map_[stringCopy(supply_name)] = voltage; +} + +float +LibertyLibrary::supplyVoltage(const char *supply_name) +{ + return supply_voltage_map_[supply_name]; +} + //////////////////////////////////////////////////////////////// LibertyCellIterator::LibertyCellIterator(const LibertyLibrary * diff --git a/liberty/Liberty.hh b/liberty/Liberty.hh index d8cb89a6..de013de5 100644 --- a/liberty/Liberty.hh +++ b/liberty/Liberty.hh @@ -68,6 +68,7 @@ typedef Map LatchEnableMap; typedef Map OcvDerateMap; typedef Vector TimingArcAttrsSeq; typedef Vector InternalPowerAttrsSeq; +typedef Map SupplyVoltageMap; typedef enum { clock_gate_none, @@ -263,6 +264,9 @@ public: void setDefaultOcvDerate(OcvDerate *derate); OcvDerate *findOcvDerate(const char *derate_name); void addOcvDerate(OcvDerate *derate); + void addSupplyVoltage(const char *suppy_name, + float voltage); + float supplyVoltage(const char *suppy_name); // Make scaled cell. Call LibertyCell::addScaledCell after it is complete. LibertyCell *makeScaledCell(const char *name, @@ -323,6 +327,7 @@ protected: float ocv_arc_depth_; OcvDerate *default_ocv_derate_; OcvDerateMap ocv_derate_map_; + SupplyVoltageMap supply_voltage_map_; // Set if any library has rise/fall capacitances. static bool found_rise_fall_caps_; diff --git a/liberty/LibertyReader.cc b/liberty/LibertyReader.cc index 05dfed82..75e185ca 100644 --- a/liberty/LibertyReader.cc +++ b/liberty/LibertyReader.cc @@ -178,6 +178,7 @@ LibertyReader::defineVisitors() defineAttrVisitor("leakage_power_unit", &LibertyReader::visitPowerUnit); defineAttrVisitor("delay_model", &LibertyReader::visitDelayModel); defineAttrVisitor("bus_naming_style", &LibertyReader::visitBusStyle); + defineAttrVisitor("voltage_map", &LibertyReader::visitVoltageMap); defineAttrVisitor("nom_temperature", &LibertyReader::visitNomTemp); defineAttrVisitor("nom_voltage", &LibertyReader::visitNomVolt); defineAttrVisitor("nom_process", &LibertyReader::visitNomProc); @@ -832,6 +833,39 @@ LibertyReader::visitBusStyle(LibertyAttr *attr) } } +void +LibertyReader::visitVoltageMap(LibertyAttr *attr) +{ + if (library_) { + if (attr->isComplex()) { + LibertyAttrValueIterator value_iter(attr->values()); + if (value_iter.hasNext()) { + LibertyAttrValue *value = value_iter.next(); + if (value->isString()) { + const char *supply_name = value->stringValue(); + if (value_iter.hasNext()) { + value = value_iter.next(); + if (value->isFloat()) { + float voltage = value->floatValue(); + library_->addSupplyVoltage(supply_name, voltage); + } + else + libWarn(attr, "voltage_map voltage is not a float.\n"); + } + else + libWarn(attr, "voltage_map missing voltage.\n"); + } + else + libWarn(attr, "voltage_map supply name is not a string.\n"); + } + else + libWarn(attr, "voltage_map missing supply name and voltage.\n"); + } + else + libWarn(attr, "voltage_map missing values suffix.\n"); + } +} + void LibertyReader::visitNomTemp(LibertyAttr *attr) { diff --git a/liberty/LibertyReaderPvt.hh b/liberty/LibertyReaderPvt.hh index 9ec1d655..f3efb63a 100644 --- a/liberty/LibertyReaderPvt.hh +++ b/liberty/LibertyReaderPvt.hh @@ -88,6 +88,7 @@ public: float &scale_var, Unit *unit_suffix); virtual void visitDelayModel(LibertyAttr *attr); + virtual void visitVoltageMap(LibertyAttr *attr); virtual void visitBusStyle(LibertyAttr *attr); virtual void visitNomTemp(LibertyAttr *attr); virtual void visitNomVolt(LibertyAttr *attr); diff --git a/search/Path.cc b/search/Path.cc index 299c4809..a63a1b44 100644 --- a/search/Path.cc +++ b/search/Path.cc @@ -21,6 +21,7 @@ #include "Clock.hh" #include "Tag.hh" #include "Corner.hh" +#include "DcalcAnalysisPt.hh" #include "PathAnalysisPt.hh" #include "PathRef.hh" #include "Path.hh" @@ -97,6 +98,19 @@ Path::pathAnalysisPtIndex(const StaState *sta) const return pathAnalysisPt(sta)->index(); } +DcalcAnalysisPt * +Path::dcalcAnalysisPt(const StaState *sta) const +{ + return pathAnalysisPt(sta)->dcalcAnalysisPt(); +} + +Slew +Path::slew(const StaState *sta) const +{ + return sta->graph()->slew(vertex(sta), transition(sta), + dcalcAnalysisPt(sta)->index()); +} + int Path::trIndex(const StaState *sta) const { diff --git a/search/Path.hh b/search/Path.hh index fed5b34f..8442f52d 100644 --- a/search/Path.hh +++ b/search/Path.hh @@ -29,6 +29,8 @@ namespace sta { +class DcalcAnalysisPt; + // Abstract base class for Path API. class Path { @@ -55,6 +57,7 @@ public: virtual const MinMax *minMax(const StaState *sta) const; virtual PathAnalysisPt *pathAnalysisPt(const StaState *sta) const = 0; virtual PathAPIndex pathAnalysisPtIndex(const StaState *sta) const; + virtual DcalcAnalysisPt *dcalcAnalysisPt(const StaState *sta) const; virtual Arrival arrival(const StaState *sta) const = 0; virtual void setArrival(Arrival arrival, const StaState *sta) = 0; @@ -66,6 +69,7 @@ public: virtual void initRequired(const StaState *sta); virtual bool requiredIsInitValue(const StaState *sta) const; virtual Slack slack(const StaState *sta) const; + virtual Slew slew(const StaState *sta) const; // This takes the same time as prevPath and prevArc combined. virtual void prevPath(const StaState *sta, // Return values. diff --git a/search/ReportPath.cc b/search/ReportPath.cc index 1a7e73d9..42dad7fe 100644 --- a/search/ReportPath.cc +++ b/search/ReportPath.cc @@ -256,10 +256,63 @@ ReportPath::setDigits(int digits) //////////////////////////////////////////////////////////////// +void +ReportPath::reportPathEndHeader() +{ + string header; + switch (format_) { + case report_path_full: + case report_path_full_clock: + case report_path_full_clock_expanded: + case report_path_short: + case report_path_endpoint: + break; + case report_path_summary: + reportSummaryHeader(header); + report_->print(header); + break; + case report_path_slack_only: + reportSlackOnlyHeader(header); + report_->print(header); + break; + default: + internalError("unsupported path type"); + break; + } +} + +void +ReportPath::reportPathEndFooter() +{ + string header; + switch (format_) { + case report_path_full: + case report_path_full_clock: + case report_path_full_clock_expanded: + case report_path_short: + break; + case report_path_endpoint: + case report_path_summary: + case report_path_slack_only: + report_->print("\n"); + break; + default: + internalError("unsupported path type"); + break; + } +} + void ReportPath::reportPathEnd(PathEnd *end) { - string header, result; + reportPathEnd(end, NULL); +} + +void +ReportPath::reportPathEnd(PathEnd *end, + PathEnd *prev_end) +{ + string result; switch (format_) { case report_path_full: case report_path_full_clock: @@ -273,24 +326,18 @@ ReportPath::reportPathEnd(PathEnd *end) report_->print(result); report_->print("\n\n"); break; - case report_path_end: - reportEndHeader(header); - report_->print(header); + case report_path_endpoint: + reportEndpointHeader(end, prev_end); reportEndLine(end, result); report_->print(result); break; case report_path_summary: - reportSummaryHeader(header); - report_->print(header); reportSummaryLine(end, result); report_->print(result); break; case report_path_slack_only: - reportSlackOnlyHeader(header); - report_->print(header); reportSlackOnly(end, result); report_->print(result); - report_->print("\n"); break; default: internalError("unsupported path type"); @@ -301,89 +348,42 @@ ReportPath::reportPathEnd(PathEnd *end) void ReportPath::reportPathEnds(PathEndSeq *ends) { - if (!ends->empty()) { - string header; - PathEndSeq::Iterator end_iter(ends); - switch (format_) { - case report_path_full: - case report_path_full_clock: - case report_path_full_clock_expanded: - while (end_iter.hasNext()) { - PathEnd *end = end_iter.next(); - string result; - end->reportFull(this, result); - report_->print(result); - report_->print("\n\n"); - } - break; - case report_path_short: - while (end_iter.hasNext()) { - PathEnd *end = end_iter.next(); - string result; - end->reportShort(this, result); - report_->print(result); - report_->print("\n\n"); - } - break; - case report_path_end: - reportPathEndsEnd(ends); - break; - case report_path_summary: - reportSummaryHeader(header); - report_->print(header); - while (end_iter.hasNext()) { - PathEnd *end = end_iter.next(); - string result; - reportSummaryLine(end, result); - report_->print(result); - } - report_->print("\n"); - break; - case report_path_slack_only: - reportSlackOnlyHeader(header); - report_->print(header); - while (end_iter.hasNext()) { - PathEnd *end = end_iter.next(); - string result; - reportSlackOnly(end, result); - report_->print(result); - } - report_->print("\n"); - break; - default: - internalError("unsupported path type"); - break; - } + reportPathEndHeader(); + PathEndSeq::Iterator end_iter(ends); + PathEnd *prev_end = NULL; + while (end_iter.hasNext()) { + PathEnd *end = end_iter.next(); + reportEndpointHeader(end, prev_end); + string result; + end->reportFull(this, result); + report_->print(result); + report_->print("\n\n"); + prev_end = end; } + reportPathEndFooter(); } void -ReportPath::reportPathEndsEnd(PathEndSeq *ends) +ReportPath::reportEndpointHeader(PathEnd *end, + PathEnd *prev_end) { PathGroup *prev_group = NULL; - PathEndSeq::Iterator end_iter(ends); - while (end_iter.hasNext()) { - PathEnd *end = end_iter.next(); - PathGroup *group = search_->pathGroup(end); - if (group != prev_group) { - if (prev_group) - report_->print("\n"); - const char *setup_hold = (end->minMax(this) == MinMax::min()) - ? "min_delay/hold" - : "max_delay/setup"; - report_->print("%s ('%s' group)\n\n", - setup_hold, - group->name()); - string header; - reportEndHeader(header); - report_->print(header); - } - string result; - reportEndLine(end, result); - report_->print(result); - prev_group = group; + if (prev_end) + prev_group = search_->pathGroup(prev_end); + PathGroup *group = search_->pathGroup(end); + if (group != prev_group) { + if (prev_group) + report_->print("\n"); + const char *setup_hold = (end->minMax(this) == MinMax::min()) + ? "min_delay/hold" + : "max_delay/setup"; + report_->print("%s ('%s' group)\n\n", + setup_hold, + group->name()); + string header; + reportEndHeader(header); + report_->print(header); } - report_->print("\n"); } void diff --git a/search/ReportPath.hh b/search/ReportPath.hh index ac878772..92cec57e 100644 --- a/search/ReportPath.hh +++ b/search/ReportPath.hh @@ -81,7 +81,16 @@ public: void setNoSplit(bool no_split); ReportField *findField(const char *name); + // Header above reportPathEnd results. + void reportPathEndHeader(); + // Footer below reportPathEnd results. + void reportPathEndFooter(); void reportPathEnd(PathEnd *end); + // Format report_path_endpoint only: + // Previous path end is used to detect path group changes + // so headers are reported by group. + void reportPathEnd(PathEnd *end, + PathEnd *prev_end); void reportPathEnds(PathEndSeq *ends); void reportPath(const Path *path); @@ -194,7 +203,8 @@ protected: bool left_justify, Unit *unit, bool enabled); - void reportPathEndsEnd(PathEndSeq *ends); + void reportEndpointHeader(PathEnd *end, + PathEnd *prev_end); void reportShort(const PathEndUnconstrained *end, PathExpanded &expanded, string &result); diff --git a/search/SearchClass.hh b/search/SearchClass.hh index 96bfd47e..e02cb561 100644 --- a/search/SearchClass.hh +++ b/search/SearchClass.hh @@ -118,7 +118,7 @@ typedef enum { report_path_full_clock, report_path_full_clock_expanded, report_path_short, - report_path_end, + report_path_endpoint, report_path_summary, report_path_slack_only } ReportPathFormat; diff --git a/search/Sta.cc b/search/Sta.cc index 7fd8cb50..5a01145a 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -2465,6 +2465,31 @@ Sta::reportPathEnds(PathEndSeq *ends) report_path_->reportPathEnds(ends); } +void +Sta::reportPathEndHeader() +{ + report_path_->reportPathEndHeader(); +} + +void +Sta::reportPathEndFooter() +{ + report_path_->reportPathEndFooter(); +} + +void +Sta::reportPathEnd(PathEnd *end) +{ + report_path_->reportPathEnd(end); +} + +void +Sta::reportPathEnd(PathEnd *end, + PathEnd *prev_end) +{ + report_path_->reportPathEnd(end, prev_end); +} + void Sta::reportPath(Path *path) { diff --git a/search/Sta.hh b/search/Sta.hh index fdb0b232..9eedb773 100644 --- a/search/Sta.hh +++ b/search/Sta.hh @@ -870,6 +870,16 @@ public: const Corner *corner, const SetupHold *setup_hold, int digits); + // Header above reportPathEnd results. + void reportPathEndHeader(); + // Footer below reportPathEnd results. + void reportPathEndFooter(); + // Format report_path_endpoint only: + // Previous path end is used to detect path group changes + // so headers are reported by group. + void reportPathEnd(PathEnd *end, + PathEnd *prev_end); + void reportPathEnd(PathEnd *end); void reportPathEnds(PathEndSeq *ends); ReportPath *reportPath() { return report_path_; } void reportPath(Path *path); diff --git a/tcl/Cmds.tcl b/tcl/Cmds.tcl index c46c2e3e..63b2551d 100644 --- a/tcl/Cmds.tcl +++ b/tcl/Cmds.tcl @@ -1793,6 +1793,8 @@ proc get_property_cmd { cmd type_key cmd_args } { return [liberty_library_property $object $attr] } elseif { $object_type == "Edge" } { return [edge_property $object $attr] + } elseif { $object_type == "PathEnd" } { + return [path_end_property $object $attr] } else { sta_error "$cmd unsupported object type $object_type." } @@ -1835,6 +1837,24 @@ proc edge_property { edge property } { } } +proc path_end_property { path_end property } { + if { $property == "startpoint" } { + return [$path_end startpoint] + } elseif { $property == "startpoint_clock" } { + return [$path_end startpoint_clock] + } elseif { $property == "endpoint" } { + return [$path_end endpoint] + } elseif { $property == "endpoint_clock" } { + return [$path_end endpoint_clock] + } elseif { $property == "endpoint_clock_pin" } { + return [$path_end endpoint_clock_pin] + } elseif { $property == "slack" } { + return [time_sta_ui [$path_end slack]] + } else { + return "" + } +} + proc get_object_type { obj } { set object_type [object_type $obj] if { $object_type == "Clock" } { diff --git a/tcl/Search.tcl b/tcl/Search.tcl index 8c84c454..4b3fceee 100644 --- a/tcl/Search.tcl +++ b/tcl/Search.tcl @@ -383,5 +383,15 @@ proc report_slew_limits { corner min_max all_violators verbose nosplit } { } } +proc report_path_ends { path_ends } { + report_path_end_header + set prev_end "NULL" + foreach path_end $path_ends { + report_path_end2 $path_end $prev_end + set prev_end $path_end + } + report_path_end_footer +} + # sta namespace end. } diff --git a/tcl/Sta.tcl b/tcl/Sta.tcl index d3b90942..8450fc1e 100644 --- a/tcl/Sta.tcl +++ b/tcl/Sta.tcl @@ -138,7 +138,7 @@ proc_redirect report_clock_skew { ################################################################ -define_sta_cmd_args "report_checks" \ +define_sta_cmd_args "find_timing_paths" \ {[-from from_list|-rise_from from_list|-fall_from from_list]\ [-through through_list|-rise_through through_list|-fall_through through_list]\ [-to to_list|-rise_to to_list|-fall_to to_list]\ @@ -150,27 +150,22 @@ define_sta_cmd_args "report_checks" \ [-slack_max slack_max]\ [-slack_min slack_min]\ [-sort_by_slack]\ - [-path_group group_name]\ - [-format full|full_clock|full_clock_expanded|short|end|summary]\ - [-fields [capacitance|transition_time|input_pin|net]]\ - [-digits digits]\ - [-no_line_splits]\ - [> filename] [>> filename]} + [-path_group group_name]} -proc_redirect report_checks { - global sta_report_unconstrained_paths - variable path_options +proc find_timing_paths { args } { + set path_ends [find_timing_paths_cmd "find_timing_paths" args] + return $path_ends +} - parse_key_args "report_checks" args \ +proc find_timing_paths_cmd { cmd args_var } { + upvar 1 $args_var args + + parse_key_args "find_timing_paths" args \ keys {-from -rise_from -fall_from -to -rise_to -fall_to \ -path_delay -corner -group_count -endpoint_count \ -slack_max -slack_min -path_group} \ flags {-sort_by_slack -unique_paths_to_endpoint} 0 - parse_report_path_options "report_checks" args "full" 0 - - set cmd "report_checks" - set min_max "max" set end_tr "rise_fall" if [info exists keys(-path_delay)] { @@ -261,7 +256,36 @@ proc_redirect report_checks { $slack_min $slack_max \ $sort_by_slack $groups \ 1 1 1 1 1 1] - if { [$path_ends empty] } { + return $path_ends +} + +################################################################ + +define_sta_cmd_args "report_checks" \ + {[-from from_list|-rise_from from_list|-fall_from from_list]\ + [-through through_list|-rise_through through_list|-fall_through through_list]\ + [-to to_list|-rise_to to_list|-fall_to to_list]\ + [-path_delay min|min_rise|min_fall|max|max_rise|max_fall|min_max]\ + [-corner corner_name]\ + [-group_count path_count] \ + [-endpoint_count path_count]\ + [-unique_paths_to_endpoint]\ + [-slack_max slack_max]\ + [-slack_min slack_min]\ + [-sort_by_slack]\ + [-path_group group_name]\ + [-format full|full_clock|full_clock_expanded|short|end|summary]\ + [-fields [capacitance|transition_time|input_pin|net]]\ + [-digits digits]\ + [-no_line_splits]\ + [> filename] [>> filename]} + +proc_redirect report_checks { + global sta_report_unconstrained_paths + + parse_report_path_options "report_checks" args "full" 0 + set path_ends [find_timing_paths_cmd "report_checks" args] + if { $path_ends == {} } { if { $sta_report_unconstrained_paths } { puts "No paths." } else { @@ -270,7 +294,6 @@ proc_redirect report_checks { } else { report_path_ends $path_ends } - delete_path_ends $path_ends } ################################################################ @@ -398,7 +421,6 @@ proc_redirect report_check_types { $recovery $removal \ $clk_gating_setup $clk_gating_hold] report_path_ends $path_ends - delete_path_ends $path_ends } if { $max_transition } { diff --git a/tcl/StaTcl.i b/tcl/StaTcl.i index bda897a7..b21b2534 100644 --- a/tcl/StaTcl.i +++ b/tcl/StaTcl.i @@ -65,6 +65,7 @@ #include "Tag.hh" #include "PathVertex.hh" #include "PathRef.hh" +#include "PathExpanded.hh" #include "PathEnd.hh" #include "PathGroup.hh" #include "CheckTiming.hh" @@ -96,7 +97,6 @@ typedef PinSet TmpPinSet; typedef PinSeq TmpPinSeq; typedef InstanceSeq TmpInstanceSeq; typedef InstanceSet TmpInstanceSet; -typedef PathEndSeq::Iterator PathEndSeqIterator; typedef MinPulseWidthCheckSeq::Iterator MinPulseWidthCheckSeqIterator; typedef FloatSeq TmpFloatSeq; typedef string TmpString; @@ -1596,7 +1596,7 @@ using namespace sta; else if (stringEq(arg, "short")) $1 = report_path_short; else if (stringEq(arg, "end")) - $1 = report_path_end; + $1 = report_path_endpoint; else if (stringEq(arg, "summary")) $1 = report_path_summary; else if (stringEq(arg, "slack_only")) @@ -1779,11 +1779,17 @@ using namespace sta; %typemap(out) PathEndSeq* { Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); -} -%typemap(out) PathEndSeqIterator* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); + Tcl_Obj *list = Tcl_NewListObj(0, NULL); + const PathEndSeq *path_ends = $1; + PathEndSeq::ConstIterator end_iter(path_ends); + while (end_iter.hasNext()) { + PathEnd *path_end = end_iter.next(); + Tcl_Obj *obj = SWIG_NewInstanceObj(path_end, SWIGTYPE_p_PathEnd, false); + Tcl_ListObjAppendElement(interp, list, obj); + } + delete path_ends; + Tcl_SetObjResult(interp, list); } %typemap(out) MinPulseWidthCheckSeqIterator* { @@ -2196,20 +2202,6 @@ private: ~PathEnd(); }; -class PathEndSeq -{ -private: - PathEnd(); - ~PathEnd(); -}; - -class PathEndSeqIterator -{ -private: - PathEndSeqIterator(); - ~PathEndSeqIterator(); -}; - class MinPulseWidthCheck { private: @@ -4412,6 +4404,31 @@ find_path_ends(ExceptionFrom *from, return ends; } +void +report_path_end_header() +{ + Sta::sta()->reportPathEndHeader(); +} + +void +report_path_end_footer() +{ + Sta::sta()->reportPathEndFooter(); +} + +void +report_path_end(PathEnd *end) +{ + Sta::sta()->reportPathEnd(end); +} + +void +report_path_end2(PathEnd *end, + PathEnd *prev_end) +{ + Sta::sta()->reportPathEnd(end, prev_end); +} + void set_report_path_format(ReportPathFormat format) { @@ -4463,18 +4480,6 @@ set_report_path_no_split(bool no_split) Sta::sta()->setReportPathNoSplit(no_split); } -void -report_path_ends(PathEndSeq *ends) -{ - Sta::sta()->reportPathEnds(ends); -} - -void -delete_path_ends(PathEndSeq *ends) -{ - delete ends; -} - void delete_path_ref(PathRef *path) { @@ -4504,12 +4509,6 @@ report_clk_skew(ClockSet *clks, delete clks; } -PathEndSeqIterator * -path_end_seq_iterator(PathEndSeq *ends) -{ - return new PathEndSeqIterator(ends); -} - TmpPinSet * startpoints() { @@ -6254,17 +6253,43 @@ Crpr common_clk_pessimism() { return self->commonClkPessimism(Sta::sta()); } TransRiseFall *target_clk_end_trans() { return const_cast(self->targetClkEndTrans(Sta::sta())); } +Pin * +startpoint() +{ + Sta *sta = Sta::sta(); + PathExpanded expanded(self->path(), sta); + return expanded.startPath()->pin(sta); } -%extend PathEndSeq { -bool empty() { return self->empty(); } -} // PathEndSeq methods +Clock * +startpoint_clock() +{ + Sta *sta = Sta::sta(); + return self->path()->clock(sta); +} -%extend PathEndSeqIterator { -bool has_next() { return self->hasNext(); } -PathEnd *next() { return self->next(); } -void finish() { delete self; } -} // PathEndSeqIterator methods +Pin * +endpoint() +{ + Sta *sta = Sta::sta(); + return self->path()->pin(sta); +} + +Clock * +endpoint_clock() +{ + Sta *sta = Sta::sta(); + return self->targetClk(sta); +} + +Pin * +endpoint_clock_pin() +{ + Sta *sta = Sta::sta(); + return self->targetClkPath()->pin(sta); +} + +} %extend MinPulseWidthCheckSeqIterator { bool has_next() { return self->hasNext(); }