Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions include/sta/Liberty.hh
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,8 @@ public:
bool isClockGateOther() const;
bool isClockGate() const;
void setClockGateType(ClockGateType type);
void setHasClkGateClkPin() { has_clk_gate_clk_pin_ = true; }
void setHasClkGateEnablePin() { has_clk_gate_enable_pin_ = true; }
const char *getDesignType() const;
const TimingArcSetSeq &timingArcSets() const { return timing_arc_sets_; }
// from or to may be nullptr to wildcard.
Expand Down Expand Up @@ -626,6 +628,8 @@ protected:
SwitchCellType switch_cell_type_;
bool interface_timing_;
ClockGateType clock_gate_type_;
bool has_clk_gate_clk_pin_;
bool has_clk_gate_enable_pin_;
TimingArcSetSeq timing_arc_sets_;
TimingArcSetMap timing_arc_set_map_;
LibertyPortPairTimingArcMap port_timing_arc_set_map_;
Expand Down
6 changes: 6 additions & 0 deletions include/sta/Search.hh
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#include <mutex>
#include <atomic>
#include <vector>

#include "MinMax.hh"
#include "UnorderedSet.hh"
Expand Down Expand Up @@ -226,6 +227,8 @@ public:

// Find arrivals for the clock tree.
void findClkArrivals();
bool isClkGated(const Vertex *vertex) const;
void updateClkGates(Vertex *vertex);
void seedArrival(Vertex *vertex);
EvalPred *evalPred() const { return eval_pred_; }
SearchPred *searchAdj() const { return search_adj_; }
Expand Down Expand Up @@ -519,6 +522,7 @@ protected:
void seedClkVertexArrivals(const Pin *pin,
Vertex *vertex);
void findClkArrivals1();
bool isClkGateInstance(Vertex *vertex);

void findAllArrivals(bool thru_latches);
void findArrivals1(Level level);
Expand Down Expand Up @@ -608,6 +612,8 @@ protected:
ArrivalVisitor *arrival_visitor_;
// Clock arrivals are known.
bool clk_arrivals_valid_;
// Per-vertex cache of whether the vertex is clock gated.
std::vector<char> clk_gated_;
Comment thread
stanminlee marked this conversation as resolved.
// Some arrivals exist.
bool arrivals_exist_;
// Arrivals at end points exist (but may be invalid).
Expand Down
2 changes: 1 addition & 1 deletion include/sta/Sta.hh
Original file line number Diff line number Diff line change
Expand Up @@ -607,8 +607,8 @@ public:
bool thru_disabled,
bool thru_constants);

// Registers whose clock pin is in the fanout of an ICG cell
InstanceSeq clockGatedRegisters();
bool isClkGatedRegister(const Instance *inst);

// The set of clocks that arrive at vertex in the clock network.
ClockSet clocks(const Pin *pin);
Expand Down
6 changes: 5 additions & 1 deletion liberty/Liberty.cc
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,8 @@ LibertyCell::LibertyCell(LibertyLibrary *library,
switch_cell_type_(SwitchCellType::fine_grain),
interface_timing_(false),
clock_gate_type_(ClockGateType::none),
has_clk_gate_clk_pin_(false),
has_clk_gate_enable_pin_(false),
has_infered_reg_timing_arcs_(false),
statetable_(nullptr),
scale_factors_(nullptr),
Expand Down Expand Up @@ -1167,7 +1169,9 @@ LibertyCell::isClockGateOther() const
bool
LibertyCell::isClockGate() const
{
return clock_gate_type_ != ClockGateType::none;
return clock_gate_type_ != ClockGateType::none
&& has_clk_gate_clk_pin_
&& has_clk_gate_enable_pin_;
}

void
Expand Down
12 changes: 12 additions & 0 deletions liberty/LibertyReader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4049,12 +4049,24 @@ void
LibertyReader::visitClockGateClockPin(LibertyAttr *attr)
{
visitPortBoolAttr(attr, &LibertyPort::setIsClockGateClock);
if (cell_) {
bool value, exists;
getAttrBool(attr, value, exists);
if (exists && value)
cell_->setHasClkGateClkPin();
}
}

void
LibertyReader::visitClockGateEnablePin(LibertyAttr *attr)
{
visitPortBoolAttr(attr, &LibertyPort::setIsClockGateEnable);
if (cell_) {
bool value, exists;
getAttrBool(attr, value, exists);
if (exists && value)
cell_->setHasClkGateEnablePin();
}
}
Comment thread
stanminlee marked this conversation as resolved.

void
Expand Down
123 changes: 123 additions & 0 deletions search/Search.cc
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,7 @@ Search::arrivalsInvalid()
requireds_exist_ = false;
requireds_seeded_ = false;
clk_arrivals_valid_ = false;
clk_gated_.clear();
arrival_iter_->clear();
required_iter_->clear();
// No need to keep track of incremental updates any more.
Expand Down Expand Up @@ -942,6 +943,7 @@ Search::findClkArrivals()
Stats stats(debug_, report_);
debugPrint(debug_, "search", 1, "find clk arrivals");
arrival_iter_->clear();
clk_gated_.assign(graph_->vertexCount() + 1, 0);
seedClkVertexArrivals();
ClkArrivalSearchPred search_clk(this);
arrival_visitor_->init(false, &search_clk);
Expand All @@ -953,6 +955,121 @@ Search::findClkArrivals()
clk_arrivals_valid_ = true;
}

