Files
OpenSTA/sdc/Clock.cc
T

657 lines
15 KiB
C++
Raw Normal View History

2018-09-28 08:54:21 -07:00
// OpenSTA, Static Timing Analyzer
2026-03-10 13:21:17 -07:00
// Copyright (c) 2026, Parallax Software, Inc.
2018-09-28 08:54:21 -07:00
//
// 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
2022-01-04 10:17:08 -07:00
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2018-09-28 08:54:21 -07:00
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
2022-01-04 10:17:08 -07:00
// along with this program. If not, see <https://www.gnu.org/licenses/>.
2025-01-21 18:54:33 -07:00
//
// The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software.
//
// Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// This notice may not be removed or altered from any source distribution.
2018-09-28 08:54:21 -07:00
2020-04-05 14:53:44 -07:00
#include "Clock.hh"
2020-04-05 11:35:51 -07:00
2018-09-28 08:54:21 -07:00
#include <algorithm>
2026-04-15 09:38:10 -07:00
#include <cstdlib>
2020-04-05 11:35:51 -07:00
2026-01-03 16:59:35 -08:00
#include "ContainerHelpers.hh"
2020-04-05 14:53:44 -07:00
#include "Error.hh"
2026-03-15 14:35:24 -07:00
#include "Format.hh"
2026-04-15 09:38:10 -07:00
#include "Graph.hh"
2020-04-05 14:53:44 -07:00
#include "MinMax.hh"
#include "Network.hh"
#include "Sdc.hh"
2026-04-15 09:38:10 -07:00
#include "StringUtil.hh"
#include "TimingRole.hh"
#include "Transition.hh"
2018-09-28 08:54:21 -07:00
namespace sta {
static bool
isPowerOfTwo(int i);
2026-03-28 19:13:35 -07:00
Clock::Clock(std::string_view name,
2026-01-03 16:59:35 -08:00
int index,
2023-01-19 11:23:45 -07:00
const Network *network) :
2026-03-28 19:13:35 -07:00
name_(name),
2023-01-19 11:23:45 -07:00
pins_(network),
leaf_pins_(network),
2026-04-15 09:38:10 -07:00
index_(index)
2018-09-28 08:54:21 -07:00
{
makeClkEdges();
}
void
2026-04-16 18:42:26 -07:00
Clock::initClk(const PinSet &pins,
2026-01-03 16:59:35 -08:00
bool add_to_pins,
float period,
2026-04-16 18:42:26 -07:00
const FloatSeq &waveform,
2026-03-28 19:13:35 -07:00
std::string_view comment,
2026-01-03 16:59:35 -08:00
const Network *network)
2018-09-28 08:54:21 -07:00
{
is_generated_ = false;
setPins(pins, network);
add_to_pins_ = add_to_pins;
waveform_ = waveform;
waveform_valid_ = true;
period_ = period;
setClkEdgeTimes();
2026-04-15 09:38:10 -07:00
setComment(comment);
2018-09-28 08:54:21 -07:00
}
bool
Clock::isVirtual() const
{
2019-10-25 08:51:59 -07:00
return pins_.empty();
2018-09-28 08:54:21 -07:00
}
void
2026-04-16 18:42:26 -07:00
Clock::setPins(const PinSet &pins,
2026-01-03 16:59:35 -08:00
const Network *network)
2018-09-28 08:54:21 -07:00
{
2026-04-16 18:42:26 -07:00
pins_ = pins;
2019-10-25 08:51:59 -07:00
makeLeafPins(network);
2018-09-28 08:54:21 -07:00
}
void
2019-10-25 08:51:59 -07:00
Clock::makeLeafPins(const Network *network)
2018-09-28 08:54:21 -07:00
{
2019-10-25 08:51:59 -07:00
leaf_pins_.clear();
2026-01-03 16:59:35 -08:00
for (const Pin *pin : pins_)
2019-10-25 08:51:59 -07:00
findLeafDriverPins(pin, network, &leaf_pins_);
2018-09-28 08:54:21 -07:00
}
void
Clock::setMasterClk(Clock *master)
{
master_clk_ = master;
waveform_valid_ = false;
}
void
Clock::makeClkEdges()
{
2026-04-16 18:42:26 -07:00
for (const RiseFall *rf : RiseFall::range()) {
2023-10-25 15:12:47 -07:00
clk_edges_[rf->index()] = new ClockEdge(this, rf);
2018-09-28 08:54:21 -07:00
}
}
Clock::~Clock()
{
2026-04-16 18:42:26 -07:00
for (size_t rf_index : RiseFall::rangeIndex())
delete clk_edges_[rf_index];
2018-09-28 08:54:21 -07:00
}
void
2023-01-19 11:23:45 -07:00
Clock::addPin(const Pin *pin)
2018-09-28 08:54:21 -07:00
{
2019-10-25 08:51:59 -07:00
pins_.insert(pin);
leaf_pins_.insert(pin);
2018-09-28 08:54:21 -07:00
}
void
2023-01-19 11:23:45 -07:00
Clock::deletePin(const Pin *pin)
2018-09-28 08:54:21 -07:00
{
2019-10-25 08:51:59 -07:00
pins_.erase(pin);
2018-09-28 08:54:21 -07:00
}
void
Clock::setAddToPins(bool add_to_pins)
{
add_to_pins_ = add_to_pins;
}
void
Clock::setClkEdgeTimes()
{
2019-11-11 15:30:19 -07:00
setClkEdgeTime(RiseFall::rise());
setClkEdgeTime(RiseFall::fall());
2018-09-28 08:54:21 -07:00
}
void
2019-11-11 15:30:19 -07:00
Clock::setClkEdgeTime(const RiseFall *rf)
2018-09-28 08:54:21 -07:00
{
2026-04-16 18:42:26 -07:00
float time = waveform_[rf->index()];
2019-11-11 15:30:19 -07:00
clk_edges_[rf->index()]->setTime(time);
2018-09-28 08:54:21 -07:00
}
2023-01-19 11:23:45 -07:00
const Pin *
2018-09-28 08:54:21 -07:00
Clock::defaultPin() const
{
2026-01-03 16:59:35 -08:00
auto itr = leaf_pins_.begin();
if (itr != leaf_pins_.end())
return *itr;
2018-09-28 08:54:21 -07:00
else
2019-03-12 17:25:53 -07:00
return nullptr;
2018-09-28 08:54:21 -07:00
}
ClockEdge *
2019-11-11 15:30:19 -07:00
Clock::edge(const RiseFall *rf) const
2018-09-28 08:54:21 -07:00
{
2019-11-11 15:30:19 -07:00
return clk_edges_[rf->index()];
2018-09-28 08:54:21 -07:00
}
void
Clock::setIsPropagated(bool propagated)
{
is_propagated_ = propagated;
}
void
2019-11-11 15:30:19 -07:00
Clock::slew(const RiseFall *rf,
2026-01-03 16:59:35 -08:00
const MinMax *min_max,
// Return values.
float &slew,
bool &exists) const
2018-09-28 08:54:21 -07:00
{
2019-11-11 15:30:19 -07:00
slews_.value(rf, min_max, slew, exists);
2018-09-28 08:54:21 -07:00
}
float
2019-11-11 15:30:19 -07:00
Clock::slew(const RiseFall *rf,
2026-01-03 16:59:35 -08:00
const MinMax *min_max) const
2018-09-28 08:54:21 -07:00
{
float slew;
bool exists;
2019-11-11 15:30:19 -07:00
slews_.value(rf, min_max, slew, exists);
2018-09-28 08:54:21 -07:00
if (!exists)
slew = 0.0;
return slew;
}
void
2019-11-11 15:30:19 -07:00
Clock::setSlew(const RiseFallBoth *rf,
2026-01-03 16:59:35 -08:00
const MinMaxAll *min_max,
float slew)
2018-09-28 08:54:21 -07:00
{
2019-11-11 15:30:19 -07:00
slews_.setValue(rf, min_max, slew);
2018-09-28 08:54:21 -07:00
}
void
2019-11-11 15:30:19 -07:00
Clock::setSlew(const RiseFall *rf,
2026-01-03 16:59:35 -08:00
const MinMax *min_max,
float slew)
2018-09-28 08:54:21 -07:00
{
2019-11-11 15:30:19 -07:00
slews_.setValue(rf, min_max, slew);
2018-09-28 08:54:21 -07:00
}
void
Clock::removeSlew()
{
slews_.clear();
}
void
2019-11-11 15:30:19 -07:00
Clock::setSlewLimit(const RiseFallBoth *rf,
2026-04-13 14:58:16 -07:00
PathClkOrData clk_data,
2026-01-03 16:59:35 -08:00
const MinMax *min_max,
float slew)
2018-09-28 08:54:21 -07:00
{
2026-04-15 09:38:10 -07:00
slew_limits_[static_cast<size_t>(clk_data)].setValue(rf, min_max, slew);
2018-09-28 08:54:21 -07:00
}
void
2019-11-11 15:30:19 -07:00
Clock::slewLimit(const RiseFall *rf,
2026-04-13 14:58:16 -07:00
PathClkOrData clk_data,
2026-01-03 16:59:35 -08:00
const MinMax *min_max,
// Return values.
float &slew,
bool &exists) const
2018-09-28 08:54:21 -07:00
{
2026-04-15 09:38:10 -07:00
slew_limits_[static_cast<size_t>(clk_data)].value(rf, min_max, slew, exists);
2018-09-28 08:54:21 -07:00
}
void
Clock::uncertainty(const SetupHold *setup_hold,
2026-01-03 16:59:35 -08:00
// Return values.
float &uncertainty,
bool &exists) const
2018-09-28 08:54:21 -07:00
{
2026-04-25 10:35:42 -07:00
uncertainties_.value(setup_hold, uncertainty, exists);
2018-09-28 08:54:21 -07:00
}
void
Clock::setUncertainty(const SetupHoldAll *setup_hold,
2026-01-03 16:59:35 -08:00
float uncertainty)
2018-09-28 08:54:21 -07:00
{
2026-04-25 10:35:42 -07:00
uncertainties_.setValue(setup_hold, uncertainty);
2018-09-28 08:54:21 -07:00
}
void
Clock::setUncertainty(const SetupHold *setup_hold,
2026-01-03 16:59:35 -08:00
float uncertainty)
2018-09-28 08:54:21 -07:00
{
2026-04-25 10:35:42 -07:00
uncertainties_.setValue(setup_hold, uncertainty);
2018-09-28 08:54:21 -07:00
}
void
Clock::removeUncertainty(const SetupHoldAll *setup_hold)
{
2026-04-25 10:35:42 -07:00
uncertainties_.removeValue(setup_hold);
2018-09-28 08:54:21 -07:00
}
void
Clock::waveformInvalid()
{
waveform_valid_ = false;
}
////////////////////////////////////////////////////////////////
void
2026-04-16 18:42:26 -07:00
Clock::initGeneratedClk(const PinSet &pins,
2026-01-03 16:59:35 -08:00
bool add_to_pins,
Pin *src_pin,
Clock *master_clk,
int divide_by,
int multiply_by,
float duty_cycle,
bool invert,
bool combinational,
2026-04-16 18:42:26 -07:00
const IntSeq &edges,
const FloatSeq &edge_shifts,
2026-01-03 16:59:35 -08:00
bool is_propagated,
2026-03-28 19:13:35 -07:00
std::string_view comment,
2026-01-03 16:59:35 -08:00
const Network *network)
2018-09-28 08:54:21 -07:00
{
is_generated_ = true;
setPins(pins, network);
add_to_pins_ = add_to_pins;
src_pin_ = src_pin;
master_clk_ = master_clk;
master_clk_infered_ = false;
waveform_valid_ = false;
divide_by_ = divide_by;
multiply_by_ = multiply_by;
duty_cycle_ = duty_cycle;
invert_ = invert;
combinational_ = combinational;
is_propagated_ = is_propagated;
2026-04-15 09:38:10 -07:00
setComment(comment);
2018-09-28 08:54:21 -07:00
edges_ = edges;
edge_shifts_ = edge_shifts;
}
void
Clock::setInferedMasterClk(Clock *master_clk)
{
master_clk_ = master_clk;
master_clk_infered_ = true;
waveform_valid_ = false;
}
bool
Clock::isGenerated() const
{
return is_generated_;
}
bool
Clock::isGeneratedWithPropagatedMaster() const
{
return is_generated_
&& master_clk_
// Insertion is zero if the master clock is ideal.
&& master_clk_->isPropagated();
}
void
Clock::generate(const Clock *src_clk)
{
2026-04-16 18:42:26 -07:00
waveform_.clear();
2018-09-28 08:54:21 -07:00
if (divide_by_ == 1.0) {
period_ = src_clk->period();
2026-04-16 18:42:26 -07:00
const FloatSeq &src_wave = src_clk->waveform();
waveform_.push_back(src_wave[0]);
waveform_.push_back(src_wave[1]);
2018-09-28 08:54:21 -07:00
}
else if (divide_by_ > 1) {
if (isPowerOfTwo(divide_by_)) {
period_ = src_clk->period() * divide_by_;
2026-04-16 18:42:26 -07:00
const FloatSeq &src_wave = src_clk->waveform();
float rise = src_wave[0];
waveform_.push_back(rise);
waveform_.push_back(rise + period_ / 2);
2018-09-28 08:54:21 -07:00
}
else
generateScaledClk(src_clk, static_cast<float>(divide_by_));
}
else if (multiply_by_ >= 1)
generateScaledClk(src_clk, 1.0F / multiply_by_);
2026-04-16 18:42:26 -07:00
else if (!edges_.empty())
2018-09-28 08:54:21 -07:00
generateEdgesClk(src_clk);
if (invert_) {
2026-04-16 18:42:26 -07:00
float first_time = waveform_[0];
2018-09-28 08:54:21 -07:00
float offset = (first_time >= period_) ? period_ : 0.0F;
2026-04-16 18:42:26 -07:00
size_t edge_count = waveform_.size();
2018-09-28 08:54:21 -07:00
for (size_t i = 0; i < edge_count - 1; i++)
2026-04-16 18:42:26 -07:00
waveform_[i] = waveform_[i + 1] - offset;
waveform_[edge_count - 1] = first_time - offset + period_;
2018-09-28 08:54:21 -07:00
}
setClkEdgeTimes();
waveform_valid_ = true;
}
void
Clock::generateScaledClk(const Clock *src_clk,
2026-01-03 16:59:35 -08:00
float scale)
2018-09-28 08:54:21 -07:00
{
period_ = src_clk->period() * scale;
if (duty_cycle_ != 0.0) {
2026-04-16 18:42:26 -07:00
float rise = src_clk->waveform()[0] * scale;
waveform_.push_back(rise);
waveform_.push_back(rise + period_ * duty_cycle_ / 100.0F);
2018-09-28 08:54:21 -07:00
}
else {
2026-04-16 18:42:26 -07:00
for (float time : src_clk->waveform())
waveform_.push_back(time * scale);
2018-09-28 08:54:21 -07:00
}
}
void
Clock::generateEdgesClk(const Clock *src_clk)
{
// The create_generated_clock tcl cmd and Sta::makeClock
// enforce this restriction.
2026-04-16 18:42:26 -07:00
if (edges_.size() == 3) {
const FloatSeq &src_wave = src_clk->waveform();
size_t src_size = src_wave.size();
2026-04-15 09:38:10 -07:00
int src_size_int = static_cast<int>(src_size);
2018-09-28 08:54:21 -07:00
float src_period = src_clk->period();
2026-04-16 18:42:26 -07:00
int edge0_1 = edges_[0] - 1;
2026-04-15 09:38:10 -07:00
div_t edge0_div = std::div(edge0_1, src_size_int);
2026-04-16 18:42:26 -07:00
float rise = src_wave[edge0_div.rem]
2026-04-15 09:38:10 -07:00
+ static_cast<float>(edge0_div.quot) * src_period;
2026-04-16 18:42:26 -07:00
if (!edge_shifts_.empty())
rise += edge_shifts_[0];
waveform_.push_back(rise);
2018-09-28 08:54:21 -07:00
2026-04-16 18:42:26 -07:00
int edge1_1 = edges_[1] - 1;
2026-04-15 09:38:10 -07:00
div_t edge1_div = std::div(edge1_1, src_size_int);
2026-04-16 18:42:26 -07:00
float fall = src_wave[edge1_div.rem]
2026-04-15 09:38:10 -07:00
+ static_cast<float>(edge1_div.quot) * src_period;
2026-04-16 18:42:26 -07:00
if (!edge_shifts_.empty())
fall += edge_shifts_[1];
waveform_.push_back(fall);
2018-09-28 08:54:21 -07:00
2026-04-16 18:42:26 -07:00
int edge2_1 = edges_[2] - 1;
2026-04-15 09:38:10 -07:00
div_t edge2_div = std::div(edge2_1, src_size_int);
2026-04-16 18:42:26 -07:00
period_ = src_wave[edge2_div.rem]
2026-04-15 09:38:10 -07:00
+ static_cast<float>(edge2_div.quot) * src_period - rise;
2026-04-16 18:42:26 -07:00
if (!edge_shifts_.empty())
period_ += edge_shifts_[2];
2018-09-28 08:54:21 -07:00
}
else
2020-12-13 18:21:35 -07:00
criticalError(244, "generated clock edges size is not three.");
2018-09-28 08:54:21 -07:00
}
static bool
isPowerOfTwo(int i)
{
return (i & (i - 1)) == 0;
}
2019-11-11 15:30:19 -07:00
const RiseFall *
Clock::masterClkEdgeTr(const RiseFall *rf) const
2018-09-28 08:54:21 -07:00
{
2019-11-11 15:30:19 -07:00
int edge_index = (rf == RiseFall::rise()) ? 0 : 1;
2026-04-16 18:42:26 -07:00
return (edges_[edge_index] - 1) % 2
2019-11-11 15:30:19 -07:00
? RiseFall::fall()
: RiseFall::rise();
2018-09-28 08:54:21 -07:00
}
void
Clock::srcPinVertices(VertexSet &src_vertices,
2026-01-03 16:59:35 -08:00
const Network *network,
Graph *graph)
2018-09-28 08:54:21 -07:00
{
if (network->isHierarchical(src_pin_)) {
// Use the clocks on a non-hierarchical pin on the same net.
2023-01-19 11:23:45 -07:00
PinSet leaf_pins(network);
2019-10-25 08:51:59 -07:00
findLeafDriverPins(src_pin_, network, &leaf_pins);
2026-01-03 16:59:35 -08:00
for (const Pin *pin : leaf_pins) {
2018-09-28 08:54:21 -07:00
Vertex *vertex, *bidirect_drvr_vertex;
graph->pinVertices(pin, vertex, bidirect_drvr_vertex);
if (vertex)
2026-01-03 16:59:35 -08:00
src_vertices.insert(vertex);
2018-09-28 08:54:21 -07:00
if (bidirect_drvr_vertex)
2026-01-03 16:59:35 -08:00
src_vertices.insert(bidirect_drvr_vertex);
2018-09-28 08:54:21 -07:00
}
}
else {
Vertex *vertex = graph->pinDrvrVertex(src_pin_);
src_vertices.insert(vertex);
}
}
bool
Clock::isDivideByOneCombinational() const
{
return combinational_
&& divide_by_ == 1
&& multiply_by_ == 0
2026-04-16 18:42:26 -07:00
&& edge_shifts_.empty();
2018-09-28 08:54:21 -07:00
}
////////////////////////////////////////////////////////////////
ClockEdge::ClockEdge(Clock *clock,
2026-01-03 16:59:35 -08:00
const RiseFall *rf) :
2018-09-28 08:54:21 -07:00
clock_(clock),
2019-11-11 15:30:19 -07:00
rf_(rf),
2026-03-15 14:35:24 -07:00
name_(sta::format("{} {}", clock_->name(), rf_->shortName())),
2019-11-11 15:30:19 -07:00
index_(clock_->index() * RiseFall::index_count + rf_->index())
2018-09-28 08:54:21 -07:00
{
}
void
ClockEdge::setTime(float time)
{
time_ = time;
}
ClockEdge *
ClockEdge::opposite() const
{
2019-11-11 15:30:19 -07:00
return clock_->edge(rf_->opposite());
2018-09-28 08:54:21 -07:00
}
float
ClockEdge::pulseWidth() const
{
ClockEdge *opp_clk_edge = opposite();
float width = opp_clk_edge->time() - time_;
if (width < 0.0)
width += clock_->period();
return width;
}
////////////////////////////////////////////////////////////////
int
clkCmp(const Clock *clk1,
const Clock *clk2)
{
2019-03-12 17:25:53 -07:00
if (clk1 == nullptr && clk2)
2018-09-28 08:54:21 -07:00
return -1;
2019-03-12 17:25:53 -07:00
else if (clk1 == nullptr && clk2 == nullptr)
2018-09-28 08:54:21 -07:00
return 0;
2019-03-12 17:25:53 -07:00
else if (clk1 && clk2 == nullptr)
2018-09-28 08:54:21 -07:00
return 1;
else {
int index1 = clk1->index();
int index2 = clk2->index();
if (index1 < index2)
return -1;
else if (index1 == index2)
return 0;
else
return 1;
}
}
int
2023-01-19 11:23:45 -07:00
clkEdgeCmp(const ClockEdge *clk_edge1,
2026-01-03 16:59:35 -08:00
const ClockEdge *clk_edge2)
2018-09-28 08:54:21 -07:00
{
2019-03-12 17:25:53 -07:00
if (clk_edge1 == nullptr && clk_edge2)
2018-09-28 08:54:21 -07:00
return -1;
2019-03-12 17:25:53 -07:00
else if (clk_edge1 == nullptr && clk_edge2 == nullptr)
2018-09-28 08:54:21 -07:00
return 0;
2019-03-12 17:25:53 -07:00
else if (clk_edge1 && clk_edge2 == nullptr)
2018-09-28 08:54:21 -07:00
return 1;
else {
int index1 = clk_edge1->index();
int index2 = clk_edge2->index();
2020-01-06 19:36:24 -08:00
if (index1 == index2)
2018-09-28 08:54:21 -07:00
return 0;
2020-01-06 19:36:24 -08:00
else if (index1 < index2)
return -1;
2018-09-28 08:54:21 -07:00
else
return 1;
}
}
bool
2023-01-19 11:23:45 -07:00
clkEdgeLess(const ClockEdge *clk_edge1,
2026-01-03 16:59:35 -08:00
const ClockEdge *clk_edge2)
2018-09-28 08:54:21 -07:00
{
return clkEdgeCmp(clk_edge1, clk_edge2) < 0;
}
////////////////////////////////////////////////////////////////
InterClockUncertainty::InterClockUncertainty(const Clock *src,
2026-01-03 16:59:35 -08:00
const Clock *target) :
2018-09-28 08:54:21 -07:00
src_(src),
target_(target)
{
}
bool
InterClockUncertainty::empty() const
{
2019-11-11 15:30:19 -07:00
return uncertainties_[RiseFall::riseIndex()].empty()
&& uncertainties_[RiseFall::fallIndex()].empty();
2018-09-28 08:54:21 -07:00
}
void
2019-11-11 15:30:19 -07:00
InterClockUncertainty::uncertainty(const RiseFall *src_rf,
2026-01-03 16:59:35 -08:00
const RiseFall *tgt_rf,
const SetupHold *setup_hold,
float &uncertainty,
bool &exists) const
2018-09-28 08:54:21 -07:00
{
2019-11-11 15:30:19 -07:00
uncertainties_[src_rf->index()].value(tgt_rf, setup_hold,
2026-01-03 16:59:35 -08:00
uncertainty, exists);
2018-09-28 08:54:21 -07:00
}
void
2019-11-11 15:30:19 -07:00
InterClockUncertainty::setUncertainty(const RiseFallBoth *src_rf,
2026-01-03 16:59:35 -08:00
const RiseFallBoth *tgt_rf,
const SetupHoldAll *setup_hold,
float uncertainty)
2018-09-28 08:54:21 -07:00
{
2019-11-11 15:30:19 -07:00
for (auto src_rf_index : src_rf->rangeIndex())
uncertainties_[src_rf_index].setValue(tgt_rf, setup_hold, uncertainty);
2018-09-28 08:54:21 -07:00
}
void
2019-11-11 15:30:19 -07:00
InterClockUncertainty::removeUncertainty(const RiseFallBoth *src_rf,
2026-01-03 16:59:35 -08:00
const RiseFallBoth *tgt_rf,
const SetupHoldAll *setup_hold)
2018-09-28 08:54:21 -07:00
{
2019-11-11 15:30:19 -07:00
for (auto src_rf_index : src_rf->rangeIndex())
uncertainties_[src_rf_index].removeValue(tgt_rf, setup_hold);
2018-09-28 08:54:21 -07:00
}
const RiseFallMinMax *
2025-03-30 15:27:53 -07:00
InterClockUncertainty::uncertainties(const RiseFall *src_rf) const
2018-09-28 08:54:21 -07:00
{
2019-11-11 15:30:19 -07:00
return &uncertainties_[src_rf->index()];
2018-09-28 08:54:21 -07:00
}
bool
InterClockUncertaintyLess::operator()(const InterClockUncertainty *inter1,
2026-01-03 16:59:35 -08:00
const InterClockUncertainty *inter2)const
2018-09-28 08:54:21 -07:00
{
return inter1->src()->index() < inter2->src()->index()
|| (inter1->src() == inter2->src()
2026-01-03 16:59:35 -08:00
&& inter1->target()->index() < inter2->target()->index());
2018-09-28 08:54:21 -07:00
}
////////////////////////////////////////////////////////////////
2023-01-19 11:23:45 -07:00
bool
ClockIndexLess::operator()(const Clock *clk1,
const Clock *clk2) const
{
return (clk1 == nullptr && clk2)
|| (clk1 && clk2
&& clk1->index() < clk2->index());
}
ClockSeq
sortByName(ClockSet *set)
2018-09-28 08:54:21 -07:00
{
2023-01-19 11:23:45 -07:00
ClockSeq clks;
for (Clock *clk : *set)
clks.push_back(clk);
2018-09-28 08:54:21 -07:00
sort(clks, ClockNameLess());
2023-01-19 11:23:45 -07:00
return clks;
}
////////////////////////////////////////////////////////////////
bool
ClockSetLess::operator()(const ClockSet *set1,
const ClockSet *set2) const
{
return sta::compare(set1, set2) < 0;
}
int
compare(const ClockSet *set1,
const ClockSet *set2)
{
2026-01-03 16:59:35 -08:00
return sta::compare(set1, set2, ClockIndexLess());
2018-09-28 08:54:21 -07:00
}
2026-04-13 14:58:16 -07:00
} // namespace sta