From 621c121998bfa6eed3dea5ad564262cb7b8ae22d Mon Sep 17 00:00:00 2001 From: Stan Lee <135666755+stanminlee@users.noreply.github.com> Date: Tue, 5 May 2026 02:27:14 -0700 Subject: [PATCH 1/4] new --- include/sta/Search.hh | 1 + search/Search.cc | 177 ++++++++++++++++++++++-------------------- 2 files changed, 94 insertions(+), 84 deletions(-) diff --git a/include/sta/Search.hh b/include/sta/Search.hh index 0261c8b4..a8085a6c 100644 --- a/include/sta/Search.hh +++ b/include/sta/Search.hh @@ -229,6 +229,7 @@ public: void findClkArrivals(); bool isClkGated(const Vertex *vertex) const; void updateClkGates(Vertex *vertex); + void computeClkGates(); void seedArrival(Vertex *vertex); EvalPred *evalPred() const { return eval_pred_; } SearchPred *searchAdj() const { return search_adj_; } diff --git a/search/Search.cc b/search/Search.cc index 35744580..5a822bb2 100644 --- a/search/Search.cc +++ b/search/Search.cc @@ -965,7 +965,6 @@ Search::isClkGated(const Vertex *vertex) const bool Search::isClkGateInstance(Vertex *vertex) { - // Return if the cell is a clock gate based on liberty cell attributes. Pin *pin = vertex->pin(); if (pin == nullptr) return false; @@ -975,33 +974,8 @@ Search::isClkGateInstance(Vertex *vertex) LibertyCell *cell = network_->libertyCell(inst); if (cell == nullptr || !cell->isClockGate()) return false; - - // Locate functional enable pin on the clock gate. - const Pin *enable_pin = nullptr; - InstancePinIterator *pin_iter = network_->pinIterator(inst); - while (pin_iter->hasNext()) { - const Pin *inst_pin = pin_iter->next(); - const LibertyPort *port = network_->libertyPort(inst_pin); - if (port != nullptr && port->isClockGateEnable()) { - enable_pin = inst_pin; - break; - } - } - delete pin_iter; - if (enable_pin == nullptr) - return false; - - // Check if the enable pin is tied to a constant to invalidate the gate. - sim_->ensureConstantsPropagated(); - LogicValue value = sim_->logicValue(enable_pin); - if (value != LogicValue::zero && value != LogicValue::one) - return true; - - // Debug message - debugPrint(debug_, "clkgates", 1, - " enable pin %s tied to constant; not considered gated", - network_->pathName(enable_pin)); - return false; + const LibertyPort *port = network_->libertyPort(pin); + return port != nullptr && port->isClockGateOut(); } void @@ -1011,62 +985,72 @@ Search::updateClkGates(Vertex *vertex) if (id >= clk_gated_.size()) return; + // Find and log instance name being evaluated. Instance *inst = network_->instance(vertex->pin()); - if (inst != nullptr) { - debugPrint(debug_, "clkgates", 1, "updating clk gates for %s (cell %s)", - network_->pathName(vertex->pin()), - network_->cellName(inst)); - } + const char *inst_name = inst != nullptr + ? network_->cellName(inst) : "unknown"; + debugPrint(debug_, "clkgates", 1, "updating clk gates for %s (cell %s)", + network_->pathName(vertex->pin()), inst_name); - // Return if the cell is a clock gate based on liberty cell attributes. - bool gated = isClkGateInstance(vertex); - if (gated) - debugPrint(debug_, "clkgates", 1, " pin %s is a clock gate", - network_->pathName(vertex->pin())); + // Check for clock-gate instance and initialize booleans for evaluation. + const bool is_gate = isClkGateInstance(vertex); + bool any_live = false; + bool all_gated = true; - // If the cell is not a clock gate, check if any of the predecessors are clock gates. - if (!gated) { - - // At least one path through the vertex must be considered gated. - VertexInEdgeIterator edge_iter(vertex, graph_); - while (edge_iter.hasNext()) { - - // Loop through all clock-tagged predecessors. - Vertex *from = edge_iter.next()->from(graph_); - if (from == nullptr) { - debugPrint(debug_, "clkgates", 1, " from edge is undefined"); - continue; - } - - // Debug print the predecessor cell name. - Pin *from_pin = from->pin(); - if (from_pin == nullptr) { - continue; - } - Instance *from_inst = network_->instance(from_pin); - std::string from_cell_name = from_inst != nullptr ? network_->cellName(from_inst) : "unknown"; - debugPrint(debug_, "clkgates", 1, " checking edge %s (cell %s)", - network_->pathName(from_pin), from_cell_name.c_str()); - - if (!isClock(from)) { - debugPrint(debug_, "clkgates", 1, " from edge %s is not a clock (cell %s)", - network_->pathName(from->pin()), from_cell_name.c_str()); - continue; - } - - // If one predecessor is gated, the vertex is gated. - if (clk_gated_[graph_->id(from)]) { - debugPrint(debug_, "clkgates", 1, " from edge %s is gated", - network_->pathName(from->pin())); - gated = true; - break; - } + // Loop through all input edges. + VertexInEdgeIterator edge_iter(vertex, graph_); + ClkTreeSearchPred clk_tree_pred(this); + while (edge_iter.hasNext()) { + + // Get the pin to evaluate. + Edge *edge = edge_iter.next(); + Vertex *from = edge->from(graph_); + if (from == nullptr) + continue; + Pin *from_pin = from->pin(); + if (from_pin == nullptr) + continue; + + // Log source cell name. + Instance *from_inst = network_->instance(from_pin); + const char *from_cell_name = from_inst != nullptr + ? network_->cellName(from_inst) : "unknown"; + debugPrint(debug_, "clkgates", 1, " checking edge %s (cell %s)", + network_->pathName(from_pin), from_cell_name); + + // Do not consider any non-clock edges or invalid timing arcs. + if (!isClock(from)) { + debugPrint(debug_, "clkgates", 1, + " edge %s is not a clock - skipped", + network_->pathName(from_pin)); + continue; + } + if (!clk_tree_pred.searchThru(edge)) { + debugPrint(debug_, "clkgates", 1, " edge %s skipped (not a live arc)", + network_->pathName(from_pin)); + continue; } + any_live = true; // encountered a live clock timing arc + + // Check if the vertex itself is gated or if the input edge is gated. + if (is_gate || clk_gated_[graph_->id(from)]) { + debugPrint(debug_, "clkgates", 1, " edge %s live, %s", + network_->pathName(from_pin), + is_gate ? "cell gates" : "source gated"); + continue; + } + + // If the input edge is not gated, all_gated is now false. + debugPrint(debug_, "clkgates", 1, " edge %s live, source NOT gated", + network_->pathName(from_pin)); + all_gated = false; + break; } - debugPrint(debug_, "clkgates", 1, - " final verdict: %s", gated ? "gated" : "not gated"); - // Update the node gated state + // Determine if the vertex is gated based on cell type. and input edges + bool gated = any_live && (is_gate || all_gated); + debugPrint(debug_, "clkgates", 1, " final verdict: %s", + gated ? "gated" : "not gated"); clk_gated_[id] = gated; } @@ -1231,6 +1215,33 @@ Search::findArrivals(Level level) findArrivals1(level); } +void +Search::computeClkGates() +{ + // Reset the clock gated set. + clk_gated_.assign(graph_->vertexCount() + 1, 0); + const Level max_level = levelize_->maxLevel(); + if (max_level < 0) + return; + + // Gather every clock-tagged vertex by level. + std::vector> by_level(max_level + 1); + VertexIterator vertex_iter(graph_); + while (vertex_iter.hasNext()) { + Vertex *vertex = vertex_iter.next(); + if (isClock(vertex)) { + Level level = vertex->level(); + if (level >= 0) + by_level[level].push_back(vertex); + } + } + + // Update clock gated state for every vertex in each ascending level. + for (auto &bucket : by_level) + for (Vertex *v : bucket) + updateClkGates(v); +} + void Search::findArrivals1(Level level) { @@ -1249,6 +1260,10 @@ Search::findArrivals1(Level level) } arrivals_exist_ = true; debugPrint(debug_, "search", 1, "found %d arrivals", arrival_count); + + // Compute clock gated registers after all arrivals are found. + if (arrival_count > 0) + computeClkGates(); } void @@ -1265,8 +1280,6 @@ Search::findArrivalsSeed() arrival_iter_->ensureSize(); required_iter_->ensureSize(); } - if (clk_gated_.size() < graph_->vertexCount() + 1) - clk_gated_.assign(graph_->vertexCount() + 1, 0); seedInvalidArrivals(); } @@ -1398,10 +1411,6 @@ ArrivalVisitor::visit(Vertex *vertex) constrainedRequiredsInvalid(vertex, is_clk); } enqueueRefPinInputDelays(pin); - - // Update the clock gate set if it is a clock vertex. - if (search_->isClock(vertex)) - search_->updateClkGates(vertex); } // When a clock arrival changes, the required time changes for any From 563b4487880927f6f95f7ba4d05d6a54a8e66a3a Mon Sep 17 00:00:00 2001 From: Stan Lee <135666755+stanminlee@users.noreply.github.com> Date: Tue, 5 May 2026 02:29:41 -0700 Subject: [PATCH 2/4] organize --- include/sta/Search.hh | 2 +- search/Search.cc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/sta/Search.hh b/include/sta/Search.hh index a8085a6c..679fd15e 100644 --- a/include/sta/Search.hh +++ b/include/sta/Search.hh @@ -230,6 +230,7 @@ public: bool isClkGated(const Vertex *vertex) const; void updateClkGates(Vertex *vertex); void computeClkGates(); + bool isClkGateVertex(Vertex *vertex); void seedArrival(Vertex *vertex); EvalPred *evalPred() const { return eval_pred_; } SearchPred *searchAdj() const { return search_adj_; } @@ -523,7 +524,6 @@ protected: void seedClkVertexArrivals(const Pin *pin, Vertex *vertex); void findClkArrivals1(); - bool isClkGateInstance(Vertex *vertex); void findAllArrivals(bool thru_latches); void findArrivals1(Level level); diff --git a/search/Search.cc b/search/Search.cc index 5a822bb2..12689820 100644 --- a/search/Search.cc +++ b/search/Search.cc @@ -963,7 +963,7 @@ Search::isClkGated(const Vertex *vertex) const } bool -Search::isClkGateInstance(Vertex *vertex) +Search::isClkGateVertex(Vertex *vertex) { Pin *pin = vertex->pin(); if (pin == nullptr) @@ -974,7 +974,7 @@ Search::isClkGateInstance(Vertex *vertex) LibertyCell *cell = network_->libertyCell(inst); if (cell == nullptr || !cell->isClockGate()) return false; - const LibertyPort *port = network_->libertyPort(pin); + LibertyPort *port = network_->libertyPort(pin); return port != nullptr && port->isClockGateOut(); } From a4a978410ba7cf1547ab5d5cebc4e7c7fbc4f22a Mon Sep 17 00:00:00 2001 From: Stan Lee <135666755+stanminlee@users.noreply.github.com> Date: Tue, 5 May 2026 02:37:27 -0700 Subject: [PATCH 3/4] fix --- search/Search.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/search/Search.cc b/search/Search.cc index 12689820..8ad5f219 100644 --- a/search/Search.cc +++ b/search/Search.cc @@ -993,7 +993,7 @@ Search::updateClkGates(Vertex *vertex) network_->pathName(vertex->pin()), inst_name); // Check for clock-gate instance and initialize booleans for evaluation. - const bool is_gate = isClkGateInstance(vertex); + const bool is_gate = isClkGateVertex(vertex); bool any_live = false; bool all_gated = true; From 9098154db17a621be17e41c02be63dd4dc8b09fc Mon Sep 17 00:00:00 2001 From: Stan Lee <135666755+stanminlee@users.noreply.github.com> Date: Tue, 5 May 2026 02:50:01 -0700 Subject: [PATCH 4/4] typo --- search/Search.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/search/Search.cc b/search/Search.cc index 8ad5f219..c6ec1809 100644 --- a/search/Search.cc +++ b/search/Search.cc @@ -1047,7 +1047,7 @@ Search::updateClkGates(Vertex *vertex) break; } - // Determine if the vertex is gated based on cell type. and input edges + // Determine if the vertex is gated based on cell type and input edges. bool gated = any_live && (is_gate || all_gated); debugPrint(debug_, "clkgates", 1, " final verdict: %s", gated ? "gated" : "not gated");