bool
Search::isClkGated(const Vertex *vertex) const
{
VertexId idx = graph_->id(vertex);
return idx < clk_gated_.size() && clk_gated_[idx] != 0;
}

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;
Instance *inst = network_->instance(pin);
if (inst == nullptr)
return false;
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;
}

void
Search::updateClkGates(Vertex *vertex)
{
VertexId id = graph_->id(vertex);
if (id >= clk_gated_.size())
return;

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));
}

// 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()));

// 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;
}
}
}
debugPrint(debug_, "clkgates", 1,
" final verdict: %s", gated ? "gated" : "not gated");

// Update the node gated state
clk_gated_[id] = gated;
}
Comment thread
stanminlee marked this conversation as resolved.

void
Search::seedClkVertexArrivals()
{
Expand Down Expand Up @@ -1148,6 +1265,8 @@ Search::findArrivalsSeed()
arrival_iter_->ensureSize();
required_iter_->ensureSize();
}
if (clk_gated_.size() < graph_->vertexCount() + 1)
clk_gated_.assign(graph_->vertexCount() + 1, 0);
seedInvalidArrivals();
}

Expand Down Expand Up @@ -1279,6 +1398,10 @@ 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
Expand Down
89 changes: 34 additions & 55 deletions search/Sta.cc
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
#include "PathAnalysisPt.hh"
#include "Corner.hh"
#include "Search.hh"
#include "GatedClk.hh"
#include "Latches.hh"
#include "PathGroup.hh"
#include "CheckTiming.hh"
Expand Down Expand Up @@ -5351,69 +5352,47 @@ pinInstances(PinSet &pins,
return insts;
}

InstanceSeq Sta::clockGatedRegisters() {
Network* network = this->network();
InstanceSeq
Sta::clockGatedRegisters()
{
InstanceSeq result;

// Map of pins that are a derivative of icg instances
std::unordered_map<const Pin*, Instance*> pin_to_icg;
std::unique_ptr<LeafInstanceIterator> insts(
network->leafInstanceIterator());

// Iterate over all leaf instances
// Find all leaf registers
std::unique_ptr<LeafInstanceIterator> insts(network_->leafInstanceIterator());
while (insts->hasNext()) {
Instance* icg = insts->next();

// Skip any non-ICG cells
LibertyCell* lc = network->libertyCell(network->cell(icg));
if (!lc || !lc->isClockGate()) continue;

// Get clock gate output pin
PinSeq from;
std::unique_ptr<InstancePinIterator> pit(network->pinIterator(icg));
while (pit->hasNext()) {
Pin* p = pit->next();
LibertyPort* lp = network->libertyPort(p);
if (lp && lp->isClockGateOut()) from.push_back(p);
}
Instance *inst = insts->next();
LibertyCell *cell = network_->libertyCell(inst);

// If no output pin, skip (shouldn't happen)
if (from.empty()) continue;
// Skip if the cell is not a register or a clock gate.
if (cell == nullptr || !cell->hasSequentials() || cell->isClockGate())
continue;

// Find all pins that are a derivative of the ICG output pin
PinSet fanout = findFanoutPins(
&from, true, true, 0, 0, false, false);
for (const Pin* p : fanout) {
if (network->isRegClkPin(p)) { // filter for register clock pins only
pin_to_icg.emplace(p, icg);
}
}
// Check if the register is clock gated based on previous graph traversal.
if (isClkGatedRegister(inst))
result.push_back(inst);
}
return result;
}
Comment thread
stanminlee marked this conversation as resolved.

// Reverse lookup from registers to determine if they are gated by an ICG
std::unique_ptr<LeafInstanceIterator> rit(
network->leafInstanceIterator());
while (rit->hasNext()) {

// Skip any non-registers
Instance* reg = rit->next();
LibertyCell* lc = network->libertyCell(network->cell(reg));
if (!lc || !lc->hasSequentials()) continue;
std::unique_ptr<InstancePinIterator> pit(network->pinIterator(reg));

// Iterate over all pins
while (pit->hasNext()) {
Pin* clk_pin = pit->next();
if (!network->isRegClkPin(clk_pin)) continue;

// Search if the pin is a derivative of an ICG output pin
auto it = pin_to_icg.find(clk_pin);
if (it == pin_to_icg.end()) continue;
result.push_back(reg);
break; // avoid duplicates
}
bool
Sta::isClkGatedRegister(const Instance *inst)
{
std::unique_ptr<InstancePinIterator>
pins(network_->pinIterator(inst));
while (pins->hasNext()) {
const Pin *pin = pins->next();

// Skip if the pin is not a register clock pin.
if (pin == nullptr || !network_->isRegClkPin(pin))
continue;
Vertex *vertex = graph_->pinLoadVertex(pin);
if (vertex == nullptr)
continue;

if (search_->isClkGated(vertex))
return true;
}
return result;
return false;
}
Comment thread
stanminlee marked this conversation as resolved.

bool
Expand Down
Loading