diff --git a/CMakeLists.txt b/CMakeLists.txt index 6dd8e8b3..beb9206a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -233,21 +233,21 @@ set(STA_TCL_FILES tcl/Util.tcl tcl/CmdArgs.tcl tcl/CmdUtil.tcl - tcl/Graph.tcl tcl/Link.tcl - tcl/Network.tcl - tcl/NetworkEdit.tcl tcl/Property.tcl - tcl/Search.tcl tcl/Sta.tcl tcl/Splash.tcl tcl/Variables.tcl dcalc/DelayCalc.tcl + graph/Graph.tcl liberty/Liberty.tcl + network/Network.tcl + network/NetworkEdit.tcl parasitics/Parasitics.tcl power/Power.tcl sdc/Sdc.tcl sdf/Sdf.tcl + search/Search.tcl spice/WriteSpice.tcl verilog/Verilog.tcl ) @@ -428,6 +428,7 @@ set_property(SOURCE ${STA_SWIG_FILE} -I${STA_HOME}/sdf -I${STA_HOME}/parasitics -I${STA_HOME}/power + -I${STA_HOME}/search -I${STA_HOME}/spice -I${STA_HOME}/tcl -I${STA_HOME}/verilog @@ -443,6 +444,7 @@ set(SWIG_FILES ${STA_HOME}/power/Power.i ${STA_HOME}/sdc/Sdc.i ${STA_HOME}/sdf/Sdf.i + ${STA_HOME}/search/Search.i ${STA_HOME}/spice/WriteSpice.i ${STA_HOME}/tcl/Exception.i ${STA_HOME}/tcl/StaTcl.i diff --git a/app/StaApp.i b/app/StaApp.i index e4adf39d..aad4502a 100644 --- a/app/StaApp.i +++ b/app/StaApp.i @@ -29,4 +29,5 @@ %include "DelayCalc.i" %include "WriteSpice.i" %include "Parasitics.i" +%include "Search.i" %include "Power.i" diff --git a/dcalc/DelayCalc.i b/dcalc/DelayCalc.i index f70895ee..2409a792 100644 --- a/dcalc/DelayCalc.i +++ b/dcalc/DelayCalc.i @@ -72,4 +72,18 @@ set_prima_reduce_order(size_t order) } } +void +find_delays() +{ + cmdLinkedNetwork(); + Sta::sta()->findDelays(); +} + +void +delays_invalid() +{ + Sta *sta = Sta::sta(); + sta->delaysInvalid(); +} + %} // inline diff --git a/tcl/Graph.tcl b/graph/Graph.tcl similarity index 100% rename from tcl/Graph.tcl rename to graph/Graph.tcl diff --git a/tcl/Network.tcl b/network/Network.tcl similarity index 100% rename from tcl/Network.tcl rename to network/Network.tcl diff --git a/tcl/NetworkEdit.tcl b/network/NetworkEdit.tcl similarity index 100% rename from tcl/NetworkEdit.tcl rename to network/NetworkEdit.tcl diff --git a/search/Search.i b/search/Search.i new file mode 100644 index 00000000..4d8c5e98 --- /dev/null +++ b/search/Search.i @@ -0,0 +1,407 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2024, Parallax Software, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +%module search + +%{ +#include "Sta.hh" +#include "Search.hh" + +using namespace sta; + +%} + +//////////////////////////////////////////////////////////////// +// +// Empty class definitions to make swig happy. +// Private constructor/destructor so swig doesn't emit them. +// +//////////////////////////////////////////////////////////////// + +class VertexPathIterator +{ +private: + VertexPathIterator(); + ~VertexPathIterator(); +}; + +class PathRef +{ +private: + PathRef(); + ~PathRef(); +}; + +class PathEnd +{ +private: + PathEnd(); + ~PathEnd(); +}; + +class MinPulseWidthCheck +{ +private: + MinPulseWidthCheck(); + ~MinPulseWidthCheck(); +}; + +class MinPulseWidthCheckSeq +{ +private: + MinPulseWidthCheckSeq(); + ~MinPulseWidthCheckSeq(); +}; + +class MinPulseWidthCheckSeqIterator +{ +private: + MinPulseWidthCheckSeqIterator(); + ~MinPulseWidthCheckSeqIterator(); +}; + +%inline %{ + +void +find_timing_cmd(bool full) +{ + cmdLinkedNetwork(); + Sta::sta()->updateTiming(full); +} + +void +arrivals_invalid() +{ + Sta *sta = Sta::sta(); + sta->arrivalsInvalid(); +} + +PinSet +startpoints() +{ + return Sta::sta()->startpointPins(); +} + +PinSet +endpoints() +{ + return Sta::sta()->endpointPins(); +} + +size_t +endpoint_count() +{ + return Sta::sta()->endpointPins().size(); +} + +void +find_requireds() +{ + cmdLinkedNetwork(); + Sta::sta()->findRequireds(); +} + +Slack +total_negative_slack_cmd(const MinMax *min_max) +{ + cmdLinkedNetwork(); + Sta *sta = Sta::sta(); + return sta->totalNegativeSlack(min_max); +} + +Slack +total_negative_slack_corner_cmd(const Corner *corner, + const MinMax *min_max) +{ + cmdLinkedNetwork(); + Sta *sta = Sta::sta(); + return sta->totalNegativeSlack(corner, min_max); +} + +Slack +worst_slack_cmd(const MinMax *min_max) +{ + cmdLinkedNetwork(); + Sta *sta = Sta::sta(); + Slack worst_slack; + Vertex *worst_vertex; + sta->worstSlack(min_max, worst_slack, worst_vertex); + return worst_slack; +} + +Vertex * +worst_slack_vertex(const MinMax *min_max) +{ + cmdLinkedNetwork(); + Sta *sta = Sta::sta(); + Slack worst_slack; + Vertex *worst_vertex; + sta->worstSlack(min_max, worst_slack, worst_vertex); + return worst_vertex;; +} + +Slack +worst_slack_corner(const Corner *corner, + const MinMax *min_max) +{ + cmdLinkedNetwork(); + Sta *sta = Sta::sta(); + Slack worst_slack; + Vertex *worst_vertex; + sta->worstSlack(corner, min_max, worst_slack, worst_vertex); + return worst_slack; +} + +PathRef * +vertex_worst_arrival_path(Vertex *vertex, + const MinMax *min_max) +{ + Sta *sta = Sta::sta(); + PathRef path = sta->vertexWorstArrivalPath(vertex, min_max); + if (!path.isNull()) + return new PathRef(path); + else + return nullptr; +} + +PathRef * +vertex_worst_arrival_path_rf(Vertex *vertex, + const RiseFall *rf, + MinMax *min_max) +{ + Sta *sta = Sta::sta(); + PathRef path = sta->vertexWorstArrivalPath(vertex, rf, min_max); + if (!path.isNull()) + return new PathRef(path); + else + return nullptr; +} + +PathRef * +vertex_worst_slack_path(Vertex *vertex, + const MinMax *min_max) +{ + Sta *sta = Sta::sta(); + PathRef path = sta->vertexWorstSlackPath(vertex, min_max); + if (!path.isNull()) + return new PathRef(path); + else + return nullptr; +} + +int +tag_group_count() +{ + return Sta::sta()->tagGroupCount(); +} + +void +report_tag_groups() +{ + Sta::sta()->search()->reportTagGroups(); +} + +void +report_tag_arrivals_cmd(Vertex *vertex) +{ + Sta::sta()->search()->reportArrivals(vertex); +} + +void +report_arrival_count_histogram() +{ + Sta::sta()->search()->reportArrivalCountHistogram(); +} + +int +tag_count() +{ + return Sta::sta()->tagCount(); +} + +void +report_tags() +{ + Sta::sta()->search()->reportTags(); +} + +void +report_clk_infos() +{ + Sta::sta()->search()->reportClkInfos(); +} + +int +clk_info_count() +{ + return Sta::sta()->clkInfoCount(); +} + +int +arrival_count() +{ + return Sta::sta()->arrivalCount(); +} + +int +required_count() +{ + return Sta::sta()->requiredCount(); +} + +int +graph_arrival_count() +{ + return Sta::sta()->graph()->arrivalCount(); +} + +int +graph_required_count() +{ + return Sta::sta()->graph()->requiredCount(); +} + +int +endpoint_violation_count(const MinMax *min_max) +{ + return Sta::sta()->endpointViolationCount(min_max); +} + +%} // inline + +//////////////////////////////////////////////////////////////// +// +// Object Methods +// +//////////////////////////////////////////////////////////////// + +%extend PathEnd { +bool is_unconstrained() { return self->isUnconstrained(); } +bool is_check() { return self->isCheck(); } +bool is_latch_check() { return self->isLatchCheck(); } +bool is_data_check() { return self->isDataCheck(); } +bool is_output_delay() { return self->isOutputDelay(); } +bool is_path_delay() { return self->isPathDelay(); } +bool is_gated_clock() { return self->isGatedClock(); } +Vertex *vertex() { return self->vertex(Sta::sta()); } +PathRef *path() { return &self->pathRef(); } +RiseFall *end_transition() +{ return const_cast(self->path()->transition(Sta::sta())); } +Slack slack() { return self->slack(Sta::sta()); } +ArcDelay margin() { return self->margin(Sta::sta()); } +Required data_required_time() { return self->requiredTimeOffset(Sta::sta()); } +Arrival data_arrival_time() { return self->dataArrivalTimeOffset(Sta::sta()); } +TimingRole *check_role() { return self->checkRole(Sta::sta()); } +MinMax *min_max() { return const_cast(self->minMax(Sta::sta())); } +float source_clk_offset() { return self->sourceClkOffset(Sta::sta()); } +Arrival source_clk_latency() { return self->sourceClkLatency(Sta::sta()); } +Arrival source_clk_insertion_delay() +{ return self->sourceClkInsertionDelay(Sta::sta()); } +const Clock *target_clk() { return self->targetClk(Sta::sta()); } +const ClockEdge *target_clk_edge() { return self->targetClkEdge(Sta::sta()); } +Path *target_clk_path() { return self->targetClkPath(); } +float target_clk_time() { return self->targetClkTime(Sta::sta()); } +float target_clk_offset() { return self->targetClkOffset(Sta::sta()); } +float target_clk_mcp_adjustment() +{ return self->targetClkMcpAdjustment(Sta::sta()); } +Arrival target_clk_delay() { return self->targetClkDelay(Sta::sta()); } +Arrival target_clk_insertion_delay() +{ return self->targetClkInsertionDelay(Sta::sta()); } +float target_clk_uncertainty() +{ return self->targetNonInterClkUncertainty(Sta::sta()); } +float inter_clk_uncertainty() +{ return self->interClkUncertainty(Sta::sta()); } +Arrival target_clk_arrival() { return self->targetClkArrival(Sta::sta()); } +bool path_delay_margin_is_external() +{ return self->pathDelayMarginIsExternal();} +Crpr check_crpr() { return self->checkCrpr(Sta::sta()); } +RiseFall *target_clk_end_trans() +{ return const_cast(self->targetClkEndTrans(Sta::sta())); } +Delay clk_skew() { return self->clkSkew(Sta::sta()); } + +} + +%extend PathRef { +float +arrival() +{ + Sta *sta = Sta::sta(); + return delayAsFloat(self->arrival(sta)); +} + +float +required() +{ + Sta *sta = Sta::sta(); + return delayAsFloat(self->required(sta)); +} + +float +slack() +{ + Sta *sta = Sta::sta(); + return delayAsFloat(self->slack(sta)); +} + +const Pin * +pin() +{ + Sta *sta = Sta::sta(); + return self->pin(sta); +} + +const char * +tag() +{ + Sta *sta = Sta::sta(); + return self->tag(sta)->asString(sta); +} + +// mea_opt3 +PinSeq +pins() +{ + Sta *sta = Sta::sta(); + PinSeq pins; + PathRef path1(self); + while (!path1.isNull()) { + pins.push_back(path1.vertex(sta)->pin()); + PathRef prev_path; + path1.prevPath(sta, prev_path); + path1.init(prev_path); + } + return pins; +} + +} + +%extend VertexPathIterator { +bool has_next() { return self->hasNext(); } +PathRef * +next() +{ + Path *path = self->next(); + return new PathRef(path); +} + +void finish() { delete self; } +} + +%extend MinPulseWidthCheckSeqIterator { +bool has_next() { return self->hasNext(); } +MinPulseWidthCheck *next() { return self->next(); } +void finish() { delete self; } +} // MinPulseWidthCheckSeqIterator methods diff --git a/tcl/Search.tcl b/search/Search.tcl similarity index 100% rename from tcl/Search.tcl rename to search/Search.tcl diff --git a/tcl/StaTcl.i b/tcl/StaTcl.i index 8fba0c20..98ac455f 100644 --- a/tcl/StaTcl.i +++ b/tcl/StaTcl.i @@ -137,48 +137,6 @@ private: ~Transition(); }; -class PathRef -{ -private: - PathRef(); - ~PathRef(); -}; - -class PathEnd -{ -private: - PathEnd(); - ~PathEnd(); -}; - -class MinPulseWidthCheck -{ -private: - MinPulseWidthCheck(); - ~MinPulseWidthCheck(); -}; - -class MinPulseWidthCheckSeq -{ -private: - MinPulseWidthCheckSeq(); - ~MinPulseWidthCheckSeq(); -}; - -class MinPulseWidthCheckSeqIterator -{ -private: - MinPulseWidthCheckSeqIterator(); - ~MinPulseWidthCheckSeqIterator(); -}; - -class VertexPathIterator -{ -private: - VertexPathIterator(); - ~VertexPathIterator(); -}; - class Corner { private: @@ -684,6 +642,16 @@ unit_scaled_suffix(const char *unit_name) return ""; } +float +unit_scale(const char *unit_name) +{ + Unit *unit = Sta::sta()->units()->find(unit_name); + if (unit) + return unit->scale(); + else + return 1.0F; +} + //////////////////////////////////////////////////////////////// const char * @@ -1230,24 +1198,6 @@ worst_clk_skew_cmd(const SetupHold *setup_hold, //////////////////////////////////////////////////////////////// -PinSet -startpoints() -{ - return Sta::sta()->startpointPins(); -} - -PinSet -endpoints() -{ - return Sta::sta()->endpointPins(); -} - -size_t -endpoint_count() -{ - return Sta::sta()->endpointPins().size(); -} - PinSet group_path_pins(const char *group_path_name) { @@ -1369,115 +1319,6 @@ report_max_skew_check(MaxSkewCheck *check, //////////////////////////////////////////////////////////////// -void -find_timing_cmd(bool full) -{ - cmdLinkedNetwork(); - Sta::sta()->updateTiming(full); -} - -void -find_requireds() -{ - cmdLinkedNetwork(); - Sta::sta()->findRequireds(); -} - -void -find_delays() -{ - cmdLinkedNetwork(); - Sta::sta()->findDelays(); -} - -Slack -total_negative_slack_cmd(const MinMax *min_max) -{ - cmdLinkedNetwork(); - Sta *sta = Sta::sta(); - return sta->totalNegativeSlack(min_max); -} - -Slack -total_negative_slack_corner_cmd(const Corner *corner, - const MinMax *min_max) -{ - cmdLinkedNetwork(); - Sta *sta = Sta::sta(); - return sta->totalNegativeSlack(corner, min_max); -} - -Slack -worst_slack_cmd(const MinMax *min_max) -{ - cmdLinkedNetwork(); - Sta *sta = Sta::sta(); - Slack worst_slack; - Vertex *worst_vertex; - sta->worstSlack(min_max, worst_slack, worst_vertex); - return worst_slack; -} - -Vertex * -worst_slack_vertex(const MinMax *min_max) -{ - cmdLinkedNetwork(); - Sta *sta = Sta::sta(); - Slack worst_slack; - Vertex *worst_vertex; - sta->worstSlack(min_max, worst_slack, worst_vertex); - return worst_vertex;; -} - -Slack -worst_slack_corner(const Corner *corner, - const MinMax *min_max) -{ - cmdLinkedNetwork(); - Sta *sta = Sta::sta(); - Slack worst_slack; - Vertex *worst_vertex; - sta->worstSlack(corner, min_max, worst_slack, worst_vertex); - return worst_slack; -} - -PathRef * -vertex_worst_arrival_path(Vertex *vertex, - const MinMax *min_max) -{ - Sta *sta = Sta::sta(); - PathRef path = sta->vertexWorstArrivalPath(vertex, min_max); - if (!path.isNull()) - return new PathRef(path); - else - return nullptr; -} - -PathRef * -vertex_worst_arrival_path_rf(Vertex *vertex, - const RiseFall *rf, - MinMax *min_max) -{ - Sta *sta = Sta::sta(); - PathRef path = sta->vertexWorstArrivalPath(vertex, rf, min_max); - if (!path.isNull()) - return new PathRef(path); - else - return nullptr; -} - -PathRef * -vertex_worst_slack_path(Vertex *vertex, - const MinMax *min_max) -{ - Sta *sta = Sta::sta(); - PathRef path = sta->vertexWorstSlackPath(vertex, min_max); - if (!path.isNull()) - return new PathRef(path); - else - return nullptr; -} - Slack find_clk_min_period(const Clock *clk, bool ignore_port_paths) @@ -1698,16 +1539,6 @@ write_timing_model_cmd(const char *lib_name, //////////////////////////////////////////////////////////////// -float -unit_scale(const char *unit_name) -{ - Unit *unit = Sta::sta()->units()->find(unit_name); - if (unit) - return unit->scale(); - else - return 1.0F; -} - bool fuzzy_equal(float value1, float value2) @@ -1844,98 +1675,6 @@ report_loops() } } -int -tag_group_count() -{ - return Sta::sta()->tagGroupCount(); -} - -void -report_tag_groups() -{ - Sta::sta()->search()->reportTagGroups(); -} - -void -report_tag_arrivals_cmd(Vertex *vertex) -{ - Sta::sta()->search()->reportArrivals(vertex); -} - -void -report_arrival_count_histogram() -{ - Sta::sta()->search()->reportArrivalCountHistogram(); -} - -int -tag_count() -{ - return Sta::sta()->tagCount(); -} - -void -report_tags() -{ - Sta::sta()->search()->reportTags(); -} - -void -report_clk_infos() -{ - Sta::sta()->search()->reportClkInfos(); -} - -int -clk_info_count() -{ - return Sta::sta()->clkInfoCount(); -} - -int -arrival_count() -{ - return Sta::sta()->arrivalCount(); -} - -int -required_count() -{ - return Sta::sta()->requiredCount(); -} - -int -graph_arrival_count() -{ - return Sta::sta()->graph()->arrivalCount(); -} - -int -graph_required_count() -{ - return Sta::sta()->graph()->requiredCount(); -} - -void -arrivals_invalid() -{ - Sta *sta = Sta::sta(); - sta->arrivalsInvalid(); -} - -void -delays_invalid() -{ - Sta *sta = Sta::sta(); - sta->delaysInvalid(); -} - -int -endpoint_violation_count(const MinMax *min_max) -{ - return Sta::sta()->endpointViolationCount(min_max); -} - %} // inline //////////////////////////////////////////////////////////////// @@ -1944,124 +1683,6 @@ endpoint_violation_count(const MinMax *min_max) // //////////////////////////////////////////////////////////////// -%extend PathEnd { -bool is_unconstrained() { return self->isUnconstrained(); } -bool is_check() { return self->isCheck(); } -bool is_latch_check() { return self->isLatchCheck(); } -bool is_data_check() { return self->isDataCheck(); } -bool is_output_delay() { return self->isOutputDelay(); } -bool is_path_delay() { return self->isPathDelay(); } -bool is_gated_clock() { return self->isGatedClock(); } -Vertex *vertex() { return self->vertex(Sta::sta()); } -PathRef *path() { return &self->pathRef(); } -RiseFall *end_transition() -{ return const_cast(self->path()->transition(Sta::sta())); } -Slack slack() { return self->slack(Sta::sta()); } -ArcDelay margin() { return self->margin(Sta::sta()); } -Required data_required_time() { return self->requiredTimeOffset(Sta::sta()); } -Arrival data_arrival_time() { return self->dataArrivalTimeOffset(Sta::sta()); } -TimingRole *check_role() { return self->checkRole(Sta::sta()); } -MinMax *min_max() { return const_cast(self->minMax(Sta::sta())); } -float source_clk_offset() { return self->sourceClkOffset(Sta::sta()); } -Arrival source_clk_latency() { return self->sourceClkLatency(Sta::sta()); } -Arrival source_clk_insertion_delay() -{ return self->sourceClkInsertionDelay(Sta::sta()); } -const Clock *target_clk() { return self->targetClk(Sta::sta()); } -const ClockEdge *target_clk_edge() { return self->targetClkEdge(Sta::sta()); } -Path *target_clk_path() { return self->targetClkPath(); } -float target_clk_time() { return self->targetClkTime(Sta::sta()); } -float target_clk_offset() { return self->targetClkOffset(Sta::sta()); } -float target_clk_mcp_adjustment() -{ return self->targetClkMcpAdjustment(Sta::sta()); } -Arrival target_clk_delay() { return self->targetClkDelay(Sta::sta()); } -Arrival target_clk_insertion_delay() -{ return self->targetClkInsertionDelay(Sta::sta()); } -float target_clk_uncertainty() -{ return self->targetNonInterClkUncertainty(Sta::sta()); } -float inter_clk_uncertainty() -{ return self->interClkUncertainty(Sta::sta()); } -Arrival target_clk_arrival() { return self->targetClkArrival(Sta::sta()); } -bool path_delay_margin_is_external() -{ return self->pathDelayMarginIsExternal();} -Crpr check_crpr() { return self->checkCrpr(Sta::sta()); } -RiseFall *target_clk_end_trans() -{ return const_cast(self->targetClkEndTrans(Sta::sta())); } -Delay clk_skew() { return self->clkSkew(Sta::sta()); } - -} - -%extend MinPulseWidthCheckSeqIterator { -bool has_next() { return self->hasNext(); } -MinPulseWidthCheck *next() { return self->next(); } -void finish() { delete self; } -} // MinPulseWidthCheckSeqIterator methods - -%extend PathRef { -float -arrival() -{ - Sta *sta = Sta::sta(); - return delayAsFloat(self->arrival(sta)); -} - -float -required() -{ - Sta *sta = Sta::sta(); - return delayAsFloat(self->required(sta)); -} - -float -slack() -{ - Sta *sta = Sta::sta(); - return delayAsFloat(self->slack(sta)); -} - -const Pin * -pin() -{ - Sta *sta = Sta::sta(); - return self->pin(sta); -} - -const char * -tag() -{ - Sta *sta = Sta::sta(); - return self->tag(sta)->asString(sta); -} - -// mea_opt3 -PinSeq -pins() -{ - Sta *sta = Sta::sta(); - PinSeq pins; - PathRef path1(self); - while (!path1.isNull()) { - pins.push_back(path1.vertex(sta)->pin()); - PathRef prev_path; - path1.prevPath(sta, prev_path); - path1.init(prev_path); - } - return pins; -} - -} - -%extend VertexPathIterator { -bool has_next() { return self->hasNext(); } -PathRef * -next() -{ - Path *path = self->next(); - return new PathRef(path); -} - -void finish() { delete self; } -} - %extend Corner { const char *name() { return self->name(); } }