diff --git a/CMakeLists.txt b/CMakeLists.txt index 7f233a8c..3fe44d6e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ cmake_minimum_required (VERSION 3.9) -project(STA VERSION 2.0.10) +project(STA VERSION 2.0.11) set(CMAKE_VERBOSE_MAKEFILE ON) set(CMAKE_CXX_STANDARD 11) diff --git a/search/Search.cc b/search/Search.cc index 4d0f6e5c..db334674 100644 --- a/search/Search.cc +++ b/search/Search.cc @@ -227,8 +227,8 @@ Search::Search(StaState *sta) : void Search::init(StaState *sta) { - crpr_path_pruning_enabled_ = true; - unconstrained_paths_ = false; + initVars(); + search_adj_ = new SearchThru(nullptr, sta); eval_pred_ = new EvalPred(sta); check_crpr_ = new CheckCrpr(sta); @@ -264,6 +264,15 @@ Search::init(StaState *sta) found_downstream_clk_pins_ = false; } +// Init "options". +void +Search::initVars() +{ + unconstrained_paths_ = false; + crpr_path_pruning_enabled_ = true; + crpr_approx_missing_requireds_ = true; +} + Search::~Search() { deletePaths(); @@ -292,8 +301,8 @@ Search::~Search() void Search::clear() { - crpr_path_pruning_enabled_ = true; - unconstrained_paths_ = false; + initVars(); + clk_arrivals_valid_ = false; arrivals_at_endpoints_exist_ = false; arrivals_seeded_ = false; @@ -328,6 +337,18 @@ Search::setCrprpathPruningEnabled(bool enabled) crpr_path_pruning_enabled_ = enabled; } +bool +Search::crprApproxMissingRequireds() const +{ + return crpr_approx_missing_requireds_; +} + +void +Search::setCrprApproxMissingRequireds(bool enabled) +{ + crpr_approx_missing_requireds_ = enabled; +} + void Search::deleteTags() { @@ -3436,7 +3457,7 @@ RequiredVisitor::visitFromToPath(const Pin *, Tag *to_tag, Arrival &, const MinMax *min_max, - const PathAnalysisPt *) + const PathAnalysisPt *path_ap) { // Don't propagate required times through latch D->Q edges. if (edge->role() != TimingRole::latchDtoQ()) { @@ -3469,8 +3490,35 @@ RequiredVisitor::visitFromToPath(const Pin *, delayAsString(required_cmp_->required(arrival_index), sta_)); required_cmp_->requiredSet(arrival_index, from_required, req_min); } - else + else { + if (sta_->search()->crprApproxMissingRequireds()) { + // Arrival on to_vertex that differs by crpr_pin was pruned. + // Find an arrival that matches everything but the crpr_pin + // as an appromate required. + VertexPathIterator to_iter(to_vertex, to_tr, path_ap, sta_); + while (to_iter.hasNext()) { + PathVertex *to_path = to_iter.next(); + Tag *to_path_tag = to_path->tag(sta_); + if (tagMatchNoCrpr(to_path_tag, to_tag)) { + Required to_required = to_path->required(sta_); + Required from_required = to_required - arc_delay; + debugPrint2(debug, "search", 3, " to tag %2u: %s\n", + to_path_tag->index(), + to_path_tag->asString(sta_)); + debugPrint5(debug, "search", 3, " %s - %s = %s %s %s\n", + delayAsString(to_required, sta_), + delayAsString(arc_delay, sta_), + delayAsString(from_required, sta_), + min_max == MinMax::max() ? "<" : ">", + delayAsString(required_cmp_->required(arrival_index), + sta_)); + required_cmp_->requiredSet(arrival_index, from_required, req_min); + break; + } + } + } from_vertex->setRequiredsPruned(true); + } // Propagate requireds pruned flag backwards. if (to_vertex->requiredsPruned()) from_vertex->setRequiredsPruned(true); diff --git a/search/Search.hh b/search/Search.hh index 3758c739..c93cad70 100644 --- a/search/Search.hh +++ b/search/Search.hh @@ -70,10 +70,15 @@ public: // Reset to virgin state. void clear(); // When enabled, non-critical path arrivals are pruned to improve - // run time and reduce memory. The side-effect is that slacks for - // non-critical paths on intermediate pins may be incorrect. + // run time and reduce memory. bool crprPathPruningEnabled() const; void setCrprpathPruningEnabled(bool enabled); + // When path pruning is enabled required times for non-critical paths + // that have been pruned require additional search. This option + // disables additional search to returns approximate required times. + bool crprApproxMissingRequireds() const; + void setCrprApproxMissingRequireds(bool enabled); + bool unconstrainedPaths() const { return unconstrained_paths_; } // from/thrus/to are owned and deleted by Search. // Use corner nullptr to report timing for all corners. @@ -344,6 +349,7 @@ public: protected: void init(StaState *sta); + void initVars(); void makeAnalysisPts(AnalysisType analysis_type); void makeAnalysisPts(bool swap_clk_min_max, bool report_min, @@ -524,6 +530,8 @@ protected: // findPathEnds arg. bool unconstrained_paths_; + bool crpr_path_pruning_enabled_; + bool crpr_approx_missing_requireds_; // Search predicates. SearchPred *search_adj_; SearchPred *search_clk_; @@ -591,7 +599,6 @@ protected: VisitPathEnds *visit_path_ends_; GatedClk *gated_clk_; CheckCrpr *check_crpr_; - bool crpr_path_pruning_enabled_; Genclks *genclks_; }; diff --git a/search/Sta.cc b/search/Sta.cc index 5209128d..976560bf 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -2880,13 +2880,14 @@ Sta::findRequired(Vertex *vertex) search_->findRequireds(vertex->level()); if (sdc_->crprEnabled() && search_->crprPathPruningEnabled() + && !search_->crprApproxMissingRequireds() // Clocks invariably have requireds that are pruned but isn't // worth finding arrivals and requireds all over again for // the entire fanout of the clock. && !search_->isClock(vertex) && vertex->requiredsPruned()) { // Invalidate arrivals and requireds and disable - // path pruning on fanout vertices. + // path pruning on fanout vertices with DFS. int fanout = 0; disableFanoutCrprPruning(vertex, fanout); debugPrint2(debug_, "search", 1, "resurrect pruned required %s fanout %d\n", @@ -2898,8 +2899,6 @@ Sta::findRequired(Vertex *vertex) } } -// DFS to invalidate fanout arrivals and requireds to -// find arrivals with pruning disabled. void Sta::disableFanoutCrprPruning(Vertex *vertex, int &fanout)