Files
OpenSTA/search/PathEnd.cc
T

2119 lines
56 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 "PathEnd.hh"
2020-04-05 11:35:51 -07:00
2026-04-13 14:58:16 -07:00
#include "ClkInfo.hh"
#include "Clock.hh"
#include "DataCheck.hh"
2020-04-05 14:53:44 -07:00
#include "Debug.hh"
2026-04-13 14:58:16 -07:00
#include "ExceptionPath.hh"
#include "Graph.hh"
#include "Latches.hh"
2020-04-05 14:53:44 -07:00
#include "Liberty.hh"
2026-04-13 14:58:16 -07:00
#include "Mode.hh"
2020-04-05 14:53:44 -07:00
#include "Network.hh"
2026-04-13 14:58:16 -07:00
#include "PathExpanded.hh"
2020-04-05 14:53:44 -07:00
#include "PortDelay.hh"
2026-04-13 14:58:16 -07:00
#include "ReportPath.hh"
2020-04-05 14:53:44 -07:00
#include "Sdc.hh"
#include "Search.hh"
#include "Sim.hh"
#include "StaState.hh"
2026-04-13 14:58:16 -07:00
#include "Tag.hh"
#include "TimingArc.hh"
#include "TimingRole.hh"
2020-04-05 14:53:44 -07:00
#include "search/Crpr.hh"
2018-09-28 08:54:21 -07:00
namespace sta {
PathEnd::PathEnd(Path *path) :
2026-04-13 14:58:16 -07:00
path_(path)
2018-09-28 08:54:21 -07:00
{
}
void
2025-03-26 18:21:03 -07:00
PathEnd::setPath(Path *path)
2018-09-28 08:54:21 -07:00
{
2025-03-26 18:21:03 -07:00
path_ = path;
2018-09-28 08:54:21 -07:00
}
void
PathEnd::setPathGroup(PathGroup *path_group)
{
path_group_ = path_group;
}
2018-09-28 08:54:21 -07:00
Vertex *
PathEnd::vertex(const StaState *sta) const
{
2025-03-26 18:21:03 -07:00
return path_->vertex(sta);
2018-09-28 08:54:21 -07:00
}
const MinMax *
PathEnd::minMax(const StaState *sta) const
{
2026-01-03 16:59:35 -08:00
return path_->minMax(sta);
2018-09-28 08:54:21 -07:00
}
2018-11-26 09:15:52 -08:00
const EarlyLate *
PathEnd::pathEarlyLate(const StaState *sta) const
{
2026-01-03 16:59:35 -08:00
return path_->minMax(sta);
2018-11-26 09:15:52 -08:00
}
const EarlyLate *
2019-01-25 18:06:24 -08:00
PathEnd::clkEarlyLate(const StaState *sta) const
2018-11-26 09:15:52 -08:00
{
2019-01-25 18:06:24 -08:00
return checkRole(sta)->tgtClkEarlyLate();
2018-11-26 09:15:52 -08:00
}
2019-11-11 15:30:19 -07:00
const RiseFall *
2018-09-28 08:54:21 -07:00
PathEnd::transition(const StaState *sta) const
{
2025-03-26 18:21:03 -07:00
return path_->transition(sta);
2018-09-28 08:54:21 -07:00
}
2023-01-19 11:23:45 -07:00
const ClockEdge *
2018-09-28 08:54:21 -07:00
PathEnd::sourceClkEdge(const StaState *sta) const
{
2025-03-26 18:21:03 -07:00
return path_->clkEdge(sta);
2018-09-28 08:54:21 -07:00
}
2026-03-13 14:06:35 -07:00
const Arrival &
2025-03-26 18:21:03 -07:00
PathEnd::dataArrivalTime(const StaState *) const
2018-09-28 08:54:21 -07:00
{
2025-03-26 18:21:03 -07:00
return path_->arrival();
2018-09-28 08:54:21 -07:00
}
Arrival
PathEnd::dataArrivalTimeOffset(const StaState *sta) const
{
2026-03-13 14:06:35 -07:00
return delaySum(dataArrivalTime(sta),
sourceClkOffset(sta),
sta);
2018-09-28 08:54:21 -07:00
}
Required
PathEnd::requiredTimeOffset(const StaState *sta) const
{
2026-03-13 14:06:35 -07:00
return delaySum(requiredTime(sta),
sourceClkOffset(sta),
sta);
2018-09-28 08:54:21 -07:00
}
2019-11-11 15:30:19 -07:00
const RiseFall *
2018-09-28 08:54:21 -07:00
PathEnd::targetClkEndTrans(const StaState *sta) const
{
2025-03-26 18:21:03 -07:00
const Path *clk_path = targetClkPath();
2018-09-28 08:54:21 -07:00
if (clk_path)
return clk_path->transition(sta);
else {
2023-01-19 11:23:45 -07:00
const ClockEdge *clk_edge = targetClkEdge(sta);
2018-09-28 08:54:21 -07:00
if (clk_edge)
return clk_edge->transition();
else
2019-03-12 17:25:53 -07:00
return nullptr;
2018-09-28 08:54:21 -07:00
}
}
const TimingRole *
PathEnd::checkGenericRole(const StaState *sta) const
{
return checkRole(sta)->genericRole();
}
Delay
PathEnd::sourceClkLatency(const StaState *) const
{
return delay_zero;
}
Delay
PathEnd::sourceClkInsertionDelay(const StaState *) const
{
return delay_zero;
}
2023-01-19 11:23:45 -07:00
const Clock *
2018-09-28 08:54:21 -07:00
PathEnd::targetClk(const StaState *) const
{
2019-03-12 17:25:53 -07:00
return nullptr;
2018-09-28 08:54:21 -07:00
}
2023-01-19 11:23:45 -07:00
const ClockEdge *
2018-09-28 08:54:21 -07:00
PathEnd::targetClkEdge(const StaState *) const
{
2019-03-12 17:25:53 -07:00
return nullptr;
2018-09-28 08:54:21 -07:00
}
float
PathEnd::targetClkTime(const StaState *) const
{
return 0.0;
}
float
PathEnd::targetClkOffset(const StaState *) const
{
return 0.0;
}
Arrival
PathEnd::targetClkArrival(const StaState *) const
{
return delay_zero;
}
Delay
PathEnd::targetClkDelay(const StaState *) const
{
return delay_zero;
}
Delay
PathEnd::targetClkInsertionDelay(const StaState *) const
{
return delay_zero;
}
float
PathEnd::targetNonInterClkUncertainty(const StaState *) const
{
return 0.0;
}
float
PathEnd::interClkUncertainty(const StaState *) const
{
return 0.0;
}
float
PathEnd::targetClkUncertainty(const StaState *) const
{
return 0.0;
}
float
PathEnd::targetClkMcpAdjustment(const StaState *) const
{
return 0.0;
}
2025-03-30 15:27:53 -07:00
const TimingRole *
2018-09-28 08:54:21 -07:00
PathEnd::checkRole(const StaState *) const
{
2019-03-12 17:25:53 -07:00
return nullptr;
2018-09-28 08:54:21 -07:00
}
2025-03-26 18:21:03 -07:00
Path *
2018-09-28 08:54:21 -07:00
PathEnd::targetClkPath()
{
2019-03-12 17:25:53 -07:00
return nullptr;
2018-09-28 08:54:21 -07:00
}
2025-03-26 18:21:03 -07:00
const Path *
2018-09-28 08:54:21 -07:00
PathEnd::targetClkPath() const
{
2019-03-12 17:25:53 -07:00
return nullptr;
2018-09-28 08:54:21 -07:00
}
bool
PathEnd::pathDelayMarginIsExternal() const
{
return false;
}
PathDelay *
PathEnd::pathDelay() const
{
2019-03-12 17:25:53 -07:00
return nullptr;
2018-09-28 08:54:21 -07:00
}
Arrival
PathEnd::borrow(const StaState *) const
{
return 0.0;
}
2018-12-11 10:47:04 -08:00
Crpr
2024-06-27 13:57:58 -07:00
PathEnd::checkCrpr(const StaState *sta) const
{
if (checkRole(sta)->genericRole() == TimingRole::hold())
2026-03-13 14:06:35 -07:00
return delayDiff(delay_zero, crpr(sta), sta);
2024-06-27 13:57:58 -07:00
else
2026-03-13 14:06:35 -07:00
return crpr(sta);
2024-06-27 13:57:58 -07:00
}
Crpr
PathEnd::crpr(const StaState *) const
2018-09-28 08:54:21 -07:00
{
return 0.0;
}
MultiCyclePath *
PathEnd::multiCyclePath() const
{
2019-03-12 17:25:53 -07:00
return nullptr;
2018-09-28 08:54:21 -07:00
}
int
PathEnd::exceptPathCmp(const PathEnd *path_end,
2026-01-03 16:59:35 -08:00
const StaState *) const
2018-09-28 08:54:21 -07:00
{
2019-03-12 17:25:53 -07:00
Type type1 = type();
Type type2 = path_end->type();
2018-09-28 08:54:21 -07:00
if (type1 == type2)
return 0;
else if (type1 < type2)
return -1;
else
return 1;
}
////////////////////////////////////////////////////////////////
2024-04-03 09:03:59 -07:00
Delay
2025-03-26 18:21:03 -07:00
PathEnd::checkTgtClkDelay(const Path *tgt_clk_path,
2026-01-03 16:59:35 -08:00
const ClockEdge *tgt_clk_edge,
const TimingRole *check_role,
const StaState *sta)
2018-09-28 08:54:21 -07:00
{
2024-04-03 09:03:59 -07:00
Delay insertion, latency;
2018-09-28 08:54:21 -07:00
checkTgtClkDelay(tgt_clk_path, tgt_clk_edge, check_role, sta,
2026-01-03 16:59:35 -08:00
insertion, latency);
2026-03-13 14:06:35 -07:00
return delaySum(insertion, latency, sta);
2018-09-28 08:54:21 -07:00
}
void
2025-03-26 18:21:03 -07:00
PathEnd::checkTgtClkDelay(const Path *tgt_clk_path,
2026-01-03 16:59:35 -08:00
const ClockEdge *tgt_clk_edge,
const TimingRole *check_role,
const StaState *sta,
// Return values.
Delay &insertion,
Delay &latency)
2018-09-28 08:54:21 -07:00
{
if (tgt_clk_path) {
Search *search = sta->search();
// If propagated clk, adjust required time for target clk network delay.
const MinMax *min_max = tgt_clk_path->minMax(sta);
const EarlyLate *early_late = check_role->tgtClkEarlyLate();
2025-09-16 15:30:16 -07:00
const ClkInfo *clk_info = tgt_clk_path->clkInfo(sta);
2018-09-28 08:54:21 -07:00
const Pin *tgt_src_pin = clk_info->clkSrc();
const Clock *tgt_clk = tgt_clk_edge->clock();
2019-11-11 15:30:19 -07:00
const RiseFall *tgt_clk_rf = tgt_clk_edge->transition();
2026-01-03 16:59:35 -08:00
const Mode *mode = tgt_clk_path->mode(sta);
2019-11-11 15:30:19 -07:00
insertion = search->clockInsertion(tgt_clk, tgt_src_pin, tgt_clk_rf,
2026-01-03 16:59:35 -08:00
min_max, early_late, mode);
if (clk_info->isPropagated()
2026-01-03 16:59:35 -08:00
// Data check target clock is always propagated.
|| check_role->isDataCheck()) {
2018-09-28 08:54:21 -07:00
// Propagated clock. Propagated arrival is seeded with
// early_late==path_min_max insertion delay.
2025-03-26 18:21:03 -07:00
Arrival clk_arrival = tgt_clk_path->arrival();
2024-04-03 09:03:59 -07:00
Delay path_insertion = search->clockInsertion(tgt_clk, tgt_src_pin,
2026-01-03 16:59:35 -08:00
tgt_clk_rf, min_max,
min_max, mode);
2026-03-13 14:06:35 -07:00
latency = delayRemove(delayDiff(clk_arrival, tgt_clk_edge->time(), sta),
path_insertion);
2018-09-28 08:54:21 -07:00
}
else
// Ideal clock.
latency = clk_info->latency();
}
else {
insertion = 0.0F;
latency = 0.0F;
}
}
float
PathEnd::checkClkUncertainty(const ClockEdge *src_clk_edge,
2026-01-03 16:59:35 -08:00
const ClockEdge *tgt_clk_edge,
const Path *tgt_clk_path,
const TimingRole *check_role,
const Sdc *sdc)
2018-09-28 08:54:21 -07:00
{
float inter_clk;
bool inter_exists;
2026-01-03 16:59:35 -08:00
checkInterClkUncertainty(src_clk_edge, tgt_clk_edge, check_role, sdc,
inter_clk, inter_exists);
2018-09-28 08:54:21 -07:00
if (inter_exists)
return inter_clk;
else
2026-01-03 16:59:35 -08:00
return checkTgtClkUncertainty(tgt_clk_path, tgt_clk_edge, check_role, sdc);
2018-09-28 08:54:21 -07:00
}
float
2025-03-26 18:21:03 -07:00
PathEnd::checkTgtClkUncertainty(const Path *tgt_clk_path,
2024-05-09 16:56:23 -07:00
const ClockEdge *tgt_clk_edge,
const TimingRole *check_role,
const StaState *sta)
2018-09-28 08:54:21 -07:00
{
2025-03-30 15:27:53 -07:00
const MinMax *min_max = check_role->pathMinMax();
2026-01-03 16:59:35 -08:00
const ClockUncertainties *uncertainties = nullptr;
2018-09-28 08:54:21 -07:00
if (tgt_clk_path && tgt_clk_path->isClock(sta))
uncertainties = tgt_clk_path->clkInfo(sta)->uncertainties();
else if (tgt_clk_edge)
2026-04-25 10:35:42 -07:00
uncertainties = &tgt_clk_edge->clock()->uncertainties();
2018-09-28 08:54:21 -07:00
float uncertainty = 0.0;
if (uncertainties) {
bool exists;
float uncertainty1;
uncertainties->value(min_max, uncertainty1, exists);
if (exists)
uncertainty = uncertainty1;
}
if (check_role->genericRole() == TimingRole::setup())
uncertainty = -uncertainty;
return uncertainty;
}
void
PathEnd::checkInterClkUncertainty(const ClockEdge *src_clk_edge,
2026-01-03 16:59:35 -08:00
const ClockEdge *tgt_clk_edge,
const TimingRole *check_role,
const Sdc *sdc,
float &uncertainty,
bool &exists)
2018-09-28 08:54:21 -07:00
{
if (src_clk_edge
2021-11-18 10:41:12 -07:00
&& src_clk_edge != sdc->defaultArrivalClockEdge()
&& tgt_clk_edge) {
2018-09-28 08:54:21 -07:00
sdc->clockUncertainty(src_clk_edge->clock(),
2021-11-18 10:41:12 -07:00
src_clk_edge->transition(),
tgt_clk_edge->clock(),
tgt_clk_edge->transition(),
check_role->pathMinMax(),
uncertainty, exists);
2018-09-28 08:54:21 -07:00
if (exists
2026-01-03 16:59:35 -08:00
&& check_role->genericRole() == TimingRole::setup())
2018-09-28 08:54:21 -07:00
uncertainty = -uncertainty;
}
else
exists = false;
}
2026-04-13 14:58:16 -07:00
bool
PathEnd::ignoreClkLatency(const Path *path,
PathDelay *path_delay,
const StaState *sta)
{
return path_delay->ignoreClkLatency() && !path->isClock(sta);
}
2018-09-28 08:54:21 -07:00
////////////////////////////////////////////////////////////////
void
2025-02-01 14:53:28 -08:00
PathEndUnconstrained::reportFull(const ReportPath *report) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
report->reportFull(this);
2018-09-28 08:54:21 -07:00
}
Slack
PathEndUnconstrained::slackNoCrpr(const StaState *) const
{
return INF;
}
void
2025-02-01 14:53:28 -08:00
PathEndUnconstrained::reportShort(const ReportPath *report) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
report->reportShort(this);
2018-09-28 08:54:21 -07:00
}
////////////////////////////////////////////////////////////////
PathEndUnconstrained::PathEndUnconstrained(Path *path) :
PathEnd(path)
{
}
PathEnd *
PathEndUnconstrained::copy() const
2018-09-28 08:54:21 -07:00
{
2026-03-15 14:29:58 -07:00
return new PathEndUnconstrained(*this);
2018-09-28 08:54:21 -07:00
}
bool
PathEndUnconstrained::isUnconstrained() const
{
return true;
}
Required
PathEndUnconstrained::requiredTime(const StaState *sta) const
{
return delayInitValue(minMax(sta)->opposite());
}
Required
PathEndUnconstrained::requiredTimeOffset(const StaState *sta) const
{
return delayInitValue(minMax(sta)->opposite());
}
ArcDelay
PathEndUnconstrained::margin(const StaState *) const
{
return delay_zero;
}
Slack
PathEndUnconstrained::slack(const StaState *) const
{
return INF;
}
float
PathEndUnconstrained::sourceClkOffset(const StaState *) const
{
return 0.0;
}
2019-03-12 17:25:53 -07:00
PathEnd::Type
2018-09-28 08:54:21 -07:00
PathEndUnconstrained::type() const
{
2019-03-12 17:25:53 -07:00
return Type::unconstrained;
}
const char *
PathEndUnconstrained::typeName() const
{
return "unconstrained";
2018-09-28 08:54:21 -07:00
}
////////////////////////////////////////////////////////////////
PathEndClkConstrained::PathEndClkConstrained(Path *path,
2026-01-03 16:59:35 -08:00
Path *clk_path) :
2018-09-28 08:54:21 -07:00
PathEnd(path),
clk_path_(clk_path),
2026-04-13 14:58:16 -07:00
crpr_(0.0)
2018-09-28 08:54:21 -07:00
{
}
void
2025-03-26 18:21:03 -07:00
PathEndClkConstrained::setPath(Path *path)
2018-09-28 08:54:21 -07:00
{
2025-03-26 18:21:03 -07:00
path_ = path;
2018-09-28 08:54:21 -07:00
crpr_valid_ = false;
}
float
PathEndClkConstrained::sourceClkOffset(const StaState *sta) const
{
return sourceClkOffset(sourceClkEdge(sta),
2026-01-03 16:59:35 -08:00
targetClkEdge(sta),
checkRole(sta),
sta);
2018-09-28 08:54:21 -07:00
}
float
PathEndClkConstrained::sourceClkOffset(const ClockEdge *src_clk_edge,
2026-01-03 16:59:35 -08:00
const ClockEdge *tgt_clk_edge,
const TimingRole *check_role,
const StaState *sta) const
2018-09-28 08:54:21 -07:00
{
2026-01-03 16:59:35 -08:00
Sdc *sdc = path_->sdc(sta);
2018-09-28 08:54:21 -07:00
CycleAccting *acct = sdc->cycleAccting(src_clk_edge, tgt_clk_edge);
return acct->sourceTimeOffset(check_role);
}
Arrival
PathEndClkConstrained::sourceClkLatency(const StaState *sta) const
{
2025-09-16 15:30:16 -07:00
const ClkInfo *clk_info = path_->clkInfo(sta);
2018-09-28 08:54:21 -07:00
return clk_info->latency();
}
Arrival
PathEndClkConstrained::sourceClkInsertionDelay(const StaState *sta) const
{
2025-09-16 15:30:16 -07:00
const ClkInfo *clk_info = path_->clkInfo(sta);
2018-09-28 08:54:21 -07:00
return clk_info->insertion();
}
2025-03-26 18:21:03 -07:00
Path *
2018-09-28 08:54:21 -07:00
PathEndClkConstrained::targetClkPath()
{
2025-03-26 18:21:03 -07:00
return clk_path_;
2018-09-28 08:54:21 -07:00
}
2025-03-26 18:21:03 -07:00
const Path *
2018-09-28 08:54:21 -07:00
PathEndClkConstrained::targetClkPath() const
{
2025-03-26 18:21:03 -07:00
return clk_path_;
2018-09-28 08:54:21 -07:00
}
float
PathEndClkConstrained::targetClkOffset(const StaState *sta) const
{
const ClockEdge *src_clk_edge = sourceClkEdge(sta);
const ClockEdge *tgt_clk_edge = targetClkEdge(sta);
const TimingRole *check_role = checkRole(sta);
2026-01-03 16:59:35 -08:00
Sdc *sdc = path_->sdc(sta);
2018-09-28 08:54:21 -07:00
CycleAccting *acct = sdc->cycleAccting(src_clk_edge, tgt_clk_edge);
return acct->targetTimeOffset(check_role);
}
2023-01-19 11:23:45 -07:00
const ClockEdge *
2018-09-28 08:54:21 -07:00
PathEndClkConstrained::targetClkEdge(const StaState *sta) const
{
2025-03-26 18:21:03 -07:00
if (clk_path_)
return clk_path_->clkEdge(sta);
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
}
2023-01-19 11:23:45 -07:00
const Clock *
2018-09-28 08:54:21 -07:00
PathEndClkConstrained::targetClk(const StaState *sta) const
{
2023-01-19 11:23:45 -07:00
const ClockEdge *clk_edge = targetClkEdge(sta);
2018-09-28 08:54:21 -07:00
if (clk_edge)
return clk_edge->clock();
else
2019-03-12 17:25:53 -07:00
return nullptr;
2018-09-28 08:54:21 -07:00
}
float
PathEndClkConstrained::targetClkTime(const StaState *sta) const
{
const ClockEdge *src_clk_edge = sourceClkEdge(sta);
const ClockEdge *tgt_clk_edge = targetClkEdge(sta);
const TimingRole *check_role = checkRole(sta);
2026-01-03 16:59:35 -08:00
Sdc *sdc = path_->sdc(sta);
2018-09-28 08:54:21 -07:00
CycleAccting *acct = sdc->cycleAccting(src_clk_edge, tgt_clk_edge);
return acct->requiredTime(check_role);
}
Arrival
PathEndClkConstrained::targetClkArrival(const StaState *sta) const
{
2026-04-13 14:58:16 -07:00
return delaySum(targetClkArrivalNoCrpr(sta), checkCrpr(sta), sta);
2018-09-28 08:54:21 -07:00
}
Arrival
PathEndClkConstrained::targetClkArrivalNoCrpr(const StaState *sta) const
{
2026-01-03 16:59:35 -08:00
Sdc *sdc = path_->sdc(sta);
2026-03-13 14:06:35 -07:00
Arrival clk_arrival = delaySum(targetClkDelay(sta),
targetClkTime(sta),
sta);
float uncertainty = checkClkUncertainty(sourceClkEdge(sta),
targetClkEdge(sta),
targetClkPath(),
checkRole(sta),
sdc);
return delaySum(delaySum(clk_arrival, uncertainty, sta),
targetClkMcpAdjustment(sta), sta);
2018-09-28 08:54:21 -07:00
}
2024-04-03 09:03:59 -07:00
Delay
2018-09-28 08:54:21 -07:00
PathEndClkConstrained::targetClkDelay(const StaState *sta) const
{
2024-05-09 16:56:23 -07:00
return checkTgtClkDelay(targetClkPath(), targetClkEdge(sta), checkRole(sta), sta);
2018-09-28 08:54:21 -07:00
}
2024-04-03 09:03:59 -07:00
Delay
2018-09-28 08:54:21 -07:00
PathEndClkConstrained::targetClkInsertionDelay(const StaState *sta) const
{
Arrival insertion, latency;
checkTgtClkDelay(targetClkPath(), targetClkEdge(sta),
2026-01-03 16:59:35 -08:00
checkRole(sta), sta,
insertion, latency);
2018-09-28 08:54:21 -07:00
return insertion;
}
float
PathEndClkConstrained::targetNonInterClkUncertainty(const StaState *sta) const
{
const ClockEdge *src_clk_edge = sourceClkEdge(sta);
const ClockEdge *tgt_clk_edge = targetClkEdge(sta);
const TimingRole *check_role = checkRole(sta);
2026-01-03 16:59:35 -08:00
Sdc *sdc = path_->sdc(sta);
2018-09-28 08:54:21 -07:00
float inter_clk;
bool inter_exists;
checkInterClkUncertainty(src_clk_edge, tgt_clk_edge, check_role,
2026-01-03 16:59:35 -08:00
sdc, inter_clk, inter_exists);
2018-09-28 08:54:21 -07:00
if (inter_exists)
// This returns non inter-clock uncertainty.
return 0.0;
else
2024-05-09 16:56:23 -07:00
return checkTgtClkUncertainty(targetClkPath(), tgt_clk_edge, check_role, sta);
2018-09-28 08:54:21 -07:00
}
float
PathEndClkConstrained::interClkUncertainty(const StaState *sta) const
{
2026-01-03 16:59:35 -08:00
Sdc *sdc = path_->sdc(sta);
2018-09-28 08:54:21 -07:00
float uncertainty;
bool exists;
checkInterClkUncertainty(sourceClkEdge(sta), targetClkEdge(sta),
2026-01-03 16:59:35 -08:00
checkRole(sta), sdc,
uncertainty, exists);
2018-09-28 08:54:21 -07:00
if (exists)
return uncertainty;
else
return 0.0;
}
float
PathEndClkConstrained::targetClkUncertainty(const StaState *sta) const
{
2026-01-03 16:59:35 -08:00
Sdc *sdc = path_->sdc(sta);
2018-09-28 08:54:21 -07:00
return checkClkUncertainty(sourceClkEdge(sta), targetClkEdge(sta),
2026-01-03 16:59:35 -08:00
targetClkPath(), checkRole(sta), sdc);
2018-09-28 08:54:21 -07:00
}
2018-12-11 10:47:04 -08:00
Crpr
2024-06-27 13:57:58 -07:00
PathEndClkConstrained::crpr(const StaState *sta) const
2018-09-28 08:54:21 -07:00
{
if (!crpr_valid_) {
2018-12-11 10:47:04 -08:00
CheckCrpr *check_crpr = sta->search()->checkCrpr();
2025-03-26 18:21:03 -07:00
crpr_ = check_crpr->checkCrpr(path_, targetClkPath());
2018-09-28 08:54:21 -07:00
crpr_valid_ = true;
}
2024-06-27 13:57:58 -07:00
return crpr_;
2018-09-28 08:54:21 -07:00
}
Required
PathEndClkConstrained::requiredTime(const StaState *sta) const
{
2026-03-13 14:06:35 -07:00
return delaySum(requiredTimeNoCrpr(sta),
checkCrpr(sta),
sta);
2018-09-28 08:54:21 -07:00
}
Required
PathEndClkConstrained::requiredTimeNoCrpr(const StaState *sta) const
{
Arrival tgt_clk_arrival = targetClkArrivalNoCrpr(sta);
ArcDelay check_margin = margin(sta);
if (checkGenericRole(sta) == TimingRole::setup())
2026-03-13 14:06:35 -07:00
return delayDiff(tgt_clk_arrival, check_margin, sta);
2018-09-28 08:54:21 -07:00
else
2026-03-13 14:06:35 -07:00
return delaySum(tgt_clk_arrival, check_margin, sta);
2018-09-28 08:54:21 -07:00
}
Slack
PathEndClkConstrained::slack(const StaState *sta) const
{
Arrival arrival = dataArrivalTime(sta);
Required required = requiredTime(sta);
if (checkGenericRole(sta) == TimingRole::setup())
2026-03-13 14:06:35 -07:00
return delayDiff(required, arrival, sta);
2018-09-28 08:54:21 -07:00
else
2026-03-13 14:06:35 -07:00
return delayDiff(arrival, required, sta);
2018-09-28 08:54:21 -07:00
}
int
PathEndClkConstrained::exceptPathCmp(const PathEnd *path_end,
2026-01-03 16:59:35 -08:00
const StaState *sta) const
2018-09-28 08:54:21 -07:00
{
int cmp = PathEnd::exceptPathCmp(path_end, sta);
if (cmp == 0) {
const PathEndClkConstrained *path_end2 =
dynamic_cast<const PathEndClkConstrained*>(path_end);
2025-03-26 18:21:03 -07:00
const Path *clk_path2 = path_end2->targetClkPath();
2018-09-28 08:54:21 -07:00
return Path::cmp(targetClkPath(), clk_path2, sta);
}
else
return cmp;
}
////////////////////////////////////////////////////////////////
PathEndClkConstrainedMcp::PathEndClkConstrainedMcp(Path *path,
2026-01-03 16:59:35 -08:00
Path *clk_path,
MultiCyclePath *mcp) :
2018-09-28 08:54:21 -07:00
PathEndClkConstrained(path, clk_path),
mcp_(mcp)
{
}
float
PathEndClkConstrainedMcp::targetClkMcpAdjustment(const StaState *sta) const
{
2025-03-26 18:21:03 -07:00
return checkMcpAdjustment(path_, targetClkEdge(sta), sta);
2018-09-28 08:54:21 -07:00
}
float
PathEndClkConstrainedMcp::checkMcpAdjustment(const Path *path,
2026-01-03 16:59:35 -08:00
const ClockEdge *tgt_clk_edge,
const StaState *sta) const
2018-09-28 08:54:21 -07:00
{
if (mcp_) {
const TimingRole *check_role = checkRole(sta);
const MinMax *min_max = check_role->pathMinMax();
const ClockEdge *src_clk_edge = path->clkEdge(sta);
2026-01-03 16:59:35 -08:00
Sdc *sdc = path_->sdc(sta);
2018-09-28 08:54:21 -07:00
if (min_max == MinMax::max())
return PathEnd::checkSetupMcpAdjustment(src_clk_edge, tgt_clk_edge,
2026-01-03 16:59:35 -08:00
mcp_, setupDefaultCycles(), sdc);
2018-09-28 08:54:21 -07:00
else {
// Hold check.
// Default arrival clock is a proxy for the target clock.
2019-03-12 17:25:53 -07:00
if (src_clk_edge == nullptr)
2026-01-03 16:59:35 -08:00
src_clk_edge = tgt_clk_edge;
2018-09-28 08:54:21 -07:00
else if (src_clk_edge->clock() == sdc->defaultArrivalClock())
2026-01-03 16:59:35 -08:00
src_clk_edge = tgt_clk_edge->clock()->edge(src_clk_edge->transition());
2018-09-28 08:54:21 -07:00
const MultiCyclePath *setup_mcp;
const MultiCyclePath *hold_mcp;
// Hold checks also need the setup mcp for cycle accounting.
findHoldMcps(tgt_clk_edge, setup_mcp, hold_mcp, sta);
if (setup_mcp && hold_mcp) {
2026-01-03 16:59:35 -08:00
int setup_mult = setup_mcp->pathMultiplier(MinMax::max());
int hold_mult = hold_mcp->pathMultiplier(MinMax::min());
const ClockEdge *setup_clk_edge =
setup_mcp->useEndClk() ? tgt_clk_edge : src_clk_edge;
float setup_period = setup_clk_edge->clock()->period();
const ClockEdge *hold_clk_edge =
hold_mcp->useEndClk() ? tgt_clk_edge : src_clk_edge;
float hold_period = hold_clk_edge->clock()->period();
return (setup_mult - 1) * setup_period - hold_mult * hold_period;
2018-09-28 08:54:21 -07:00
}
else if (hold_mcp) {
2026-01-03 16:59:35 -08:00
int mult = hold_mcp->pathMultiplier(min_max);
const ClockEdge *clk_edge =
hold_mcp->useEndClk() ? tgt_clk_edge : src_clk_edge;
float period = clk_edge->clock()->period();
return -mult * period;
2018-09-28 08:54:21 -07:00
}
else if (setup_mcp) {
2026-01-03 16:59:35 -08:00
int mult = setup_mcp->pathMultiplier(min_max);
const ClockEdge *clk_edge =
setup_mcp->useEndClk() ? tgt_clk_edge : src_clk_edge;
float period = clk_edge->clock()->period();
return (mult - 1) * period;
2018-09-28 08:54:21 -07:00
}
else
2026-01-03 16:59:35 -08:00
return 0.0;
2018-09-28 08:54:21 -07:00
}
}
else
return 0.0;
}
float
PathEnd::checkSetupMcpAdjustment(const ClockEdge *src_clk_edge,
2026-01-03 16:59:35 -08:00
const ClockEdge *tgt_clk_edge,
const MultiCyclePath *mcp,
int default_cycles,
Sdc *sdc)
2018-09-28 08:54:21 -07:00
{
if (mcp) {
// Default arrival clock is a proxy for the target clock.
2019-03-12 17:25:53 -07:00
if (src_clk_edge == nullptr)
2018-09-28 08:54:21 -07:00
src_clk_edge = tgt_clk_edge;
else if (src_clk_edge->clock() == sdc->defaultArrivalClock())
src_clk_edge = tgt_clk_edge->clock()->edge(src_clk_edge->transition());
if (mcp->minMax()->matches(MinMax::max())) {
int mult = mcp->pathMultiplier(MinMax::max());
const ClockEdge *clk_edge =
2026-01-03 16:59:35 -08:00
mcp->useEndClk() ? tgt_clk_edge : src_clk_edge;
2018-09-28 08:54:21 -07:00
float period = clk_edge->clock()->period();
return (mult - default_cycles) * period;
2018-09-28 08:54:21 -07:00
}
else
return 0.0;
}
else
return 0.0;
}
Slack
PathEndClkConstrained::slackNoCrpr(const StaState *sta) const
{
Arrival arrival = dataArrivalTime(sta);
Required required = requiredTimeNoCrpr(sta);
if (checkGenericRole(sta) == TimingRole::setup())
2026-03-13 14:06:35 -07:00
return delayDiff(required, arrival, sta);
2018-09-28 08:54:21 -07:00
else
2026-03-13 14:06:35 -07:00
return delayDiff(arrival, required, sta);
2018-09-28 08:54:21 -07:00
}
void
PathEndClkConstrainedMcp::findHoldMcps(const ClockEdge *tgt_clk_edge,
2026-01-03 16:59:35 -08:00
const MultiCyclePath *&setup_mcp,
const MultiCyclePath *&hold_mcp,
const StaState *sta) const
2018-09-28 08:54:21 -07:00
{
2025-03-26 18:21:03 -07:00
Pin *pin = path_->pin(sta);
const RiseFall *rf = path_->transition(sta);
2018-09-28 08:54:21 -07:00
// Mcp may be setup, hold or setup_hold, since all match min paths.
const MinMaxAll *mcp_min_max = mcp_->minMax();
Search *search = sta->search();
if (mcp_min_max->matches(MinMax::min())) {
hold_mcp = mcp_;
setup_mcp =
2019-03-12 17:25:53 -07:00
dynamic_cast<MultiCyclePath*>(search->exceptionTo(ExceptionPathType::multi_cycle,
2026-01-03 16:59:35 -08:00
path_, pin, rf,
tgt_clk_edge,
MinMax::max(), true,
false,
path_->sdc(sta)));
2018-09-28 08:54:21 -07:00
}
else {
setup_mcp = mcp_;
hold_mcp =
2019-03-12 17:25:53 -07:00
dynamic_cast<MultiCyclePath*>(search->exceptionTo(ExceptionPathType::multi_cycle,
2026-01-03 16:59:35 -08:00
path_, pin, rf,
tgt_clk_edge,
MinMax::min(), true,
false,
path_->sdc(sta)));
2018-09-28 08:54:21 -07:00
}
}
int
PathEndClkConstrainedMcp::exceptPathCmp(const PathEnd *path_end,
2026-01-03 16:59:35 -08:00
const StaState *sta) const
2018-09-28 08:54:21 -07:00
{
int cmp = PathEndClkConstrained::exceptPathCmp(path_end, sta);
if (cmp == 0) {
const PathEndClkConstrainedMcp *path_end2 =
dynamic_cast<const PathEndClkConstrainedMcp*>(path_end);
const MultiCyclePath *mcp2 = path_end2->mcp_;
if (mcp_ == mcp2)
return 0;
else if (mcp_ < mcp2)
return -1;
else
return 1;
}
else
return cmp;
}
////////////////////////////////////////////////////////////////
PathEndCheck::PathEndCheck(Path *path,
2026-01-03 16:59:35 -08:00
TimingArc *check_arc,
Edge *check_edge,
Path *clk_path,
MultiCyclePath *mcp,
const StaState *) :
2018-09-28 08:54:21 -07:00
PathEndClkConstrainedMcp(path, clk_path, mcp),
check_arc_(check_arc),
check_edge_(check_edge)
{
}
PathEnd *
PathEndCheck::copy() const
2018-09-28 08:54:21 -07:00
{
2026-03-15 14:29:58 -07:00
return new PathEndCheck(*this);
2018-09-28 08:54:21 -07:00
}
2019-03-12 17:25:53 -07:00
PathEnd::Type
2018-09-28 08:54:21 -07:00
PathEndCheck::type() const
{
2019-03-12 17:25:53 -07:00
return Type::check;
}
const char *
PathEndCheck::typeName() const
{
return "check";
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
PathEndCheck::reportFull(const ReportPath *report) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
report->reportFull(this);
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
PathEndCheck::reportShort(const ReportPath *report) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
report->reportShort(this);
2018-09-28 08:54:21 -07:00
}
2025-03-30 15:27:53 -07:00
const TimingRole *
2018-09-28 08:54:21 -07:00
PathEndCheck::checkRole(const StaState *) const
{
return check_edge_->role();
}
ArcDelay
PathEndCheck::margin(const StaState *sta) const
{
2025-03-26 18:21:03 -07:00
return sta->search()->deratedDelay(clk_path_->vertex(sta),
2026-01-03 16:59:35 -08:00
check_arc_, check_edge_, false,
path_->minMax(sta),
path_->dcalcAnalysisPtIndex(sta),
path_->sdc(sta));
2018-09-28 08:54:21 -07:00
}
int
PathEndCheck::exceptPathCmp(const PathEnd *path_end,
2026-01-03 16:59:35 -08:00
const StaState *sta) const
2018-09-28 08:54:21 -07:00
{
int cmp = PathEndClkConstrainedMcp::exceptPathCmp(path_end, sta);
if (cmp == 0) {
const PathEndCheck *path_end2=dynamic_cast<const PathEndCheck*>(path_end);
const TimingArc *check_arc2 = path_end2->check_arc_;
if (check_arc_ == check_arc2)
return 0;
else if (check_arc_ < check_arc2)
return -1;
else
return 1;
}
else
return cmp;
}
Delay
PathEndCheck::clkSkew(const StaState *sta)
{
2026-03-13 14:06:35 -07:00
Delay skew = delayDiff(sourceClkDelay(sta),
targetClkDelay(sta),
sta);
skew = delayDiff(skew, crpr(sta), sta);
// Uncertainty decreases slack, but increases skew.
skew = delayDiff(skew,
checkTgtClkUncertainty(clk_path_,
clk_path_->clkEdge(sta),
checkRole(sta),
sta),
sta);
return skew;
}
2024-04-03 09:03:59 -07:00
Delay
PathEndCheck::sourceClkDelay(const StaState *sta) const
{
2025-03-26 18:21:03 -07:00
PathExpanded expanded(path_, sta);
const Path *src_clk_path = expanded.clkPath();
if (src_clk_path) {
2025-09-16 15:30:16 -07:00
const ClkInfo *src_clk_info = path_->tag(sta)->clkInfo();
2024-04-03 09:03:59 -07:00
if (src_clk_info->isPropagated()) {
// Propagated clock. Propagated arrival is seeded with insertion delay.
2025-03-26 18:21:03 -07:00
Arrival clk_arrival = src_clk_path->arrival();
2024-04-03 09:03:59 -07:00
const ClockEdge *src_clk_edge = src_clk_info->clkEdge();
2024-04-13 21:18:39 -07:00
Delay insertion = sourceClkInsertionDelay(sta);
2026-03-13 14:06:35 -07:00
return delayRemove(delayDiff(clk_arrival, src_clk_edge->time(), sta),
insertion);
2024-04-03 09:03:59 -07:00
}
else
// Ideal clock.
return sourceClkLatency(sta);
}
else
return 0.0;
}
Required
PathEndCheck::requiredTimeNoCrpr(const StaState *sta) const
{
Arrival tgt_clk_arrival = targetClkArrivalNoCrpr(sta);
ArcDelay check_margin = margin(sta);
float macro_clk_tree_delay = macroClkTreeDelay(sta);
if (checkGenericRole(sta) == TimingRole::setup())
2026-03-13 14:06:35 -07:00
return delayDiff(tgt_clk_arrival,
delaySum(check_margin,
macro_clk_tree_delay,
sta),
sta);
else
2026-03-13 14:06:35 -07:00
return delaySum(tgt_clk_arrival,
delayDiff(check_margin,
macro_clk_tree_delay,
sta),
sta);
}
float
PathEndCheck::macroClkTreeDelay(const StaState *sta) const
{
const ClockEdge *tgt_clk_edge = targetClkEdge(sta);
const Clock *tgt_clk = tgt_clk_edge->clock();
const Network *network = sta->network();
2025-03-26 18:21:03 -07:00
const Pin *clk_pin = clk_path_->pin(sta);
const Instance *inst = network->instance(clk_pin);
const LibertyCell *inst_cell = network->libertyCell(inst);
if (tgt_clk->isIdeal()
&& inst_cell && inst_cell->isMacro()) {
LibertyPort *clk_port = network->libertyPort(clk_pin);
if (clk_port) {
2025-03-26 18:21:03 -07:00
const MinMax *min_max = clk_path_->minMax(sta);
const RiseFall *rf = clk_path_->transition(sta);
2026-03-13 14:06:35 -07:00
float slew = delayAsFloat(clk_path_->slew(sta), min_max, sta);
return clk_port->clkTreeDelay(slew, rf, min_max);
}
}
return 0.0;
}
2018-09-28 08:54:21 -07:00
////////////////////////////////////////////////////////////////
PathEndLatchCheck::PathEndLatchCheck(Path *path,
2026-01-03 16:59:35 -08:00
TimingArc *check_arc,
Edge *check_edge,
Path *disable_path,
MultiCyclePath *mcp,
PathDelay *path_delay,
const StaState *sta) :
2019-03-12 17:25:53 -07:00
PathEndCheck(path, check_arc, check_edge, nullptr, mcp, sta),
2018-09-28 08:54:21 -07:00
disable_path_(disable_path),
path_delay_(path_delay),
src_clk_arrival_(0.0)
{
Latches *latches = sta->latches();
2026-01-03 16:59:35 -08:00
Path *enable_path = latches->latchEnableOtherPath(disable_path);
2019-11-11 13:03:38 -07:00
clk_path_ = enable_path;
2018-09-28 08:54:21 -07:00
Search *search = sta->search();
// Same as PathEndPathDelay::findRequired.
2026-04-13 14:58:16 -07:00
if (path_delay_ && PathEnd::ignoreClkLatency(path_, path_delay_, sta))
2025-03-26 18:21:03 -07:00
src_clk_arrival_ = search->pathClkPathArrival(path_);
2018-09-28 08:54:21 -07:00
}
PathEnd *
PathEndLatchCheck::copy() const
2018-09-28 08:54:21 -07:00
{
2026-03-15 14:29:58 -07:00
return new PathEndLatchCheck(*this);
2018-09-28 08:54:21 -07:00
}
2019-03-12 17:25:53 -07:00
PathEnd::Type
2018-09-28 08:54:21 -07:00
PathEndLatchCheck::type() const
{
2019-03-12 17:25:53 -07:00
return Type::latch_check;
}
const char *
PathEndLatchCheck::typeName() const
{
return "latch_check";
2018-09-28 08:54:21 -07:00
}
2025-03-26 18:21:03 -07:00
Path *
2018-09-28 08:54:21 -07:00
PathEndLatchCheck::latchDisable()
{
2025-03-26 18:21:03 -07:00
return disable_path_;
2018-09-28 08:54:21 -07:00
}
2025-03-26 18:21:03 -07:00
const Path *
2018-09-28 08:54:21 -07:00
PathEndLatchCheck::latchDisable() const
{
2025-03-26 18:21:03 -07:00
return disable_path_;
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
PathEndLatchCheck::reportFull(const ReportPath *report) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
report->reportFull(this);
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
PathEndLatchCheck::reportShort(const ReportPath *report) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
report->reportShort(this);
2018-09-28 08:54:21 -07:00
}
float
PathEndLatchCheck::sourceClkOffset(const StaState *sta) const
{
if (path_delay_)
return pathDelaySrcClkOffset(path_, path_delay_, src_clk_arrival_, sta);
else
return PathEndClkConstrained::sourceClkOffset(sourceClkEdge(sta),
2026-01-03 16:59:35 -08:00
disable_path_->clkEdge(sta),
TimingRole::setup(),
sta);
2018-09-28 08:54:21 -07:00
}
2025-03-30 15:27:53 -07:00
const TimingRole *
2018-09-28 08:54:21 -07:00
PathEndLatchCheck::checkRole(const StaState *sta) const
{
2026-02-27 16:57:08 -08:00
if (clk_path_ && clk_path_->clkInfo(sta)->isPulseClk())
2018-09-28 08:54:21 -07:00
// Pulse latches use register cycle accounting.
return TimingRole::setup();
else
// Setup cycle accting is slightly different because it is wrt
// the enable opening edge, not the disable (setup check) edge.
return TimingRole::latchSetup();
}
float
PathEndLatchCheck::targetClkTime(const StaState *sta) const
{
if (path_delay_)
return 0.0;
else
return PathEndClkConstrained::targetClkTime(sta);
}
float
PathEndLatchCheck::targetClkOffset(const StaState *sta) const
{
if (path_delay_)
return -targetClkEdge(sta)->time();
else
return PathEndClkConstrained::targetClkOffset(sta);
}
2018-09-28 08:54:21 -07:00
Required
PathEndLatchCheck::requiredTime(const StaState *sta) const
{
Required required;
Arrival borrow, adjusted_data_arrival, time_given_to_startpoint;
Latches *latches = sta->latches();
2025-03-26 18:21:03 -07:00
latches->latchRequired(path_, targetClkPath(), latchDisable(),
2026-01-03 16:59:35 -08:00
mcp_, path_delay_, src_clk_arrival_, margin(sta),
required, borrow, adjusted_data_arrival,
time_given_to_startpoint);
2018-09-28 08:54:21 -07:00
return required;
}
Arrival
PathEndLatchCheck::borrow(const StaState *sta) const
{
Latches *latches = sta->latches();
Required required;
Arrival borrow, adjusted_data_arrival, time_given_to_startpoint;
2025-03-26 18:21:03 -07:00
latches->latchRequired(path_, targetClkPath(), latchDisable(),
2026-01-03 16:59:35 -08:00
mcp_, path_delay_, src_clk_arrival_, margin(sta),
required, borrow, adjusted_data_arrival,
time_given_to_startpoint);
2018-09-28 08:54:21 -07:00
return borrow;
}
void
PathEndLatchCheck::latchRequired(const StaState *sta,
2026-01-03 16:59:35 -08:00
// Return values.
Required &required,
Delay &borrow,
Arrival &adjusted_data_arrival,
Delay &time_given_to_startpoint) const
2018-09-28 08:54:21 -07:00
{
Latches *latches = sta->latches();
2025-03-26 18:21:03 -07:00
latches->latchRequired(path_, targetClkPath(), latchDisable(),
2026-01-03 16:59:35 -08:00
mcp_, path_delay_, src_clk_arrival_, margin(sta),
required, borrow, adjusted_data_arrival,
time_given_to_startpoint);
2018-09-28 08:54:21 -07:00
}
void
PathEndLatchCheck::latchBorrowInfo(const StaState *sta,
2026-01-03 16:59:35 -08:00
// Return values.
float &nom_pulse_width,
Delay &open_latency,
Delay &latency_diff,
float &open_uncertainty,
Crpr &open_crpr,
Crpr &crpr_diff,
Delay &max_borrow,
bool &borrow_limit_exists) const
2018-09-28 08:54:21 -07:00
{
Latches *latches = sta->latches();
2025-03-26 18:21:03 -07:00
latches->latchBorrowInfo(path_, targetClkPath(), latchDisable(),
2026-01-03 16:59:35 -08:00
margin(sta),
path_delay_ && ignoreClkLatency(sta),
nom_pulse_width, open_latency,
latency_diff, open_uncertainty,
open_crpr, crpr_diff, max_borrow,
borrow_limit_exists);
2018-09-28 08:54:21 -07:00
}
Arrival
PathEndLatchCheck::targetClkWidth(const StaState *sta) const
{
const Search *search = sta->search();
2025-03-26 18:21:03 -07:00
Arrival disable_arrival = search->clkPathArrival(disable_path_);
Arrival enable_arrival = search->clkPathArrival(clk_path_);
2025-09-16 15:30:16 -07:00
const ClkInfo *enable_clk_info = clk_path_->clkInfo(sta);
2018-09-28 08:54:21 -07:00
if (enable_clk_info->isPulseClk())
2026-03-13 14:06:35 -07:00
return delayDiff(disable_arrival, enable_arrival, sta);
2018-09-28 08:54:21 -07:00
else {
2020-07-11 17:43:30 -07:00
if (delayGreater(enable_arrival, disable_arrival, sta)) {
2023-01-19 11:23:45 -07:00
const Clock *disable_clk = enable_clk_info->clock();
2022-01-15 12:51:05 -07:00
if (disable_clk)
2026-03-13 14:06:35 -07:00
disable_arrival = delaySum(disable_arrival,
disable_clk->period(),
sta);
2018-09-28 08:54:21 -07:00
}
2026-03-13 14:06:35 -07:00
return delayDiff(disable_arrival, enable_arrival, sta);
2018-09-28 08:54:21 -07:00
}
}
int
PathEndLatchCheck::exceptPathCmp(const PathEnd *path_end,
2026-01-03 16:59:35 -08:00
const StaState *sta) const
2018-09-28 08:54:21 -07:00
{
2026-04-13 14:58:16 -07:00
int cmp = PathEndCheck::exceptPathCmp(path_end, sta);
2018-09-28 08:54:21 -07:00
if (cmp == 0) {
const PathEndLatchCheck *path_end2 =
dynamic_cast<const PathEndLatchCheck*>(path_end);
const TimingArc *check_arc2 = path_end2->check_arc_;
if (check_arc_ == check_arc2) {
2025-03-26 18:21:03 -07:00
const Path *disable_path2 = path_end2->disable_path_;
return Path::cmp(disable_path_, disable_path2, sta);
2018-09-28 08:54:21 -07:00
}
else if (check_arc_ < check_arc2)
return -1;
else
return 1;
}
else
return cmp;
}
2024-08-07 12:46:44 -07:00
bool
PathEndLatchCheck::ignoreClkLatency(const StaState *sta) const
{
return PathEnd::ignoreClkLatency(path_, path_delay_, sta);
}
2018-09-28 08:54:21 -07:00
///////////////////////////////////////////////////////////////
PathEndOutputDelay::PathEndOutputDelay(OutputDelay *output_delay,
2026-01-03 16:59:35 -08:00
Path *path,
Path *clk_path,
MultiCyclePath *mcp,
const StaState *) :
2018-09-28 08:54:21 -07:00
// No target clk_path_ for output delays.
PathEndClkConstrainedMcp(path, clk_path, mcp),
output_delay_(output_delay)
{
}
PathEnd *
PathEndOutputDelay::copy() const
2018-09-28 08:54:21 -07:00
{
2026-03-15 14:29:58 -07:00
return new PathEndOutputDelay(*this);
2018-09-28 08:54:21 -07:00
}
2019-03-12 17:25:53 -07:00
PathEnd::Type
2018-09-28 08:54:21 -07:00
PathEndOutputDelay::type() const
{
2019-03-12 17:25:53 -07:00
return Type::output_delay;
}
const char *
PathEndOutputDelay::typeName() const
{
return "output_delay";
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
PathEndOutputDelay::reportFull(const ReportPath *report) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
report->reportFull(this);
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
PathEndOutputDelay::reportShort(const ReportPath *report) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
report->reportShort(this);
2018-09-28 08:54:21 -07:00
}
ArcDelay
PathEndOutputDelay::margin(const StaState *sta) const
{
2025-03-26 18:21:03 -07:00
return outputDelayMargin(output_delay_, path_, sta);
2018-09-28 08:54:21 -07:00
}
float
PathEnd::outputDelayMargin(OutputDelay *output_delay,
2026-01-03 16:59:35 -08:00
const Path *path,
const StaState *sta)
2018-09-28 08:54:21 -07:00
{
2019-11-11 15:30:19 -07:00
const RiseFall *rf = path->transition(sta);
2018-09-28 08:54:21 -07:00
const MinMax *min_max = path->minMax(sta);
2019-11-11 15:30:19 -07:00
float margin = output_delay->delays()->value(rf, min_max);
2018-09-28 08:54:21 -07:00
if (min_max == MinMax::max())
return margin;
else
return -margin;
}
2025-03-30 15:27:53 -07:00
const TimingRole *
2018-09-28 08:54:21 -07:00
PathEndOutputDelay::checkRole(const StaState *sta) const
{
2025-03-26 18:21:03 -07:00
if (path_->minMax(sta) == MinMax::max())
2018-09-28 08:54:21 -07:00
return TimingRole::outputSetup();
else
return TimingRole::outputHold();
}
2023-01-19 11:23:45 -07:00
const ClockEdge *
2018-09-28 08:54:21 -07:00
PathEndOutputDelay::targetClkEdge(const StaState *sta) const
{
2025-03-26 18:21:03 -07:00
if (clk_path_)
return clk_path_->clkEdge(sta);
2018-09-28 08:54:21 -07:00
else
return output_delay_->clkEdge();
}
Arrival
PathEndOutputDelay::targetClkArrivalNoCrpr(const StaState *sta) const
{
2025-03-26 18:21:03 -07:00
if (clk_path_)
2018-09-28 08:54:21 -07:00
return PathEndClkConstrained::targetClkArrivalNoCrpr(sta);
else {
const ClockEdge *tgt_clk_edge = targetClkEdge(sta);
const TimingRole *check_role = checkRole(sta);
2026-03-13 14:06:35 -07:00
Arrival base = delaySum(targetClkTime(sta),
tgtClkDelay(tgt_clk_edge, check_role, sta),
sta);
return delaySum(delaySum(base,
targetClkUncertainty(sta),
sta),
checkMcpAdjustment(path_, tgt_clk_edge, sta),
sta);
2018-09-28 08:54:21 -07:00
}
}
2018-12-11 10:47:04 -08:00
Crpr
2024-06-27 13:57:58 -07:00
PathEndOutputDelay::crpr(const StaState *sta) const
2018-09-28 08:54:21 -07:00
{
if (!crpr_valid_) {
2018-12-11 10:47:04 -08:00
CheckCrpr *check_crpr = sta->search()->checkCrpr();
2025-03-26 18:21:03 -07:00
crpr_ = check_crpr->outputDelayCrpr(path_, targetClkEdge(sta));
2024-06-27 13:57:58 -07:00
crpr_valid_ = true;
2018-09-28 08:54:21 -07:00
}
return crpr_;
}
2024-04-03 09:03:59 -07:00
Delay
2018-09-28 08:54:21 -07:00
PathEndOutputDelay::targetClkDelay(const StaState *sta) const
{
2025-03-26 18:21:03 -07:00
if (clk_path_)
2018-09-28 08:54:21 -07:00
return PathEndClkConstrained::targetClkDelay(sta);
else
return tgtClkDelay(targetClkEdge(sta), checkRole(sta), sta);
}
Arrival
PathEndOutputDelay::tgtClkDelay(const ClockEdge *tgt_clk_edge,
2026-01-03 16:59:35 -08:00
const TimingRole *check_role,
const StaState *sta) const
2018-09-28 08:54:21 -07:00
{
Arrival insertion, latency;
tgtClkDelay(tgt_clk_edge, check_role, sta,
2026-01-03 16:59:35 -08:00
insertion, latency);
2026-03-13 14:06:35 -07:00
return delaySum(insertion, latency, sta);
2018-09-28 08:54:21 -07:00
}
void
PathEndOutputDelay::tgtClkDelay(const ClockEdge *tgt_clk_edge,
2026-01-03 16:59:35 -08:00
const TimingRole *check_role,
const StaState *sta,
// Return values.
Arrival &insertion,
Arrival &latency) const
2018-09-28 08:54:21 -07:00
{
// Early late: setup early, hold late.
const EarlyLate *early_late = check_role->tgtClkEarlyLate();
// Latency min_max depends on bc_wc or ocv.
2026-01-03 16:59:35 -08:00
const MinMax *latency_min_max = path_->tgtClkMinMax(sta);
2018-09-28 08:54:21 -07:00
Clock *tgt_clk = tgt_clk_edge->clock();
2025-03-30 15:27:53 -07:00
const RiseFall *tgt_clk_rf = tgt_clk_edge->transition();
2026-01-03 16:59:35 -08:00
const Mode *mode = path_->mode(sta);
2018-09-28 08:54:21 -07:00
if (!output_delay_->sourceLatencyIncluded())
insertion = sta->search()->clockInsertion(tgt_clk,
2026-01-03 16:59:35 -08:00
tgt_clk->defaultPin(),
tgt_clk_rf,
latency_min_max,
early_late, mode);
2018-09-28 08:54:21 -07:00
else
insertion = 0.0;
if (!tgt_clk->isPropagated()
&& !output_delay_->networkLatencyIncluded())
2026-01-03 16:59:35 -08:00
latency = mode->sdc()->clockLatency(tgt_clk, tgt_clk_rf, latency_min_max);
2018-09-28 08:54:21 -07:00
else
latency = 0.0;
}
2024-04-03 09:03:59 -07:00
Delay
2018-09-28 08:54:21 -07:00
PathEndOutputDelay::targetClkInsertionDelay(const StaState *sta) const
{
2025-03-26 18:21:03 -07:00
if (clk_path_)
2018-09-28 08:54:21 -07:00
return PathEndClkConstrained::targetClkInsertionDelay(sta);
else {
Arrival insertion, latency;
tgtClkDelay(targetClkEdge(sta), checkRole(sta), sta,
2026-01-03 16:59:35 -08:00
insertion, latency);
2018-09-28 08:54:21 -07:00
return insertion;
}
}
int
PathEndOutputDelay::exceptPathCmp(const PathEnd *path_end,
2026-01-03 16:59:35 -08:00
const StaState *sta) const
2018-09-28 08:54:21 -07:00
{
int cmp = PathEndClkConstrainedMcp::exceptPathCmp(path_end, sta);
if (cmp == 0) {
const PathEndOutputDelay *path_end2 =
dynamic_cast<const PathEndOutputDelay*>(path_end);
OutputDelay *output_delay2 = path_end2->output_delay_;
if (output_delay_ == output_delay2)
return 0;
else if (output_delay_ < output_delay2)
return -1;
else
return 1;
}
else
return cmp;
}
////////////////////////////////////////////////////////////////
PathEndGatedClock::PathEndGatedClock(Path *gating_ref,
2026-01-03 16:59:35 -08:00
Path *clk_path,
const TimingRole *check_role,
MultiCyclePath *mcp,
ArcDelay margin,
const StaState *) :
2018-09-28 08:54:21 -07:00
PathEndClkConstrainedMcp(gating_ref, clk_path, mcp),
check_role_(check_role),
margin_(margin)
{
}
PathEnd *
PathEndGatedClock::copy() const
2018-09-28 08:54:21 -07:00
{
2026-03-15 14:29:58 -07:00
return new PathEndGatedClock(*this);
2018-09-28 08:54:21 -07:00
}
2019-03-12 17:25:53 -07:00
PathEnd::Type
2018-09-28 08:54:21 -07:00
PathEndGatedClock::type() const
{
2019-03-12 17:25:53 -07:00
return Type::gated_clk;
}
const char *
PathEndGatedClock::typeName() const
{
return "gated_clk";
2018-09-28 08:54:21 -07:00
}
2025-03-30 15:27:53 -07:00
const TimingRole *
2018-09-28 08:54:21 -07:00
PathEndGatedClock::checkRole(const StaState *) const
{
return check_role_;
}
void
2025-02-01 14:53:28 -08:00
PathEndGatedClock::reportFull(const ReportPath *report) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
report->reportFull(this);
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
PathEndGatedClock::reportShort(const ReportPath *report) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
report->reportShort(this);
2018-09-28 08:54:21 -07:00
}
int
PathEndGatedClock::exceptPathCmp(const PathEnd *path_end,
2026-01-03 16:59:35 -08:00
const StaState *sta) const
2018-09-28 08:54:21 -07:00
{
int cmp = PathEndClkConstrainedMcp::exceptPathCmp(path_end, sta);
if (cmp == 0) {
const PathEndGatedClock *path_end2 =
dynamic_cast<const PathEndGatedClock*>(path_end);
2025-03-30 15:27:53 -07:00
const TimingRole *check_role2 = path_end2->check_role_;
2018-09-28 08:54:21 -07:00
if (check_role_ == check_role2)
return 0;
else if (check_role_ < check_role2)
return -1;
else
return 1;
}
else
return cmp;
}
////////////////////////////////////////////////////////////////
PathEndDataCheck::PathEndDataCheck(DataCheck *check,
2026-01-03 16:59:35 -08:00
Path *data_path,
Path *data_clk_path,
MultiCyclePath *mcp,
const StaState *sta) :
2019-03-12 17:25:53 -07:00
PathEndClkConstrainedMcp(data_path, nullptr, mcp),
2018-09-28 08:54:21 -07:00
data_clk_path_(data_clk_path),
check_(check)
{
2025-03-26 18:21:03 -07:00
clk_path_ = clkPath(data_clk_path, sta);
2018-09-28 08:54:21 -07:00
}
// PathExpanded::expand() and PathExpanded::clkPath().
2025-03-26 18:21:03 -07:00
Path *
PathEndDataCheck::clkPath(Path *path,
const StaState *sta)
{
Path *p = path;
while (p) {
Path *prev_path = p->prevPath();
TimingArc *prev_arc = p->prevArc(sta);
if (p->isClock(sta))
return p;
if (prev_arc) {
2025-03-30 15:27:53 -07:00
const TimingRole *prev_role = prev_arc->role();
if (prev_role == TimingRole::regClkToQ()
2026-01-03 16:59:35 -08:00
|| prev_role == TimingRole::latchEnToQ()) {
2025-03-26 18:21:03 -07:00
prev_path = p->prevPath();
2026-01-03 16:59:35 -08:00
return prev_path;
}
else if (prev_role == TimingRole::latchDtoQ()) {
2026-01-03 16:59:35 -08:00
const Latches *latches = sta->latches();
Edge *prev_edge = p->prevEdge(sta);
Path *enable_path = latches->latchEnablePath(p, prev_edge);
return enable_path;
}
}
p = prev_path;
}
2025-03-26 18:21:03 -07:00
return nullptr;
}
2018-09-28 08:54:21 -07:00
PathEnd *
PathEndDataCheck::copy() const
2018-09-28 08:54:21 -07:00
{
2026-03-15 14:29:58 -07:00
return new PathEndDataCheck(*this);
2018-09-28 08:54:21 -07:00
}
2019-03-12 17:25:53 -07:00
PathEnd::Type
2018-09-28 08:54:21 -07:00
PathEndDataCheck::type() const
{
2019-03-12 17:25:53 -07:00
return Type::data_check;
}
const char *
PathEndDataCheck::typeName() const
{
return "data_check";
2018-09-28 08:54:21 -07:00
}
2023-01-19 11:23:45 -07:00
const ClockEdge *
2021-12-14 08:18:53 -07:00
PathEndDataCheck::targetClkEdge(const StaState *sta) const
{
// clk_path_ can be null if data_clk_path is from an input port.
2025-03-26 18:21:03 -07:00
return data_clk_path_->clkEdge(sta);
2021-12-14 08:18:53 -07:00
}
2018-09-28 08:54:21 -07:00
Arrival
PathEndDataCheck::requiredTimeNoCrpr(const StaState *sta) const
{
2025-03-26 18:21:03 -07:00
Arrival data_clk_arrival = data_clk_path_->arrival();
float data_clk_time = data_clk_path_->clkEdge(sta)->time();
2026-03-13 14:06:35 -07:00
Arrival data_clk_delay = delayDiff(data_clk_arrival,
data_clk_time,
sta);
Arrival tgt_clk_arrival =
delaySum(delaySum(targetClkTime(sta),
data_clk_delay,
sta),
delaySum(targetClkUncertainty(sta),
targetClkMcpAdjustment(sta),
sta),
sta);
2018-09-28 08:54:21 -07:00
2018-11-26 09:15:52 -08:00
ArcDelay check_margin = margin(sta);
2018-09-28 08:54:21 -07:00
if (checkGenericRole(sta) == TimingRole::setup())
2026-03-13 14:06:35 -07:00
return delayDiff(tgt_clk_arrival, check_margin, sta);
2018-09-28 08:54:21 -07:00
else
2026-03-13 14:06:35 -07:00
return delaySum(tgt_clk_arrival, check_margin, sta);
2018-09-28 08:54:21 -07:00
}
ArcDelay
PathEndDataCheck::margin(const StaState *sta) const
{
float margin;
bool margin_exists;
2025-03-26 18:21:03 -07:00
check_->margin(data_clk_path_->transition(sta),
2026-01-03 16:59:35 -08:00
path_->transition(sta),
path_->minMax(sta),
margin, margin_exists);
2018-09-28 08:54:21 -07:00
return margin;
}
2025-03-30 15:27:53 -07:00
const TimingRole *
2018-09-28 08:54:21 -07:00
PathEndDataCheck::checkRole(const StaState *sta) const
{
2025-03-26 18:21:03 -07:00
if (path_->minMax(sta) == MinMax::max())
2018-09-28 08:54:21 -07:00
return TimingRole::dataCheckSetup();
else
return TimingRole::dataCheckHold();
}
void
2025-02-01 14:53:28 -08:00
PathEndDataCheck::reportFull(const ReportPath *report) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
report->reportFull(this);
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
PathEndDataCheck::reportShort(const ReportPath *report) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
report->reportShort(this);
2018-09-28 08:54:21 -07:00
}
int
PathEndDataCheck::exceptPathCmp(const PathEnd *path_end,
2026-01-03 16:59:35 -08:00
const StaState *sta) const
2018-09-28 08:54:21 -07:00
{
int cmp = PathEndClkConstrainedMcp::exceptPathCmp(path_end, sta);
if (cmp == 0) {
const PathEndDataCheck *path_end2 =
dynamic_cast<const PathEndDataCheck*>(path_end);
const DataCheck *check2 = path_end2->check_;
if (check_ == check2)
return 0;
else if (check_ < check2)
return -1;
else
return 1;
}
else
return cmp;
}
////////////////////////////////////////////////////////////////
PathEndPathDelay::PathEndPathDelay(PathDelay *path_delay,
2026-01-03 16:59:35 -08:00
Path *path,
const StaState *sta):
2019-03-12 17:25:53 -07:00
PathEndClkConstrained(path, nullptr),
2018-09-28 08:54:21 -07:00
path_delay_(path_delay),
2019-03-12 17:25:53 -07:00
check_arc_(nullptr),
check_edge_(nullptr),
output_delay_(nullptr)
2018-09-28 08:54:21 -07:00
{
findSrcClkArrival(sta);
}
PathEndPathDelay::PathEndPathDelay(PathDelay *path_delay,
2026-01-03 16:59:35 -08:00
Path *path,
OutputDelay *output_delay,
const StaState *sta):
2019-03-12 17:25:53 -07:00
PathEndClkConstrained(path, nullptr),
2018-09-28 08:54:21 -07:00
path_delay_(path_delay),
2019-03-12 17:25:53 -07:00
check_arc_(nullptr),
check_edge_(nullptr),
2018-09-28 08:54:21 -07:00
output_delay_(output_delay)
{
findSrcClkArrival(sta);
}
PathEndPathDelay::PathEndPathDelay(PathDelay *path_delay,
2026-01-03 16:59:35 -08:00
Path *path,
Path *clk_path,
TimingArc *check_arc,
Edge *check_edge,
const StaState *sta) :
2018-09-28 08:54:21 -07:00
PathEndClkConstrained(path, clk_path),
path_delay_(path_delay),
check_arc_(check_arc),
check_edge_(check_edge),
2019-03-12 17:25:53 -07:00
output_delay_(nullptr)
2018-09-28 08:54:21 -07:00
{
findSrcClkArrival(sta);
}
PathEnd *
PathEndPathDelay::copy() const
2018-09-28 08:54:21 -07:00
{
2026-03-15 14:29:58 -07:00
return new PathEndPathDelay(*this);
2018-09-28 08:54:21 -07:00
}
2019-03-12 17:25:53 -07:00
PathEnd::Type
2018-09-28 08:54:21 -07:00
PathEndPathDelay::type() const
{
2019-03-12 17:25:53 -07:00
return Type::path_delay;
}
const char *
PathEndPathDelay::typeName() const
{
return "path_delay";
2018-09-28 08:54:21 -07:00
}
void
PathEndPathDelay::findSrcClkArrival(const StaState *sta)
{
2026-04-13 14:58:16 -07:00
if (PathEnd::ignoreClkLatency(path_, path_delay_, sta)) {
2018-09-28 08:54:21 -07:00
Search *search = sta->search();
2025-03-26 18:21:03 -07:00
src_clk_arrival_ = search->pathClkPathArrival(path_);
2018-09-28 08:54:21 -07:00
}
else
src_clk_arrival_ = 0.0;
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
PathEndPathDelay::reportFull(const ReportPath *report) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
report->reportFull(this);
2018-09-28 08:54:21 -07:00
}
void
2025-02-01 14:53:28 -08:00
PathEndPathDelay::reportShort(const ReportPath *report) const
2018-09-28 08:54:21 -07:00
{
2020-12-28 19:51:34 -08:00
report->reportShort(this);
2018-09-28 08:54:21 -07:00
}
bool
PathEndPathDelay::pathDelayMarginIsExternal() const
{
2019-03-12 17:25:53 -07:00
return check_arc_ == nullptr;
2018-09-28 08:54:21 -07:00
}
2025-03-30 15:27:53 -07:00
const TimingRole *
2018-09-28 08:54:21 -07:00
PathEndPathDelay::checkRole(const StaState *sta) const
{
if (check_edge_)
return check_edge_->role();
else if (minMax(sta) == MinMax::max())
return TimingRole::setup();
else
return TimingRole::hold();
}
ArcDelay
PathEndPathDelay::margin(const StaState *sta) const
{
if (check_arc_) {
return sta->search()->deratedDelay(check_edge_->from(sta->graph()),
2026-01-03 16:59:35 -08:00
check_arc_, check_edge_, false,
path_->minMax(sta),
path_->dcalcAnalysisPtIndex(sta),
path_->sdc(sta));
2018-09-28 08:54:21 -07:00
}
else if (output_delay_)
2025-03-26 18:21:03 -07:00
return outputDelayMargin(output_delay_, path_, sta);
2018-09-28 08:54:21 -07:00
else
return delay_zero;
}
float
PathEndPathDelay::sourceClkOffset(const StaState *sta) const
{
return pathDelaySrcClkOffset(path_, path_delay_, src_clk_arrival_, sta);
}
2024-04-13 21:18:39 -07:00
Delay
2024-04-03 09:03:59 -07:00
PathEnd::clkSkew(const StaState *)
{
return 0.0;
}
2018-09-28 08:54:21 -07:00
// Helper shared by PathEndLatchCheck.
float
2025-03-26 18:21:03 -07:00
PathEnd::pathDelaySrcClkOffset(const Path *path,
2026-01-03 16:59:35 -08:00
PathDelay *path_delay,
Arrival src_clk_arrival,
const StaState *sta)
2018-09-28 08:54:21 -07:00
{
float offset = 0.0;
2025-03-26 18:21:03 -07:00
const ClockEdge *clk_edge = path->clkEdge(sta);
2018-09-28 08:54:21 -07:00
if (clk_edge) {
if (ignoreClkLatency(path, path_delay, sta))
2026-03-13 14:06:35 -07:00
offset = -delayAsFloat(src_clk_arrival, path->minMax(sta), sta);
2018-09-28 08:54:21 -07:00
else
// Arrival includes src clock edge time that is not counted in the
// path delay.
offset = -clk_edge->time();
}
return offset;
}
2023-01-19 11:23:45 -07:00
const ClockEdge *
PathEndPathDelay::targetClkEdge(const StaState *sta) const
{
2025-03-26 18:21:03 -07:00
if (clk_path_)
return clk_path_->clkEdge(sta);
else if (output_delay_)
return output_delay_->clkEdge();
else
return nullptr;
}
2018-09-28 08:54:21 -07:00
float
PathEndPathDelay::targetClkTime(const StaState *sta) const
{
const ClockEdge *tgt_clk_edge = targetClkEdge(sta);
if (tgt_clk_edge)
return tgt_clk_edge->time();
else
return 0.0;
}
Arrival
PathEndPathDelay::targetClkArrivalNoCrpr(const StaState *sta) const
{
2023-01-19 11:23:45 -07:00
const ClockEdge *tgt_clk_edge = targetClkEdge(sta);
if (tgt_clk_edge)
2026-03-13 14:06:35 -07:00
return delaySum(targetClkDelay(sta),
targetClkUncertainty(sta),
sta);
2025-03-26 18:21:03 -07:00
else if (clk_path_)
return clk_path_->arrival();
2018-09-28 08:54:21 -07:00
else
return 0.0;
}
float
PathEndPathDelay::targetClkOffset(const StaState *) const
{
return 0.0;
}
Required
PathEndPathDelay::requiredTime(const StaState *sta) const
{
float delay = path_delay_->delay();
if (path_delay_->ignoreClkLatency()) {
2026-03-13 14:06:35 -07:00
Delay with_delay = path_->isClock(sta)
? Delay(path_->clkEdge(sta)->time() + delay)
: delaySum(src_clk_arrival_, delay, sta);
ArcDelay m = margin(sta);
return (minMax(sta) == MinMax::max())
? delayDiff(with_delay, m, sta)
: delaySum(with_delay, m, sta);
2018-09-28 08:54:21 -07:00
}
else {
Arrival tgt_clk_arrival = targetClkArrival(sta);
2018-09-28 08:54:21 -07:00
float src_clk_offset = sourceClkOffset(sta);
// Path delay includes target clk latency and timing check setup/hold
// margin or external departure at target.
2026-03-13 14:06:35 -07:00
Delay base = delaySum(tgt_clk_arrival,
delay,
sta);
Delay with_src = delayDiff(base,
src_clk_offset,
sta);
ArcDelay m = margin(sta);
return (minMax(sta) == MinMax::max())
? delayDiff(with_src, m, sta)
: delaySum(with_src, m, sta);
2018-09-28 08:54:21 -07:00
}
}
bool
PathEndPathDelay::ignoreClkLatency(const StaState *sta) const
{
return PathEnd::ignoreClkLatency(path_, path_delay_, sta);
}
2018-09-28 08:54:21 -07:00
int
PathEndPathDelay::exceptPathCmp(const PathEnd *path_end,
2026-01-03 16:59:35 -08:00
const StaState *sta) const
2018-09-28 08:54:21 -07:00
{
int cmp = PathEndClkConstrained::exceptPathCmp(path_end, sta);
if (cmp == 0) {
const PathEndPathDelay *path_end2 =
dynamic_cast<const PathEndPathDelay*>(path_end);
PathDelay *path_delay2 = path_end2->path_delay_;
if (path_delay_ == path_delay2) {
const TimingArc *check_arc2 = path_end2->check_arc_;
if (check_arc_ == check_arc2)
2026-01-03 16:59:35 -08:00
return 0;
2018-09-28 08:54:21 -07:00
else if (check_arc_ < check_arc2)
2026-01-03 16:59:35 -08:00
return -1;
2018-09-28 08:54:21 -07:00
else
2026-01-03 16:59:35 -08:00
return 1;
2018-09-28 08:54:21 -07:00
}
else if (path_delay_ < path_delay2)
return -1;
else
return 1;
}
else
return cmp;
}
////////////////////////////////////////////////////////////////
bool
PathEnd::less(const PathEnd *path_end1,
2026-01-03 16:59:35 -08:00
const PathEnd *path_end2,
2026-03-09 10:15:53 -07:00
bool cmp_slack,
2026-01-03 16:59:35 -08:00
const StaState *sta)
2018-09-28 08:54:21 -07:00
{
2026-03-09 10:15:53 -07:00
return cmp(path_end1, path_end2, cmp_slack, sta) < 0;
2018-09-28 08:54:21 -07:00
}
int
PathEnd::cmp(const PathEnd *path_end1,
2026-01-03 16:59:35 -08:00
const PathEnd *path_end2,
2026-03-09 10:15:53 -07:00
bool cmp_slack,
2026-01-03 16:59:35 -08:00
const StaState *sta)
2018-09-28 08:54:21 -07:00
{
2026-03-09 10:15:53 -07:00
int cmp = !cmp_slack || path_end1->isUnconstrained()
2018-09-28 08:54:21 -07:00
? -cmpArrival(path_end1, path_end2, sta)
: cmpSlack(path_end1, path_end2, sta);
if (cmp == 0) {
const Path *path1 = path_end1->path();
const Path *path2 = path_end2->path();
cmp = Path::cmpPinTrClk(path1, path2, sta);
2020-01-05 13:56:51 -08:00
if (cmp == 0) {
2020-01-06 20:52:49 -08:00
const Path *clk_path1 = path_end1->targetClkPath();
const Path *clk_path2 = path_end2->targetClkPath();
cmp = Path::cmpPinTrClk(clk_path1, clk_path2, sta);
if (cmp == 0) {
2026-01-03 16:59:35 -08:00
cmp = Path::cmpAll(path1, path2, sta);
if (cmp == 0)
cmp = Path::cmpAll(clk_path1, clk_path2, sta);
2020-01-06 20:52:49 -08:00
}
2020-01-05 13:56:51 -08:00
}
2018-09-28 08:54:21 -07:00
}
2020-01-06 13:56:47 -08:00
return cmp;
2018-09-28 08:54:21 -07:00
}
int
PathEnd::cmpSlack(const PathEnd *path_end1,
2026-01-03 16:59:35 -08:00
const PathEnd *path_end2,
const StaState *sta)
2018-09-28 08:54:21 -07:00
{
Slack slack1 = path_end1->slack(sta);
Slack slack2 = path_end2->slack(sta);
2026-03-13 14:06:35 -07:00
if (delayZero(slack1, sta)
&& delayZero(slack2, sta)
2018-09-28 08:54:21 -07:00
&& path_end1->isLatchCheck()
&& path_end2->isLatchCheck()) {
Arrival borrow1 = path_end1->borrow(sta);
Arrival borrow2 = path_end2->borrow(sta);
// Latch slack is zero if there is borrowing so break ties
// based on borrow time.
2026-03-13 14:06:35 -07:00
if (delayEqual(borrow1, borrow2, sta))
2018-09-28 08:54:21 -07:00
return 0;
2020-07-11 17:43:30 -07:00
else if (delayGreater(borrow1, borrow2, sta))
2018-09-28 08:54:21 -07:00
return -1;
else
return 1;
}
2026-03-13 14:06:35 -07:00
else if (delayEqual(slack1, slack2, sta))
2018-09-28 08:54:21 -07:00
return 0;
2020-07-11 17:43:30 -07:00
else if (delayLess(slack1, slack2, sta))
2018-09-28 08:54:21 -07:00
return -1;
else
return 1;
}
int
PathEnd::cmpArrival(const PathEnd *path_end1,
2026-01-03 16:59:35 -08:00
const PathEnd *path_end2,
const StaState *sta)
2018-09-28 08:54:21 -07:00
{
Arrival arrival1 = path_end1->dataArrivalTime(sta);
Arrival arrival2 = path_end2->dataArrivalTime(sta);
const MinMax *min_max = path_end1->minMax(sta);
2026-03-13 14:06:35 -07:00
if (delayEqual(arrival1, arrival2, sta))
2018-09-28 08:54:21 -07:00
return 0;
2020-07-11 17:43:30 -07:00
else if (delayLess(arrival1, arrival2, min_max, sta))
2018-09-28 08:54:21 -07:00
return -1;
else
return 1;
}
int
PathEnd::cmpNoCrpr(const PathEnd *path_end1,
2026-01-03 16:59:35 -08:00
const PathEnd *path_end2,
const StaState *sta)
2018-09-28 08:54:21 -07:00
{
int cmp = path_end1->exceptPathCmp(path_end2, sta);
if (cmp == 0) {
const Path *path1 = path_end1->path();
const Path *path2 = path_end2->path();
return Path::cmpNoCrpr(path1, path2, sta);
}
else
return cmp;
}
////////////////////////////////////////////////////////////////
2026-03-09 10:15:53 -07:00
PathEndLess::PathEndLess(bool cmp_slack,
const StaState *sta) :
cmp_slack_(cmp_slack),
sta_(sta)
{
}
bool
PathEndLess::operator()(const PathEnd *path_end1,
const PathEnd *path_end2) const
{
return PathEnd::less(path_end1, path_end2, cmp_slack_, sta_);
}
////////////////////////////////////////////////////////////////
PathEndSlackLess::PathEndSlackLess(bool cmp_slack,
const StaState *sta) :
cmp_slack_(cmp_slack),
2018-09-28 08:54:21 -07:00
sta_(sta)
{
}
bool
PathEndSlackLess::operator()(const PathEnd *path_end1,
2026-01-03 16:59:35 -08:00
const PathEnd *path_end2) const
2018-09-28 08:54:21 -07:00
{
int cmp = path_end1->isUnconstrained()
? -PathEnd::cmpArrival(path_end1, path_end2, sta_)
: PathEnd::cmpSlack(path_end1, path_end2, sta_);
return cmp < 0;
}
////////////////////////////////////////////////////////////////
PathEndNoCrprLess::PathEndNoCrprLess(const StaState *sta) :
sta_(sta)
{
}
bool
PathEndNoCrprLess::operator()(const PathEnd *path_end1,
2026-01-03 16:59:35 -08:00
const PathEnd *path_end2) const
2018-09-28 08:54:21 -07:00
{
int cmp = path_end1->exceptPathCmp(path_end2, sta_);
if (cmp == 0) {
const Path *path1 = path_end1->path();
const Path *path2 = path_end2->path();
return Path::cmpNoCrpr(path1, path2, sta_) < 0;
}
else
return cmp < 0;
}
2026-04-13 14:58:16 -07:00
} // namespace sta