// 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 . #pragma once #include "NetworkClass.hh" #include "SdcClass.hh" #include "GraphClass.hh" #include "StaState.hh" namespace sta { class SearchPred; class LevelizeObserver; class Levelize : public StaState { public: explicit Levelize(StaState *sta); virtual ~Levelize(); // Space between initially assigned levels that is filled in by // incremental levelization. Set level space before levelization. void setLevelSpace(Level space); bool levelized() { return levels_valid_; } void ensureLevelized(); void invalid(); // Levels downstream from vertex are invalid. void invalidFrom(Vertex *vertex); void relevelizeFrom(Vertex *vertex); void deleteVertexBefore(Vertex *vertex); void deleteEdgeBefore(Edge *edge); int maxLevel() const { return max_level_; } // Vertices with no fanin edges. VertexSet *roots() { return roots_; } bool isRoot(Vertex *vertex); // Reset to virgin state. void clear(); // Edge is disabled to break combinational loops. bool isDisabledLoop(Edge *edge) const; // Only valid when levels are valid. GraphLoopSeq *loops() { return loops_; } // Set the observer for level changes. void setObserver(LevelizeObserver *observer); protected: void levelize(); void findRoots(); void sortRoots(VertexSeq &roots); void levelizeFrom(VertexSeq &roots); void visit(Vertex *vertex, Level level, Level level_space, EdgeSeq &path); void levelizeCycles(); void relevelize(); void clearLoopEdges(); void deleteLoops(); void recordLoop(Edge *edge, EdgeSeq &path); EdgeSeq *loopEdges(EdgeSeq &path, Edge *closing_edge); void ensureLatchLevels(); void setLevel(Vertex *vertex, Level level); void reportPath(EdgeSeq &path) const; SearchPred *search_pred_; bool levelized_; bool levels_valid_; Level max_level_; Level level_space_; VertexSet *roots_; VertexSet *relevelize_from_; GraphLoopSeq *loops_; EdgeSet loop_edges_; EdgeSet disabled_loop_edges_; EdgeSet latch_d_to_q_edges_; LevelizeObserver *observer_; }; // Loops broken by levelization may not necessarily be combinational. // For example, a register/latch output can feed back to a gated clock // enable on the register/latch clock. class GraphLoop { public: explicit GraphLoop(EdgeSeq *edges); ~GraphLoop(); EdgeSeq *edges() { return edges_; } bool isCombinational() const; void report(Report *report, Network *network, Graph *graph) const; private: EdgeSeq *edges_; }; class LevelizeObserver { public: LevelizeObserver() {} virtual ~LevelizeObserver() {} virtual void levelChangedBefore(Vertex *vertex) = 0; }; } // namespace