lvf squish

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2026-03-13 14:06:35 -07:00
parent 0a5b95a523
commit d6e7b4256c
96 changed files with 7580 additions and 6659 deletions

View File

@ -32,7 +32,7 @@ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.14)
cmake_policy(SET CMP0086 NEW)
endif()
project(STA VERSION 3.0.0
project(STA VERSION 3.0.1
LANGUAGES CXX
)
@ -82,13 +82,17 @@ endif()
set(STA_SOURCE
app/StaMain.cc
dcalc/ArcDelayCalc.cc
dcalc/ArcDcalcWaveforms.cc
dcalc/ArcDelayCalc.cc
dcalc/ArnoldiDelayCalc.cc
dcalc/ArnoldiReduce.cc
dcalc/CcsCeffDelayCalc.cc
dcalc/Delay.cc
dcalc/DelayCalc.cc
dcalc/DelayCalcBase.cc
dcalc/DelayNormal.cc
dcalc/DelayScalar.cc
dcalc/DelaySkewNormal.cc
dcalc/DmpCeff.cc
dcalc/DmpDelayCalc.cc
dcalc/FindRoot.cc
@ -99,9 +103,6 @@ set(STA_SOURCE
dcalc/PrimaDelayCalc.cc
dcalc/UnitDelayCalc.cc
graph/DelayFloat.cc
graph/DelayNormal1.cc
graph/DelayNormal2.cc
graph/Graph.cc
graph/GraphCmp.cc
@ -199,6 +200,7 @@ set(STA_SOURCE
search/PathEnum.cc
search/PathExpanded.cc
search/PathGroup.cc
search/PocvMode.cc
search/Property.cc
search/ReportPath.cc
search/Search.cc
@ -403,11 +405,6 @@ find_package(Eigen3 REQUIRED)
include(cmake/FindCUDD.cmake)
if("${SSTA}" STREQUAL "")
set(SSTA 0)
endif()
message(STATUS "SSTA: ${SSTA}")
# configure a header file to pass some of the CMake settings
configure_file(${STA_HOME}/util/StaConfig.hh.cmake
${CMAKE_CURRENT_BINARY_DIR}/include/sta/StaConfig.hh
@ -554,7 +551,7 @@ endif()
# common to gcc/clang
set(CXX_FLAGS -Wall -Wextra -pedantic -Wcast-qual -Wredundant-decls
-Wformat-security -Werror=misleading-indentation)
-Wformat-security -Werror=misleading-indentation -Wundef)
if(ENABLE_TSAN)
message(STATUS "Thread sanitizer: ${ENABLE_TSAN}")

View File

@ -61,7 +61,8 @@ ArcDcalcWaveforms::inputWaveform(ArcDcalcArg &dcalc_arg,
library->supplyVoltage("VDD", vdd, vdd_exists);
if (!vdd_exists)
report->error(1751, "VDD not defined in library %s", library->name());
Waveform in_waveform = driver_waveform->waveform(delayAsFloat(in_slew));
float slew1 = delayAsFloat(in_slew, min_max, sta);
Waveform in_waveform = driver_waveform->waveform(slew1);
// Delay time axis.
FloatSeq time_values;
for (float time : in_waveform.axis1()->values())

View File

@ -257,18 +257,18 @@ ArcDcalcResult::ArcDcalcResult(size_t load_count) :
}
void
ArcDcalcResult::setGateDelay(ArcDelay gate_delay)
ArcDcalcResult::setGateDelay(const ArcDelay &gate_delay)
{
gate_delay_ = gate_delay;
}
void
ArcDcalcResult::setDrvrSlew(Slew drvr_slew)
ArcDcalcResult::setDrvrSlew(const Slew &drvr_slew)
{
drvr_slew_ = drvr_slew;
}
ArcDelay
const ArcDelay &
ArcDcalcResult::wireDelay(size_t load_idx) const
{
return wire_delays_[load_idx];
@ -276,7 +276,7 @@ ArcDcalcResult::wireDelay(size_t load_idx) const
void
ArcDcalcResult::setWireDelay(size_t load_idx,
ArcDelay wire_delay)
const ArcDelay &wire_delay)
{
wire_delays_[load_idx] = wire_delay;
}
@ -288,7 +288,7 @@ ArcDcalcResult::setLoadCount(size_t load_count)
load_slews_.resize(load_count);
}
Slew
const Slew &
ArcDcalcResult::loadSlew(size_t load_idx) const
{
return load_slews_[load_idx];
@ -296,7 +296,7 @@ ArcDcalcResult::loadSlew(size_t load_idx) const
void
ArcDcalcResult::setLoadSlew(size_t load_idx,
Slew load_slew)
const Slew &load_slew)
{
load_slews_[load_idx] = load_slew;
}

View File

@ -237,7 +237,6 @@ private:
ArnoldiReduce *reduce_;
delay_work *delay_work_;
std::vector<rcmodel*> unsaved_parasitics_;
bool pocv_enabled_;
};
ArcDelayCalc *
@ -397,7 +396,6 @@ ArnoldiDelayCalc::gateDelay(const Pin *drvr_pin,
ConcreteParasitic *cparasitic =
reinterpret_cast<ConcreteParasitic*>(const_cast<Parasitic*>(parasitic));
rcmodel_ = dynamic_cast<rcmodel*>(cparasitic);
pocv_enabled_ = variables_->pocvEnabled();
GateTableModel *table_model = arc->gateTableModel(scene, min_max);
if (table_model && rcmodel_) {
const Pvt *pvt = pinPvt(drvr_pin, scene, min_max);
@ -453,8 +451,8 @@ ArnoldiDelayCalc::gateDelaySlew(const LibertyCell *drvr_cell,
auto load_idx_itr = load_pin_index_map.find(load_pin);
if (load_idx_itr != load_pin_index_map.end()) {
size_t load_idx = load_idx_itr->second;
ArcDelay wire_delay = _delayV[i] - _delayV[0];
Slew load_slew = _slewV[i];
double wire_delay = _delayV[i] - _delayV[0];
double load_slew = _slewV[i];
thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew);
dcalc_result.setWireDelay(load_idx, wire_delay);
dcalc_result.setLoadSlew(load_idx, load_slew);
@ -1325,9 +1323,8 @@ ArnoldiDelayCalc::ra_get_r(delay_work *D,
float c1;
double tlohi,r;
c1 = ctot;
ArcDelay d1;
Slew s1;
tab->table->gateDelay(tab->pvt, tab->in_slew, c1, pocv_enabled_, d1, s1);
float d1, s1;
tab->table->gateDelay(tab->pvt, tab->in_slew, c1, d1, s1);
tlohi = slew_derate*delayAsFloat(s1);
r = tlohi/(c_log*c1);
if (rdelay>0.0 && r > rdelay)
@ -1346,9 +1343,8 @@ ArnoldiDelayCalc::ra_get_s(delay_work *D,
double c_log = con->vlg;
double c_smin = con->smin;
double tlohi,smin,s;
ArcDelay d1;
Slew s1;
tab->table->gateDelay(tab->pvt, tab->in_slew, c, pocv_enabled_, d1, s1);
float d1, s1;
tab->table->gateDelay(tab->pvt, tab->in_slew, c, d1, s1);
tlohi = slew_derate*delayAsFloat(s1);
smin = r*c*c_smin; // c_smin = ra_hinv((1-vhi)/vhi-log(vhi)) + log(vhi);
if (c_log*r*c >= tlohi) {
@ -1378,10 +1374,9 @@ ArnoldiDelayCalc::ra_rdelay_1(timing_table *tab,
float c2 = 0.5*c1;
if (c1==c2)
return 0.0;
ArcDelay d1, d2;
Slew s1, s2;
tab->table->gateDelay(tab->pvt, tab->in_slew, c1, pocv_enabled_, d1, s1);
tab->table->gateDelay(tab->pvt, tab->in_slew, c2, pocv_enabled_, d2, s2);
float d1, d2, s1, s2;
tab->table->gateDelay(tab->pvt, tab->in_slew, c1, d1, s1);
tab->table->gateDelay(tab->pvt, tab->in_slew, c2, d2, s2);
double dt50 = delayAsFloat(d1)-delayAsFloat(d2);
if (dt50 <= 0.0)
return 0.0;
@ -1402,8 +1397,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
double vlo = con->vlo;
double ctot = mod->ctot;
double ceff,tlohi,t50_sy,r,s,t50_sr,rdelay;
ArcDelay df;
Slew sf;
float df, sf;
debugPrint(debug_, "arnoldi", 1, "ctot=%s",
units_->capacitanceUnit()->asString(ctot));
@ -1432,7 +1426,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
units_->timeUnit()->asString(s));
thix = ra_solve_for_t(p,s,vhi);
tlox = ra_solve_for_t(p,s,vlo);
tab->table->gateDelay(tab->pvt,tab->in_slew, ctot, pocv_enabled_, df, sf);
tab->table->gateDelay(tab->pvt,tab->in_slew, ctot, df, sf);
debugPrint(debug_, "arnoldi", 1, "table slew (in_slew %s ctot %s) = %s",
units_->timeUnit()->asString(tab->in_slew),
units_->capacitanceUnit()->asString(ctot),
@ -1443,8 +1437,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
units_->timeUnit()->asString(tlox-thix));
}
ceff = ctot;
tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, pocv_enabled_,
df, sf);
tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, df, sf);
t50_sy = delayAsFloat(df);
t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5);
@ -1485,7 +1478,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
units_->timeUnit()->asString(ceff_time),
units_->capacitanceUnit()->asString(ceff));
tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, pocv_enabled_, df, sf);
tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, df, sf);
t50_sy = delayAsFloat(df);
t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5);
for (j=0;j<mod->n;j++) {

View File

@ -113,14 +113,12 @@ CcsCeffDelayCalc::gateDelay(const Pin *drvr_pin,
vh_ = drvr_library->slewUpperThreshold(drvr_rf_) * vdd_;
drvr_cell->ensureVoltageWaveforms(scenes_);
in_slew_ = delayAsFloat(in_slew);
output_waveforms_ = output_waveforms;
ref_time_ = output_waveforms_->referenceTime(in_slew_);
debugPrint(debug_, "ccs_dcalc", 1, "%s %s",
drvr_cell->name(),
drvr_rf_->shortName());
ArcDelay gate_delay;
Slew drvr_slew;
double gate_delay, drvr_slew;
gateDelaySlew(drvr_library, drvr_rf_, gate_delay, drvr_slew);
return makeResult(drvr_library,drvr_rf_,gate_delay,drvr_slew,load_pin_index_map);
}
@ -133,8 +131,8 @@ void
CcsCeffDelayCalc::gateDelaySlew(const LibertyLibrary *drvr_library,
const RiseFall *rf,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew)
double &gate_delay,
double &drvr_slew)
{
initRegions(drvr_library, rf);
findCsmWaveform();
@ -145,7 +143,7 @@ CcsCeffDelayCalc::gateDelaySlew(const LibertyLibrary *drvr_library,
"gate_delay %s drvr_slew %s (initial)",
delayAsString(gate_delay, this),
delayAsString(drvr_slew, this));
float prev_drvr_slew = delayAsFloat(drvr_slew);
float prev_drvr_slew = drvr_slew;
constexpr int max_iterations = 5;
for (int iter = 0; iter < max_iterations; iter++) {
debugPrint(debug_, "ccs_dcalc", 2, "iteration %d", iter);
@ -185,9 +183,9 @@ CcsCeffDelayCalc::gateDelaySlew(const LibertyLibrary *drvr_library,
"gate_delay %s drvr_slew %s",
delayAsString(gate_delay, this),
delayAsString(drvr_slew, this));
if (std::abs(delayAsFloat(drvr_slew) - prev_drvr_slew) < .01 * prev_drvr_slew)
if (std::abs(drvr_slew - prev_drvr_slew) < .01 * prev_drvr_slew)
break;
prev_drvr_slew = delayAsFloat(drvr_slew);
prev_drvr_slew = drvr_slew;
}
}
@ -309,8 +307,8 @@ CcsCeffDelayCalc::findCsmWaveform()
ArcDcalcResult
CcsCeffDelayCalc::makeResult(const LibertyLibrary *drvr_library,
const RiseFall *rf,
ArcDelay &gate_delay,
Slew &drvr_slew,
double &gate_delay,
double &drvr_slew,
const LoadPinIndexMap &load_pin_index_map)
{
ArcDcalcResult dcalc_result(load_pin_index_map.size());
@ -322,8 +320,7 @@ CcsCeffDelayCalc::makeResult(const LibertyLibrary *drvr_library,
dcalc_result.setDrvrSlew(drvr_slew);
for (const auto &[load_pin, load_idx] : load_pin_index_map) {
ArcDelay wire_delay;
Slew load_slew;
double wire_delay, load_slew;
loadDelaySlew(load_pin, drvr_library, rf, drvr_slew, wire_delay, load_slew);
dcalc_result.setWireDelay(load_idx, wire_delay);
dcalc_result.setLoadSlew(load_idx, load_slew);
@ -335,13 +332,14 @@ void
CcsCeffDelayCalc::loadDelaySlew(const Pin *load_pin,
const LibertyLibrary *drvr_library,
const RiseFall *rf,
Slew &drvr_slew,
double &drvr_slew,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew)
double &wire_delay,
double &load_slew)
{
wire_delay = 0.0;
load_slew = drvr_slew;
bool elmore_exists = false;
float elmore = 0.0;
if (parasitic_
@ -351,7 +349,7 @@ CcsCeffDelayCalc::loadDelaySlew(const Pin *load_pin,
if (elmore_exists &&
(elmore == 0.0
// Elmore delay is small compared to driver slew.
|| elmore < delayAsFloat(drvr_slew) * 1e-3)) {
|| elmore < drvr_slew * 1e-3)) {
wire_delay = elmore;
load_slew = drvr_slew;
}
@ -363,11 +361,11 @@ CcsCeffDelayCalc::loadDelaySlew(const Pin *load_pin,
void
CcsCeffDelayCalc::loadDelaySlew(const Pin *load_pin,
Slew &drvr_slew,
double &drvr_slew,
float elmore,
// Return values.
ArcDelay &delay,
Slew &slew)
double &delay,
double &slew)
{
for (size_t i = 0; i <= region_count_; i++) {
region_ramp_times_[i] = region_times_[i];

View File

@ -73,29 +73,29 @@ protected:
void gateDelaySlew(const LibertyLibrary *drvr_library,
const RiseFall *rf,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew);
double &gate_delay,
double &drvr_slew);
void initRegions(const LibertyLibrary *drvr_library,
const RiseFall *rf);
void findCsmWaveform();
ArcDcalcResult makeResult(const LibertyLibrary *drvr_library,
const RiseFall *rf,
ArcDelay &gate_delay,
Slew &drvr_slew,
double &gate_delay,
double &drvr_slew,
const LoadPinIndexMap &load_pin_index_map);
void loadDelaySlew(const Pin *load_pin,
const LibertyLibrary *drvr_library,
const RiseFall *rf,
Slew &drvr_slew,
double &drvr_slew,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew);
double &wire_delay,
double &load_slew);
void loadDelaySlew(const Pin *load_pin,
Slew &drvr_slew,
double &drvr_slew,
float elmore,
// Return values.
ArcDelay &delay,
Slew &slew);
double &delay,
double &slew);
double findVlTime(double v,
double elmore);
bool makeWaveformPreamble(const Pin *in_pin,

515
dcalc/Delay.cc Normal file
View File

@ -0,0 +1,515 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// 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.
#include "Delay.hh"
#include <cmath>
#include "StaConfig.hh"
#include "Fuzzy.hh"
#include "Units.hh"
#include "StaState.hh"
#include "Variables.hh"
namespace sta {
static Delay delay_init_values[MinMax::index_count];
void
initDelayConstants()
{
delay_init_values[MinMax::minIndex()] = MinMax::min()->initValue();
delay_init_values[MinMax::maxIndex()] = MinMax::max()->initValue();
}
Delay::Delay() :
values_{0.0, 0.0, 0.0, 0.0}
{
}
Delay::Delay(float mean) :
values_{mean, 0.0, 0.0, 0.0}
{
}
Delay::Delay(float mean,
float std_dev2) :
values_{mean, 0.0, std_dev2, 0.0}
{
}
Delay::Delay(float mean,
float mean_shift,
float std_dev2,
float skewness) :
values_{mean, mean_shift, std_dev2, skewness}
{
}
void
Delay::operator=(float delay)
{
values_[0] = delay;
values_[1] = 0.0;
values_[2] = 0.0;
values_[3] = 0.0;
}
void
Delay::setValues(float mean,
float mean_shift,
float std_dev2,
float skewnes)
{
values_[0] = mean;
values_[1] = mean_shift;
values_[2] = std_dev2;
values_[3] = skewnes;
}
void
Delay::setMean(float mean)
{
values_[0] = mean;
}
void
Delay::setMeanShift(float mean_shift)
{
values_[1] = mean_shift;
}
float
Delay::stdDev() const
{
float std_dev2 = values_[2];
if (std_dev2 < 0.0)
// std_dev is negative for crpr to offset std_dev in the common
// clock path.
return -std::sqrt(-std_dev2);
else
return std::sqrt(std_dev2);
}
void
Delay::setStdDev(float std_dev)
{
values_[2] = square(std_dev);
}
void
Delay::setSkewness(float skewness)
{
values_[3] = skewness;
}
////////////////////////////////////////////////////////////////
DelayDbl::DelayDbl() :
values_{0.0, 0.0, 0.0, 0.0}
{
}
DelayDbl::DelayDbl(double mean) :
values_{mean, 0.0, 0.0, 0.0}
{
}
void
DelayDbl::setMean(double mean)
{
values_[0] = mean;
}
double
DelayDbl::stdDev() const
{
float std_dev2 = values_[2];
if (std_dev2 < 0.0)
// std_dev is negative for crpr to offset std_dev in the common
// clock path.
return -std::sqrt(-std_dev2);
else
return std::sqrt(std_dev2);
}
void
DelayDbl::setValues(double mean,
double mean_shift,
double std_dev2,
double skewnes)
{
values_[0] = mean;
values_[1] = mean_shift;
values_[2] = std_dev2;
values_[3] = skewnes;
}
void
DelayDbl::operator=(double delay)
{
values_[0] = delay;
values_[1] = 0.0;
values_[2] = 0.0;
values_[3] = 0.0;
}
////////////////////////////////////////////////////////////////
Delay
makeDelay(float mean,
float mean_shift,
float std_dev,
float skewness)
{
return Delay(mean, mean_shift, square(std_dev), skewness);
}
Delay
makeDelay(float mean,
float std_dev)
{
return Delay(mean, 0.0, square(std_dev), 0.0);
}
Delay
makeDelay2(float mean,
float std_dev)
{
return Delay(mean, 0.0, std_dev, 0.0);
}
void
delaySetMean(Delay &delay,
float mean)
{
delay.setMean(mean);
}
////////////////////////////////////////////////////////////////
Delay
delayDblAsDelay(DelayDbl &delay)
{
return Delay(delay.mean(), delay.meanShift(), delay.stdDev2(), delay.skewness());
}
const char *
delayAsString(const Delay &delay,
const StaState *sta)
{
return delayAsString(delay, EarlyLate::late(),
sta->units()->timeUnit()->digits(), sta);
}
const char *
delayAsString(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta)
{
return delayAsString(delay, early_late, sta->units()->timeUnit()->digits(), sta);
}
const char *
delayAsString(const Delay &delay,
const EarlyLate *early_late,
int digits,
const StaState *sta)
{
const Unit *unit = sta->units()->timeUnit();
float mean_std_dev = delayAsFloat(delay, early_late, sta);
return unit->asString(mean_std_dev, digits);
}
const char *
delayAsString(const Delay &delay,
const EarlyLate *early_late,
bool report_variance,
int digits,
const StaState *sta)
{
if (report_variance)
return sta->delayOps()->asStringVariance(delay, digits, sta);
else
return delayAsString(delay, early_late, digits, sta);
}
float
delayAsFloat(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta)
{
return sta->delayOps()->asFloat(delay, early_late, sta);
}
float
delayAsFloat(const DelayDbl &delay,
const EarlyLate *early_late,
const StaState *sta)
{
return sta->delayOps()->asFloat(delay, early_late, sta);
}
float
delayAsFloat(const Delay &delay)
{
return delay.mean();
}
const Delay &
delayInitValue(const MinMax *min_max)
{
return delay_init_values[min_max->index()];
}
bool
delayIsInitValue(const Delay &delay,
const MinMax *min_max)
{
return fuzzyEqual(delay.mean(), min_max->initValue());
}
bool
delayZero(const Delay &delay,
const StaState *sta)
{
return sta->delayOps()->isZero(delay);
}
bool
delayInf(const Delay &delay,
const StaState *sta)
{
return sta->delayOps()->isInf(delay);
}
bool
delayEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta)
{
return sta->delayOps()->equal(delay1, delay2, sta);
}
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const StaState *sta)
{
return sta->delayOps()->less(delay1, delay2, sta);
}
bool
delayLess(const DelayDbl &delay1,
const DelayDbl &delay2,
const StaState *sta)
{
return sta->delayOps()->less(delay1, delay2, sta);
}
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
{
if (min_max == MinMax::max())
return sta->delayOps()->less(delay1, delay2, sta);
else
return sta->delayOps()->greater(delay1, delay2, sta);
}
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta)
{
return sta->delayOps()->lessEqual(delay1, delay2, sta);
}
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
{
if (min_max == MinMax::max())
return sta->delayOps()->lessEqual(delay1, delay2, sta);
else
return sta->delayOps()->greaterEqual(delay1, delay2, sta);
}
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const StaState *sta)
{
return sta->delayOps()->greater(delay1, delay2, sta);
}
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
{
if (min_max == MinMax::max())
return sta->delayOps()->greater(delay1, delay2, sta);
else
return sta->delayOps()->less(delay1, delay2, sta);
}
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta)
{
return sta->delayOps()->greaterEqual(delay1, delay2, sta);
}
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
{
if (min_max == MinMax::max())
return sta->delayOps()->greaterEqual(delay1, delay2, sta);
else
return sta->delayOps()->lessEqual(delay1, delay2, sta);
}
Delay
delayRemove(const Delay &delay1,
const Delay &delay2)
{
return makeDelay2(delay1.mean() - delay2.mean(),
delay1.stdDev2() - delay2.stdDev2());
}
Delay
delaySum(const Delay &delay1,
const Delay &delay2,
const StaState *sta)
{
return sta->delayOps()->sum(delay1, delay2);
}
Delay
delaySum(const Delay &delay1,
float delay2,
const StaState *sta)
{
return sta->delayOps()->sum(delay1, delay2);
}
Delay
delayDiff(const Delay &delay1,
const Delay &delay2,
const StaState *sta)
{
return sta->delayOps()->diff(delay1, delay2);
}
Delay
delayDiff(const Delay &delay1,
float delay2,
const StaState *sta)
{
return sta->delayOps()->diff(delay1, delay2);
}
Delay
delayDiff(float delay1,
const Delay &delay2,
const StaState *sta)
{
return sta->delayOps()->diff(delay1, delay2);
}
void
delayIncr(Delay &delay1,
const Delay &delay2,
const StaState *sta)
{
sta->delayOps()->incr(delay1, delay2);
}
void
delayIncr(DelayDbl &delay1,
const Delay &delay2,
const StaState *sta)
{
sta->delayOps()->incr(delay1, delay2);
}
void
delayIncr(Delay &delay1,
float delay2,
const StaState *sta)
{
sta->delayOps()->incr(delay1, delay2);
}
void
delayDecr(Delay &delay1,
const Delay &delay2,
const StaState *sta)
{
sta->delayOps()->decr(delay1, delay2);
}
void
delayDecr(DelayDbl &delay1,
const Delay &delay2,
const StaState *sta)
{
sta->delayOps()->decr(delay1, delay2);
}
Delay
delayProduct(const Delay &delay1,
float delay2,
const StaState *sta)
{
return sta->delayOps()->product(delay1, delay2);
}
Delay
delayDiv(float delay1,
const Delay &delay2,
const StaState *sta)
{
return sta->delayOps()->div(delay1, delay2);
}
float
delayStdDev2(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta)
{
return sta->delayOps()->stdDev2(delay, early_late);
}
} // namespace

View File

@ -135,8 +135,6 @@ proc set_delay_calculator { alg } {
}
}
define_cmd_args "set_pocv_sigma_factor" { factor }
################################################################
define_cmd_args "set_assigned_delay" \
@ -382,22 +380,31 @@ proc set_assigned_transition { args } {
################################################################
define_cmd_args "report_slews" {[-scenes scenes] pin}
define_cmd_args "report_slews" {[-scenes scenes] [-digits digits]\
[-report_variance] pin}
proc report_slews { args } {
global sta_report_default_digits
parse_key_args "report_slews" args keys {-corner -scenes} flags {}
parse_key_args "report_slews" args keys {-corner -scenes -digits} \
flags {-report_variance}
check_argc_eq1 "report_slews" $args
set scenes [parse_scenes_or_all keys]
set pin [get_port_pin_error "pin" [lindex $args 0]]
set digits $sta_report_default_digits
if [info exists keys(-digits)] {
set digits $keys(-digits)
check_positive_integer "-digits" $digits
} else {
set digits $sta_report_default_digits
}
set report_variance [info exists flags(-report_variance)]
foreach vertex [$pin vertices] {
set rise_min [format_time [$vertex slew_scenes rise $scenes min] $digits]
set rise_max [format_time [$vertex slew_scenes rise $scenes max] $digits]
set fall_min [format_time [$vertex slew_scenes fall $scenes min] $digits]
set fall_max [format_time [$vertex slew_scenes fall $scenes max] $digits]
set rise_min [$vertex slew_scenes_string rise $scenes min $report_variance $digits]
set rise_max [$vertex slew_scenes_string rise $scenes max $report_variance $digits]
set fall_min [$vertex slew_scenes_string fall $scenes min $report_variance $digits]
set fall_max [$vertex slew_scenes_string fall $scenes max $report_variance $digits]
report_line "[vertex_path_name $vertex] [rise_short_name] $rise_min:$rise_max [fall_short_name] $fall_min:$fall_max"
}
}

View File

@ -81,10 +81,10 @@ DelayCalcBase::finishDrvrPin()
void
DelayCalcBase::dspfWireDelaySlew(const Pin *load_pin,
const RiseFall *rf,
Slew drvr_slew,
double drvr_slew,
float elmore,
ArcDelay &wire_delay,
Slew &load_slew)
double &wire_delay,
double &load_slew)
{
LibertyLibrary *load_library = thresholdLibrary(load_pin);
@ -107,8 +107,8 @@ void
DelayCalcBase::thresholdAdjust(const Pin *load_pin,
const LibertyLibrary *drvr_library,
const RiseFall *rf,
ArcDelay &load_delay,
Slew &load_slew)
double &wire_delay,
double &load_slew)
{
LibertyLibrary *load_library = thresholdLibrary(load_pin);
if (load_library
@ -118,11 +118,11 @@ DelayCalcBase::thresholdAdjust(const Pin *load_pin,
float load_vth = load_library->inputThreshold(rf);
float drvr_slew_delta = drvr_library->slewUpperThreshold(rf)
- drvr_library->slewLowerThreshold(rf);
float load_delay_delta =
float wire_delay_delta =
delayAsFloat(load_slew) * ((load_vth - drvr_vth) / drvr_slew_delta);
load_delay += (rf == RiseFall::rise())
? load_delay_delta
: -load_delay_delta;
wire_delay += (rf == RiseFall::rise())
? wire_delay_delta
: -wire_delay_delta;
float load_slew_delta = load_library->slewUpperThreshold(rf)
- load_library->slewLowerThreshold(rf);
float drvr_slew_derate = drvr_library->slewDerateFromLibrary();
@ -162,9 +162,8 @@ DelayCalcBase::checkDelay(const Pin *check_pin,
float from_slew1 = delayAsFloat(from_slew);
float to_slew1 = delayAsFloat(to_slew);
return model->checkDelay(pinPvt(check_pin, scene, min_max),
from_slew1, to_slew1,
related_out_cap,
variables_->pocvEnabled());
from_slew1, to_slew1, related_out_cap,
min_max, variables_->pocvMode());
}
else
return delay_zero;
@ -187,8 +186,8 @@ DelayCalcBase::reportCheckDelay(const Pin *check_pin,
float to_slew1 = delayAsFloat(to_slew);
return model->reportCheckDelay(pinPvt(check_pin, scene, min_max),
from_slew1, from_slew_annotation,
to_slew1, related_out_cap, false,
digits);
to_slew1, related_out_cap, min_max,
PocvMode::scalar, digits);
}
return "";
}

View File

@ -72,16 +72,16 @@ protected:
void thresholdAdjust(const Pin *load_pin,
const LibertyLibrary *drvr_library,
const RiseFall *rf,
ArcDelay &load_delay,
Slew &load_slew);
double &load_delay,
double &load_slew);
// Helper function for input ports driving dspf parasitic.
void dspfWireDelaySlew(const Pin *load_pin,
const RiseFall *rf,
Slew drvr_slew,
double drvr_slew,
float elmore,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew);
double &wire_delay,
double &load_slew);
const Pvt *pinPvt(const Pin *pin,
const Scene *scene,
const MinMax *min_max);

231
dcalc/DelayNormal.cc Normal file
View File

@ -0,0 +1,231 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// 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.
#include "DelayNormal.hh"
#include <cmath> // sqrt
#include "Error.hh"
#include "Fuzzy.hh"
#include "Units.hh"
#include "StaState.hh"
#include "Variables.hh"
namespace sta {
float
DelayOpsNormal::stdDev2(const Delay &delay,
const EarlyLate *) const
{
return delay.stdDev2();
}
float
DelayOpsNormal::asFloat(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta) const
{
float quantile = sta->variables()->pocvQuantile();
if (early_late == EarlyLate::early())
return delay.mean() - delay.stdDev() * quantile;
else // (early_late == EarlyLate::late())
return delay.mean() + delay.stdDev() * quantile;
}
double
DelayOpsNormal::asFloat(const DelayDbl &delay,
const EarlyLate *early_late,
const StaState *sta) const
{
double quantile = sta->variables()->pocvQuantile();
if (early_late == EarlyLate::early())
return delay.mean() - delay.stdDev() * quantile;
else // (early_late == EarlyLate::late())
return delay.mean() + delay.stdDev() * quantile;
}
bool
DelayOpsNormal::isZero(const Delay &delay) const
{
return fuzzyZero(delay.mean())
&& fuzzyZero(delay.stdDev2());
}
bool
DelayOpsNormal::isInf(const Delay &delay) const
{
return fuzzyInf(delay.mean());
}
bool
DelayOpsNormal::equal(const Delay &delay1,
const Delay &delay2,
const StaState *) const
{
return fuzzyEqual(delay1.mean(), delay2.mean())
&& fuzzyEqual(delay1.stdDev2(), delay2.stdDev2());
}
bool
DelayOpsNormal::less(const Delay &delay1,
const Delay &delay2,
const StaState *sta) const
{
return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta),
delayAsFloat(delay2, EarlyLate::early(), sta));
}
bool
DelayOpsNormal::less(const DelayDbl &delay1,
const DelayDbl &delay2,
const StaState *sta) const
{
return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta),
delayAsFloat(delay2, EarlyLate::early(), sta));
}
bool
DelayOpsNormal::lessEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta) const
{
return fuzzyLessEqual(delayAsFloat(delay1, EarlyLate::early(), sta),
delayAsFloat(delay2, EarlyLate::early(), sta));
}
bool
DelayOpsNormal::greater(const Delay &delay1,
const Delay &delay2,
const StaState *sta) const
{
return fuzzyGreater(delayAsFloat(delay1, EarlyLate::late(), sta),
delayAsFloat(delay2, EarlyLate::late(), sta));
}
bool
DelayOpsNormal::greaterEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta) const
{
return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta),
delayAsFloat(delay2, EarlyLate::late(), sta));
}
Delay
DelayOpsNormal::sum(const Delay &delay1,
const Delay &delay2) const
{
return Delay(delay1.mean() + delay2.mean(),
delay1.stdDev2() + delay2.stdDev2());
}
Delay
DelayOpsNormal::sum(const Delay &delay1,
float delay2) const
{
return Delay(delay1.mean() + delay2,
delay1.stdDev2());
}
Delay
DelayOpsNormal::diff(const Delay &delay1,
const Delay &delay2) const
{
return Delay(delay1.mean() - delay2.mean(),
delay1.stdDev2() + delay2.stdDev2());
}
Delay
DelayOpsNormal::diff(const Delay &delay1,
float delay2) const
{
return Delay(delay1.mean() - delay2,
delay1.stdDev2());
}
Delay
DelayOpsNormal::diff(float delay1,
const Delay &delay2) const
{
return Delay(delay1 - delay2.mean(),
delay2.stdDev2());
}
void
DelayOpsNormal::incr(Delay &delay1,
const Delay &delay2) const
{
delay1.setValues(delay1.mean() + delay2.mean(), 0.0,
delay1.stdDev2() + delay2.stdDev2(), 0.0);
}
void
DelayOpsNormal::incr(DelayDbl &delay1,
const Delay &delay2) const
{
delay1.setValues(delay1.mean() + delay2.mean(), 0.0,
delay1.stdDev2() + delay2.stdDev2(), 0.0);
}
void
DelayOpsNormal::decr(Delay &delay1,
const Delay &delay2) const
{
delay1.setMean(delay1.mean() - delay2.mean());
}
void
DelayOpsNormal::decr(DelayDbl &delay1,
const Delay &delay2) const
{
delay1.setMean(delay1.mean() - delay2.mean());
}
Delay
DelayOpsNormal::product(const Delay &delay1,
float delay2) const
{
return Delay(delay1.mean() * delay2,
delay1.stdDev2() * square(delay2));
}
Delay
DelayOpsNormal::div(float delay1,
const Delay &delay2) const
{
return Delay(delay1 / delay2.mean());
}
const char *
DelayOpsNormal::asStringVariance(const Delay &delay,
int digits,
const StaState *sta) const
{
const Unit *unit = sta->units()->timeUnit();
return stringPrintTmp("%s[%s]",
unit->asString(delay.mean(), digits),
unit->asString(delay.stdDev(), digits));
}
} // namespace

206
dcalc/DelayScalar.cc Normal file
View File

@ -0,0 +1,206 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// 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.
// Delay as floats, non-SSTA.
#include "DelayScalar.hh"
#include "Fuzzy.hh"
#include "Units.hh"
#include "StaState.hh"
namespace sta {
float
DelayOpsScalar::stdDev2(const Delay &,
const EarlyLate *) const
{
return 0.0;
}
float
DelayOpsScalar::asFloat(const Delay &delay,
const EarlyLate *,
const StaState *) const
{
return delay.mean();
}
double
DelayOpsScalar::asFloat(const DelayDbl &delay,
const EarlyLate *,
const StaState *) const
{
return delay.mean();
}
bool
DelayOpsScalar::isZero(const Delay &delay) const
{
return fuzzyZero(delay.mean());
}
bool
DelayOpsScalar::isInf(const Delay &delay) const
{
return fuzzyInf(delay.mean());
}
bool
DelayOpsScalar::equal(const Delay &delay1,
const Delay &delay2,
const StaState *) const
{
return fuzzyEqual(delay1.mean(), delay2.mean());
}
bool
DelayOpsScalar::less(const Delay &delay1,
const Delay &delay2,
const StaState *) const
{
return fuzzyLess(delay1.mean(), delay2.mean());
}
bool
DelayOpsScalar::less(const DelayDbl &delay1,
const DelayDbl &delay2,
const StaState *) const
{
return fuzzyLess(delay1.mean(), delay2.mean());
}
bool
DelayOpsScalar::lessEqual(const Delay &delay1,
const Delay &delay2,
const StaState *) const
{
return fuzzyLessEqual(delay1.mean(), delay2.mean());
}
bool
DelayOpsScalar::greater(const Delay &delay1,
const Delay &delay2,
const StaState *) const
{
return fuzzyGreater(delay1.mean(), delay2.mean());
}
bool
DelayOpsScalar::greaterEqual(const Delay &delay1,
const Delay &delay2,
const StaState *) const
{
return fuzzyGreaterEqual(delay1.mean(), delay2.mean());
}
Delay
DelayOpsScalar::sum(const Delay &delay1,
const Delay &delay2) const
{
return Delay(delay1.mean() + delay2.mean());
}
Delay
DelayOpsScalar::sum(const Delay &delay1,
float delay2) const
{
return Delay(delay1.mean() + delay2);
}
Delay
DelayOpsScalar::diff(const Delay &delay1,
const Delay &delay2) const
{
return Delay(delay1.mean() - delay2.mean());
}
Delay
DelayOpsScalar::diff(const Delay &delay1,
float delay2) const
{
return Delay(delay1.mean() - delay2);
}
Delay
DelayOpsScalar::diff(float delay1,
const Delay &delay2) const
{
return Delay(delay1 - delay2.mean());
}
void
DelayOpsScalar::incr(Delay &delay1,
const Delay &delay2) const
{
delay1.setMean(delay1.mean() + delay2.mean());
}
void
DelayOpsScalar::incr(DelayDbl &delay1,
const Delay &delay2) const
{
delay1.setMean(delay1.mean() + delay2.mean());
}
void
DelayOpsScalar::decr(Delay &delay1,
const Delay &delay2) const
{
delay1.setMean(delay1.mean() - delay2.mean());
}
void
DelayOpsScalar::decr(DelayDbl &delay1,
const Delay &delay2) const
{
delay1.setMean(delay1.mean() - delay2.mean());
}
Delay
DelayOpsScalar::product(const Delay &delay1,
float delay2) const
{
return Delay(delay1.mean() * delay2);
}
Delay
DelayOpsScalar::div(float delay1,
const Delay &delay2) const
{
return Delay(delay1 / delay2.mean());
}
const char *
DelayOpsScalar::asStringVariance(const Delay &delay,
int digits,
const StaState *sta) const
{
const Unit *unit = sta->units()->timeUnit();
return unit->asString(delay.mean(), digits);
}
} // namespace

292
dcalc/DelaySkewNormal.cc Normal file
View File

@ -0,0 +1,292 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// 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.
#include "DelaySkewNormal.hh"
#include <cmath> // sqrt
#include "Error.hh"
#include "Fuzzy.hh"
#include "Units.hh"
#include "StaState.hh"
#include "Variables.hh"
namespace sta {
float
DelayOpsSkewNormal::stdDev2(const Delay &delay,
const EarlyLate *) const
{
return delay.stdDev2();
}
float
DelayOpsSkewNormal::asFloat(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta) const
{
// LVF: mean + mean_shift + sigma * sigma_factor with skewness consideration.
float quantile = sta->variables()->pocvQuantile();
if (early_late == EarlyLate::early())
return delay.mean() + delay.meanShift()
- delay.stdDev() * (quantile + delay.skewness() * (square(quantile)-1.0) / 6.0);
else // (early_late == EarlyLate::late())
return delay.mean() + delay.meanShift()
+ delay.stdDev() * (quantile + delay.skewness() * (square(quantile)-1.0) / 6.0);
}
double
DelayOpsSkewNormal::asFloat(const DelayDbl &delay,
const EarlyLate *early_late,
const StaState *sta) const
{
// LVF: mean + mean_shift + sigma * sigma_factor with skewness consideration.
double quantile = sta->variables()->pocvQuantile();
if (early_late == EarlyLate::early())
return delay.mean() + delay.meanShift()
- delay.stdDev() * (quantile + delay.skewness() * (square(quantile)-1.0) / 6.0);
else // (early_late == EarlyLate::late())
return delay.mean() + delay.meanShift()
+ delay.stdDev() * (quantile + delay.skewness() * (square(quantile)-1.0) / 6.0);
}
bool
DelayOpsSkewNormal::isZero(const Delay &delay) const
{
return fuzzyZero(delay.mean())
&& fuzzyZero(delay.meanShift())
&& fuzzyZero(delay.stdDev2())
&& fuzzyZero(delay.skewness());
}
bool
DelayOpsSkewNormal::isInf(const Delay &delay) const
{
return fuzzyInf(delay.mean());
}
bool
DelayOpsSkewNormal::equal(const Delay &delay1,
const Delay &delay2,
const StaState *) const
{
return fuzzyEqual(delay1.mean(), delay2.mean())
&& fuzzyEqual(delay1.meanShift(), delay2.meanShift())
&& fuzzyEqual(delay1.stdDev2(), delay2.stdDev2())
&& fuzzyEqual(delay1.skewness(), delay2.skewness());
}
bool
DelayOpsSkewNormal::less(const Delay &delay1,
const Delay &delay2,
const StaState *sta) const
{
return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta),
delayAsFloat(delay2, EarlyLate::early(), sta));
}
bool
DelayOpsSkewNormal::less(const DelayDbl &delay1,
const DelayDbl &delay2,
const StaState *sta) const
{
return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta),
delayAsFloat(delay2, EarlyLate::early(), sta));
}
bool
DelayOpsSkewNormal::lessEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta) const
{
return fuzzyLessEqual(delayAsFloat(delay1, EarlyLate::early(), sta),
delayAsFloat(delay2, EarlyLate::early(), sta));
}
bool
DelayOpsSkewNormal::greater(const Delay &delay1,
const Delay &delay2,
const StaState *sta) const
{
return fuzzyGreater(delayAsFloat(delay1, EarlyLate::late(), sta),
delayAsFloat(delay2, EarlyLate::late(), sta));
}
bool
DelayOpsSkewNormal::greaterEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta) const
{
return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta),
delayAsFloat(delay2, EarlyLate::late(), sta));
}
Delay
DelayOpsSkewNormal::sum(const Delay &delay1,
const Delay &delay2) const
{
return Delay(delay1.mean() + delay2.mean(),
delay1.meanShift() + delay2.meanShift(),
delay1.stdDev2() + delay2.stdDev2(),
skewnessSum(delay1, delay2));
}
float
DelayOpsSkewNormal::skewnessSum(const Delay &delay1,
const Delay &delay2) const
{
return skewnessSum(delay1.stdDev(), delay1.skewness(),
delay2.stdDev(), delay2.skewness());
}
// Helper function to compute combined skewness from std dev and skewness values.
double
DelayOpsSkewNormal::skewnessSum(double std_dev1,
double skewness1,
double std_dev2,
double skewness2) const
{
double std_dev_sum = square(std_dev1) + square(std_dev2);
if (std_dev_sum == 0.0)
return 0.0;
else {
// Un-normalize the skews so they are third moments so they can be added.
double skew = (skewness1 * cube(std_dev1) + skewness2 * cube(std_dev2))
// std_dev_sum^(3/2)
/ (std_dev_sum * std::sqrt(std_dev_sum));
return skew;
}
}
Delay
DelayOpsSkewNormal::sum(const Delay &delay1,
float delay2) const
{
return Delay(delay1.mean() + delay2,
delay1.meanShift(),
delay1.stdDev2(),
delay1.skewness());
}
Delay
DelayOpsSkewNormal::diff(const Delay &delay1,
const Delay &delay2) const
{
return Delay(delay1.mean() - delay2.mean(),
delay1.meanShift() - delay2.meanShift(),
delay1.stdDev2() + delay2.stdDev2(),
skewnessSum(delay1, delay2));
}
Delay
DelayOpsSkewNormal::diff(const Delay &delay1,
float delay2) const
{
return Delay(delay1.mean() - delay2,
delay1.meanShift(),
delay1.stdDev2(),
delay1.skewness());
}
Delay
DelayOpsSkewNormal::diff(float delay1,
const Delay &delay2) const
{
return Delay(delay1 - delay2.mean(),
delay2.meanShift(),
delay2.stdDev2(),
delay2.skewness());
}
void
DelayOpsSkewNormal::incr(Delay &delay1,
const Delay &delay2) const
{
delay1.setValues(delay1.mean() + delay2.mean(),
delay1.meanShift() + delay2.meanShift(),
delay1.stdDev2() + delay2.stdDev2(),
skewnessSum(delay1, delay2));
}
void
DelayOpsSkewNormal::incr(DelayDbl &delay1,
const Delay &delay2) const
{
delay1.setValues(delay1.mean() + delay2.mean(),
delay1.meanShift() + delay2.meanShift(),
delay1.stdDev2() + delay2.stdDev2(),
skewnessSum(delay1.stdDev(), delay1.skewness()));
}
void
DelayOpsSkewNormal::decr(Delay &delay1,
const Delay &delay2) const
{
delay1.setValues(delay1.mean() - delay2.mean(),
delay1.meanShift() + delay2.meanShift(),
delay1.stdDev2() + delay2.stdDev2(),
skewnessSum(delay1, delay2));
}
void
DelayOpsSkewNormal::decr(DelayDbl &delay1,
const Delay &delay2) const
{
delay1.setValues(delay1.mean() - delay2.mean(),
delay1.meanShift() + delay2.meanShift(),
delay1.stdDev2() + delay2.stdDev2(),
skewnessSum(delay1.stdDev(), delay1.skewness()));
}
Delay
DelayOpsSkewNormal::product(const Delay &delay1,
float delay2) const
{
return Delay(delay1.mean() * delay2,
delay1.meanShift() * delay2,
delay1.stdDev2() * square(delay2),
delay1.skewness() * cube(delay2));
}
Delay
DelayOpsSkewNormal::div(float delay1,
const Delay &delay2) const
{
return Delay(delay1 / delay2.mean());
}
const char *
DelayOpsSkewNormal::asStringVariance(const Delay &delay,
int digits,
const StaState *sta) const
{
const Unit *unit = sta->units()->timeUnit();
return stringPrintTmp("%s[%s,%s,%s]",
unit->asString(delay.mean(), digits),
unit->asString(delay.meanShift(), digits),
unit->asString(delay.stdDev(), digits),
sta->units()->scalarUnit()->asString(delay.skewness(), digits));
}
} // namespace

View File

@ -90,8 +90,7 @@ gateModelRd(const LibertyCell *cell,
double in_slew,
double c2,
double c1,
const Pvt *pvt,
bool pocv_enabled);
const Pvt *pvt);
static void
newtonRaphson(const int max_iter,
double x[],
@ -143,8 +142,8 @@ public:
virtual void loadDelaySlew(const Pin *load_pin,
double elmore,
// Return values.
ArcDelay &delay,
Slew &slew);
double &delay,
double &slew);
double ceff() { return ceff_; }
// Given x_ as a vector of input parameters, fill fvec_ with the
@ -348,13 +347,10 @@ DmpAlg::gateCapDelaySlew(double ceff,
double &delay,
double &slew)
{
ArcDelay model_delay;
Slew model_slew;
gate_model_->gateDelay(pvt_, in_slew_, ceff,
variables_->pocvEnabled(),
model_delay, model_slew);
delay = delayAsFloat(model_delay);
slew = delayAsFloat(model_slew);
float model_delay, model_slew;
gate_model_->gateDelay(pvt_, in_slew_, ceff, model_delay, model_slew);
delay = model_delay;
slew = model_slew;
}
void
@ -543,8 +539,8 @@ DmpAlg::showVo()
void
DmpAlg::loadDelaySlew(const Pin *,
double elmore,
ArcDelay &delay,
Slew &slew)
double &delay,
double &slew)
{
if (!driver_valid_
|| elmore == 0.0
@ -700,8 +696,8 @@ public:
void loadDelaySlew(const Pin *,
double elmore,
// Return values.
ArcDelay &delay,
Slew &slew) override;
double &delay,
double &slew) override;
void evalDmpEqns() override;
double voCrossingUpperBound() override;
@ -753,8 +749,8 @@ DmpCap::gateDelaySlew(// Return values.
void
DmpCap::loadDelaySlew(const Pin *,
double elmore,
ArcDelay &delay,
Slew &slew)
double &delay,
double &slew)
{
delay = elmore;
slew = drvr_slew_;
@ -1498,21 +1494,36 @@ DmpCeffDelayCalc::gateDelay(const Pin *drvr_pin,
parasitics_->piModel(parasitic, c2, rpi, c1);
if (std::isnan(c2) || std::isnan(c1) || std::isnan(rpi))
report_->error(1040, "parasitic Pi model has NaNs.");
setCeffAlgorithm(drvr_library, drvr_cell, pinPvt(drvr_pin, scene, min_max),
const Pvt *pvt = pinPvt(drvr_pin, scene, min_max);
setCeffAlgorithm(drvr_library, drvr_cell, pvt,
table_model, rf, in_slew1, c2, rpi, c1);
double gate_delay, drvr_slew;
gateDelaySlew(gate_delay, drvr_slew);
// Fill in pocv parameters.
double ceff = dmp_alg_->ceff();
ArcDelay gate_delay2(gate_delay);
Slew drvr_slew2(drvr_slew);
if (variables_->pocvEnabled())
table_model->gateDelayPocv(pvt, in_slew1, ceff, min_max,
variables_->pocvMode(),
gate_delay2, drvr_slew2);
ArcDcalcResult dcalc_result(load_pin_index_map.size());
dcalc_result.setGateDelay(gate_delay);
dcalc_result.setDrvrSlew(drvr_slew);
dcalc_result.setGateDelay(gate_delay2);
dcalc_result.setDrvrSlew(drvr_slew2);
for (const auto &[load_pin, load_idx] : load_pin_index_map) {
ArcDelay wire_delay;
Slew load_slew;
double wire_delay;
double load_slew;
loadDelaySlew(load_pin, drvr_slew, rf, drvr_library, parasitic,
wire_delay, load_slew);
dcalc_result.setWireDelay(load_idx, wire_delay);
dcalc_result.setLoadSlew(load_idx, load_slew);
// Copy pocv params from driver.
ArcDelay wire_delay2(gate_delay2);
Slew load_slew2(drvr_slew2);
delaySetMean(wire_delay2, wire_delay);
delaySetMean(load_slew2, load_slew);
dcalc_result.setWireDelay(load_idx, wire_delay2);
dcalc_result.setLoadSlew(load_idx, load_slew2);
}
return dcalc_result;
}
@ -1543,8 +1554,7 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library,
{
double rd = 0.0;
if (gate_model) {
rd = gateModelRd(drvr_cell, gate_model, rf, in_slew, c2, c1,
pvt, variables_->pocvEnabled());
rd = gateModelRd(drvr_cell, gate_model, rf, in_slew, c2, c1, pvt);
// Zero Rd means the table is constant and thus independent of load cap.
if (rd < 1e-2
// Rpi is small compared to Rd, which makes the load capacitive.
@ -1612,14 +1622,12 @@ DmpCeffDelayCalc::reportGateDelay(const Pin *drvr_pin,
else
c_eff = load_cap;
if (model) {
const Unit *time_unit = units->timeUnit();
float in_slew1 = delayAsFloat(in_slew);
result += model->reportGateDelay(pinPvt(drvr_pin, scene, min_max),
in_slew1, c_eff,
variables_->pocvEnabled(), digits);
in_slew1, c_eff, min_max,
variables_->pocvMode(), digits);
result += "Driver waveform slew = ";
float drvr_slew = delayAsFloat(dcalc_result.drvrSlew());
result += time_unit->asString(drvr_slew, digits);
result += delayAsString(dcalc_result.drvrSlew(), min_max, digits, this);
result += '\n';
}
return result;
@ -1632,18 +1640,15 @@ gateModelRd(const LibertyCell *cell,
double in_slew,
double c2,
double c1,
const Pvt *pvt,
bool pocv_enabled)
const Pvt *pvt)
{
float cap1 = c1 + c2;
float cap2 = cap1 + 1e-15;
ArcDelay d1, d2;
Slew s1, s2;
gate_model->gateDelay(pvt, in_slew, cap1, pocv_enabled, d1, s1);
gate_model->gateDelay(pvt, in_slew, cap2, pocv_enabled, d2, s2);
float d1, d2, s1, s2;
gate_model->gateDelay(pvt, in_slew, cap1, d1, s1);
gate_model->gateDelay(pvt, in_slew, cap2, d2, s2);
double vth = cell->libertyLibrary()->outputThreshold(rf);
float rd = -std::log(vth) * std::abs(delayAsFloat(d1) - delayAsFloat(d2))
/ (cap2 - cap1);
float rd = -std::log(vth) * std::abs(d1 - d2) / (cap2 - cap1);
return rd;
}
@ -1658,8 +1663,8 @@ DmpCeffDelayCalc::gateDelaySlew(// Return values.
void
DmpCeffDelayCalc::loadDelaySlewElmore(const Pin *load_pin,
double elmore,
ArcDelay &delay,
Slew &slew)
double &delay,
double &slew)
{
if (dmp_alg_)
dmp_alg_->loadDelaySlew(load_pin, elmore, delay, slew);

View File

@ -69,15 +69,15 @@ protected:
const LibertyLibrary *drvr_library,
const Parasitic *parasitic,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew) = 0;
double &wire_delay,
double &load_slew) = 0;
void gateDelaySlew(// Return values.
double &delay,
double &slew);
void loadDelaySlewElmore(const Pin *load_pin,
double elmore,
ArcDelay &delay,
Slew &slew);
double &delay,
double &slew);
// Select the appropriate special case Dartu/Menezes/Pileggi algorithm.
void setCeffAlgorithm(const LibertyLibrary *library,
const LibertyCell *cell,

View File

@ -59,8 +59,8 @@ protected:
const LibertyLibrary *drvr_library,
const Parasitic *parasitic,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew) override;
double &wire_delay,
double &load_slew) override;
};
ArcDelayCalc *
@ -93,8 +93,8 @@ DmpCeffElmoreDelayCalc::inputPortDelay(const Pin *,
ArcDcalcResult dcalc_result(load_pin_index_map.size());
LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
for (auto [load_pin, load_idx] : load_pin_index_map) {
ArcDelay wire_delay = 0.0;
Slew load_slew = in_slew;
double wire_delay = 0.0;
double load_slew = in_slew;
bool elmore_exists = false;
float elmore = 0.0;
if (parasitic)
@ -116,8 +116,8 @@ DmpCeffElmoreDelayCalc::loadDelaySlew(const Pin *load_pin,
const LibertyLibrary *drvr_library,
const Parasitic *parasitic,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew)
double &wire_delay,
double &load_slew)
{
wire_delay = 0.0;
load_slew = drvr_slew;
@ -143,14 +143,14 @@ public:
Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const Scene *scene,
const MinMax *min_max) override;
const MinMax *min_max) override;
ArcDcalcResult inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const Scene *scene,
const MinMax *min_max) override;
const MinMax *min_max) override;
ArcDcalcResult gateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
@ -158,7 +158,7 @@ public:
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const Scene *scene,
const MinMax *min_max) override;
const MinMax *min_max) override;
private:
void loadDelaySlew(const Pin *load_pin,
@ -167,14 +167,14 @@ private:
const LibertyLibrary *drvr_library,
const Parasitic *parasitic,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew) override;
double &wire_delay,
double &load_slew) override;
void loadDelay(double drvr_slew,
Parasitic *pole_residue,
double p1,
double k1,
ArcDelay &wire_delay,
Slew &load_slew);
double &wire_delay,
double &load_slew);
float loadDelay(double vth,
double p1,
double p2,
@ -267,8 +267,8 @@ DmpCeffTwoPoleDelayCalc::inputPortDelay(const Pin *,
{
const Parasitics *parasitics = scene->parasitics(min_max);
ArcDcalcResult dcalc_result(load_pin_index_map.size());
ArcDelay wire_delay = 0.0;
Slew load_slew = in_slew;
double wire_delay = 0.0;
double load_slew = in_slew;
LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
for (const auto [load_pin, load_idx] : load_pin_index_map) {
if (parasitics->isPiPoleResidue(parasitic)) {
@ -323,8 +323,8 @@ DmpCeffTwoPoleDelayCalc::loadDelaySlew(const Pin *load_pin,
const LibertyLibrary *drvr_library,
const Parasitic *parasitic,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew)
double &wire_delay,
double &load_slew)
{
parasitic_is_pole_residue_ = parasitics_->isPiPoleResidue(parasitic);
// Should handle PiElmore parasitic.
@ -362,12 +362,12 @@ DmpCeffTwoPoleDelayCalc::loadDelay(double drvr_slew,
double p1,
double k1,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew)
double &wire_delay,
double &load_slew)
{
ComplexFloat pole2, residue2;
parasitics_->poleResidue(pole_residue, 1, pole2, residue2);
if (!delayZero(drvr_slew)
if (!delayZero(drvr_slew, this)
&& pole2.imag() == 0.0
&& residue2.imag() == 0.0) {
double p2 = pole2.real();

View File

@ -646,17 +646,17 @@ GraphDelayCalc::findInputArcDelay(const Pin *drvr_pin,
ArcDcalcResult intrinsic_result =
arc_delay_calc_->gateDelay(drvr_pin, arc, Slew(from_slew), 0.0, nullptr,
load_pin_index_map, scene, min_max);
ArcDelay intrinsic_delay = intrinsic_result.gateDelay();
const ArcDelay &intrinsic_delay = intrinsic_result.gateDelay();
ArcDcalcResult gate_result = arc_delay_calc_->gateDelay(drvr_pin, arc,
Slew(from_slew), load_cap,
parasitic,
load_pin_index_map,
scene, min_max);
ArcDelay gate_delay = gate_result.gateDelay();
Slew gate_slew = gate_result.drvrSlew();
const ArcDelay &gate_delay = gate_result.gateDelay();
const Slew &gate_slew = gate_result.drvrSlew();
ArcDelay load_delay = gate_delay - intrinsic_delay;
const ArcDelay load_delay = delayDiff(gate_delay, intrinsic_delay, this);
debugPrint(debug_, "delay_calc", 3,
" gate delay = %s intrinsic = %s slew = %s",
delayAsString(gate_delay, this),
@ -729,9 +729,8 @@ GraphDelayCalc::loadSlews(LoadPinIndexMap &load_pin_index_map)
Vertex *load_vertex = graph_->pinLoadVertex(pin);
SlewSeq &slews = load_slews[index];;
slews.resize(slew_count);
Slew *vertex_slews = load_vertex->slews();
for (size_t i = 0; i < slew_count; i++)
slews[i] = vertex_slews[i];
slews[i] = graph_->slew(load_vertex, i);
}
return load_slews;
}
@ -744,9 +743,9 @@ GraphDelayCalc::loadSlewsChanged(DrvrLoadSlews &load_slews_prev,
for (auto const [pin, index] : load_pin_index_map) {
Vertex *load_vertex = graph_->pinLoadVertex(pin);
SlewSeq &slews_prev = load_slews_prev[index];;
const Slew *slews = load_vertex->slews();
for (size_t i = 0; i < slew_count; i++) {
if (!delayEqual(slews[i], slews_prev[i]))
const Slew &slew = graph_->slew(load_vertex, i);
if (!delayEqual(slew, slews_prev[i], this))
return true;
}
}
@ -915,19 +914,18 @@ GraphDelayCalc::initLoadSlews(Vertex *drvr_vertex)
Edge *wire_edge = edge_iter.next();
if (wire_edge->isWire()) {
Vertex *load_vertex = wire_edge->to(graph_);
for (Scene *scene : scenes_) {
for (const MinMax *min_max : MinMax::range()) {
DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max);
Slew slew_init_value(min_max->initValue());
for (const RiseFall *rf : RiseFall::range()) {
for (const RiseFall *rf : RiseFall::range()) {
if (!load_vertex->slewAnnotated(rf, min_max))
graph_->setSlew(load_vertex, rf, ap_index, slew_init_value);
graph_->setSlew(load_vertex, rf, ap_index, slew_init_value);
}
}
}
}
}
}
}
bool
@ -965,12 +963,12 @@ GraphDelayCalc::initRootSlews(Vertex *vertex)
for (Scene *scene : scenes_) {
for (const MinMax *min_max : MinMax::range()) {
DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max);
for (const RiseFall *rf : RiseFall::range()) {
for (const RiseFall *rf : RiseFall::range()) {
if (!vertex->slewAnnotated(rf, min_max))
graph_->setSlew(vertex, rf, ap_index, default_slew);
graph_->setSlew(vertex, rf, ap_index, default_slew);
}
}
}
}
}
void
@ -1195,8 +1193,8 @@ GraphDelayCalc::annotateDelaysSlews(Edge *edge,
bool
GraphDelayCalc::annotateDelaySlew(Edge *edge,
const TimingArc *arc,
ArcDelay &gate_delay,
Slew &gate_slew,
const ArcDelay &gate_delay,
const Slew &gate_slew,
const Scene *scene,
const MinMax *min_max)
{
@ -1258,8 +1256,8 @@ GraphDelayCalc::annotateLoadDelays(Vertex *drvr_vertex,
Vertex *load_vertex = wire_edge->to(graph_);
Pin *load_pin = load_vertex->pin();
size_t load_idx = load_pin_index_map[load_pin];
ArcDelay wire_delay = dcalc_result.wireDelay(load_idx);
Slew load_slew = dcalc_result.loadSlew(load_idx);
const ArcDelay &wire_delay = dcalc_result.wireDelay(load_idx);
const Slew &load_slew = dcalc_result.loadSlew(load_idx);
debugPrint(debug_, "delay_calc", 3,
" %s load delay = %s slew = %s",
load_vertex->to_string(this).c_str(),
@ -1287,7 +1285,7 @@ GraphDelayCalc::annotateLoadDelays(Vertex *drvr_vertex,
// annotate the same wire edges so they must be combined
// rather than set.
const ArcDelay &delay = graph_->wireArcDelay(wire_edge, drvr_rf, ap_index);
Delay wire_delay_extra = extra_delay + wire_delay;
Delay wire_delay_extra = delaySum(extra_delay, wire_delay, this);
if (!merge
|| delayGreater(wire_delay_extra, delay, min_max, this)) {
graph_->setWireArcDelay(wire_edge, drvr_rf, ap_index, wire_delay_extra);

View File

@ -118,7 +118,7 @@ LumpedCapDelayCalc::inputPortDelay(const Pin *,
const MinMax *)
{
const LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
return makeResult(drvr_library,rf, 0.0, in_slew, load_pin_index_map);
return makeResult(drvr_library,rf, delay_zero, in_slew, load_pin_index_map);
}
ArcDcalcResult
@ -139,16 +139,22 @@ LumpedCapDelayCalc::gateDelay(const Pin *drvr_pin,
const RiseFall *rf = arc->toEdge()->asRiseFall();
const LibertyLibrary *drvr_library = arc->to()->libertyLibrary();
if (model) {
ArcDelay gate_delay;
Slew drvr_slew;
float gate_delay, drvr_slew;
float in_slew1 = delayAsFloat(in_slew);
// NaNs cause seg faults during table lookup.
if (std::isnan(load_cap) || std::isnan(delayAsFloat(in_slew)))
if (std::isnan(load_cap) || std::isnan(in_slew.mean()))
report_->error(1350, "gate delay input variable is NaN");
model->gateDelay(pinPvt(drvr_pin, scene, min_max), in_slew1, load_cap,
variables_->pocvEnabled(),
gate_delay, drvr_slew);
return makeResult(drvr_library, rf, gate_delay, drvr_slew, load_pin_index_map);
const Pvt *pvt = pinPvt(drvr_pin, scene, min_max);
model->gateDelay(pvt, in_slew1, load_cap, gate_delay, drvr_slew);
// Fill in pocv parameters.
ArcDelay gate_delay2(gate_delay);
Slew drvr_slew2(drvr_slew);
if (variables_->pocvEnabled())
model->gateDelayPocv(pvt, in_slew1, load_cap, min_max, variables_->pocvMode(),
gate_delay2, drvr_slew2);
return makeResult(drvr_library, rf, gate_delay2, drvr_slew2, load_pin_index_map);
}
else
return makeResult(drvr_library, rf, delay_zero, delay_zero, load_pin_index_map);
@ -157,17 +163,18 @@ LumpedCapDelayCalc::gateDelay(const Pin *drvr_pin,
ArcDcalcResult
LumpedCapDelayCalc::makeResult(const LibertyLibrary *drvr_library,
const RiseFall *rf,
ArcDelay gate_delay,
Slew drvr_slew,
const ArcDelay &gate_delay,
const Slew &drvr_slew,
const LoadPinIndexMap &load_pin_index_map)
{
ArcDcalcResult dcalc_result(load_pin_index_map.size());
dcalc_result.setGateDelay(gate_delay);
dcalc_result.setDrvrSlew(drvr_slew);
double drvr_slew1 = delayAsFloat(drvr_slew);
for (const auto [load_pin, load_idx] : load_pin_index_map) {
ArcDelay wire_delay = 0.0;
Slew load_slew = drvr_slew;
double wire_delay = 0.0;
double load_slew = drvr_slew1;
thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew);
dcalc_result.setWireDelay(load_idx, wire_delay);
dcalc_result.setLoadSlew(load_idx, load_slew);
@ -190,7 +197,8 @@ LumpedCapDelayCalc::reportGateDelay(const Pin *check_pin,
if (model) {
float in_slew1 = delayAsFloat(in_slew);
return model->reportGateDelay(pinPvt(check_pin, scene, min_max),
in_slew1, load_cap, false, digits);
in_slew1, load_cap, min_max,
PocvMode::scalar, digits);
}
return "";
}

View File

@ -74,8 +74,8 @@ public:
protected:
ArcDcalcResult makeResult(const LibertyLibrary *drvr_library,
const RiseFall *rf,
ArcDelay gate_delay,
Slew drvr_slew,
const ArcDelay &gate_delay,
const Slew &drvr_slew,
const LoadPinIndexMap &load_pin_index_map);
using ArcDelayCalc::reduceParasitic;

View File

@ -88,13 +88,13 @@ ParallelDelayCalc::gateDelaysParallel(ArcDcalcArgSeq &dcalc_args,
load_pin_index_map, scene, min_max);
ArcDelay gate_delay = gate_result.gateDelay();
Slew drvr_slew = gate_result.drvrSlew();
ArcDelay load_delay = gate_delay - intrinsic_delay;
ArcDelay load_delay = delayDiff(gate_delay, intrinsic_delay, this);
load_delays[drvr_idx] = load_delay;
if (!delayZero(load_delay))
load_delay_sum += 1.0 / load_delay;
if (!delayZero(drvr_slew))
slew_sum += 1.0 / drvr_slew;
if (!delayZero(load_delay, this))
delayIncr(load_delay_sum, delayDiv(1.0, load_delay, this), this);
if (!delayZero(drvr_slew, this))
delayIncr(slew_sum, delayDiv(1.0, drvr_slew, this), this);
dcalc_result.setLoadCount(load_pin_index_map.size());
for (const auto &[load_pin, load_idx] : load_pin_index_map) {
@ -103,14 +103,16 @@ ParallelDelayCalc::gateDelaysParallel(ArcDcalcArgSeq &dcalc_args,
}
}
ArcDelay gate_load_delay = delayZero(load_delay_sum)
ArcDelay gate_load_delay = delayZero(load_delay_sum, this)
? delay_zero
: 1.0 / load_delay_sum;
ArcDelay drvr_slew = delayZero(slew_sum) ? delay_zero : 1.0 / slew_sum;
: delayDiv(1.0, load_delay_sum, this);
ArcDelay drvr_slew = delayZero(slew_sum, this)
? delay_zero
: delayDiv(1.0, slew_sum, this);
for (size_t drvr_idx = 0; drvr_idx < drvr_count; drvr_idx++) {
ArcDcalcResult &dcalc_result = dcalc_results[drvr_idx];
dcalc_result.setGateDelay(intrinsic_delays[drvr_idx] + gate_load_delay);
dcalc_result.setGateDelay(delaySum(intrinsic_delays[drvr_idx], gate_load_delay, this));
dcalc_result.setDrvrSlew(drvr_slew);
}
return dcalc_results;

View File

@ -166,8 +166,8 @@ PrimaDelayCalc::inputPortDelay(const Pin *drvr_pin,
for (auto load_pin_index : load_pin_index_map) {
const Pin *load_pin = load_pin_index.first;
size_t load_idx = load_pin_index.second;
ArcDelay wire_delay = 0.0;
Slew load_slew = in_slew;
double wire_delay = 0.0;
double load_slew = in_slew;
bool elmore_exists = false;
float elmore = 0.0;
if (pi_elmore)
@ -722,8 +722,8 @@ PrimaDelayCalc::dcalcResults()
size_t drvr_node = pin_node_map_[drvr_pin];
ThresholdTimes &drvr_times = threshold_times_[drvr_node];
float ref_time = output_waveforms_[drvr_idx]->referenceTime(dcalc_arg.inSlewFlt());
ArcDelay gate_delay = drvr_times[threshold_vth] - ref_time;
Slew drvr_slew = std::abs(drvr_times[threshold_vh] - drvr_times[threshold_vl]);
double gate_delay = drvr_times[threshold_vth] - ref_time;
double drvr_slew = std::abs(drvr_times[threshold_vh] - drvr_times[threshold_vl]);
dcalc_result.setGateDelay(gate_delay);
dcalc_result.setDrvrSlew(drvr_slew);
debugPrint(debug_, "ccs_dcalc", 2,
@ -739,8 +739,8 @@ PrimaDelayCalc::dcalcResults()
size_t load_node = pin_node_map_[load_pin];
ThresholdTimes &wire_times = threshold_times_[load_node];
ThresholdTimes &drvr_times = threshold_times_[drvr_node];
ArcDelay wire_delay = wire_times[threshold_vth] - drvr_times[threshold_vth];
Slew load_slew = std::abs(wire_times[threshold_vh] - wire_times[threshold_vl]);
double wire_delay = wire_times[threshold_vth] - drvr_times[threshold_vth];
double load_slew = std::abs(wire_times[threshold_vh] - wire_times[threshold_vl]);
debugPrint(debug_, "ccs_dcalc", 2,
"load %s %s delay %s slew %s",
network_->pathName(load_pin),
@ -920,7 +920,8 @@ PrimaDelayCalc::reportGateDelay(const Pin *drvr_pin,
if (model) {
float in_slew1 = delayAsFloat(in_slew);
return model->reportGateDelay(pinPvt(drvr_pin, scene, min_max),
in_slew1, load_cap, false, digits);
in_slew1, load_cap, min_max,
PocvMode::scalar, digits);
}
return "";
}

View File

@ -62,6 +62,8 @@ The Vector/Map/Set/UnorderedSet classes have been removed and replaced by
the std containers. The member functions are now templated functions found
in ContainerHelpers.hh.
The Graph slew_rf_count option is no longer supported.
Release 2.6.2 2025/03/30
------------------------

View File

@ -3,6 +3,134 @@ OpenSTA Timing Analyzer Release Notes
This file summarizes user visible changes for each release.
Release 3.0.1 2026/03/12
------------------------
Statistical timing (SSTA) with Liberty LVF (Liberty Variation Format)
models is now supported. Statistical timing uses a probaility
distribution to represent a delay or slew ranther than a single
number.
Normal and skew normal probability distributions are supported.
SSTA is enabled with the sta_pocv_mode variaable.
set sta_pocv_mode scalar|normal|skew_normal
scalar mode is for non-SSTA analysis
normal mode uses gaussian normal distributions
skew_normal'mode is for skew normal LVF moment based distributions
The target quantile of a delay probability distribution (confidence level) is
set with the sta_pocv_quantile variable.
sta_pocv_quantile <float>
The default value is 3 standard deviations, or sigma.
Use the variance field with report_checks or report_check_types to see
distribution parameters in timing reports.
A command file for analyzing a design with statisical timing with an
LVF library is shown below.
read_liberty lvf_library.lib.gz
read_verilog design.v
link_design top
create_clock -period 50 clk
set_input_delay -clock clk 1 {in1 in2}
set sta_pocv_mode skew_normal
report_checks -fields {slew variation input_pin variation} -digits 3
Startpoint: r2 (rising edge-triggered flip-flop clocked by clk)
Endpoint: r3 (rising edge-triggered flip-flop clocked by clk)
Path Group: clk
Path Type: max
Slew Delay Variation Time Description
---------------------------------------------------------------------------
0.000 0.000 0.000 clock clk (rise edge)
0.000 0.000 clock network delay (ideal)
0.000 0.000 0.000 ^ r2/CK (FDPQ1)
12.026 mean
0.017 mean_shift
0.366 std_dev
0.000 skewness
4.648 12.409 12.409 v r2/Q (FFQ1)
4.648 0.000 12.409 v u1/A (BUF1)
6.084 mean
0.007 mean_shift
0.188 std_dev
0.000 skewness
2.513 6.137 18.546 v u1/X (BUF1)
2.513 0.000 18.546 v u2/A2 (AN21)
6.447 mean
0.008 mean_shift
0.191 std_dev
0.000 skewness
2.565 6.497 25.043 v u2/X (AN21)
2.565 0.000 25.043 v r3/D (FFQ1)
25.043 data arrival time
0.000 50.000 50.000 clock clk (rise edge)
0.000 50.000 clock network delay (ideal)
0.000 50.000 clock reconvergence pessimism
50.000 ^ r3/CK (FFQ1)
-9.376 40.624 library setup time
40.624 data required time
---------------------------------------------------------------------------
40.624 data required time
-25.043 data arrival time
---------------------------------------------------------------------------
15.581 slack (MET)
The following commands now support a -report_variance arggument.
report_arrival [-report_variance]
report_required [-report_variance]
report_slack [-report_variance]
report_slews [-report_variance]
report_edges [-report_variance]
The following commands now support a -digits option.
report_edges [-digits digits]
report_slews [-digits digits]
The standard deviation for normal distributions is specified with the
following liberty timing groups.
ocv_sigma_cell_rise
ocv_sigma_cell_fall
ocv_sigma_rise_transition
ocv_sigma_fall_transition
ocv_sigma_rise_constraint
ocv_sigma_fall_constraint
LVF skew normal distributions are specified with liberty groups below.
ocv_std_dev_cell_rise
ocv_std_dev_cell_fall
ocv_mean_shift_cell_rise
ocv_mean_shift_cell_fall
ocv_skewness_cell_rise
ocv_skewness_cell_fall
ocv_std_dev_rise_transition
ocv_std_dev_fall_transition
ocv_skewness_rise_transition
ocv_skewness_fall_transition
ocv_mean_shift_rise_transition
ocv_mean_shift_fall_transition
ocv_std_dev_rise_constraint
ocv_std_dev_fall_constraint
ocv_skewness_rise_constraint
ocv_skewness_fall_constraint
ocv_mean_shift_rise_constraint
ocv_mean_shift_fall_constraint
2026/02/24
----------

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -323,28 +323,6 @@ net have wire edges between the pin vertices. Timing arc sets in the
leaf instance timing models have corresponding edges in the graph
between pins on the instance.
The Graph class constructor option slew_tr_count is used to prevent
the grpah from reserving memory to store slews. Similarly, if the
have_arc_delays option is false no memory is reserved for storing arc
delay values. This is useful if an external delay calculator is used
to annotate delays on the graph. In this case the Graph functions
arcDelay and wireDelay should be overloaded to return delay values
stored outside of the STA.
A graph with no slews or delays is constructed using:
Graph(this, 0, false, ap_count);
A graph with one slew for rising and falling edges is constructed using:
Graph(this, 1, true, ap_count);
A graph with separate rising and falling slews (the default) is
constructed using:
Graph(this, 2, true, ap_count);
SDC
---

View File

@ -1,199 +0,0 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2026, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// 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.
#include "Delay.hh"
#include "StaConfig.hh"
#include "Fuzzy.hh"
#include "Units.hh"
#include "StaState.hh"
// Non-SSTA compilation.
#if !SSTA
namespace sta {
static Delay delay_init_values[MinMax::index_count];
void
initDelayConstants()
{
delay_init_values[MinMax::minIndex()] = MinMax::min()->initValue();
delay_init_values[MinMax::maxIndex()] = MinMax::max()->initValue();
}
const char *
delayAsString(const Delay &delay,
const StaState *sta)
{
return delayAsString(delay, sta, sta->units()->timeUnit()->digits());
}
const char *
delayAsString(const Delay &delay,
const StaState *sta,
int digits)
{
return sta->units()->timeUnit()->asString(delay, digits);
}
const char *
delayAsString(const Delay &delay,
const EarlyLate *,
const StaState *sta,
int digits)
{
const Unit *unit = sta->units()->timeUnit();
return unit->asString(delay, digits);
}
const Delay &
delayInitValue(const MinMax *min_max)
{
return delay_init_values[min_max->index()];
}
bool
delayIsInitValue(const Delay &delay,
const MinMax *min_max)
{
return fuzzyEqual(delay, min_max->initValue());
}
bool
delayZero(const Delay &delay)
{
return fuzzyZero(delay);
}
bool
delayInf(const Delay &delay)
{
return fuzzyInf(delay);
}
bool
delayEqual(const Delay &delay1,
const Delay &delay2)
{
return fuzzyEqual(delay1, delay2);
}
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const StaState *)
{
return fuzzyLess(delay1, delay2);
}
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *)
{
if (min_max == MinMax::max())
return fuzzyLess(delay1, delay2);
else
return fuzzyGreater(delay1, delay2);
}
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const StaState *)
{
return fuzzyLessEqual(delay1, delay2);
}
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *)
{
if (min_max == MinMax::max())
return fuzzyLessEqual(delay1, delay2);
else
return fuzzyGreaterEqual(delay1, delay2);
}
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const StaState *)
{
return fuzzyGreater(delay1, delay2);
}
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *)
{
if (min_max == MinMax::max())
return fuzzyGreater(delay1, delay2);
else
return fuzzyLess(delay1, delay2);
}
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const StaState *)
{
return fuzzyGreaterEqual(delay1, delay2);
}
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *)
{
if (min_max == MinMax::max())
return fuzzyGreaterEqual(delay1, delay2);
else
return fuzzyLessEqual(delay1, delay2);
}
Delay
delayRemove(const Delay &delay1,
const Delay &delay2)
{
return delay1 - delay2;
}
float
delayRatio(const Delay &delay1,
const Delay &delay2)
{
return delay1 / delay2;
}
} // namespace
#endif // !SSTA

View File

@ -1,483 +0,0 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2026, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// 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.
#include "Delay.hh"
#include <cmath> // sqrt
#include "StaConfig.hh"
#include "Error.hh"
#include "StringUtil.hh"
#include "Fuzzy.hh"
#include "Units.hh"
#include "StaState.hh"
#include "Variables.hh"
// SSTA compilation.
#if (SSTA == 1)
namespace sta {
inline float
square(float x)
{
return x * x;
}
static Delay delay_init_values[MinMax::index_count];
void
initDelayConstants()
{
delay_init_values[MinMax::minIndex()] = MinMax::min()->initValue();
delay_init_values[MinMax::maxIndex()] = MinMax::max()->initValue();
}
const Delay &
delayInitValue(const MinMax *min_max)
{
return delay_init_values[min_max->index()];
}
Delay::Delay() :
mean_(0.0),
sigma2_(0.0)
{
}
Delay::Delay(const Delay &delay) :
mean_(delay.mean_),
sigma2_(delay.sigma2_)
{
}
Delay::Delay(const DelayDbl &delay) :
mean_(delay.mean_),
sigma2_(delay.sigma2_)
{
}
Delay::Delay(float mean) :
mean_(mean),
sigma2_(0.0)
{
}
Delay::Delay(float mean,
float sigma2) :
mean_(mean),
sigma2_(sigma2)
{
}
float
Delay::sigma() const
{
if (sigma2_ < 0.0)
// Sigma is negative for crpr to offset sigmas in the common
// clock path.
return -sqrt(-sigma2_);
else
return sqrt(sigma2_);
}
float
Delay::sigma2() const
{
return sigma2_;
}
void
Delay::operator=(const Delay &delay)
{
mean_ = delay.mean_;
sigma2_ = delay.sigma2_;
}
void
Delay::operator=(float delay)
{
mean_ = delay;
sigma2_ = 0.0;
}
void
Delay::operator+=(const Delay &delay)
{
mean_ += delay.mean_;
sigma2_ += delay.sigma2_;
}
void
Delay::operator+=(float delay)
{
mean_ += delay;
}
Delay
Delay::operator+(const Delay &delay) const
{
return Delay(mean_ + delay.mean_,
sigma2_ + delay.sigma2_);
}
Delay
Delay::operator+(float delay) const
{
return Delay(mean_ + delay, sigma2_);
}
Delay
Delay::operator-(const Delay &delay) const
{
return Delay(mean_ - delay.mean_,
sigma2_ + delay.sigma2_);
}
Delay
Delay::operator-(float delay) const
{
return Delay(mean_ - delay, sigma2_);
}
Delay
Delay::operator-() const
{
return Delay(-mean_, sigma2_);
}
void
Delay::operator-=(float delay)
{
mean_ -= delay;
}
void
Delay::operator-=(const Delay &delay)
{
mean_ -= delay.mean_;
sigma2_ += delay.sigma2_;
}
bool
Delay::operator==(const Delay &delay) const
{
return delayEqual(*this, delay);
}
////////////////////////////////////////////////////////////////
DelayDbl::DelayDbl() :
mean_(0.0),
sigma2_(0.0)
{
}
void
DelayDbl::operator=(float delay)
{
mean_ = delay;
sigma2_ = 0.0;
}
void
DelayDbl::operator+=(const Delay &delay)
{
mean_ += delay.mean_;
sigma2_ += delay.sigma2_;
}
void
DelayDbl::operator-=(const Delay &delay)
{
mean_ -= delay.mean_;
sigma2_ += delay.sigma2_;
}
////////////////////////////////////////////////////////////////
Delay
makeDelay(float delay,
float sigma,
float)
{
return Delay(delay, square(sigma));
}
Delay
makeDelay2(float delay,
float sigma2,
float )
{
return Delay(delay, sigma2);
}
float
delayAsFloat(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta)
{
if (sta->variables()->pocvEnabled()) {
if (early_late == EarlyLate::early())
return delay.mean() - delay.sigma() * sta->sigmaFactor();
else if (early_late == EarlyLate::late())
return delay.mean() + delay.sigma() * sta->sigmaFactor();
else
sta->report()->critical(1020, "unknown early/late value.");
}
return delay.mean();
}
float
delaySigma2(const Delay &delay,
const EarlyLate *)
{
return delay.sigma2();
}
const char *
delayAsString(const Delay &delay,
const StaState *sta)
{
return delayAsString(delay, sta, sta->units()->timeUnit()->digits());
}
const char *
delayAsString(const Delay &delay,
const StaState *sta,
int digits)
{
const Unit *unit = sta->units()->timeUnit();
if (sta->variables()->pocvEnabled()) {
float sigma = delay.sigma();
return stringPrintTmp("%s[%s]",
unit->asString(delay.mean(), digits),
unit->asString(sigma, digits));
}
else
return unit->asString(delay.mean(), digits);
}
const char *
delayAsString(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta,
int digits)
{
float mean_sigma = delayAsFloat(delay, early_late, sta);
return sta->units()->timeUnit()->asString(mean_sigma, digits);
}
bool
delayIsInitValue(const Delay &delay,
const MinMax *min_max)
{
return fuzzyEqual(delay.mean(), min_max->initValue())
&& delay.sigma2() == 0.0;
}
bool
delayZero(const Delay &delay)
{
return fuzzyZero(delay.mean())
&& fuzzyZero(delay.sigma2());
}
bool
delayInf(const Delay &delay)
{
return fuzzyInf(delay.mean());
}
bool
delayEqual(const Delay &delay1,
const Delay &delay2)
{
return fuzzyEqual(delay1.mean(), delay2.mean())
&& fuzzyEqual(delay1.sigma2(), delay2.sigma2());
}
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const StaState *sta)
{
return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta),
delayAsFloat(delay2, EarlyLate::early(), sta));
}
bool
delayLess(const Delay &delay1,
float delay2,
const StaState *sta)
{
return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta),
delay2);
}
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
{
if (min_max == MinMax::max())
return delayLess(delay1, delay2, sta);
else
return delayGreater(delay1, delay2, sta);
}
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta)
{
return fuzzyLessEqual(delayAsFloat(delay1, EarlyLate::early(), sta),
delayAsFloat(delay2, EarlyLate::early(), sta));
}
bool
delayLessEqual(const Delay &delay1,
float delay2,
const StaState *sta)
{
return fuzzyLessEqual(delayAsFloat(delay1, EarlyLate::early(), sta),
delay2);
}
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
{
if (min_max == MinMax::max())
return delayLessEqual(delay1, delay2, sta);
else
return delayGreaterEqual(delay1, delay2, sta);
}
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const StaState *sta)
{
return fuzzyGreater(delayAsFloat(delay1, EarlyLate::late(), sta),
delayAsFloat(delay2, EarlyLate::late(), sta));
}
bool
delayGreater(const Delay &delay1,
float delay2,
const StaState *sta)
{
return fuzzyGreater(delayAsFloat(delay1, EarlyLate::late(), sta),
delay2);
}
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta)
{
return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta),
delayAsFloat(delay2, EarlyLate::late(), sta));
}
bool
delayGreaterEqual(const Delay &delay1,
float delay2,
const StaState *sta)
{
return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta),
delay2);
}
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
{
if (min_max == MinMax::max())
return delayGreater(delay1, delay2, sta);
else
return delayLess(delay1, delay2, sta);
}
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
{
if (min_max == MinMax::max())
return delayGreaterEqual(delay1, delay2, sta);
else
return delayLessEqual(delay1, delay2, sta);
}
Delay
delayRemove(const Delay &delay1,
const Delay &delay2)
{
return Delay(delay1.mean() - delay2.mean(),
delay1.sigma2() - delay2.sigma2());
}
float
delayRatio(const Delay &delay1,
const Delay &delay2)
{
return delay1.mean() / delay2.mean();
}
Delay
operator+(float delay1,
const Delay &delay2)
{
return Delay(delay1 + delay2.mean(),
delay2.sigma2());
}
Delay
operator/(float delay1,
const Delay &delay2)
{
return Delay(delay1 / delay2.mean(),
delay2.sigma2());
}
Delay
operator*(const Delay &delay1,
float delay2)
{
return Delay(delay1.mean() * delay2,
delay1.sigma2() * delay2 * delay2);
}
} // namespace
#endif // (SSTA == 1)

View File

@ -1,517 +0,0 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2026, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// 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.
#include "Delay.hh"
#include <cmath> // sqrt
#include "StaConfig.hh"
#include "Error.hh"
#include "StringUtil.hh"
#include "Fuzzy.hh"
#include "Units.hh"
#include "StaState.hh"
// SSTA compilation.
#if (SSTA == 2)
namespace sta {
inline float
square(float x)
{
return x * x;
}
static Delay delay_init_values[MinMax::index_count];
void
initDelayConstants()
{
delay_init_values[MinMax::minIndex()] = MinMax::min()->initValue();
delay_init_values[MinMax::maxIndex()] = MinMax::max()->initValue();
}
const Delay &
delayInitValue(const MinMax *min_max)
{
return delay_init_values[min_max->index()];
}
Delay::Delay() :
mean_(0.0),
sigma2_{0.0, 0.0}
{
}
Delay::Delay(const Delay &delay) :
mean_(delay.mean_)
{
sigma2_[EarlyLate::earlyIndex()] = delay.sigma2_[EarlyLate::earlyIndex()];
sigma2_[EarlyLate::lateIndex()] = delay.sigma2_[EarlyLate::lateIndex()];
}
Delay::Delay(const DelayDbl &delay) :
mean_(delay.mean_)
{
sigma2_[EarlyLate::earlyIndex()] = delay.sigma2_[EarlyLate::earlyIndex()];
sigma2_[EarlyLate::lateIndex()] = delay.sigma2_[EarlyLate::lateIndex()];
}
Delay::Delay(float mean) :
mean_(mean),
sigma2_{0.0, 0.0}
{
}
Delay::Delay(float mean,
float sigma2_early,
float sigma2_late) :
mean_(mean),
sigma2_{sigma2_early, sigma2_late}
{
}
float
Delay::sigma(const EarlyLate *early_late) const
{
float sigma = sigma2_[early_late->index()];
if (sigma < 0.0)
// Sigma is negative for crpr to offset sigmas in the common
// clock path.
return -sqrt(-sigma);
else
return sqrt(sigma);
}
float
Delay::sigma2(const EarlyLate *early_late) const
{
return sigma2_[early_late->index()];
}
float
Delay::sigma2Early() const
{
return sigma2_[early_index];
}
float
Delay::sigma2Late() const
{
return sigma2_[late_index];
}
void
Delay::operator=(const Delay &delay)
{
mean_ = delay.mean_;
sigma2_[early_index] = delay.sigma2_[early_index];
sigma2_[late_index] = delay.sigma2_[late_index];
}
void
Delay::operator=(float delay)
{
mean_ = delay;
sigma2_[early_index] = 0.0;
sigma2_[late_index] = 0.0;
}
void
Delay::operator+=(const Delay &delay)
{
mean_ += delay.mean_;
sigma2_[early_index] += delay.sigma2_[early_index];
sigma2_[late_index] += delay.sigma2_[late_index];
}
void
Delay::operator+=(float delay)
{
mean_ += delay;
}
Delay
Delay::operator+(const Delay &delay) const
{
return Delay(mean_ + delay.mean_,
sigma2_[early_index] + delay.sigma2_[early_index],
sigma2_[late_index] + delay.sigma2_[late_index]);
}
Delay
Delay::operator+(float delay) const
{
return Delay(mean_ + delay, sigma2_[early_index], sigma2_[late_index]);
}
Delay
Delay::operator-(const Delay &delay) const
{
return Delay(mean_ - delay.mean_,
sigma2_[early_index] + delay.sigma2_[late_index],
sigma2_[late_index] + delay.sigma2_[early_index]);
}
Delay
Delay::operator-(float delay) const
{
return Delay(mean_ - delay, sigma2_[early_index], sigma2_[late_index]);
}
Delay
Delay::operator-() const
{
return Delay(-mean_, sigma2_[late_index], sigma2_[early_index]);
}
void
Delay::operator-=(float delay)
{
mean_ -= delay;
}
void
Delay::operator-=(const Delay &delay)
{
mean_ -= delay.mean_;
sigma2_[early_index] += delay.sigma2_[early_index];
sigma2_[late_index] += delay.sigma2_[late_index];
}
bool
Delay::operator==(const Delay &delay) const
{
return mean_ == delay.mean_
&& sigma2_[early_index] == delay.sigma2_[late_index]
&& sigma2_[late_index] == delay.sigma2_[early_index];
}
////////////////////////////////////////////////////////////////
DelayDbl::DelayDbl() :
mean_(0.0),
sigma2_{0.0, 0.0}
{
}
void
DelayDbl::operator=(float delay)
{
mean_ = delay;
sigma2_[early_index] = 0.0;
sigma2_[late_index] = 0.0;
}
void
DelayDbl::operator+=(const Delay &delay)
{
mean_ += delay.mean_;
sigma2_[early_index] += delay.sigma2_[early_index];
sigma2_[late_index] += delay.sigma2_[late_index];
}
void
DelayDbl::operator-=(const Delay &delay)
{
mean_ -= delay.mean_;
sigma2_[early_index] += delay.sigma2_[early_index];
sigma2_[late_index] += delay.sigma2_[late_index];
}
////////////////////////////////////////////////////////////////
Delay
makeDelay(float delay,
float sigma_early,
float sigma_late)
{
return Delay(delay, square(sigma_early), square(sigma_late));
}
Delay
makeDelay2(float delay,
float sigma2_early,
float sigma2_late)
{
return Delay(delay, sigma2_early, sigma2_late);
}
bool
delayIsInitValue(const Delay &delay,
const MinMax *min_max)
{
return fuzzyEqual(delay.mean(), min_max->initValue())
&& fuzzyZero(delay.sigma2Early())
&& fuzzyZero(delay.sigma2Late());
}
bool
delayZero(const Delay &delay)
{
return fuzzyZero(delay.mean())
&& fuzzyZero(delay.sigma2Early())
&& fuzzyZero(delay.sigma2Late());
}
bool
delayInf(const Delay &delay)
{
return fuzzyInf(delay.mean());
}
bool
delayEqual(const Delay &delay1,
const Delay &delay2)
{
return fuzzyEqual(delay1.mean(), delay2.mean())
&& fuzzyEqual(delay1.sigma2Early(), delay2.sigma2Early())
&& fuzzyEqual(delay1.sigma2Late(), delay2.sigma2Late());
}
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const StaState *sta)
{
return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta),
delayAsFloat(delay2, EarlyLate::early(), sta));
}
bool
delayLess(const Delay &delay1,
float delay2,
const StaState *sta)
{
return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta),
delay2);
}
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
{
if (min_max == MinMax::max())
return delayLess(delay1, delay2, sta);
else
return delayGreater(delay1, delay2, sta);
}
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta)
{
return fuzzyLessEqual(delayAsFloat(delay1, EarlyLate::early(), sta),
delayAsFloat(delay2, EarlyLate::early(), sta));
}
bool
delayLessEqual(const Delay &delay1,
float delay2,
const StaState *sta)
{
return fuzzyLessEqual(delayAsFloat(delay1, EarlyLate::early(), sta),
delay2);
}
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
{
if (min_max == MinMax::max())
return delayLessEqual(delay1, delay2, sta);
else
return delayGreaterEqual(delay1, delay2, sta);
}
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const StaState *sta)
{
return fuzzyGreater(delayAsFloat(delay1, EarlyLate::late(), sta),
delayAsFloat(delay2, EarlyLate::late(), sta));
}
bool
delayGreater(const Delay &delay1,
float delay2,
const StaState *sta)
{
return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta),
delayAsFloat(delay2, EarlyLate::late(), sta));
}
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta)
{
return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta),
delayAsFloat(delay2, EarlyLate::late(), sta));
}
bool
delayGreaterEqual(const Delay &delay1,
float delay2,
const StaState *sta)
{
return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta),
delay2);
}
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
{
if (min_max == MinMax::max())
return delayGreater(delay1, delay2, sta);
else
return delayLess(delay1, delay2, sta);
}
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
{
if (min_max == MinMax::max())
return delayGreaterEqual(delay1, delay2, sta);
else
return delayLessEqual(delay1, delay2, sta);
}
float
delayAsFloat(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta)
{
if (sta->pocvEnabled()) {
if (early_late == EarlyLate::early())
return delay.mean() - delay.sigma(early_late) * sta->sigmaFactor();
else if (early_late == EarlyLate::late())
return delay.mean() + delay.sigma(early_late) * sta->sigmaFactor();
else
sta->report()->critical(1030, "unknown early/late value.");
}
return delay.mean();
}
float
delaySigma2(const Delay &delay,
const EarlyLate *early_late)
{
return delay.sigma2(early_late);
}
const char *
delayAsString(const Delay &delay,
const StaState *sta)
{
return delayAsString(delay, sta, sta->units()->timeUnit()->digits());
}
const char *
delayAsString(const Delay &delay,
const StaState *sta,
int digits)
{
const Unit *unit = sta->units()->timeUnit();
if (sta->pocvEnabled()) {
float sigma_early = delay.sigma(EarlyLate::early());
float sigma_late = delay.sigma(EarlyLate::late());
return stringPrintTmp("%s[%s:%s]",
unit->asString(delay.mean(), digits),
unit->asString(sigma_early, digits),
unit->asString(sigma_late, digits));
}
else
return unit->asString(delay.mean(), digits);
}
const char *
delayAsString(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta,
int digits)
{
float mean_sigma = delayAsFloat(delay, early_late, sta);
return sta->units()->timeUnit()->asString(mean_sigma, digits);
}
Delay
delayRemove(const Delay &delay1,
const Delay &delay2)
{
return Delay(delay1.mean() - delay2.mean(),
delay1.sigma2Early() - delay2.sigma2Early(),
delay1.sigma2Late() - delay2.sigma2Late());
}
float
delayRatio(const Delay &delay1,
const Delay &delay2)
{
return delay1.mean() / delay2.mean();
}
Delay
operator+(float delay1,
const Delay &delay2)
{
return Delay(delay1 + delay2.mean(),
delay2.sigma2Early(),
delay2.sigma2Late());
}
Delay
operator/(float delay1,
const Delay &delay2)
{
return Delay(delay1 / delay2.mean(),
delay2.sigma2Early(),
delay2.sigma2Late());
}
Delay
operator*(const Delay &delay1,
float delay2)
{
return Delay(delay1.mean() * delay2,
delay1.sigma2Early() * delay2 * delay2,
delay1.sigma2Late() * delay2 * delay2);
}
} // namespace
#endif // (SSTA == 2)

View File

@ -36,6 +36,7 @@
#include "PortDirection.hh"
#include "Network.hh"
#include "FuncExpr.hh"
#include "Variables.hh"
namespace sta {
@ -46,12 +47,10 @@ namespace sta {
////////////////////////////////////////////////////////////////
Graph::Graph(StaState *sta,
int slew_rf_count,
DcalcAPIndex ap_count) :
StaState(sta),
vertices_(nullptr),
edges_(nullptr),
slew_rf_count_(slew_rf_count),
ap_count_(ap_count),
period_check_annotations_(nullptr),
reg_clk_vertices_(makeVertexSet(this))
@ -583,15 +582,31 @@ Graph::slew(const Vertex *vertex,
const RiseFall *rf,
DcalcAPIndex ap_index)
{
if (slew_rf_count_) {
const Slew *slews = vertex->slews();
size_t slew_index = (slew_rf_count_ == 1)
? ap_index
: ap_index*slew_rf_count_+rf->index();
size_t slew_index = ap_index * RiseFall::index_count + rf->index();
const float *slews_flt = vertex->slewsFloat();
if (variables_->pocvEnabled()) {
const Slew *slews = std::bit_cast<const Slew*>(slews_flt);
return slews[slew_index];
}
else {
static Slew slew(0.0);
static Slew slew;
slew = slews_flt[slew_index];
return slew;
}
}
const Slew &
Graph::slew(const Vertex *vertex,
size_t index)
{
const float *slews_flt = vertex->slewsFloat();
if (variables_->pocvEnabled()) {
const Slew *slews = std::bit_cast<const Slew*>(slews_flt);
return slews[index];
}
else {
static Slew slew;
slew = slews_flt[index];
return slew;
}
}
@ -602,18 +617,15 @@ Graph::setSlew(Vertex *vertex,
DcalcAPIndex ap_index,
const Slew &slew)
{
if (slew_rf_count_) {
size_t slew_index = ap_index * RiseFall::index_count + rf->index();
if (variables_->pocvEnabled()) {
Slew *slews = vertex->slews();
if (slews == nullptr) {
int slew_count = slew_rf_count_ * ap_count_;
slews = new Slew[slew_count];
vertex->setSlews(slews);
}
size_t slew_index = (slew_rf_count_ == 1)
? ap_index
: ap_index*slew_rf_count_+rf->index();
slews[slew_index] = slew;
}
else {
float *slews_flt = vertex->slewsFloat();
slews_flt[slew_index] = slew.mean();
}
}
////////////////////////////////////////////////////////////////
@ -665,25 +677,39 @@ Graph::deleteEdge(Edge *edge)
edges_->destroy(edge);
}
ArcDelay
const ArcDelay &
Graph::arcDelay(const Edge *edge,
const TimingArc *arc,
DcalcAPIndex ap_index) const
{
ArcDelay *delays = edge->arcDelays();
size_t index = arc->index() * ap_count_ + ap_index;
return delays[index];
if (variables_->pocvEnabled()) {
ArcDelay *delays = std::bit_cast<ArcDelay*>(edge->arcDelays());
return delays[index];
}
else {
const float *delays = edge->arcDelays();
static ArcDelay delay;
delay = delays[index];
return delay;
}
}
void
Graph::setArcDelay(Edge *edge,
const TimingArc *arc,
DcalcAPIndex ap_index,
ArcDelay delay)
const ArcDelay &delay)
{
ArcDelay *arc_delays = edge->arcDelays();
size_t index = arc->index() * ap_count_ + ap_index;
arc_delays[index] = delay;
if (variables_->pocvEnabled()) {
ArcDelay *delays = std::bit_cast<ArcDelay*>(edge->arcDelays());
delays[index] = delay;
}
else {
float *delays = edge->arcDelays();
delays[index] = delay.mean();
}
}
const ArcDelay &
@ -691,9 +717,17 @@ Graph::wireArcDelay(const Edge *edge,
const RiseFall *rf,
DcalcAPIndex ap_index)
{
ArcDelay *delays = edge->arcDelays();
size_t index = rf->index() * ap_count_ + ap_index;
return delays[index];
if (variables_->pocvEnabled()) {
ArcDelay *delays = std::bit_cast<ArcDelay*>(edge->arcDelays());
return delays[index];
}
else {
const float *delays = edge->arcDelays();
static ArcDelay delay;
delay = delays[index];
return delay;
}
}
void
@ -702,9 +736,15 @@ Graph::setWireArcDelay(Edge *edge,
DcalcAPIndex ap_index,
const ArcDelay &delay)
{
ArcDelay *delays = edge->arcDelays();
size_t index = rf->index() * ap_count_ + ap_index;
delays[index] = delay;
if (variables_->pocvEnabled()) {
ArcDelay *delays = std::bit_cast<ArcDelay*>(edge->arcDelays());
delays[index] = delay;
}
else {
float *delays = edge->arcDelays();
delays[index] = delay.mean();
}
}
////////////////////////////////////////////////////////////////
@ -788,16 +828,20 @@ void
Graph::initSlews(Vertex *vertex)
{
size_t slew_count = slewCount();
Slew *slews = new Slew[slew_count];
vertex->setSlews(slews);
for (size_t i = 0; i < slew_count; i++)
slews[i] = 0.0;
if (variables_->pocvEnabled()) {
float *slews = std::bit_cast<float*>(new Slew[slew_count]{});
vertex->setSlews(slews);
}
else {
float *slews = new float[slew_count]{};
vertex->setSlews(slews);
}
}
size_t
Graph::slewCount()
{
return slew_rf_count_ * ap_count_;
return RiseFall::index_count * ap_count_;
}
void
@ -805,10 +849,14 @@ Graph::initArcDelays(Edge *edge)
{
size_t arc_count = edge->timingArcSet()->arcCount();
size_t delay_count = arc_count * ap_count_;
ArcDelay *arc_delays = new ArcDelay[delay_count];
edge->setArcDelays(arc_delays);
for (size_t i = 0; i < delay_count; i++)
arc_delays[i] = 0.0;
if (variables_->pocvEnabled()) {
float *delays = std::bit_cast<float*>(new ArcDelay[delay_count]{});
edge->setArcDelays(delays);
}
else {
float *delays = new float[delay_count]{};
edge->setArcDelays(delays);
}
}
////////////////////////////////////////////////////////////////
@ -1040,7 +1088,7 @@ Vertex::setVisited2(bool visited)
}
void
Vertex::setSlews(Slew *slews)
Vertex::setSlews(float *slews)
{
delete [] slews_;
slews_ = slews;
@ -1251,10 +1299,10 @@ Edge::setTimingArcSet(TimingArcSet *set)
}
void
Edge::setArcDelays(ArcDelay *arc_delays)
Edge::setArcDelays(float *delays)
{
delete [] arc_delays_;
arc_delays_ = arc_delays;
arc_delays_ = delays;
}
bool

View File

@ -132,21 +132,24 @@ bool is_bidirect_driver() { return self->isBidirectDriver(); }
int level() { return Sta::sta()->vertexLevel(self); }
int tag_group_index() { return self->tagGroupIndex(); }
Slew
float
slew(const RiseFallBoth *rf,
const MinMax *min_max)
{
Sta *sta = Sta::sta();
return sta->slew(self, rf, sta->scenes(), min_max);
return delayAsFloat(sta->slew(self, rf, sta->scenes(), min_max), min_max, sta);
}
Slew
slew_scenes(const RiseFallBoth *rf,
const SceneSeq scenes,
const MinMax *min_max)
std::string
slew_scenes_string(const RiseFallBoth *rf,
const SceneSeq scenes,
const MinMax *min_max,
bool report_variance,
int digits)
{
Sta *sta = Sta::sta();
return sta->slew(self, rf, scenes, min_max);
Slew slew = sta->slew(self, rf, scenes, min_max);
return delayAsString(slew, min_max, report_variance, digits, sta);
}
VertexOutEdgeIterator *
@ -223,22 +226,29 @@ arc_delays(TimingArc *arc)
{
Sta *sta = Sta::sta();
FloatSeq delays;
DcalcAPIndex ap_count = sta->dcalcAnalysisPtCount();
for (DcalcAPIndex ap_index = 0; ap_index < ap_count; ap_index++)
delays.push_back(delayAsFloat(sta->arcDelay(self, arc, ap_index)));
for (Scene *scene : sta->scenes()) {
for (const MinMax *min_max : MinMax::range()) {
DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max);
delays.push_back(delayAsFloat(sta->arcDelay(self, arc, ap_index), min_max, sta));
}
}
return delays;
}
StringSeq
arc_delay_strings(TimingArc *arc,
bool report_variance,
int digits)
{
Sta *sta = Sta::sta();
StringSeq delays;
DcalcAPIndex ap_count = sta->dcalcAnalysisPtCount();
for (DcalcAPIndex ap_index = 0; ap_index < ap_count; ap_index++)
delays.push_back(delayAsString(sta->arcDelay(self, arc, ap_index),
sta, digits));
for (Scene *scene : sta->scenes()) {
for (const MinMax *min_max : MinMax::range()) {
DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max);
delays.push_back(delayAsString(sta->arcDelay(self, arc, ap_index),
min_max, report_variance, digits, sta));
}
}
return delays;
}
@ -255,8 +265,9 @@ arc_delay(TimingArc *arc,
const Scene *scene,
const MinMax *min_max)
{
Sta *sta = Sta::sta();
DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max);
return delayAsFloat(Sta::sta()->arcDelay(self, arc, ap_index));
return delayAsFloat(Sta::sta()->arcDelay(self, arc, ap_index), min_max, sta);
}
std::string

View File

@ -26,51 +26,64 @@
namespace eval sta {
define_cmd_args "report_edges" {[-from from_pin] [-to to_pin]}
define_cmd_args "report_edges" {[-from from_pin] [-to to_pin]\
[-digits digits] [-report_variance]}
proc report_edges { args } {
parse_key_args "report_edges" args keys {-from -to} flags {}
global sta_report_default_digits
parse_key_args "report_edges" args keys {-from -to -digits} flags {-report_variance}
check_argc_eq0 "report_edges" $args
if [info exists keys(-digits)] {
set digits $keys(-digits)
check_positive_integer "-digits" $digits
} else {
set digits $sta_report_default_digits
}
set report_variance [info exists flags(-report_variance)]
if { [info exists keys(-from)] && [info exists keys(-to)] } {
set from_pin [get_port_pin_error "from_pin" $keys(-from)]
set to_pin [get_port_pin_error "to_pin" $keys(-to)]
foreach from_vertex [$from_pin vertices] {
foreach to_vertex [$to_pin vertices] {
report_edges_between_ $from_vertex $to_vertex
report_edges_between_ $from_vertex $to_vertex $digits $report_variance
}
}
} elseif [info exists keys(-from)] {
set from_pin [get_port_pin_error "from_pin" $keys(-from)]
foreach from_vertex [$from_pin vertices] {
report_edges_ $from_vertex out_edge_iterator \
vertex_port_name vertex_path_name
vertex_port_name vertex_path_name $digits $report_variance
}
} elseif [info exists keys(-to)] {
set to_pin [get_port_pin_error "to_pin" $keys(-to)]
foreach to_vertex [$to_pin vertices] {
report_edges_ $to_vertex in_edge_iterator \
vertex_path_name vertex_port_name
vertex_path_name vertex_port_name $digits $report_variance
}
}
}
proc report_edges_between_ { from_vertex to_vertex } {
proc report_edges_between_ { from_vertex to_vertex digits report_variance } {
set iter [$from_vertex out_edge_iterator]
while {[$iter has_next]} {
set edge [$iter next]
if { [$edge to] == $to_vertex } {
if { [$edge role] == "wire" } {
report_edge_ $edge vertex_path_name vertex_path_name
report_edge_ $edge vertex_path_name vertex_path_name $digits $report_variance
} else {
report_edge_ $edge vertex_port_name vertex_port_name
report_edge_ $edge vertex_port_name vertex_port_name $digits $report_variance
}
}
}
$iter finish
}
proc report_edges_ { vertex iter_proc wire_from_name_proc wire_to_name_proc } {
proc report_edges_ { vertex iter_proc wire_from_name_proc wire_to_name_proc \
digits report_variance } {
# First report edges internal to the device.
set device_header 0
set iter [$vertex $iter_proc]
@ -84,7 +97,7 @@ proc report_edges_ { vertex iter_proc wire_from_name_proc wire_to_name_proc } {
}
set device_header 1
}
report_edge_ $edge vertex_port_name vertex_port_name
report_edge_ $edge vertex_port_name vertex_port_name $digits $report_variance
}
}
$iter finish
@ -94,15 +107,14 @@ proc report_edges_ { vertex iter_proc wire_from_name_proc wire_to_name_proc } {
while {[$iter has_next]} {
set edge [$iter next]
if { [$edge role] == "wire" } {
report_edge_ $edge $wire_from_name_proc $wire_to_name_proc
report_edge_ $edge $wire_from_name_proc $wire_to_name_proc $digits $report_variance
}
}
$iter finish
}
proc report_edge_ { edge vertex_from_name_proc vertex_to_name_proc } {
global sta_report_default_digits
proc report_edge_ { edge vertex_from_name_proc vertex_to_name_proc \
digits report_variance } {
set latch_enable [$edge latch_d_to_q_en]
if { $latch_enable != "" } {
set latch_enable " enable $latch_enable"
@ -125,7 +137,7 @@ proc report_edge_ { edge vertex_from_name_proc vertex_to_name_proc } {
}
foreach arc [$edge timing_arcs] {
set delays [$edge arc_delay_strings $arc $sta_report_default_digits]
set delays [$edge arc_delay_strings $arc $report_variance $digits]
set delays_fmt [format_delays $delays]
set disable_reason ""
if { [timing_arc_disabled $edge $arc] } {
@ -135,18 +147,6 @@ proc report_edge_ { edge vertex_from_name_proc vertex_to_name_proc } {
}
}
# Separate list elements with colons.
proc format_times { values digits } {
set result ""
foreach value $values {
if { $result != "" } {
append result ":"
}
append result [format_time $value $digits]
}
return $result
}
# Separate delay list elements with colons.
proc format_delays { values } {
set result ""

View File

@ -119,15 +119,15 @@ public:
ArcDcalcResult(size_t load_count);
void setLoadCount(size_t load_count);
ArcDelay &gateDelay() { return gate_delay_; }
void setGateDelay(ArcDelay gate_delay);
void setGateDelay(const ArcDelay &gate_delay);
Slew &drvrSlew() { return drvr_slew_; }
void setDrvrSlew(Slew drvr_slew);
ArcDelay wireDelay(size_t load_idx) const;
void setDrvrSlew(const Slew &drvr_slew);
const ArcDelay &wireDelay(size_t load_idx) const;
void setWireDelay(size_t load_idx,
ArcDelay wire_delay);
Slew loadSlew(size_t load_idx) const;
const ArcDelay &wire_delay);
const Slew &loadSlew(size_t load_idx) const;
void setLoadSlew(size_t load_idx,
Slew load_slew);
const Slew &load_slew);
protected:
ArcDelay gate_delay_;

View File

@ -24,27 +24,326 @@
#pragma once
#include "StaConfig.hh"
#include <array>
#include <cstddef>
// IWYU pragma: begin_exports
#if (SSTA == 1)
// Delays are Normal PDFs.
#include "DelayNormal1.hh"
#elif (SSTA == 2)
// Delays are Normal PDFs with early/late sigma.
#include "DelayNormal2.hh"
#else
// Delays are floats.
#include "DelayFloat.hh"
#endif
// IWYU pragma: end_exports
#include "StaConfig.hh"
#include "MinMax.hh"
namespace sta {
class StaState;
class Delay
{
public:
Delay();
Delay(float mean);
Delay(float mean,
// std_dev^2
float std_dev2);
Delay(float mean,
float mean_shift,
// std_dev^2
float std_dev2,
float skewness);
void setValues(float mean,
float mean_shift,
float std_dev2,
float skewnes);
float mean() const { return values_[0]; }
void setMean(float mean);
float meanShift() const { return values_[1]; }
void setMeanShift(float mean_shift);
float stdDev() const;
// std_dev ^ 2
float stdDev2() const { return values_[2]; }
void setStdDev(float std_dev);
float skewness() const { return values_[3]; }
void setSkewness(float skewness);
void operator=(float delay);
private:
std::array<float, 4> values_;
};
// Delay with doubles for accumulating Delays.
// Only a subset of operations are required for DelayDbl.
class DelayDbl
{
public:
DelayDbl();
DelayDbl(double value);
double mean() const { return values_[0]; }
void setMean(double mean);
double meanShift() const { return values_[1]; }
// std_dev ^ 2
double stdDev2() const { return values_[2]; }
double stdDev() const;
double skewness() const { return values_[3]; }
void setValues(double mean,
double mean_shift,
double std_dev2,
double skewnes);
void operator=(double delay);
private:
std::array<double, 4> values_;
};
using ArcDelay = Delay;
using Slew = Delay;
using Arrival = Delay;
using Required = Delay;
using Slack = Delay;
const Delay delay_zero(0.0);
class DelayOps
{
public:
virtual ~DelayOps() {}
virtual float stdDev2(const Delay &delay,
const EarlyLate *early_late) const = 0;
virtual float asFloat(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta) const = 0;
virtual double asFloat(const DelayDbl &delay,
const EarlyLate *early_late,
const StaState *sta) const = 0;
virtual bool isZero(const Delay &delay) const = 0;
virtual bool isInf(const Delay &delay) const = 0;
virtual bool equal(const Delay &delay1,
const Delay &delay2,
const StaState *sta) const = 0;
virtual bool less(const Delay &delay1,
const Delay &delay2,
const StaState *sta) const = 0;
virtual bool less(const DelayDbl &delay1,
const DelayDbl &delay2,
const StaState *sta) const = 0;
virtual bool lessEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta) const = 0;
virtual bool greater(const Delay &delay1,
const Delay &delay2,
const StaState *sta) const = 0;
virtual bool greaterEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta) const = 0;
virtual Delay sum(const Delay &delay1,
const Delay &delay2) const = 0;
virtual Delay sum(const Delay &delay1,
float delay2) const = 0;
virtual Delay diff(const Delay &delay1,
const Delay &delay2) const = 0;
virtual Delay diff(const Delay &delay1,
float delay2) const = 0;
virtual Delay diff(float delay1,
const Delay &delay2) const = 0;
virtual void incr(Delay &delay1,
const Delay &delay2) const = 0;
virtual void incr(DelayDbl &delay1,
const Delay &delay2) const = 0;
virtual void decr(Delay &delay1,
const Delay &delay2) const = 0;
virtual void decr(DelayDbl &delay1,
const Delay &delay2) const = 0;
virtual Delay product(const Delay &delay1,
float delay2) const = 0;
virtual Delay div(float delay1,
const Delay &delay2) const = 0;
virtual const char *asStringVariance(const Delay &delay,
int digits,
const StaState *sta) const = 0;
};
void
initDelayConstants();
inline float
square(float x)
{
return x * x;
}
inline double
square(double x)
{
return x * x;
}
inline float
cube(float x)
{
return x * x * x;
}
inline double
cube(double x)
{
return x * x * x;
}
Delay
makeDelay(float mean,
float mean_shift,
float std_dev,
float skewness);
Delay
makeDelay(float mean,
float std_dev);
Delay
makeDelay2(float mean,
float std_dev);
void
delaySetMean(Delay &delay,
float mean);
const char *
delayAsString(const Delay &delay,
const StaState *sta);
const char *
delayAsString(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta);
const char *
delayAsString(const Delay &delay,
const EarlyLate *early_late,
int digits,
const StaState *sta);
const char *
delayAsString(const Delay &delay,
const EarlyLate *early_late,
bool report_variance,
int digits,
const StaState *sta);
float
delayAsFloat(const Delay &delay);
float
delayAsFloat(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta);
float
delayAsFloat(const DelayDbl &delay,
const EarlyLate *early_late,
const StaState *sta);
Delay
delayDblAsDelay(DelayDbl &delay);
Delay
delaySum(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
Delay
delaySum(const Delay &delay1,
float delay2,
const StaState *sta);
Delay
delayDiff(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
Delay
delayDiff(const Delay &delay1,
float delay2,
const StaState *sta);
Delay
delayDiff(float delay1,
const Delay &delay2,
const StaState *sta);
void
delayIncr(Delay &delay1,
const Delay &delay2,
const StaState *sta);
void
delayIncr(DelayDbl &delay1,
const Delay &delay2,
const StaState *sta);
void
delayIncr(Delay &delay1,
float delay2,
const StaState *sta);
void
delayDecr(Delay &delay1,
const Delay &delay2,
const StaState *sta);
void
delayDecr(DelayDbl &delay1,
const Delay &delay2,
const StaState *sta);
Delay
delayProduct(const Delay &delay1,
float delay2,
const StaState *sta);
Delay
delayDiv(float delay1,
const Delay &delay2,
const StaState *sta);
const Delay &
delayInitValue(const MinMax *min_max);
bool
delayIsInitValue(const Delay &delay,
const MinMax *min_max);
bool
delayZero(const Delay &delay,
const StaState *sta);
bool
delayInf(const Delay &delay,
const StaState *sta);
bool
delayEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
bool
delayLess(const DelayDbl &delay1,
const DelayDbl &delay2,
const StaState *sta);
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
// delay1-delay2 subtracting sigma instead of addiing.
Delay
delayRemove(const Delay &delay1,
const Delay &delay2);
} // namespace

View File

@ -1,152 +0,0 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2026, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// 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.
#pragma once
#include "MinMax.hh"
// Delay values defined as floats.
namespace sta {
class StaState;
using Delay = float;
// Delay double for accumulating Delays.
using DelayDbl = double;
const Delay delay_zero = 0.0;
void
initDelayConstants();
const char *
delayAsString(const Delay &delay,
const StaState *sta);
const char *
delayAsString(const Delay &delay,
const StaState *sta,
int digits);
const char *
delayAsString(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta,
int digits);
inline Delay
makeDelay(float delay,
float,
float)
{
return delay;
}
inline Delay
makeDelay2(float delay,
float,
float)
{
return delay;
}
inline float
delayAsFloat(const Delay &delay)
{
return delay;
}
// mean late+/early- sigma
inline float
delayAsFloat(const Delay &delay,
const EarlyLate *,
const StaState *)
{
return delay;
}
inline float
delaySigma2(const Delay &,
const EarlyLate *)
{
return 0.0;
}
const Delay &
delayInitValue(const MinMax *min_max);
bool
delayIsInitValue(const Delay &delay,
const MinMax *min_max);
bool
delayZero(const Delay &delay);
bool
delayInf(const Delay &delay);
bool
delayEqual(const Delay &delay1,
const Delay &delay2);
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
// delay1-delay2 subtracting sigma instead of addiing.
Delay
delayRemove(const Delay &delay1,
const Delay &delay2);
float
delayRatio(const Delay &delay1,
const Delay &delay2);
} // namespace

View File

@ -0,0 +1,90 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// 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.
#pragma once
#include "Delay.hh"
namespace sta {
class DelayOpsNormal : public DelayOps
{
public:
float stdDev2(const Delay &delay,
const EarlyLate *early_late) const override;
float asFloat(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta) const override;
double asFloat(const DelayDbl &delay,
const EarlyLate *early_late,
const StaState *sta) const override;
bool isZero(const Delay &delay) const override;
bool isInf(const Delay &delay) const override;
bool equal(const Delay &delay1,
const Delay &delay2,
const StaState *sta) const override;
bool less(const Delay &delay1,
const Delay &delay2,
const StaState *sta) const override;
bool less(const DelayDbl &delay1,
const DelayDbl &delay2,
const StaState *sta) const override;
bool lessEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta) const override;
bool greater(const Delay &delay1,
const Delay &delay2,
const StaState *sta) const override;
bool greaterEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta) const override;
Delay sum(const Delay &delay1,
const Delay &delay2) const override;
Delay sum(const Delay &delay1,
float delay2) const override;
Delay diff(const Delay &delay1,
const Delay &delay2) const override;
Delay diff(const Delay &delay1,
float delay2) const override;
Delay diff(float delay1,
const Delay &delay2) const override;
void incr(Delay &delay1,
const Delay &delay2) const override;
void incr(DelayDbl &delay1,
const Delay &delay2) const override;
void decr(Delay &delay1,
const Delay &delay2) const override;
void decr(DelayDbl &delay1,
const Delay &delay2) const override;
Delay product(const Delay &delay1,
float delay2) const override;
Delay div(float delay1,
const Delay &delay2) const override;
const char *asStringVariance(const Delay &delay,
int digits,
const StaState *sta) const override;
};
} // namespace

View File

@ -1,203 +0,0 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2026, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// 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.
#pragma once
#include "MinMax.hh"
namespace sta {
class Delay;
class DelayDbl;
class StaState;
// Normal distribution with std deviation.
class Delay
{
public:
Delay();
Delay(const Delay &delay);
Delay(const DelayDbl &delay);
Delay(float mean);
Delay(float mean,
float sigma2);
float mean() const { return mean_; }
float sigma() const;
// sigma^2
float sigma2() const;
void operator=(const Delay &delay);
void operator=(float delay);
void operator+=(const Delay &delay);
void operator+=(float delay);
Delay operator+(const Delay &delay) const;
Delay operator+(float delay) const;
Delay operator-(const Delay &delay) const;
Delay operator-(float delay) const;
Delay operator-() const;
void operator-=(float delay);
void operator-=(const Delay &delay);
bool operator==(const Delay &delay) const;
private:
float mean_;
// Sigma^2
float sigma2_;
friend class DelayDbl;
};
// Dwlay with doubles for accumulating delays.
class DelayDbl
{
public:
DelayDbl();
float mean() const { return mean_; }
float sigma() const;
// sigma^2
float sigma2() const;
void operator=(float delay);
void operator+=(const Delay &delay);
void operator-=(const Delay &delay);
private:
double mean_;
// Sigma^2
double sigma2_;
friend class Delay;
};
const Delay delay_zero(0.0);
void
initDelayConstants();
const char *
delayAsString(const Delay &delay,
const StaState *sta);
const char *
delayAsString(const Delay &delay,
const StaState *sta,
int digits);
const char *
delayAsString(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta,
int digits);
Delay
makeDelay(float delay,
float sigma_early,
float sigma_late);
Delay
makeDelay2(float delay,
// sigma^2
float sigma_early,
float sigma_late);
inline float
delayAsFloat(const Delay &delay)
{
return delay.mean();
}
// mean late+/early- sigma
float
delayAsFloat(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta);
float
delaySigma2(const Delay &delay,
const EarlyLate *early_late);
const Delay &
delayInitValue(const MinMax *min_max);
bool
delayIsInitValue(const Delay &delay,
const MinMax *min_max);
bool
delayZero(const Delay &delay);
bool
delayInf(const Delay &delay);
bool
delayEqual(const Delay &delay1,
const Delay &delay2);
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
// delay1-delay2 subtracting sigma instead of addiing.
Delay delayRemove(const Delay &delay1,
const Delay &delay2);
float
delayRatio(const Delay &delay1,
const Delay &delay2);
// Most non-operator functions on Delay are not defined as member
// functions so they can be defined on floats, where there is no class
// to define them.
Delay operator+(float delay1,
const Delay &delay2);
// Used for parallel gate delay calc.
Delay operator/(float delay1,
const Delay &delay2);
// Used for parallel gate delay calc.
Delay operator*(const Delay &delay1,
float delay2);
} // namespace

View File

@ -1,214 +0,0 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2026, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// 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.
#pragma once
#include "MinMax.hh"
namespace sta {
class Delay;
class DelayDbl;
class StaState;
// Normal distribution with early(left)/late(right) std deviations.
class Delay
{
public:
Delay();
Delay(const Delay &delay);
Delay(const DelayDbl &delay);
Delay(float mean);
Delay(float mean,
float sigma2_early,
float sigma2_late);
float mean() const { return mean_; }
float sigma(const EarlyLate *early_late) const;
// sigma^2
float sigma2(const EarlyLate *early_late) const;
float sigma2Early() const;
float sigma2Late() const;
void operator=(const Delay &delay);
void operator=(float delay);
void operator+=(const Delay &delay);
void operator+=(float delay);
Delay operator+(const Delay &delay) const;
Delay operator+(float delay) const;
Delay operator-(const Delay &delay) const;
Delay operator-(float delay) const;
Delay operator-() const;
void operator-=(float delay);
void operator-=(const Delay &delay);
bool operator==(const Delay &delay) const;
protected:
static const int early_index = 0;
static const int late_index = 1;
private:
float mean_;
// Sigma^2
float sigma2_[EarlyLate::index_count];
friend class DelayDbl;
};
// Dwlay with doubles for accumulating delays.
class DelayDbl
{
public:
DelayDbl();
float mean() const { return mean_; }
float sigma() const;
// sigma^2
float sigma2() const;
void operator=(float delay);
void operator+=(const Delay &delay);
void operator-=(const Delay &delay);
protected:
static const int early_index = 0;
static const int late_index = 1;
private:
double mean_;
// Sigma^2
double sigma2_[EarlyLate::index_count];
friend class Delay;
};
const Delay delay_zero(0.0);
void
initDelayConstants();
const char *
delayAsString(const Delay &delay,
const StaState *sta);
const char *
delayAsString(const Delay &delay,
const StaState *sta,
int digits);
const char *
delayAsString(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta,
int digits);
Delay
makeDelay(float delay,
float sigma_early,
float sigma_late);
Delay
makeDelay2(float delay,
// sigma^2
float sigma_early,
float sigma_late);
inline float
delayAsFloat(const Delay &delay)
{
return delay.mean();
}
// mean late+/early- sigma
float
delayAsFloat(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta);
float
delaySigma2(const Delay &delay,
const EarlyLate *early_late);
const Delay &
delayInitValue(const MinMax *min_max);
bool
delayIsInitValue(const Delay &delay,
const MinMax *min_max);
bool
delayZero(const Delay &delay);
bool
delayInf(const Delay &delay);
bool
delayEqual(const Delay &delay1,
const Delay &delay2);
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
// delay1-delay2 subtracting sigma instead of addiing.
Delay delayRemove(const Delay &delay1,
const Delay &delay2);
float
delayRatio(const Delay &delay1,
const Delay &delay2);
// Most non-operator functions on Delay are not defined as member
// functions so they can be defined on floats, where there is no class
// to define them.
Delay operator+(float delay1,
const Delay &delay2);
// Used for parallel gate delay calc.
Delay operator/(float delay1,
const Delay &delay2);
// Used for parallel gate delay calc.
Delay operator*(const Delay &delay1,
float delay2);
} // namespace

View File

@ -0,0 +1,90 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// 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.
#pragma once
#include "Delay.hh"
namespace sta {
class DelayOpsScalar : public DelayOps
{
public:
float stdDev2(const Delay &delay,
const EarlyLate *early_late) const override;
float asFloat(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta) const override;
double asFloat(const DelayDbl &delay,
const EarlyLate *early_late,
const StaState *sta) const override;
bool isZero(const Delay &delay) const override;
bool isInf(const Delay &delay) const override;
bool equal(const Delay &delay1,
const Delay &delay2,
const StaState *sta) const override;
bool less(const Delay &delay1,
const Delay &delay2,
const StaState *sta) const override;
bool less(const DelayDbl &delay1,
const DelayDbl &delay2,
const StaState *sta) const override;
bool lessEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta) const override;
bool greater(const Delay &delay1,
const Delay &delay2,
const StaState *sta) const override;
bool greaterEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta) const override;
Delay sum(const Delay &delay1,
const Delay &delay2) const override;
Delay sum(const Delay &delay1,
float delay2) const override;
Delay diff(const Delay &delay1,
const Delay &delay2) const override;
Delay diff(const Delay &delay1,
float delay2) const override;
Delay diff(float delay1,
const Delay &delay2) const override;
void incr(Delay &delay1,
const Delay &delay2) const override;
void incr(DelayDbl &delay1,
const Delay &delay2) const override;
void decr(Delay &delay1,
const Delay &delay2) const override;
void decr(DelayDbl &delay1,
const Delay &delay2) const override;
Delay product(const Delay &delay1,
float delay2) const override;
Delay div(float delay1,
const Delay &delay2) const override;
const char *asStringVariance(const Delay &delay,
int digits,
const StaState *sta) const override;
};
} // namespace

View File

@ -0,0 +1,98 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// 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.
#pragma once
#include "Delay.hh"
namespace sta {
class DelayOpsSkewNormal : public DelayOps
{
public:
float stdDev2(const Delay &delay,
const EarlyLate *early_late) const override;
float asFloat(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta) const override;
double asFloat(const DelayDbl &delay,
const EarlyLate *early_late,
const StaState *sta) const override;
bool isZero(const Delay &delay) const override;
bool isInf(const Delay &delay) const override;
bool equal(const Delay &delay1,
const Delay &delay2,
const StaState *sta) const override;
bool less(const Delay &delay1,
const Delay &delay2,
const StaState *sta) const override;
bool less(const DelayDbl &delay1,
const DelayDbl &delay2,
const StaState *sta) const override;
bool lessEqual(const Delay &delay1,
const Delay &delay2,
const StaState *) const override;
bool greater(const Delay &delay1,
const Delay &delay2,
const StaState *) const override;
bool greaterEqual(const Delay &delay1,
const Delay &delay2,
const StaState *) const override;
Delay sum(const Delay &delay1,
const Delay &delay2) const override;
Delay sum(const Delay &delay1,
float delay2) const override;
Delay diff(const Delay &delay1,
const Delay &delay2) const override;
Delay diff(const Delay &delay1,
float delay2) const override;
Delay diff(float delay1,
const Delay &delay2) const override;
void incr(Delay &delay1,
const Delay &delay2) const override;
void incr(DelayDbl &delay1,
const Delay &delay2) const override;
void decr(Delay &delay1,
const Delay &delay2) const override;
void decr(DelayDbl &delay1,
const Delay &delay2) const override;
Delay product(const Delay &delay1,
float delay2) const override;
Delay div(float delay1,
const Delay &delay2) const override;
const char *asStringVariance(const Delay &delay,
int digits,
const StaState *sta) const override;
private:
float skewnessSum(const Delay &delay1,
const Delay &delay2) const;
double skewnessSum(double std_dev1,
double skewness1,
double std_dev2,
double skewness2) const;
};
} // namespace

View File

@ -58,13 +58,7 @@ static constexpr ObjectIdx vertex_idx_null = object_idx_null;
class Graph : public StaState
{
public:
// slew_rf_count is
// 0 no slews
// 1 one slew for rise/fall
// 2 rise/fall slews
// ap_count is the dcalc analysis point count.
Graph(StaState *sta,
int slew_rf_count,
DcalcAPIndex ap_count);
void makeGraph();
~Graph();
@ -100,6 +94,8 @@ public:
const Slew &slew(const Vertex *vertex,
const RiseFall *rf,
DcalcAPIndex ap_index);
const Slew &slew(const Vertex *vertex,
size_t index);
void setSlew(Vertex *vertex,
const RiseFall *rf,
DcalcAPIndex ap_index,
@ -128,13 +124,13 @@ public:
Edge *&edge,
const TimingArc *&arc) const;
ArcDelay arcDelay(const Edge *edge,
const TimingArc *arc,
DcalcAPIndex ap_index) const;
const ArcDelay &arcDelay(const Edge *edge,
const TimingArc *arc,
DcalcAPIndex ap_index) const;
void setArcDelay(Edge *edge,
const TimingArc *arc,
DcalcAPIndex ap_index,
ArcDelay delay);
const ArcDelay &delay);
// Alias for arcDelays using library wire arcs.
const ArcDelay &wireArcDelay(const Edge *edge,
const RiseFall *rf,
@ -222,7 +218,6 @@ protected:
// driver/source (top level input, instance pin output) vertex
// in pin_bidirect_drvr_vertex_map
PinVertexMap pin_bidirect_drvr_vertex_map_;
int slew_rf_count_;
DcalcAPIndex ap_count_;
// Sdf period check annotations.
PeriodCheckAnnotations *period_check_annotations_;
@ -258,8 +253,6 @@ public:
[[nodiscard]] bool isRoot() const{ return level_ == 0; }
[[nodiscard]] bool hasFanin() const;
[[nodiscard]] bool hasFanout() const;
Slew *slews() { return slews_; }
const Slew *slews() const { return slews_; }
Path *paths() const { return paths_; }
Path *makePaths(uint32_t count);
void setPaths(Path *paths);
@ -298,14 +291,18 @@ protected:
bool is_bidirect_drvr,
bool is_reg_clk);
void clear();
void setSlews(Slew *slews);
Slew *slews() { return std::bit_cast<Slew*>(slews_); }
const Slew *slews() const { return std::bit_cast<const Slew*>(slews_); }
float *slewsFloat() { return slews_; }
const float *slewsFloat() const { return slews_; }
void setSlews(float *slews);
Pin *pin_;
EdgeId in_edges_; // Edges to this vertex.
EdgeId out_edges_; // Edges from this vertex.
// Delay calc
Slew *slews_;
float *slews_;
// Search
Path *paths_;
@ -356,8 +353,9 @@ public:
TimingSense sense() const;
TimingArcSet *timingArcSet() const { return arc_set_; }
void setTimingArcSet(TimingArcSet *set);
ArcDelay *arcDelays() const { return arc_delays_; }
void setArcDelays(ArcDelay *arc_delays);
float *arcDelays() { return arc_delays_; }
const float *arcDelays() const { return arc_delays_; }
void setArcDelays(float *delays);
bool delay_Annotation_Is_Incremental() const {return delay_annotation_is_incremental_;};
void setDelayAnnotationIsIncremental(bool is_incr);
// Edge is disabled to break combinational loops.
@ -398,7 +396,7 @@ protected:
EdgeId vertex_in_link_; // Vertex in edges list.
EdgeId vertex_out_next_; // Vertex out edges doubly linked list.
EdgeId vertex_out_prev_;
ArcDelay *arc_delays_;
float *arc_delays_;
union {
uintptr_t bits_;
std::vector<bool> *seq_;

View File

@ -245,8 +245,8 @@ protected:
bool annotateDelaySlew(Edge *edge,
const TimingArc *arc,
ArcDelay &gate_delay,
Slew &gate_slew,
const ArcDelay &gate_delay,
const Slew &gate_slew,
const Scene *scene,
const MinMax *min_max);
bool annotateLoadDelays(Vertex *drvr_vertex,

View File

@ -33,44 +33,11 @@
namespace sta {
class InternalPowerModel;
using InternalPowerModels =
std::array<std::shared_ptr<InternalPowerModel>, RiseFall::index_count>;
class InternalPower
{
public:
InternalPower(LibertyPort *port,
LibertyPort *related_port,
LibertyPort *related_pg_pin,
const std::shared_ptr<FuncExpr> &when,
InternalPowerModels &models);
//InternalPower(InternalPower &&other) noexcept;
LibertyCell *libertyCell() const;
LibertyPort *port() const { return port_; }
LibertyPort *relatedPort() const { return related_port_; }
FuncExpr *when() const { return when_.get(); }
LibertyPort *relatedPgPin() const { return related_pg_pin_; }
float power(const RiseFall *rf,
const Pvt *pvt,
float in_slew,
float load_cap) const;
const InternalPowerModel *model(const RiseFall *rf) const;
protected:
LibertyPort *port_;
LibertyPort *related_port_;
LibertyPort *related_pg_pin_;
std::shared_ptr<FuncExpr> when_;
InternalPowerModels models_;
};
class InternalPowerModel
{
public:
InternalPowerModel(TableModel *model);
~InternalPowerModel();
InternalPowerModel();
InternalPowerModel(std::shared_ptr<TableModel> model);
float power(const LibertyCell *cell,
const Pvt *pvt,
float in_slew,
@ -80,7 +47,7 @@ public:
float in_slew,
float load_cap,
int digits) const;
const TableModel *model() const { return model_; }
const TableModel *model() const { return model_.get(); }
protected:
void findAxisValues(float in_slew,
@ -95,7 +62,36 @@ protected:
bool checkAxes(const TableModel *model);
bool checkAxis(const TableAxis *axis);
TableModel *model_;
std::shared_ptr<TableModel> model_;
};
using InternalPowerModels = std::array<InternalPowerModel, RiseFall::index_count>;
class InternalPower
{
public:
InternalPower(LibertyPort *port,
LibertyPort *related_port,
LibertyPort *related_pg_pin,
const std::shared_ptr<FuncExpr> &when,
const InternalPowerModels &models);
LibertyCell *libertyCell() const;
LibertyPort *port() const { return port_; }
LibertyPort *relatedPort() const { return related_port_; }
FuncExpr *when() const { return when_.get(); }
LibertyPort *relatedPgPin() const { return related_pg_pin_; }
float power(const RiseFall *rf,
const Pvt *pvt,
float in_slew,
float load_cap) const;
const InternalPowerModel &model(const RiseFall *rf) const;
protected:
LibertyPort *port_;
LibertyPort *related_port_;
LibertyPort *related_pg_pin_;
std::shared_ptr<FuncExpr> when_;
InternalPowerModels models_;
};
} // namespace

View File

@ -589,7 +589,7 @@ public:
LibertyPort *related_port,
LibertyPort *related_pg_pin,
const std::shared_ptr<FuncExpr> &when,
InternalPowerModels &models);
const InternalPowerModels &models);
void makeLeakagePower(LibertyPort *related_pg_port,
FuncExpr *when,
float power);

View File

@ -37,14 +37,22 @@ public:
void gateDelay(const Pvt *pvt,
float in_slew,
float load_cap,
bool pocv_enabled,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew) const override;
float &gate_delay,
float &drvr_slew) const override;
void gateDelayPocv(const Pvt *pvt,
float in_slew,
float load_cap,
const MinMax *min_max,
PocvMode pocv_mode,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew) const override;
std::string reportGateDelay(const Pvt *pvt,
float in_slew,
float load_cap,
bool pocv_enabled,
const MinMax *min_max,
PocvMode pocv_mode,
int digits) const override;
float driveResistance(const Pvt *pvt) const override;
@ -64,13 +72,15 @@ public:
float from_slew,
float to_slew,
float related_out_cap,
bool pocv_enabled) const override;
const MinMax *min_max,
PocvMode pocv_mode) const override;
std::string reportCheckDelay(const Pvt *pvt,
float from_slew,
const char *from_slew_annotation,
float to_slew,
float related_out_cap,
bool pocv_enabled,
const MinMax *min_max,
PocvMode pocv_mode,
int digits) const override;
protected:

View File

@ -45,14 +45,14 @@ public:
const StaState *sta);
Path(Vertex *vertex,
Tag *tag,
Arrival arrival,
const Arrival &arrival,
Path *prev_path,
Edge *prev_edge,
TimingArc *prev_arc,
const StaState *sta);
Path(Vertex *vertex,
Tag *tag,
Arrival arrival,
const Arrival &arrival,
Path *prev_path,
Edge *prev_edge,
TimingArc *prev_arc,
@ -62,11 +62,11 @@ public:
bool isNull() const;
// prev_path null
void init(Vertex *vertex,
Arrival arrival,
const Arrival &arrival,
const StaState *sta);
void init(Vertex *vertex,
Tag *tag,
Arrival arrival,
const Arrival &arrival,
Path *prev_path,
Edge *prev_edge,
TimingArc *prev_arc,
@ -76,7 +76,7 @@ public:
const StaState *sta);
void init(Vertex *vertex,
Tag *tag,
Arrival arrival,
const Arrival &arrival,
const StaState *sta);
Vertex *vertex(const StaState *sta) const;
@ -98,14 +98,12 @@ public:
const MinMax *minMax(const StaState *sta) const;
PathAPIndex pathAnalysisPtIndex(const StaState *sta) const;
DcalcAPIndex dcalcAnalysisPtIndex(const StaState *sta) const;
Arrival &arrival() { return arrival_; }
const Arrival &arrival() const { return arrival_; }
void setArrival(Arrival arrival);
Required &required() { return required_; }
const Required &required() const {return required_; }
void setRequired(const Required &required);
Slack slack(const StaState *sta) const;
Slew slew(const StaState *sta) const;
const Slew &slew(const StaState *sta) const;
// This takes the same time as prevPath and prevArc combined.
Path *prevPath() const;
void setPrevPath(Path *prev_path);

View File

@ -98,7 +98,7 @@ public:
virtual const char *typeName() const = 0;
virtual int exceptPathCmp(const PathEnd *path_end,
const StaState *sta) const;
virtual Arrival dataArrivalTime(const StaState *sta) const;
virtual const Arrival &dataArrivalTime(const StaState *sta) const;
// Arrival time with source clock offset.
Arrival dataArrivalTimeOffset(const StaState *sta) const;
virtual Required requiredTime(const StaState *sta) const = 0;

View File

@ -22,19 +22,15 @@
//
// This notice may not be removed or altered from any source distribution.
#include "Machine.hh"
#include "StringUtil.hh"
#include "Units.hh"
#include "StaState.hh"
#include "Delay.hh"
#pragma once
namespace sta {
enum class PocvMode { scalar, normal, skew_normal };
const char *
delayAsString(const Delay &delay,
const StaState *sta)
{
return delayAsString(delay, sta, sta->units()->timeUnit()->digits());
}
pocvModeName(PocvMode mode);
PocvMode
findPocvMode(const char *mode_name);
} // namespace

View File

@ -982,11 +982,11 @@ public:
bool report_cap,
bool report_slew,
bool report_fanout,
bool report_variation,
bool report_src_attr);
ReportField *findReportPathField(const char *name);
void setReportPathDigits(int digits);
void setReportPathNoSplit(bool no_split);
void setReportPathSigmas(bool report_sigmas);
void reportPathEnd(PathEnd *end);
void reportPathEnds(PathEndSeq *ends);
ReportPath *reportPath() { return report_path_; }
@ -998,7 +998,7 @@ public:
const SetupHold *setup_hold,
bool include_internal_latency,
int digits);
float findWorstClkSkew(const SetupHold *setup_hold,
Delay findWorstClkSkew(const SetupHold *setup_hold,
bool include_internal_latency);
void reportClkLatency(ConstClockSeq &clks,
@ -1126,12 +1126,15 @@ public:
void reportArrivalWrtClks(const Pin *pin,
const Scene *scene,
bool report_variance,
int digits);
void reportRequiredWrtClks(const Pin *pin,
const Scene *scene,
bool report_variance,
int digits);
void reportSlackWrtClks(const Pin *pin,
const Scene *scene,
bool report_variance,
int digits);
Slew slew(Vertex *vertex,
@ -1139,9 +1142,9 @@ public:
const SceneSeq &scenes,
const MinMax *min_max);
ArcDelay arcDelay(Edge *edge,
TimingArc *arc,
DcalcAPIndex ap_index);
const ArcDelay &arcDelay(Edge *edge,
TimingArc *arc,
DcalcAPIndex ap_index);
// True if the timing arc has been back-annotated.
bool arcDelayAnnotated(Edge *edge,
TimingArc *arc,
@ -1403,12 +1406,13 @@ public:
// TCL variable sta_crpr_mode.
CrprMode crprMode() const;
void setCrprMode(CrprMode mode);
// TCL variable sta_pocv_enabled.
// TCL variable sta_pocv_mode.
// Parametric on chip variation (statisical sta).
bool pocvEnabled() const;
void setPocvEnabled(bool enabled);
PocvMode pocvMode() const;
void setPocvMode(PocvMode mode);
// Number of std deviations from mean to use for normal distributions.
void setSigmaFactor(float factor);
float pocvQuantile();
void setPocvQuantile(float quantile);
// TCL variable sta_propagate_gated_clock_enable.
// Propagate gated clock enable arrivals.
bool propagateGatedClockEnable() const;
@ -1505,17 +1509,20 @@ protected:
void reportDelaysWrtClks(const Pin *pin,
const Scene *scene,
bool report_variance,
int digits,
bool find_required,
PathDelayFunc get_path_delay);
void reportDelaysWrtClks(Vertex *vertex,
const Scene *scene,
bool report_variance,
int digits,
bool find_required,
PathDelayFunc get_path_delay);
void reportDelaysWrtClks(Vertex *vertex,
const ClockEdge *clk_edge,
const Scene *scene,
bool report_variance,
int digits,
PathDelayFunc get_path_delay);
RiseFallMinMaxDelay findDelaysWrtClks(Vertex *vertex,
@ -1525,6 +1532,7 @@ protected:
std::string formatDelay(const RiseFall *rf,
const MinMax *min_max,
const RiseFallMinMaxDelay &delays,
bool report_variance,
int digits);
void connectDrvrPinAfter(Vertex *vertex);

View File

@ -47,6 +47,7 @@ class GraphDelayCalc;
class Latches;
class DispatchQueue;
class Variables;
class DelayOps;
using ModeSeq = std::vector<Mode*>;
using ModeSet = std::set<Mode*>;
@ -96,10 +97,10 @@ public:
GraphDelayCalc *graphDelayCalc() const { return graph_delay_calc_; }
Search *search() { return search_; }
Search *search() const { return search_; }
const DelayOps *delayOps() const { return delay_ops_; }
Latches *latches() { return latches_; }
Latches *latches() const { return latches_; }
unsigned threadCount() const { return thread_count_; }
float sigmaFactor() const { return sigma_factor_; }
bool crprActive(const Mode *mode) const;
Variables *variables() { return variables_; }
const Variables *variables() const { return variables_; }
@ -133,11 +134,11 @@ protected:
ArcDelayCalc *arc_delay_calc_;
GraphDelayCalc *graph_delay_calc_;
Search *search_;
DelayOps *delay_ops_;
Latches *latches_;
Variables *variables_;
int thread_count_;
DispatchQueue *dispatch_queue_;
float sigma_factor_;
};
} // namespace

View File

@ -33,12 +33,14 @@
#include "Transition.hh"
#include "LibertyClass.hh"
#include "TimingModel.hh"
#include "Variables.hh"
namespace sta {
class Unit;
class Units;
class Report;
class TableModels;
class Table;
class TableModel;
class TableAxis;
@ -63,43 +65,41 @@ class GateTableModel : public GateTimingModel
{
public:
GateTableModel(LibertyCell *cell,
TableModel *delay_model,
TableModelsEarlyLate delay_sigma_models,
TableModel *slew_model,
TableModelsEarlyLate slew_sigma_models,
TableModels *delay_models,
TableModels *slew_models,
ReceiverModelPtr receiver_model,
OutputWaveforms *output_waveforms);
GateTableModel(LibertyCell *cell,
TableModel *delay_model,
TableModel *slew_model);
TableModels *delay_models,
TableModels *slew_models);
~GateTableModel() override;
void gateDelay(const Pvt *pvt,
float in_slew,
float load_cap,
bool pocv_enabled,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew) const override;
// deprecated 2024-01-07
// related_out_cap arg removed.
void gateDelay(const Pvt *pvt,
float in_slew,
float load_cap,
float related_out_cap,
bool pocv_enabled,
ArcDelay &gate_delay,
Slew &drvr_slew) const __attribute__ ((deprecated));
float &gate_delay,
float &drvr_slew) const override;
// Fill in pocv parameters in gate_delay, drvr_slew.
void gateDelayPocv(const Pvt *pvt,
float in_slew,
float load_cap,
const MinMax *min_max,
PocvMode pocv_mode,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew) const override;
std::string reportGateDelay(const Pvt *pvt,
float in_slew,
float load_cap,
bool pocv_enabled,
const MinMax *min_max,
PocvMode pocv_mode,
int digits) const override;
float driveResistance(const Pvt *pvt) const override;
const TableModel *delayModel() const { return delay_model_.get(); }
const TableModel *slewModel() const { return slew_model_.get(); }
const TableModel *delaySigmaModel(const EarlyLate *el) const;
const TableModel *slewSigmaModel(const EarlyLate *el) const;
const TableModels *delayModels() const { return delay_models_.get(); }
const TableModel *delayModel() const;
const TableModels *slewModels() const { return slew_models_.get(); }
const TableModel *slewModel() const;
const ReceiverModel *receiverModel() const { return receiver_model_.get(); }
OutputWaveforms *outputWaveforms() const { return output_waveforms_.get(); }
// Check the axes before making the model.
@ -138,10 +138,8 @@ protected:
float &axis_value3) const;
static bool checkAxis(const TableAxis *axis);
std::unique_ptr<TableModel> delay_model_;
TableModelsEarlyLate delay_sigma_models_;
std::unique_ptr<TableModel> slew_model_;
TableModelsEarlyLate slew_sigma_models_;
std::unique_ptr<TableModels> delay_models_;
std::unique_ptr<TableModels> slew_models_;
ReceiverModelPtr receiver_model_;
std::unique_ptr<OutputWaveforms> output_waveforms_;
};
@ -150,25 +148,24 @@ class CheckTableModel : public CheckTimingModel
{
public:
CheckTableModel(LibertyCell *cell,
TableModel *model,
TableModelsEarlyLate sigma_models);
CheckTableModel(LibertyCell *cell,
TableModel *model);
TableModels *check_models);
~CheckTableModel() override;
ArcDelay checkDelay(const Pvt *pvt,
float from_slew,
float to_slew,
float related_out_cap,
bool pocv_enabled) const override;
const MinMax *min_max,
PocvMode pocv_mode) const override;
std::string reportCheckDelay(const Pvt *pvt,
float from_slew,
const char *from_slew_annotation,
float to_slew,
float related_out_cap,
bool pocv_enabled,
const MinMax *min_max,
PocvMode pocv_mode,
int digits) const override;
const TableModel *model() const { return model_.get(); }
const TableModel *sigmaModel(const EarlyLate *el) const;
const TableModels *checkModels() const { return check_models_.get(); }
const TableModel *checkModel() const;
// Check the axes before making the model.
// Return true if the model axes are supported.
@ -202,8 +199,7 @@ protected:
int digits) const;
static bool checkAxis(const TableAxis *axis);
std::unique_ptr<TableModel> model_;
TableModelsEarlyLate sigma_models_;
std::unique_ptr<TableModels> check_models_;
};
class TableAxis
@ -311,6 +307,8 @@ public:
private:
void clear();
float findValueOrder2(float axis_value1, float axis_value2) const;
float findValueOrder3(float axis_value1, float axis_value2, float axis_value3) const;
std::string reportValueOrder0(const char *result_name,
const char *comment1,
const Unit *table_unit,
@ -408,6 +406,34 @@ protected:
bool is_scaled_:1;
};
// cell/transition/check nldm/ocv/lvf models for one rise/fall edge.
class TableModels
{
public:
TableModels();
TableModels(TableModel *model);
~TableModels();
TableModel *model() const { return model_.get(); }
void setModel(TableModel *model);
TableModel *sigma(const EarlyLate *early_late) const;
void setSigma(TableModel *table,
const EarlyLate *early_late);
TableModel *meanShift() const { return mean_shift_.get(); }
void setMeanShift(TableModel *table);
TableModel *skewness() const { return skewness_.get(); }
void setSkewness(TableModel *table);
TableModel *stdDev() const { return std_dev_.get(); }
void setStdDev(TableModel *table);
protected:
std::unique_ptr<TableModel> model_;
// Note early/late can point to the same model.
std::array<TableModel*, EarlyLate::index_count> sigma_;
std::unique_ptr<TableModel> std_dev_;
std::unique_ptr<TableModel> mean_shift_;
std::unique_ptr<TableModel> skewness_;
};
////////////////////////////////////////////////////////////////
class ReceiverModel

View File

@ -28,6 +28,7 @@
#include "Delay.hh"
#include "LibertyClass.hh"
#include "Variables.hh"
namespace sta {
@ -52,14 +53,23 @@ public:
virtual void gateDelay(const Pvt *pvt,
float in_slew,
float load_cap,
bool pocv_enabled,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew) const = 0;
float &gate_delay,
float &drvr_slew) const = 0;
// Fill in pocv parameters in gate_delay, drvr_slew.
virtual void gateDelayPocv(const Pvt *pvt,
float in_slew,
float load_cap,
const MinMax *min_max,
PocvMode pocv_mode,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew) const = 0;
virtual std::string reportGateDelay(const Pvt *pvt,
float in_slew,
float load_cap,
bool pocv_enabled,
const MinMax *min_max,
PocvMode pocv_mode,
int digits) const = 0;
virtual float driveResistance(const Pvt *pvt) const = 0;
};
@ -74,13 +84,15 @@ public:
float from_slew,
float to_slew,
float related_out_cap,
bool pocv_enabled) const = 0;
const MinMax *min_max,
PocvMode pocv_mode) const = 0;
virtual std::string reportCheckDelay(const Pvt *pvt,
float from_slew,
const char *from_slew_annotation,
float to_slew,
float related_out_cap,
bool pocv_enabled,
const MinMax *min_max,
PocvMode pocv_mode,
int digits) const = 0;
};

View File

@ -24,6 +24,8 @@
#pragma once
#include "PocvMode.hh"
namespace sta {
enum class CrprMode { same_pin, same_transition };
@ -72,8 +74,11 @@ public:
// TCL variable sta_input_port_default_clock.
bool useDefaultArrivalClock() { return use_default_arrival_clock_; }
void setUseDefaultArrivalClock(bool enable);
bool pocvEnabled() const { return pocv_enabled_; }
void setPocvEnabled(bool enabled);
bool pocvEnabled() const;
PocvMode pocvMode() const { return pocv_mode_; }
void setPocvMode(PocvMode mode);
float pocvQuantile() const { return pocv_quantile_; }
void setPocvQuantile(float quartile);
private:
bool crpr_enabled_;
@ -88,7 +93,8 @@ private:
bool dynamic_loop_breaking_;
bool propagate_all_clks_;
bool use_default_arrival_clock_;
bool pocv_enabled_;
PocvMode pocv_mode_;
float pocv_quantile_;
};
} // namespace

View File

@ -37,7 +37,7 @@ InternalPower::InternalPower(LibertyPort *port,
LibertyPort *related_port,
LibertyPort *related_pg_pin,
const std::shared_ptr<FuncExpr> &when,
InternalPowerModels &models) :
const InternalPowerModels &models) :
port_(port),
related_port_(related_port),
related_pg_pin_(related_pg_pin),
@ -52,36 +52,32 @@ InternalPower::libertyCell() const
return port_->libertyCell();
}
const InternalPowerModel &
InternalPower::model(const RiseFall *rf) const
{
return models_[rf->index()];
}
float
InternalPower::power(const RiseFall *rf,
const Pvt *pvt,
float in_slew,
float load_cap) const
{
const std::shared_ptr<InternalPowerModel> &model = models_[rf->index()];
if (model)
return model->power(libertyCell(), pvt, in_slew, load_cap);
else
return 0.0;
}
const InternalPowerModel *
InternalPower::model(const RiseFall *rf) const
{
const std::shared_ptr<InternalPowerModel> &m = models_[rf->index()];
return m.get();
const InternalPowerModel &model = models_[rf->index()];
return model.power(libertyCell(), pvt, in_slew, load_cap);
}
////////////////////////////////////////////////////////////////
InternalPowerModel::InternalPowerModel(TableModel *model) :
model_(model)
InternalPowerModel::InternalPowerModel() :
model_(nullptr)
{
}
InternalPowerModel::~InternalPowerModel()
InternalPowerModel::InternalPowerModel(std::shared_ptr<TableModel> model) :
model_(model)
{
delete model_;
}
float

View File

@ -1262,7 +1262,7 @@ LibertyCell::makeInternalPower(LibertyPort *port,
LibertyPort *related_port,
LibertyPort *related_pg_pin,
const std::shared_ptr<FuncExpr> &when,
InternalPowerModels &models)
const InternalPowerModels &models)
{
internal_powers_.emplace_back(port, related_port, related_pg_pin, when, models);
port_internal_powers_[port].push_back(internal_powers_.size() - 1);

View File

@ -2122,80 +2122,76 @@ LibertyReader::makeTableModels(LibertyCell *cell,
{
bool found_model = false;
for (const RiseFall *rf : RiseFall::range()) {
std::string delay_attr_name = "cell_" + rf->to_string();
TableModel *delay = readGateTableModel(timing_group, delay_attr_name.c_str(), rf,
TableTemplateType::delay, time_scale_,
ScaleFactorType::cell);
std::string transition_attr_name = rf->to_string() + "_transition";
TableModel *transition = readGateTableModel(timing_group,
transition_attr_name.c_str(),
rf, TableTemplateType::delay,
time_scale_,
ScaleFactorType::transition);
if (delay || transition) {
std::string delay_sigma_attr_name = "ocv_sigma_cell_" + rf->to_string();
TableModelsEarlyLate delay_sigmas =
readEarlyLateTableModels(timing_group,
delay_sigma_attr_name.c_str(),
rf, TableTemplateType::delay,
time_scale_,
ScaleFactorType::unknown);
TableModel *delay_model = readTableModel(timing_group,
"cell_" + rf->to_string(),
rf, TableTemplateType::delay,
time_scale_,
ScaleFactorType::cell,
GateTableModel::checkAxes);
TableModel *slew_model = readTableModel(timing_group,
rf->to_string() + "_transition",
rf, TableTemplateType::delay,
time_scale_,
ScaleFactorType::transition,
GateTableModel::checkAxes);
if (delay_model || slew_model) {
TableModels *delay_models = new TableModels(delay_model);
readLvfModels(timing_group,
"ocv_sigma_cell_" + rf->to_string(),
"ocv_std_dev_cell_" + rf->to_string(),
"ocv_mean_shift_cell_" + rf->to_string(),
"ocv_skewness_cell_" + rf->to_string(),
rf, delay_models, GateTableModel::checkAxes);
std::string slew_sigma_attr_name = "ocv_sigma_" + rf->to_string()
+ "_transition";
TableModelsEarlyLate slew_sigmas =
readEarlyLateTableModels(timing_group,
slew_sigma_attr_name.c_str(),
rf, TableTemplateType::delay,
time_scale_,
ScaleFactorType::unknown);
TableModels *slew_models = new TableModels(slew_model);
readLvfModels(timing_group,
"ocv_sigma_" + rf->to_string() + "_transition",
"ocv_std_dev_" + rf->to_string() + "_transition",
"ocv_mean_shift_" + rf->to_string() + "_transition",
"ocv_skewness_" + rf->to_string() + "_transition",
rf, slew_models, GateTableModel::checkAxes);
ReceiverModelPtr receiver_model = readReceiverCapacitance(timing_group, rf);
OutputWaveforms *output_waveforms = readOutputWaveforms(timing_group, rf);
timing_attrs->setModel(rf, new GateTableModel(cell, delay,
std::move(delay_sigmas),
transition,
std::move(slew_sigmas),
timing_attrs->setModel(rf, new GateTableModel(cell, delay_models,
slew_models,
receiver_model,
output_waveforms));
TimingType timing_type = timing_attrs->timingType();
if (isGateTimingType(timing_type)) {
if (transition == nullptr)
if (slew_model == nullptr)
libWarn(1210, timing_group, "missing %s_transition.", rf->name());
if (delay == nullptr)
if (delay_model == nullptr)
libWarn(1211, timing_group, "missing cell_%s.", rf->name());
}
found_model = true;
}
else {
std::string constraint_attr_name = rf->to_string() + "_constraint";
ScaleFactorType scale_factor_type =
timingTypeScaleFactorType(timing_attrs->timingType());
TableModel *constraint = readCheckTableModel(timing_group,
constraint_attr_name.c_str(),
rf, TableTemplateType::delay,
time_scale_, scale_factor_type);
if (constraint) {
std::string constraint_sigma_attr_name = "ocv_sigma_" + rf->to_string()
+ "_constraint";
TableModelsEarlyLate constraint_sigmas =
readEarlyLateTableModels(timing_group,
constraint_sigma_attr_name.c_str(),
rf, TableTemplateType::delay,
time_scale_,
ScaleFactorType::unknown);
timing_attrs->setModel(rf, new CheckTableModel(cell, constraint,
std::move(constraint_sigmas)));
found_model = true;
}
std::string constraint_attr_name = rf->to_string() + "_constraint";
ScaleFactorType scale_factor_type =
timingTypeScaleFactorType(timing_attrs->timingType());
TableModel *check_model = readTableModel(timing_group,
constraint_attr_name.c_str(),
rf, TableTemplateType::delay,
time_scale_, scale_factor_type,
CheckTableModel::checkAxes);
if (check_model) {
TableModels *check_models = new TableModels(check_model);
readLvfModels(timing_group,
"ocv_sigma_" + rf->to_string() + "_constraint",
"ocv_std_dev_" + rf->to_string() + "_constraint",
"ocv_mean_shift_" + rf->to_string() + "_constraint",
"ocv_skewness_" + rf->to_string() + "_constraint",
rf, check_models, CheckTableModel::checkAxes);
timing_attrs->setModel(rf, new CheckTableModel(cell, check_models));
found_model = true;
}
}
if (!found_model)
libWarn(1311, timing_group, "no table models found in timing group.");
}
bool
LibertyReader::isGateTimingType(TimingType timing_type)
{
@ -2215,41 +2211,66 @@ LibertyReader::isGateTimingType(TimingType timing_type)
}
TableModel *
LibertyReader::readGateTableModel(const LibertyGroup *timing_group,
const char *table_group_name,
const RiseFall *rf,
TableTemplateType template_type,
float scale,
ScaleFactorType scale_factor_type)
LibertyReader::readTableModel(const LibertyGroup *timing_group,
const std::string &table_group_name,
const RiseFall *rf,
TableTemplateType template_type,
float scale,
ScaleFactorType scale_factor_type,
const std::function<bool(TableModel *model)> check_axes)
{
const LibertyGroup *table_group = timing_group->findSubgroup(table_group_name);
if (table_group) {
TableModel *model = readTableModel(table_group, rf, template_type, scale,
scale_factor_type);
if (model && !GateTableModel::checkAxes(model))
libWarn(1251, table_group, "unsupported model axis.");
return model;
}
if (table_group)
return readTableModel(table_group, rf, template_type, scale,
scale_factor_type, check_axes);
return nullptr;
}
TableModel *
LibertyReader::readCheckTableModel(const LibertyGroup *timing_group,
const char *table_group_name,
const RiseFall *rf,
TableTemplateType template_type,
float scale,
ScaleFactorType scale_factor_type)
void
LibertyReader::readLvfModels(const LibertyGroup *timing_group,
const std::string &sigma_group_name,
const std::string &std_dev_group_name,
const std::string &mean_shift_group_name,
const std::string &skewness_group_name,
const RiseFall *rf,
TableModels *table_models,
const std::function<bool(TableModel *model)> check_axes)
{
const LibertyGroup *table_group = timing_group->findSubgroup(table_group_name);
if (table_group) {
TableModel *model = readTableModel(table_group, rf, template_type, scale,
scale_factor_type);
if (model && !CheckTableModel::checkAxes(model))
libWarn(1252, table_group, "unsupported model axis.");
return model;
TableModelsEarlyLate sigmas =
readEarlyLateTableModels(timing_group,
sigma_group_name.c_str(),
rf, TableTemplateType::delay,
time_scale_,
ScaleFactorType::unknown,
check_axes);
for (const EarlyLate *early_late : EarlyLate::range())
table_models->setSigma(sigmas[early_late->index()], early_late);
const LibertyGroup *std_dev_group = timing_group->findSubgroup(std_dev_group_name);
if (std_dev_group) {
TableModel *std_dev = readTableModel(std_dev_group, rf, TableTemplateType::delay,
time_scale_, ScaleFactorType::unknown,
check_axes);
table_models->setStdDev(std_dev);
}
const LibertyGroup *mean_shift_group=timing_group->findSubgroup(mean_shift_group_name);
if (mean_shift_group) {
TableModel *mean_shift = readTableModel(mean_shift_group, rf,
TableTemplateType::delay,
time_scale_, ScaleFactorType::unknown,
check_axes);
table_models->setMeanShift(mean_shift);
}
const LibertyGroup *skewness_group = timing_group->findSubgroup(skewness_group_name);
if (skewness_group) {
TableModel *skewness = readTableModel(skewness_group, rf,
TableTemplateType::delay,
1.0, ScaleFactorType::unknown,
check_axes);
table_models->setSkewness(skewness);
}
return nullptr;
}
TableModelsEarlyLate
@ -2258,12 +2279,13 @@ LibertyReader::readEarlyLateTableModels(const LibertyGroup *timing_group,
const RiseFall *rf,
TableTemplateType template_type,
float scale,
ScaleFactorType scale_factor_type)
ScaleFactorType scale_factor_type,
const std::function<bool(TableModel *model)> check_axes)
{
TableModelsEarlyLate models{};
for (const LibertyGroup *table_group : timing_group->findSubgroups(table_group_name)) {
TableModel *model = readTableModel(table_group, rf, template_type, scale,
scale_factor_type);
scale_factor_type, check_axes);
const std::string *early_late = table_group->findAttrString("sigma_type");
if (early_late == nullptr
|| *early_late == "early_and_late") {
@ -2274,9 +2296,6 @@ LibertyReader::readEarlyLateTableModels(const LibertyGroup *timing_group,
models[EarlyLate::early()->index()] = model;
else if (*early_late == "late")
models[EarlyLate::late()->index()] = model;
//if (model && !GateTableModel::checkAxes(model))
// libWarn(1182, table_group, "unsupported model axis.");
}
return models;
}
@ -2445,7 +2464,8 @@ LibertyReader::readTableModel(const LibertyGroup *table_group,
const RiseFall *rf,
TableTemplateType template_type,
float scale,
ScaleFactorType scale_factor_type)
ScaleFactorType scale_factor_type,
const std::function<bool(TableModel *model)> &check_axes)
{
const char *template_name = table_group->firstName();
if (library_ && template_name) {
@ -2456,6 +2476,9 @@ LibertyReader::readTableModel(const LibertyGroup *table_group,
if (table) {
TableModel *table_model = new TableModel(table, tbl_template,
scale_factor_type, rf);
if (!check_axes(table_model)) {
libWarn(1251, table_group, "unsupported model axis.");
}
return table_model;
}
}
@ -2682,7 +2705,7 @@ LibertyReader::readInternalPowerGroups(LibertyCell *cell,
FuncExpr *when1 = readFuncExpr(cell, ipwr_group, "when");
if (when1)
when = std::shared_ptr<FuncExpr>(when1);
InternalPowerModels models;
InternalPowerModels models{};
// rise/fall_power group
for (const RiseFall *rf : RiseFall::range()) {
std::string pwr_attr_name = rf->to_string() + "_power";
@ -2691,7 +2714,9 @@ LibertyReader::readInternalPowerGroups(LibertyCell *cell,
TableModel *model = readTableModel(pwr_group, rf, TableTemplateType::power,
energyScale(),
ScaleFactorType::internal_power);
models[rf->index()] = std::make_shared<InternalPowerModel>(model);
std::shared_ptr<TableModel> table_model(model);
InternalPowerModel pwr_model(table_model);
models[rf->index()] = pwr_model;
}
}
// power group (rise/fall power are the same)
@ -2701,9 +2726,11 @@ LibertyReader::readInternalPowerGroups(LibertyCell *cell,
TableTemplateType::power,
energyScale(),
ScaleFactorType::internal_power);
auto pwr_model = std::make_shared<InternalPowerModel>(model);
for (const RiseFall *rf : RiseFall::range())
std::shared_ptr<TableModel> table_model(model);
for (const RiseFall *rf : RiseFall::range()) {
InternalPowerModel pwr_model(table_model);
models[rf->index()] = pwr_model;
}
}
if (related_ports.empty())
cell->makeInternalPower(port, nullptr, related_pg_port, when, models);
@ -2792,9 +2819,9 @@ LibertyReader::makeScalarCheckModel(LibertyCell *cell,
library_->findTableTemplate("scalar", TableTemplateType::delay);
TableModel *table_model = new TableModel(table, tbl_template,
scale_factor_type, rf);
TableModelsEarlyLate sigmas{};
CheckTableModel *check_model = new CheckTableModel(cell, table_model,
std::move(sigmas));
TableModels *check_models = new TableModels(table_model);
TimingModel *check_model = new CheckTableModel(cell, check_models);
return check_model;
}
@ -3713,7 +3740,7 @@ PortNameBitIterator::init(const char *port_name)
range_bit_ = from;
findRangeBusNameNext();
}
size_ = abs(from - to) + 1;
size_ = std::abs(from - to) + 1;
}
else
visitor_->libWarn(1294, line_, "port %s not found.", port_name);

View File

@ -232,25 +232,21 @@ protected:
const LibertyPortSeq &ports,
const LibertyGroup *port_group);
bool isGateTimingType(TimingType timing_type);
TableModel *readGateTableModel(const LibertyGroup *timing_group,
const char *table_group_name,
const RiseFall *rf,
TableTemplateType template_type,
float scale,
ScaleFactorType scale_factor_type);
TableModel *readTableModel(const LibertyGroup *timing_group,
const std::string &table_group_name,
const RiseFall *rf,
TableTemplateType template_type,
float scale,
ScaleFactorType scale_factor_type,
const std::function<bool(TableModel *model)> check_axes);
TableModelsEarlyLate
readEarlyLateTableModels(const LibertyGroup *timing_group,
const char *table_group_name,
const RiseFall *rf,
TableTemplateType template_type,
float scale,
ScaleFactorType scale_factor_type);
TableModel *readCheckTableModel(const LibertyGroup *timing_group,
const char *table_group_name,
const RiseFall *rf,
TableTemplateType template_type,
float scale,
ScaleFactorType scale_factor_type);
ScaleFactorType scale_factor_type,
const std::function<bool(TableModel *model)> check_axes);
ReceiverModelPtr readReceiverCapacitance(const LibertyGroup *timing_group,
const RiseFall *rf);
void readReceiverCapacitance(const LibertyGroup *timing_group,
@ -268,7 +264,9 @@ protected:
const RiseFall *rf,
TableTemplateType template_type,
float scale,
ScaleFactorType scale_factor_type);
ScaleFactorType scale_factor_type,
const std::function<bool(TableModel *model)> &check_axes =
[](TableModel *) { return true; });
TablePtr readTableModel(const LibertyGroup *table_group,
const TableTemplate *tbl_template,
float scale);
@ -281,6 +279,14 @@ protected:
void makeTableModels(LibertyCell *cell,
const LibertyGroup *timing_group,
TimingArcAttrsPtr timing_attrs);
void readLvfModels(const LibertyGroup *timing_group,
const std::string &sigma_group_name,
const std::string &std_dev_group_name,
const std::string &mean_shift_group_name,
const std::string &skewness_group_name,
const RiseFall *rf,
TableModels *table_models,
const std::function<bool(TableModel *model)> check_axes);
TableAxisPtr makeTableAxis(const LibertyGroup *table_group,
const char *index_attr_name,

View File

@ -466,13 +466,14 @@ LibertyWriter::writeTimingModels(const TimingArc *arc,
const TableModel *slew_model = gate_model->slewModel();
if (slew_model) {
const std::string &slew_template_name = slew_model->tblTemplate()->name();
fprintf(stream_, " %s_transition(%s) {\n", rf->name(), slew_template_name.c_str());
fprintf(stream_, " %s_transition(%s) {\n", rf->name(),
slew_template_name.c_str());
writeTableModel(slew_model);
fprintf(stream_, " }\n");
}
}
else if (check_model) {
const TableModel *model = check_model->model();
const TableModel *model = check_model->checkModel();
const std::string &template_name = model->tblTemplate()->name();
fprintf(stream_, " %s_constraint(%s) {\n", rf->name(), template_name.c_str());
writeTableModel(model);

View File

@ -42,20 +42,32 @@ void
GateLinearModel::gateDelay(const Pvt *,
float,
float load_cap,
bool,
// return values
ArcDelay &gate_delay,
Slew &drvr_slew) const
float &gate_delay,
float &drvr_slew) const
{
gate_delay = intrinsic_ + resistance_ * load_cap;
drvr_slew = 0.0;
}
void
GateLinearModel::gateDelayPocv(const Pvt *,
float,
float,
const MinMax *,
PocvMode,
// return values
ArcDelay &,
Slew &) const
{
}
std::string
GateLinearModel::reportGateDelay(const Pvt *,
float,
float load_cap,
bool,
const MinMax *,
PocvMode,
int digits) const
{
const LibertyLibrary *library = cell_->libertyLibrary();
@ -98,7 +110,8 @@ CheckLinearModel::checkDelay(const Pvt *,
float,
float,
float,
bool) const
const MinMax *,
PocvMode) const
{
return intrinsic_;
}
@ -109,7 +122,8 @@ CheckLinearModel::reportCheckDelay(const Pvt *,
const char *,
float,
float,
bool,
const MinMax *,
PocvMode,
int digits) const
{
const LibertyLibrary *library = cell_->libertyLibrary();

View File

@ -38,8 +38,6 @@ namespace sta {
size_t
findValueIndex(float value,
const FloatSeq *values);
static void
sigmaModelsDelete(TableModelsEarlyLate &models);
static std::string
reportPvt(const LibertyCell *cell,
const Pvt *pvt,
@ -53,139 +51,189 @@ TimingModel::TimingModel(LibertyCell *cell) :
{
}
////////////////////////////////////////////////////////////////
GateTableModel::GateTableModel(LibertyCell *cell,
TableModel *delay_model,
TableModelsEarlyLate delay_sigma_models,
TableModel *slew_model,
TableModelsEarlyLate slew_sigma_models,
TableModels *delay_models,
TableModels *slew_models,
ReceiverModelPtr receiver_model,
OutputWaveforms *output_waveforms) :
GateTimingModel(cell),
delay_model_(delay_model),
delay_sigma_models_(std::move(delay_sigma_models)),
slew_model_(slew_model),
slew_sigma_models_(std::move(slew_sigma_models)),
delay_models_(delay_models),
slew_models_(slew_models),
receiver_model_(receiver_model),
output_waveforms_(output_waveforms)
{
}
GateTableModel::GateTableModel(LibertyCell *cell,
TableModel *delay_model,
TableModel *slew_model) :
TableModels *delay_models,
TableModels *slew_models) :
GateTimingModel(cell),
delay_model_(delay_model),
delay_sigma_models_{},
slew_model_(slew_model),
slew_sigma_models_{},
delay_models_(delay_models),
slew_models_(slew_models),
receiver_model_(nullptr),
output_waveforms_(nullptr)
{
}
GateTableModel::~GateTableModel()
GateTableModel::~GateTableModel() = default;
const TableModel *
GateTableModel::delayModel() const
{
sigmaModelsDelete(slew_sigma_models_);
sigmaModelsDelete(delay_sigma_models_);
return delay_models_ ? delay_models_->model() : nullptr;
}
static void
sigmaModelsDelete(TableModelsEarlyLate &models)
const TableModel *
GateTableModel::slewModel() const
{
TableModel *early_model = models[EarlyLate::earlyIndex()];
TableModel *late_model = models[EarlyLate::lateIndex()];
if (early_model == late_model)
delete early_model;
else {
delete early_model;
delete late_model;
}
return slew_models_ ? slew_models_->model() : nullptr;;
}
void
GateTableModel::setIsScaled(bool is_scaled)
{
if (delay_model_)
delay_model_->setIsScaled(is_scaled);
if (slew_model_)
slew_model_->setIsScaled(is_scaled);
if (delay_models_)
delay_models_->model()->setIsScaled(is_scaled);
if (slew_models_)
slew_models_->model()->setIsScaled(is_scaled);
}
void
GateTableModel::gateDelay(const Pvt *pvt,
float in_slew,
float load_cap,
bool pocv_enabled,
// return values
ArcDelay &gate_delay,
Slew &drvr_slew) const
float &gate_delay,
float &drvr_slew) const
{
float delay = findValue(pvt, delay_model_.get(), in_slew, load_cap, 0.0);
float sigma_early = 0.0;
float sigma_late = 0.0;
if (pocv_enabled && delay_sigma_models_[EarlyLate::earlyIndex()])
sigma_early = findValue(pvt, delay_sigma_models_[EarlyLate::earlyIndex()],
in_slew, load_cap, 0.0);
if (pocv_enabled && delay_sigma_models_[EarlyLate::lateIndex()])
sigma_late = findValue(pvt, delay_sigma_models_[EarlyLate::lateIndex()],
in_slew, load_cap, 0.0);
gate_delay = makeDelay(delay, sigma_early, sigma_late);
float slew = findValue(pvt, slew_model_.get(), in_slew, load_cap, 0.0);
if (pocv_enabled && slew_sigma_models_[EarlyLate::earlyIndex()])
sigma_early = findValue(pvt, slew_sigma_models_[EarlyLate::earlyIndex()],
in_slew, load_cap, 0.0);
if (pocv_enabled && slew_sigma_models_[EarlyLate::lateIndex()])
sigma_late = findValue(pvt, slew_sigma_models_[EarlyLate::lateIndex()],
in_slew, load_cap, 0.0);
if (delay_models_)
gate_delay = findValue(pvt, delay_models_->model(), in_slew, load_cap, 0.0);
else
gate_delay = 0.0;
if (slew_models_)
drvr_slew = findValue(pvt, slew_models_->model(), in_slew, load_cap, 0.0);
else
drvr_slew = 0.0;
// Clip negative slews to zero.
if (slew < 0.0)
slew = 0.0;
drvr_slew = makeDelay(slew, sigma_early, sigma_late);
if (drvr_slew < 0.0)
drvr_slew = 0.0;
}
void
GateTableModel::gateDelay(const Pvt *pvt,
float in_slew,
float load_cap,
float,
bool pocv_enabled,
ArcDelay &gate_delay,
Slew &drvr_slew) const
GateTableModel::gateDelayPocv(const Pvt *pvt,
float in_slew,
float load_cap,
const MinMax *min_max,
PocvMode pocv_mode,
// return values
ArcDelay &gate_delay,
Slew &drvr_slew) const
{
gateDelay(pvt, in_slew, load_cap, pocv_enabled, gate_delay, drvr_slew);
switch (pocv_mode) {
case PocvMode::normal: {
// Delay
TableModel *std_dev_model = delay_models_->stdDev();
if (std_dev_model == nullptr)
std_dev_model = delay_models_->sigma(min_max);
if (std_dev_model) {
float std_dev = findValue(pvt, std_dev_model, in_slew, load_cap, 0.0);
gate_delay.setStdDev(std_dev);
}
// Slew
std_dev_model = slew_models_->stdDev();
if (std_dev_model == nullptr)
std_dev_model = slew_models_->sigma(min_max);
if (std_dev_model) {
float std_dev = findValue(pvt, std_dev_model, in_slew, load_cap, 0.0);
drvr_slew.setStdDev(std_dev);
}
break;
}
case PocvMode::skew_normal: {
// Delay
if (delay_models_->meanShift()) {
float mean_shift = findValue(pvt, delay_models_->meanShift(),
in_slew, load_cap, 0.0);
gate_delay.setMeanShift(mean_shift);
}
if (delay_models_->stdDev()) {
float std_dev = findValue(pvt, delay_models_->stdDev(), in_slew, load_cap, 0.0);
gate_delay.setStdDev(std_dev);
}
if (delay_models_->skewness()) {
float skewness = findValue(pvt, delay_models_->skewness(), in_slew, load_cap, 0.0);
gate_delay.setSkewness(skewness);
}
// Slew
if (slew_models_->meanShift()) {
float mean_shift = findValue(pvt, slew_models_->meanShift(),
in_slew, load_cap, 0.0);
drvr_slew.setMeanShift(mean_shift);
}
if (slew_models_->stdDev()) {
float std_dev = findValue(pvt, slew_models_->stdDev(), in_slew, load_cap, 0.0);
drvr_slew.setStdDev(std_dev);
}
if (slew_models_->skewness()) {
float skewness = findValue(pvt, slew_models_->skewness(), in_slew, load_cap, 0.0);
drvr_slew.setSkewness(skewness);
}
break;
}
default:
break;
}
}
std::string
GateTableModel::reportGateDelay(const Pvt *pvt,
float in_slew,
float load_cap,
bool pocv_enabled,
const MinMax *min_max,
PocvMode pocv_mode,
int digits) const
{
std::string result = reportPvt(cell_, pvt, digits);
result += reportTableLookup("Delay", pvt, delay_model_.get(), in_slew,
result += reportTableLookup("Delay", pvt, delay_models_->model(), in_slew,
load_cap, 0.0, digits);
if (pocv_enabled && delay_sigma_models_[EarlyLate::earlyIndex()])
result += reportTableLookup("Delay sigma(early)", pvt,
delay_sigma_models_[EarlyLate::earlyIndex()],
in_slew, load_cap, 0.0, digits);
if (pocv_enabled && delay_sigma_models_[EarlyLate::lateIndex()])
result += reportTableLookup("Delay sigma(late)", pvt,
delay_sigma_models_[EarlyLate::lateIndex()],
in_slew, load_cap, 0.0, digits);
result += '\n';
result += reportTableLookup("Slew", pvt, slew_model_.get(), in_slew,
load_cap, 9.0, digits);
if (pocv_enabled && slew_sigma_models_[EarlyLate::earlyIndex()])
result += reportTableLookup("Slew sigma(early)", pvt,
slew_sigma_models_[EarlyLate::earlyIndex()],
in_slew, load_cap, 0.0, digits);
if (pocv_enabled && slew_sigma_models_[EarlyLate::lateIndex()])
result += reportTableLookup("Slew sigma(late)", pvt,
slew_sigma_models_[EarlyLate::lateIndex()],
in_slew, load_cap, 0.0, digits);
float drvr_slew = findValue(pvt, slew_model_.get(), in_slew, load_cap, 0.0);
if (pocv_mode != PocvMode::scalar) {
if (delay_models_->sigma(min_max))
result += reportTableLookup("Delay sigma(early)", pvt,
delay_models_->sigma(min_max),
in_slew, load_cap, 0.0, digits);
if (delay_models_->sigma(EarlyLate::late()))
result += reportTableLookup("Delay sigma(late)", pvt,
delay_models_->sigma(min_max),
in_slew, load_cap, 0.0, digits);
result += '\n';
result += reportTableLookup("Slew", pvt, slew_models_->model(), in_slew,
load_cap, 9.0, digits);
if (slew_models_->sigma(EarlyLate::early()))
result += reportTableLookup("Slew sigma(early)", pvt,
slew_models_->sigma(min_max),
in_slew, load_cap, 0.0, digits);
if (slew_models_->sigma(EarlyLate::late()))
result += reportTableLookup("Slew sigma(late)", pvt,
slew_models_->sigma(min_max),
in_slew, load_cap, 0.0, digits);
}
else {
result += '\n';
result += reportTableLookup("Slew", pvt, slew_models_->model(), in_slew,
load_cap, 9.0, digits);
}
float drvr_slew = findValue(pvt, slew_models_->model(), in_slew, load_cap, 0.0);
if (drvr_slew < 0.0)
result += "Negative slew clipped to 0.0\n";
return result;
@ -284,46 +332,30 @@ GateTableModel::driveResistance(const Pvt *pvt) const
return slew / cap;
}
const TableModel *
GateTableModel::delaySigmaModel(const EarlyLate *el) const
{
return delay_sigma_models_[el->index()];
}
const TableModel *
GateTableModel::slewSigmaModel(const EarlyLate *el) const
{
return slew_sigma_models_[el->index()];
}
void
GateTableModel::maxCapSlew(float in_slew,
const Pvt *pvt,
float &slew,
float &cap) const
{
if (!slew_model_) {
cap = 1.0;
slew = 0.0;
return;
}
const TableAxis *axis1 = slew_model_->axis1();
const TableAxis *axis2 = slew_model_->axis2();
const TableAxis *axis3 = slew_model_->axis3();
TableModel *model = slew_models_->model();
const TableAxis *axis1 = model->axis1();
const TableAxis *axis2 = model->axis2();
const TableAxis *axis3 = model->axis3();
if (axis1
&& axis1->variable() == TableAxisVariable::total_output_net_capacitance) {
cap = axis1->axisValue(axis1->size() - 1);
slew = findValue(pvt, slew_model_.get(), in_slew, cap, 0.0);
slew = findValue(pvt, model, in_slew, cap, 0.0);
}
else if (axis2
&& axis2->variable()==TableAxisVariable::total_output_net_capacitance) {
cap = axis2->axisValue(axis2->size() - 1);
slew = findValue(pvt, slew_model_.get(), in_slew, cap, 0.0);
slew = findValue(pvt, model, in_slew, cap, 0.0);
}
else if (axis3
&& axis3->variable()==TableAxisVariable::total_output_net_capacitance) {
cap = axis3->axisValue(axis3->size() - 1);
slew = findValue(pvt, slew_model_.get(), in_slew, cap, 0.0);
slew = findValue(pvt, model, in_slew, cap, 0.0);
}
else {
// Table not dependent on capacitance.
@ -416,38 +448,24 @@ ReceiverModel::checkAxes(const TableModel *table)
////////////////////////////////////////////////////////////////
CheckTableModel::CheckTableModel(LibertyCell *cell,
TableModel *model,
TableModelsEarlyLate sigma_models) :
TableModels *check_models) :
CheckTimingModel(cell),
model_(model),
sigma_models_(std::move(sigma_models))
check_models_(check_models)
{
}
CheckTableModel::CheckTableModel(LibertyCell *cell,
TableModel *model) :
CheckTimingModel(cell),
model_(model),
sigma_models_{}
{
}
CheckTableModel::~CheckTableModel() = default;
CheckTableModel::~CheckTableModel()
const TableModel *
CheckTableModel::checkModel() const
{
sigmaModelsDelete(sigma_models_);
return check_models_ ? check_models_->model() : nullptr;
}
void
CheckTableModel::setIsScaled(bool is_scaled)
{
if (model_)
model_->setIsScaled(is_scaled);
}
const TableModel *
CheckTableModel::sigmaModel(const EarlyLate *el) const
{
return sigma_models_[el->index()];
check_models_->model()->setIsScaled(is_scaled);
}
ArcDelay
@ -455,22 +473,51 @@ CheckTableModel::checkDelay(const Pvt *pvt,
float from_slew,
float to_slew,
float related_out_cap,
bool pocv_enabled) const
const MinMax *min_max,
PocvMode pocv_mode) const
{
if (model_) {
float mean = findValue(pvt, model_.get(), from_slew, to_slew, related_out_cap);
float sigma_early = 0.0;
float sigma_late = 0.0;
if (pocv_enabled && sigma_models_[EarlyLate::earlyIndex()])
sigma_early = findValue(pvt, sigma_models_[EarlyLate::earlyIndex()],
from_slew, to_slew, related_out_cap);
if (pocv_enabled && sigma_models_[EarlyLate::lateIndex()])
sigma_late = findValue(pvt, sigma_models_[EarlyLate::lateIndex()],
from_slew, to_slew, related_out_cap);
return makeDelay(mean, sigma_early, sigma_late);
ArcDelay check_delay;
if (check_models_) {
float margin = findValue(pvt, check_models_->model(), from_slew,
to_slew, related_out_cap);
check_delay.setMean(margin);
switch (pocv_mode) {
case PocvMode::normal: {
TableModel *std_dev_model = check_models_->stdDev();
if (std_dev_model == nullptr)
std_dev_model = check_models_->sigma(min_max);
if (std_dev_model) {
float std_dev = findValue(pvt, std_dev_model, from_slew, to_slew, related_out_cap);
check_delay.setStdDev(std_dev);
}
break;
}
case PocvMode::skew_normal: {
if (check_models_->meanShift()) {
float mean_shift = findValue(pvt, check_models_->meanShift(),
from_slew, to_slew, related_out_cap);
check_delay.setMeanShift(mean_shift);
}
if (check_models_->stdDev()) {
float std_dev = findValue(pvt, check_models_->stdDev(),
from_slew, to_slew, related_out_cap);
check_delay.setStdDev(std_dev);
}
if (check_models_->skewness()) {
float skewness = findValue(pvt, check_models_->skewness(),
from_slew, to_slew, related_out_cap);
check_delay.setSkewness(skewness);
}
break;
}
default:
break;
}
}
else
return 0.0;
return check_delay;
}
float
@ -496,22 +543,28 @@ CheckTableModel::reportCheckDelay(const Pvt *pvt,
const char *from_slew_annotation,
float to_slew,
float related_out_cap,
bool pocv_enabled,
const MinMax *min_max,
PocvMode pocv_mode,
int digits) const
{
std::string result = reportTableDelay("Check", pvt, model_.get(),
from_slew, from_slew_annotation, to_slew,
related_out_cap, digits);
if (pocv_enabled && sigma_models_[EarlyLate::earlyIndex()])
result += reportTableDelay("Check sigma early", pvt,
sigma_models_[EarlyLate::earlyIndex()],
from_slew, from_slew_annotation, to_slew,
related_out_cap, digits);
if (pocv_enabled && sigma_models_[EarlyLate::lateIndex()])
result += reportTableDelay("Check sigma late", pvt,
sigma_models_[EarlyLate::lateIndex()],
from_slew, from_slew_annotation, to_slew,
related_out_cap, digits);
std::string result = reportTableDelay("Check", pvt, check_models_->model(),
from_slew, from_slew_annotation, to_slew,
related_out_cap, digits);
switch (pocv_mode) {
case PocvMode::normal:
case PocvMode::skew_normal: {
TableModel *check_table = check_models_->stdDev();
if (check_table == nullptr)
check_table = check_models_->sigma(min_max);
if (check_table)
result += reportTableDelay("Check sigma", pvt, check_table,
from_slew, from_slew_annotation, to_slew,
related_out_cap, digits);
break;
}
default:
break;
}
return result;
}
@ -530,10 +583,11 @@ CheckTableModel::reportTableDelay(const char *result_name,
findAxisValues(from_slew, to_slew, related_out_cap,
axis_value1, axis_value2, axis_value3);
std::string result = reportPvt(cell_, pvt, digits);
result += model_->reportValue(result_name, cell_, pvt,
axis_value1, from_slew_annotation, axis_value2,
axis_value3,
cell_->libertyLibrary()->units()->timeUnit(), digits);
const Unit *time_unit = cell_->libertyLibrary()->units()->timeUnit();
result += check_models_->model()->reportValue(result_name, cell_, pvt,
axis_value1, from_slew_annotation,
axis_value2, axis_value3,
time_unit, digits);
return result;
}
return "";
@ -548,31 +602,32 @@ CheckTableModel::findAxisValues(float from_slew,
float &axis_value2,
float &axis_value3) const
{
switch (model_->order()) {
TableModel *model = check_models_->model();
switch (model->order()) {
case 0:
axis_value1 = 0.0;
axis_value2 = 0.0;
axis_value3 = 0.0;
break;
case 1:
axis_value1 = axisValue(model_->axis1(), from_slew, to_slew,
axis_value1 = axisValue(model->axis1(), from_slew, to_slew,
related_out_cap);
axis_value2 = 0.0;
axis_value3 = 0.0;
break;
case 2:
axis_value1 = axisValue(model_->axis1(), from_slew, to_slew,
axis_value1 = axisValue(model->axis1(), from_slew, to_slew,
related_out_cap);
axis_value2 = axisValue(model_->axis2(), from_slew, to_slew,
axis_value2 = axisValue(model->axis2(), from_slew, to_slew,
related_out_cap);
axis_value3 = 0.0;
break;
case 3:
axis_value1 = axisValue(model_->axis1(), from_slew, to_slew,
axis_value1 = axisValue(model->axis1(), from_slew, to_slew,
related_out_cap);
axis_value2 = axisValue(model_->axis2(), from_slew, to_slew,
axis_value2 = axisValue(model->axis2(), from_slew, to_slew,
related_out_cap);
axis_value3 = axisValue(model_->axis3(), from_slew, to_slew,
axis_value3 = axisValue(model->axis3(), from_slew, to_slew,
related_out_cap);
break;
default:
@ -626,6 +681,75 @@ CheckTableModel::checkAxis(const TableAxis *axis)
////////////////////////////////////////////////////////////////
TableModels::TableModels() :
model_(nullptr),
sigma_{},
std_dev_(nullptr),
mean_shift_(nullptr),
skewness_(nullptr)
{
}
TableModels::TableModels(TableModel *model) :
model_(model),
sigma_{},
std_dev_(nullptr),
mean_shift_(nullptr),
skewness_(nullptr)
{
}
TableModels::~TableModels()
{
TableModel *sigma_early = sigma_[EarlyLate::earlyIndex()];
TableModel *sigma_late = sigma_[EarlyLate::lateIndex()];
if (sigma_early == sigma_late)
delete sigma_early;
else {
delete sigma_early;
delete sigma_late;
}
}
void
TableModels::setModel(TableModel *model)
{
model_.reset(model);
}
TableModel *
TableModels::sigma(const EarlyLate *early_late) const
{
return sigma_[early_late->index()];
}
void
TableModels::setSigma(TableModel *table,
const EarlyLate *early_late)
{
sigma_[early_late->index()] = table;
}
void
TableModels::setMeanShift(TableModel *table)
{
mean_shift_.reset(table);
}
void
TableModels::setSkewness(TableModel *table)
{
skewness_.reset(table);
}
void
TableModels::setStdDev(TableModel *table)
{
std_dev_.reset(table);
}
////////////////////////////////////////////////////////////////
TableModel::TableModel() :
table_(nullptr),
tbl_template_(nullptr),
@ -959,51 +1083,65 @@ Table::findValue(float axis_value1,
return value_;
if (order_ == 1)
return findValue(axis_value1);
if (order_ == 2) {
size_t size1 = axis1_->size();
size_t size2 = axis2_->size();
if (size1 == 1) {
if (size2 == 1)
return value(0, 0);
size_t axis_index2 = axis2_->findAxisIndex(axis_value2);
double x2 = axis_value2;
double y00 = value(0, axis_index2);
double x2l = axis2_->axisValue(axis_index2);
double x2u = axis2_->axisValue(axis_index2 + 1);
double dx2 = (x2 - x2l) / (x2u - x2l);
double y01 = value(0, axis_index2 + 1);
return (1 - dx2) * y00 + dx2 * y01;
}
if (size2 == 1) {
size_t axis_index1 = axis1_->findAxisIndex(axis_value1);
double x1 = axis_value1;
double y00 = value(axis_index1, 0);
double x1l = axis1_->axisValue(axis_index1);
double x1u = axis1_->axisValue(axis_index1 + 1);
double dx1 = (x1 - x1l) / (x1u - x1l);
double y10 = value(axis_index1 + 1, 0);
return (1 - dx1) * y00 + dx1 * y10;
}
size_t axis_index1 = axis1_->findAxisIndex(axis_value1);
if (order_ == 2)
return findValueOrder2(axis_value1, axis_value2);
else
return findValueOrder3(axis_value1, axis_value2, axis_value3);
}
float
Table::findValueOrder2(float axis_value1,
float axis_value2) const
{
size_t size1 = axis1_->size();
size_t size2 = axis2_->size();
if (size1 == 1) {
if (size2 == 1)
return value(0, 0);
size_t axis_index2 = axis2_->findAxisIndex(axis_value2);
double x1 = axis_value1;
double x2 = axis_value2;
double y00 = value(axis_index1, axis_index2);
double x1l = axis1_->axisValue(axis_index1);
double x1u = axis1_->axisValue(axis_index1 + 1);
double dx1 = (x1 - x1l) / (x1u - x1l);
double y10 = value(axis_index1 + 1, axis_index2);
double y11 = value(axis_index1 + 1, axis_index2 + 1);
double y00 = value(0, axis_index2);
double x2l = axis2_->axisValue(axis_index2);
double x2u = axis2_->axisValue(axis_index2 + 1);
double dx2 = (x2 - x2l) / (x2u - x2l);
double y01 = value(axis_index1, axis_index2 + 1);
return (1 - dx1) * (1 - dx2) * y00
+ dx1 * (1 - dx2) * y10
+ dx1 * dx2 * y11
+ (1 - dx1) * dx2 * y01;
double y01 = value(0, axis_index2 + 1);
return (1 - dx2) * y00 + dx2 * y01;
}
// order_ == 3 - trilinear interpolation
if (size2 == 1) {
size_t axis_index1 = axis1_->findAxisIndex(axis_value1);
double x1 = axis_value1;
double y00 = value(axis_index1, 0);
double x1l = axis1_->axisValue(axis_index1);
double x1u = axis1_->axisValue(axis_index1 + 1);
double dx1 = (x1 - x1l) / (x1u - x1l);
double y10 = value(axis_index1 + 1, 0);
return (1 - dx1) * y00 + dx1 * y10;
}
size_t axis_index1 = axis1_->findAxisIndex(axis_value1);
size_t axis_index2 = axis2_->findAxisIndex(axis_value2);
double x1 = axis_value1;
double x2 = axis_value2;
double y00 = value(axis_index1, axis_index2);
double x1l = axis1_->axisValue(axis_index1);
double x1u = axis1_->axisValue(axis_index1 + 1);
double dx1 = (x1 - x1l) / (x1u - x1l);
double y10 = value(axis_index1 + 1, axis_index2);
double y11 = value(axis_index1 + 1, axis_index2 + 1);
double x2l = axis2_->axisValue(axis_index2);
double x2u = axis2_->axisValue(axis_index2 + 1);
double dx2 = (x2 - x2l) / (x2u - x2l);
double y01 = value(axis_index1, axis_index2 + 1);
return (1 - dx1) * (1 - dx2) * y00
+ dx1 * (1 - dx2) * y10
+ dx1 * dx2 * y11
+ (1 - dx1) * dx2 * y01;
}
float
Table::findValueOrder3(float axis_value1,
float axis_value2,
float axis_value3) const
{
size_t axis_index1 = axis1_->findAxisIndex(axis_value1);
size_t axis_index2 = axis2_->findAxisIndex(axis_value2);
size_t axis_index3 = axis3_->findAxisIndex(axis_value3);

View File

@ -152,9 +152,8 @@ TimingArc::intrinsicDelay() const
{
GateTimingModel *model = dynamic_cast<GateTimingModel*>(model_);
if (model) {
ArcDelay arc_delay;
Slew slew;
model->gateDelay(nullptr, 0.0, 0.0, false, arc_delay, slew);
float arc_delay, slew;
model->gateDelay(nullptr, 0.0, 0.0, arc_delay, slew);
return arc_delay;
}
else

View File

@ -1173,7 +1173,7 @@ Power::findInputInternalPower(const Pin *pin,
int rf_count = 0;
for (const RiseFall *rf : RiseFall::range()) {
float slew = getSlew(vertex, rf, scene);
if (!delayInf(slew)) {
if (!delayInf(slew, this)) {
float table_energy = pwr->power(rf, pvt, slew, load_cap);
energy += table_energy;
rf_count++;
@ -1238,17 +1238,18 @@ Power::getMinRfSlew(const Pin *pin)
graph_->pinVertices(pin, vertex, bidir_vertex);
if (vertex) {
const MinMax *min_max = MinMax::min();
Slew mm_slew = min_max->initValue();
float mm_slew = min_max->initValue();
for (DcalcAPIndex ap_index = 0;
ap_index < dcalcAnalysisPtCount();
ap_index++) {
const Slew &slew1 = graph_->slew(vertex, RiseFall::rise(), ap_index);
const Slew &slew2 = graph_->slew(vertex, RiseFall::fall(), ap_index);
Slew slew = delayAsFloat(slew1 + slew2) / 2.0;
if (delayGreater(slew, mm_slew, min_max, this))
mm_slew = slew;
float slew_avg = (delayAsFloat(slew1, min_max, this)
+ delayAsFloat(slew2, min_max, this)) / 2.0;
if (delayGreater(slew_avg, mm_slew, min_max, this))
mm_slew = slew_avg;
}
return delayAsFloat(mm_slew);
return mm_slew;
}
return 0.0;
}
@ -1343,7 +1344,7 @@ Power::findOutputInternalPower(const LibertyPort *to_port,
float slew = from_vertex
? getSlew(from_vertex, from_rf, scene)
: 0.0;
if (!delayInf(slew)) {
if (!delayInf(slew, this)) {
float table_energy = pwr->power(to_rf, pvt, slew, load_cap);
energy += table_energy;
rf_count++;

View File

@ -39,7 +39,8 @@ Variables::Variables() :
dynamic_loop_breaking_(false),
propagate_all_clks_(false),
use_default_arrival_clock_(false),
pocv_enabled_(false)
pocv_mode_(PocvMode::scalar),
pocv_quantile_(3.0)
{
}
@ -115,10 +116,24 @@ Variables::setUseDefaultArrivalClock(bool enable)
use_default_arrival_clock_ = enable;
}
void
Variables::setPocvEnabled(bool enabled)
////////////////////////////////////////////////////////////////
bool
Variables::pocvEnabled() const
{
pocv_enabled_ = enabled;
return pocv_mode_ != PocvMode::scalar;
}
void
Variables::setPocvMode(PocvMode mode)
{
pocv_mode_ = mode;
}
void
Variables::setPocvQuantile(float quantile)
{
pocv_quantile_ = quantile;
}
} // namespace

View File

@ -735,7 +735,7 @@ SdfReader::setEdgeArcDelays(Edge *edge,
if (value_ptr) {
ArcDelay delay;
if (in_incremental_)
delay = *value_ptr + graph_->arcDelay(edge, arc, arc_delay_index);
delay = delaySum(graph_->arcDelay(edge, arc, arc_delay_index), *value_ptr, this);
else
delay = *value_ptr;
graph_->setArcDelay(edge, arc, arc_delay_index, delay);
@ -784,7 +784,7 @@ SdfReader::setEdgeArcDelaysCondUse(Edge *edge,
&& triple_index != null_index_) {
ArcDelay delay(*value);
if (!is_incremental_only_ && in_incremental_)
delay = graph_->arcDelay(edge, arc, arc_delay_index) + *value;
delay = delaySum(graph_->arcDelay(edge, arc, arc_delay_index), *value, this);
else if (graph_->arcDelayAnnotated(edge, arc, arc_delay_index)) {
ArcDelay prev_value = graph_->arcDelay(edge, arc, arc_delay_index);
if (delayGreater(prev_value, delay, min_max, this))

View File

@ -430,11 +430,11 @@ SdfWriter::writeArcDelays(Edge *edge)
TimingArcSet *arc_set = edge->timingArcSet();
for (TimingArc *arc : arc_set->arcs()) {
const RiseFall *rf = arc->toEdge()->asRiseFall();
ArcDelay min_delay = graph_->arcDelay(edge, arc, arc_delay_min_index_);
delays.setValue(rf, MinMax::min(), delayAsFloat(min_delay));
const ArcDelay &min_delay = graph_->arcDelay(edge, arc, arc_delay_min_index_);
delays.setValue(rf, MinMax::min(), delayAsFloat(min_delay, MinMax::min(), this));
ArcDelay max_delay = graph_->arcDelay(edge, arc, arc_delay_max_index_);
delays.setValue(rf, MinMax::max(), delayAsFloat(max_delay));
const ArcDelay &max_delay = graph_->arcDelay(edge, arc, arc_delay_max_index_);
delays.setValue(rf, MinMax::max(), delayAsFloat(max_delay, MinMax::max(), this));
}
if (delays.hasValue(RiseFall::rise(), MinMax::min())
@ -527,8 +527,10 @@ SdfWriter::writeTimingChecks(const Instance *inst,
TimingArc *arc;
graph_->minPulseWidthArc(vertex, hi_low, edge, arc);
if (edge) {
min_width = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_min_index_));
max_width = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_max_index_));
min_width = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_min_index_),
MinMax::min(), this);
max_width = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_max_index_),
MinMax::max(), this);
ensureTimingCheckheaders(check_header, inst, inst_header);
writeWidthCheck(pin, hi_low, min_width, max_width);
}
@ -615,30 +617,37 @@ SdfWriter::writeEdgeCheck(Edge *edge,
if (arcs[clk_rf_index][RiseFall::riseIndex()]
&& arcs[clk_rf_index][RiseFall::fallIndex()]
&& arcs[clk_rf_index][RiseFall::riseIndex()]
&& arcs[clk_rf_index][RiseFall::fallIndex()]
&& delayEqual(graph_->arcDelay(edge,
arcs[clk_rf_index][RiseFall::riseIndex()],
arc_delay_min_index_),
graph_->arcDelay(edge,
arcs[clk_rf_index][RiseFall::fallIndex()],
arc_delay_min_index_))
&& delayEqual(graph_->arcDelay(edge,
arcs[clk_rf_index][RiseFall::riseIndex()],
arc_delay_max_index_),
graph_->arcDelay(edge,
arcs[clk_rf_index][RiseFall::fallIndex()],
arc_delay_max_index_)))
// Rise/fall margins are the same, so no data edge specifier is required.
writeCheck(edge, arcs[clk_rf_index][RiseFall::riseIndex()],
sdf_check, false, true);
else {
if (arcs[clk_rf_index][RiseFall::riseIndex()])
writeCheck(edge, arcs[clk_rf_index][RiseFall::riseIndex()],
sdf_check, true, true);
if (arcs[clk_rf_index][RiseFall::fallIndex()])
writeCheck(edge, arcs[clk_rf_index][RiseFall::fallIndex()],
sdf_check, true, true);
&& arcs[clk_rf_index][RiseFall::fallIndex()]) {
float rise_min=delayAsFloat(graph_->arcDelay(edge,
arcs[clk_rf_index][RiseFall::riseIndex()],
arc_delay_min_index_),
MinMax::min(), this);
float fall_min=delayAsFloat(graph_->arcDelay(edge,
arcs[clk_rf_index][RiseFall::fallIndex()],
arc_delay_min_index_),
MinMax::min(), this);
float rise_max=delayAsFloat(graph_->arcDelay(edge,
arcs[clk_rf_index][RiseFall::riseIndex()],
arc_delay_max_index_),
MinMax::max(), this);
float fall_max=delayAsFloat(graph_->arcDelay(edge,
arcs[clk_rf_index][RiseFall::fallIndex()],
arc_delay_max_index_),
MinMax::max(), this);
if (fuzzyEqual(rise_min, fall_min)
&& fuzzyEqual(rise_max, fall_max)) {
// Rise/fall margins are the same, so no data edge specifier is required.
writeCheck(edge, arcs[clk_rf_index][RiseFall::riseIndex()],
sdf_check, false, true);
return;
}
}
if (arcs[clk_rf_index][RiseFall::riseIndex()])
writeCheck(edge, arcs[clk_rf_index][RiseFall::riseIndex()],
sdf_check, true, true);
if (arcs[clk_rf_index][RiseFall::fallIndex()])
writeCheck(edge, arcs[clk_rf_index][RiseFall::fallIndex()],
sdf_check, true, true);
}
void
@ -689,9 +698,11 @@ SdfWriter::writeCheck(Edge *edge,
gzprintf(stream_, " ");
ArcDelay min_delay = graph_->arcDelay(edge, arc, arc_delay_min_index_);
ArcDelay max_delay = graph_->arcDelay(edge, arc, arc_delay_max_index_);
writeSdfTriple(delayAsFloat(min_delay), delayAsFloat(max_delay));
float min_delay = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_min_index_),
MinMax::min(), this);
float max_delay = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_max_index_),
MinMax::max(), this);
writeSdfTriple(min_delay, max_delay);
gzprintf(stream_, ")\n");
}

View File

@ -178,15 +178,15 @@ MaxSkewCheck::maxSkew(const StaState *sta) const
}
Delay
MaxSkewCheck::skew() const
MaxSkewCheck::skew(const StaState *sta) const
{
return Delay(clk_path_->arrival() - ref_path_->arrival());
return delayDiff(clk_path_->arrival(), ref_path_->arrival(), sta);
}
Slack
MaxSkewCheck::slack(const StaState *sta) const
{
return maxSkew(sta) - skew();
return delayDiff(maxSkew(sta), skew(sta), sta);
}
////////////////////////////////////////////////////////////////
@ -203,7 +203,7 @@ MaxSkewSlackLess::operator()(const MaxSkewCheck &check1,
Slack slack1 = check1.slack(sta_);
Slack slack2 = check2.slack(sta_);
return delayLess(slack1, slack2, sta_)
|| (delayEqual(slack1, slack2)
|| (delayEqual(slack1, slack2, sta_)
// Break ties based on constrained pin names.
&& sta_->network()->pinLess(check1.clkPin(sta_), check2.clkPin(sta_)));
}

View File

@ -48,7 +48,7 @@ public:
Pin *clkPin(const StaState *sta) const;
const Path *refPath() const { return ref_path_; }
Pin *refPin(const StaState *sta) const;
Delay skew() const;
Delay skew(const StaState *sta) const;
ArcDelay maxSkew(const StaState *sta) const;
Slack slack(const StaState *sta) const;
TimingArc *checkArc() const { return check_arc_; }

View File

@ -198,7 +198,7 @@ MinPeriodSlackLess::operator()(const MinPeriodCheck &check1,
const Pin *pin2 = check2.pin();
return delayLess(slack1, slack2, sta_)
// Break ties based on pin and clock names.
|| (delayEqual(slack1, slack2)
|| (delayEqual(slack1, slack2, sta_)
&& (sta_->network()->pinLess(pin1, pin2)
|| (pin1 == pin2
&& ClockNameLess()(check1.clk(),

View File

@ -252,13 +252,13 @@ MinPulseWidthCheck::closeArrival(const StaState *sta) const
Arrival
MinPulseWidthCheck::openDelay(const StaState *sta) const
{
return openArrival(sta) - openClkEdge(sta)->time();
return delayDiff(openArrival(sta), openClkEdge(sta)->time(), sta);
}
Arrival
MinPulseWidthCheck::closeDelay(const StaState *sta) const
{
return closeArrival(sta) - closeClkEdge(sta)->time();
return delayDiff(closeArrival(sta), closeClkEdge(sta)->time(), sta);
}
const ClockEdge *
@ -289,9 +289,11 @@ MinPulseWidthCheck::closeOffset(const StaState *sta) const
Arrival
MinPulseWidthCheck::width(const StaState *sta) const
{
return closeArrival(sta) + closeOffset(sta)
- open_path_->arrival()
+ checkCrpr(sta);
Arrival close_with_offset = delaySum(closeArrival(sta),
closeOffset(sta),
sta);
Arrival minus_open = delayDiff(close_with_offset, open_path_->arrival(), sta);
return delaySum(minus_open, checkCrpr(sta), sta);
}
float
@ -323,6 +325,7 @@ minPulseWidth(const Path *path,
// set_min_pulse_width command.
sdc->minPulseWidth(pin, clk, rf, min_width, exists);
if (!exists) {
const MinMax *min_max = path->minMax(sta);
DcalcAPIndex dcalc_ap = path->dcalcAnalysisPtIndex(sta);
Vertex *vertex = path->vertex(sta);
Graph *graph = sta->graph();
@ -330,7 +333,7 @@ minPulseWidth(const Path *path,
TimingArc *arc;
graph->minPulseWidthArc(vertex, rf, edge, arc);
if (edge) {
min_width = delayAsFloat(graph->arcDelay(edge, arc, dcalc_ap));
min_width = delayAsFloat(graph->arcDelay(edge, arc, dcalc_ap), min_max, sta);
exists = true;
}
}
@ -350,7 +353,7 @@ MinPulseWidthCheck::checkCrpr(const StaState *sta) const
Slack
MinPulseWidthCheck::slack(const StaState *sta) const
{
return width(sta) - minWidth(sta);
return delayDiff(width(sta), minWidth(sta), sta);
}
Scene *
@ -375,7 +378,7 @@ MinPulseWidthSlackLess::operator()(const MinPulseWidthCheck &check1,
const Pin *pin1 = check1.pin(sta_);
const Pin *pin2 = check2.pin(sta_);
return delayLess(slack1, slack2, sta_)
|| (delayEqual(slack1, slack2)
|| (delayEqual(slack1, slack2, sta_)
// Break ties for the sake of regression stability.
&& (sta_->network()->pinLess(pin1, pin2)
|| (pin1 == pin2

View File

@ -61,9 +61,9 @@ public:
StaState *sta);
private:
static float insertionDelay(Path *clk_path,
static Delay insertionDelay(Path *clk_path,
StaState *sta);
static float delay(Path *clk_path,
static Delay delay(Path *clk_path,
StaState *sta);
static float clkTreeDelay(Path *clk_path,
StaState *sta);

View File

@ -102,7 +102,7 @@ ClkInfo::findHash(const StaState *sta)
hashIncr(hash_, hash_float(uncertainty));
}
hashIncr(hash_, hash_float(latency_));
hashIncr(hash_, hash_float(delayAsFloat(insertion_)));
hashIncr(hash_, hash_float(insertion_.mean()));
hashIncr(hash_, is_propagated_);
hashIncr(hash_, is_gen_clk_src_path_);
hashIncr(hash_, is_pulse_clk_);
@ -152,9 +152,10 @@ ClkInfo::to_string(const StaState *sta) const
Network *network = sta->network();
std::string result;
const MinMax *min_max = minMax();
result += scene_->name();
result += "/";
result += minMax()->to_string();
result += min_max->to_string();
result += " ";
if (clk_edge_)
@ -186,7 +187,7 @@ ClkInfo::to_string(const StaState *sta) const
if (delayGreater(insertion_, 0.0, sta)) {
result += " insert";
result += delayAsString(insertion_, sta);
result += delayAsString(insertion_, min_max, sta);
}
if (uncertainties_) {

View File

@ -116,15 +116,15 @@ ClkLatency::reportClkLatency(const Clock *clk,
report_->reportLine(" min max");
report_->reportLine("%7s %7s source latency",
delayAsString(insertion_min, this, digits),
delayAsString(insertion_max, this, digits));
delayAsString(insertion_min, MinMax::min(), digits, this),
delayAsString(insertion_max, MinMax::max(), digits, this));
report_->reportLine("%7s %7s network latency %s",
delayAsString(delay_min, this, digits),
delayAsString(delay_min, MinMax::min(), digits, this),
"",
sdc_network_->pathName(path_min.pin(this)));
report_->reportLine("%7s %7s network latency %s",
"",
delayAsString(delay_max, this, digits),
delayAsString(delay_max, MinMax::max(), digits, this),
sdc_network_->pathName(path_max.pin(this)));
if (internal_latency_min != 0.0
|| internal_latency_max != 0.0)
@ -133,11 +133,11 @@ ClkLatency::reportClkLatency(const Clock *clk,
time_unit->asString(internal_latency_max, digits));
report_->reportLine("---------------");
report_->reportLine("%7s %7s latency",
delayAsString(latency_min, this, digits),
delayAsString(latency_max, this, digits));
Delay skew = latency_max - latency_min;
delayAsString(latency_min, MinMax::min(), digits, this),
delayAsString(latency_max, MinMax::max(), digits, this));
Delay skew = delayDiff(latency_max, latency_min, this);
report_->reportLine(" %7s skew",
delayAsString(skew, this, digits));
delayAsString(skew, MinMax::max(), digits, this));
report_->reportBlankLine();
}
}
@ -255,10 +255,10 @@ ClkDelays::setLatency(const RiseFall *src_rf,
int end_rf_index = end_rf->index();
int mm_index = min_max->index();
float insertion = insertionDelay(path, sta);
Delay insertion = insertionDelay(path, sta);
insertion_[src_rf_index][end_rf_index][mm_index] = insertion;
float delay1 = delay(path, sta);
Delay delay1 = delay(path, sta);
delay_[src_rf_index][end_rf_index][mm_index] = delay1;
float internal_latency = 0.0;
@ -267,7 +267,7 @@ ClkDelays::setLatency(const RiseFall *src_rf,
internal_latency_[src_rf_index][end_rf_index][mm_index] = internal_latency;
}
float latency = insertion + delay1 + internal_latency;
Delay latency = delaySum(delay1, delaySum(insertion, internal_latency, sta), sta);
latency_[src_rf_index][end_rf_index][mm_index] = latency;
path_[src_rf_index][end_rf_index][mm_index] = *path;
@ -279,22 +279,22 @@ ClkDelays::latency(Path *clk_path,
StaState *sta)
{
float insertion = insertionDelay(clk_path, sta);
float delay1 = delay(clk_path, sta);
Delay insertion = insertionDelay(clk_path, sta);
Delay delay1 = delay(clk_path, sta);
float lib_clk_delay = clkTreeDelay(clk_path, sta);
return insertion + delay1 + lib_clk_delay;
return delaySum(delay1, delaySum(insertion, lib_clk_delay, sta), sta);
}
float
Delay
ClkDelays::delay(Path *clk_path,
StaState *sta)
{
Arrival arrival = clk_path->arrival();
const ClockEdge *path_clk_edge = clk_path->clkEdge(sta);
return delayAsFloat(arrival) - path_clk_edge->time();
return delayDiff(arrival, path_clk_edge->time(), sta);
}
float
Delay
ClkDelays::insertionDelay(Path *clk_path,
StaState *sta)
{
@ -305,8 +305,7 @@ ClkDelays::insertionDelay(Path *clk_path,
const Pin *src_pin = clk_info->clkSrc();
const MinMax *min_max = clk_path->minMax(sta);
const Mode *mode = clk_path->mode(sta);
return delayAsFloat(sta->search()->clockInsertion(clk, src_pin, clk_rf, min_max,
min_max, mode));
return sta->search()->clockInsertion(clk, src_pin, clk_rf, min_max, min_max, mode);
}
float
@ -318,7 +317,7 @@ ClkDelays::clkTreeDelay(Path *clk_path,
const LibertyPort *port = sta->network()->libertyPort(pin);
const MinMax *min_max = clk_path->minMax(sta);
const RiseFall *rf = clk_path->transition(sta);
float slew = delayAsFloat(clk_path->slew(sta));
float slew = delayAsFloat(clk_path->slew(sta), min_max, sta);
return port->clkTreeDelay(slew, rf, min_max);
}

View File

@ -95,16 +95,17 @@ ClkSkews::reportClkSkew(ClkSkew &clk_skew,
Unit *time_unit = units_->timeUnit();
Path *src_path = clk_skew.srcPath();
Path *tgt_path = clk_skew.tgtPath();
float src_latency = clk_skew.srcLatency(this);
const MinMax *src_min_max = src_path->minMax(this);
Arrival src_latency = clk_skew.srcLatency(this);
float tgt_latency = clk_skew.tgtLatency(this);
float src_internal_clk_latency = clk_skew.srcInternalClkLatency(this);
float tgt_internal_clk_latency = clk_skew.tgtInternalClkLatency(this);
float uncertainty = clk_skew.uncertainty(this);
if (src_internal_clk_latency != 0.0)
src_latency -= src_internal_clk_latency;
delayDecr(src_latency, src_internal_clk_latency, this);
report_->reportLine("%7s source latency %s %s",
time_unit->asString(src_latency, digits),
delayAsString(src_latency, src_min_max, digits, this),
sdc_network_->pathName(src_path->pin(this)),
src_path->transition(this)->shortName());
if (src_internal_clk_latency != 0.0)
@ -124,15 +125,32 @@ ClkSkews::reportClkSkew(ClkSkew &clk_skew,
report_->reportLine("%7s clock uncertainty",
time_unit->asString(uncertainty, digits));
report_->reportLine("%7s CRPR",
time_unit->asString(delayAsFloat(-clk_skew.crpr(this)),
digits));
delayAsString(delayDiff(0.0, clk_skew.crpr(this), this),
MinMax::max(), digits, this));
report_->reportLine("--------------");
report_->reportLine("%7s %s skew",
time_unit->asString(clk_skew.skew(), digits),
delayAsString(clk_skew.skew(), MinMax::max(), digits, this),
src_path->minMax(this) == MinMax::max() ? "setup" : "hold");
}
float
static float
delayAbsMax(const Delay &delay,
const StaState *sta)
{
float min = delayAsFloat(delay, MinMax::min(), sta);
float max = delayAsFloat(delay, MinMax::max(), sta);
return std::max(std::abs(min), std::abs(max));
}
static bool
delayAbsGreater(const Delay &delay1,
const Delay &delay2,
const StaState *sta)
{
return delayAbsMax(delay1, sta) > delayAbsMax(delay2, sta);
}
Delay
ClkSkews::findWorstClkSkew(const SceneSeq &scenes,
const SetupHold *setup_hold,
bool include_internal_latency)
@ -143,10 +161,10 @@ ClkSkews::findWorstClkSkew(const SceneSeq &scenes,
clks.push_back(clk);
}
findClkSkew(clks, scenes, include_internal_latency);
float worst_skew = 0.0;
Delay worst_skew = 0.0;
for (const auto& [clk, clk_skews] : skews_) {
float skew = clk_skews[setup_hold->index()].skew();
if (std::abs(skew) > std::abs(worst_skew))
Delay skew = clk_skews[setup_hold->index()].skew();
if (delayAbsGreater(skew, worst_skew, this))
worst_skew = skew;
}
return worst_skew;
@ -206,10 +224,12 @@ ClkSkews::findClkSkew(ConstClockSeq &clks,
for (int setup_hold_idx : SetupHold::rangeIndex()) {
ClkSkew &final_skew = itr->second[setup_hold_idx];
ClkSkew &partial_skew_val = partial_skew[setup_hold_idx];
float partial_skew1 = partial_skew_val.skew();
float final_skew1 = final_skew.skew();
if (std::abs(partial_skew1) > std::abs(final_skew1)
|| (fuzzyEqual(std::abs(partial_skew1), std::abs(final_skew1))
Delay partial_skew1 = partial_skew_val.skew();
Delay final_skew1 = final_skew.skew();
float partial_skew_max = delayAbsMax(partial_skew1, this);
float final_skew_max = delayAbsMax(final_skew1, this);
if (partial_skew_max > final_skew_max
|| (fuzzyEqual(partial_skew_max, final_skew_max)
// Break ties based on source/target path names.
&& ClkSkew::srcTgtPathNameLess(partial_skew_val, final_skew, this)))
final_skew = partial_skew_val;
@ -299,7 +319,8 @@ ClkSkews::findClkSkew(Vertex *src_vertex,
&& src_rf->matches(src_path->transition(this))
&& clk_set_.contains(src_clk)
&& scenes_set_.contains(src_scene)) {
const MinMax *tgt_min_max = src_path->minMax(this)->opposite();
const MinMax *src_min_max = src_path->minMax(this);
const MinMax *tgt_min_max = src_min_max->opposite();
VertexPathIterator tgt_iter(tgt_vertex, this);
while (tgt_iter.hasNext()) {
Path *tgt_path = tgt_iter.next();
@ -316,14 +337,14 @@ ClkSkews::findClkSkew(Vertex *src_vertex,
"%s %s %s -> %s %s %s crpr = %s skew = %s",
network_->pathName(src_path->pin(this)),
src_path->transition(this)->shortName(),
time_unit->asString(probe.srcLatency(this)),
delayAsString(probe.srcLatency(this), src_min_max, this),
network_->pathName(tgt_path->pin(this)),
tgt_path->transition(this)->shortName(),
time_unit->asString(probe.tgtLatency(this)),
delayAsString(probe.crpr(this), this),
time_unit->asString(probe.skew()));
delayAsString(probe.skew(), MinMax::max(), this));
if (clk_skew.srcPath() == nullptr
|| std::abs(probe.skew()) > std::abs(clk_skew.skew()))
|| delayAbsGreater(probe.skew(), clk_skew.skew(), this))
clk_skew = probe;
}
}
@ -380,10 +401,8 @@ ClkSkew::ClkSkew(Path *src_path,
tgt_path_(tgt_path),
include_internal_latency_(include_internal_latency)
{
skew_ = srcLatency(sta)
- tgtLatency(sta)
- delayAsFloat(crpr(sta))
+ uncertainty(sta);
skew_ = delayDiff(delaySum(srcLatency(sta), uncertainty(sta), sta),
delaySum(tgtLatency(sta), crpr(sta), sta), sta);
}
ClkSkew::ClkSkew(const ClkSkew &clk_skew)
@ -403,12 +422,11 @@ ClkSkew::operator=(const ClkSkew &clk_skew)
skew_ = clk_skew.skew_;
}
float
Arrival
ClkSkew::srcLatency(const StaState *sta)
{
Arrival src_arrival = src_path_->arrival();
return delayAsFloat(src_arrival) - src_path_->clkEdge(sta)->time()
+ clkTreeDelay(src_path_, sta);
return delayDiff(delaySum(src_path_->arrival(), clkTreeDelay(src_path_, sta), sta),
src_path_->clkEdge(sta)->time(), sta);
}
float
@ -421,8 +439,8 @@ float
ClkSkew::tgtLatency(const StaState *sta)
{
Arrival tgt_arrival = tgt_path_->arrival();
return delayAsFloat(tgt_arrival) - tgt_path_->clkEdge(sta)->time()
+ clkTreeDelay(tgt_path_, sta);
return delayAsFloat(delaySum(delayDiff(tgt_arrival, tgt_path_->clkEdge(sta)->time(),sta),
clkTreeDelay(tgt_path_, sta), sta));
}
float
@ -441,7 +459,7 @@ ClkSkew::clkTreeDelay(Path *clk_path,
const LibertyPort *port = sta->network()->libertyPort(pin);
const MinMax *min_max = clk_path->minMax(sta);
const RiseFall *rf = clk_path->transition(sta);
float slew = delayAsFloat(clk_path->slew(sta));
float slew = delayAsFloat(clk_path->slew(sta), min_max, sta);
return port->clkTreeDelay(slew, rf, min_max);
}
else

View File

@ -52,13 +52,13 @@ public:
void operator=(const ClkSkew &clk_skew);
Path *srcPath() { return src_path_; }
Path *tgtPath() { return tgt_path_; }
float srcLatency(const StaState *sta);
Arrival srcLatency(const StaState *sta);
float tgtLatency(const StaState *sta);
float srcInternalClkLatency(const StaState *sta);
float tgtInternalClkLatency(const StaState *sta);
Crpr crpr(const StaState *sta);
float uncertainty(const StaState *sta);
float skew() const { return skew_; }
Delay skew() const { return skew_; }
static bool srcTgtPathNameLess(ClkSkew &clk_skew1,
ClkSkew &clk_skew2,
const StaState *sta);
@ -70,7 +70,7 @@ private:
Path *src_path_;
Path *tgt_path_;
bool include_internal_latency_;
float skew_;
Delay skew_;
};
using ClkSkewMap = std::map<const Clock*, ClkSkew[SetupHold::index_count]>;
@ -97,7 +97,7 @@ public:
bool include_internal_latency,
int digits);
// Find worst clock skew between src/target registers.
float findWorstClkSkew(const SceneSeq &scenes,
Delay findWorstClkSkew(const SceneSeq &scenes,
const SetupHold *setup_hold,
bool include_internal_latency);

View File

@ -273,19 +273,16 @@ CheckCrpr::findCrpr1(const Path *src_clk_path,
if (variables_->pocvEnabled()) {
// Remove variation on the common path.
// Note that the crpr sigma is negative to offset the
// sigma of the common clock path.
const EarlyLate *src_el = src_clk_path->minMax(this);
const EarlyLate *tgt_el = tgt_clk_path->minMax(this);
Arrival src_arrival = src_clk_path->arrival();
Arrival tgt_arrival = tgt_clk_path->arrival();
// std_dev of the common clock path.
const Arrival &src_arrival = src_clk_path->arrival();
const Arrival &tgt_arrival = tgt_clk_path->arrival();
float src_clk_time = src_clk_path->clkEdge(this)->time();
float tgt_clk_time = tgt_clk_path->clkEdge(this)->time();
float crpr_mean = std::abs(delayAsFloat(src_arrival) - src_clk_time
- (delayAsFloat(tgt_arrival) - tgt_clk_time));
float crpr_mean = std::abs(src_arrival.mean() - src_clk_time
- (tgt_arrival.mean() - tgt_clk_time));
// Remove the sigma from both source and target path arrivals.
float crpr_sigma2 = delaySigma2(src_arrival, src_el)
+ delaySigma2(tgt_arrival, tgt_el);
return makeDelay2(crpr_mean, -crpr_sigma2, -crpr_sigma2);
float crpr_sigma2 = src_arrival.stdDev2() + tgt_arrival.stdDev2();
return makeDelay2(crpr_mean, -crpr_sigma2);
}
else {
// The source and target edges are different so the crpr
@ -308,8 +305,9 @@ float
CheckCrpr::crprArrivalDiff(const Path *path)
{
Arrival other_arrival = otherMinMaxArrival(path);
float crpr_diff = std::abs(delayAsFloat(path->arrival())
- delayAsFloat(other_arrival));
const MinMax *min_max = path->minMax(this);
float crpr_diff = std::abs(delayAsFloat(path->arrival(), min_max, this)
- delayAsFloat(other_arrival, min_max->opposite(), this));
return crpr_diff;
}

View File

@ -70,7 +70,7 @@ Latches::latchRequired(const Path *data_path,
ignore_clk_latency = path_delay->ignoreClkLatency();
}
if (ignore_clk_latency) {
required = max_delay + src_clk_latency;
required = delaySum(src_clk_latency, max_delay, this);
borrow = 0.0;
adjusted_data_arrival = data_arrival;
time_given_to_startpoint = 0.0;
@ -98,13 +98,15 @@ Latches::latchRequired(const Path *data_path,
// checkTgtClkTime
float tgt_clk_time = path_delay ? 0.0 : acct->requiredTime(check_role);
// checkTgtClkArrival broken down into components.
Arrival enable_arrival = max_delay
+ tgt_clk_time
+ open_latency
+ open_uncertainty
+ PathEnd::checkSetupMcpAdjustment(data_clk_edge, enable_clk_edge, mcp,
1, sdc)
+ open_crpr;
Arrival enable_arrival = delaySum(max_delay
+ tgt_clk_time
+ open_uncertainty
+ PathEnd::checkSetupMcpAdjustment(data_clk_edge,
enable_clk_edge,
mcp, 1, sdc),
open_latency,
this);
enable_arrival = delaySum(enable_arrival, open_crpr, this);
debugPrint(debug_, "latch", 1, "data %s enable %s",
delayAsString(data_arrival, this),
delayAsString(enable_arrival, this));
@ -117,25 +119,31 @@ Latches::latchRequired(const Path *data_path,
}
else {
// Data arrives while latch is transparent.
borrow = data_arrival - enable_arrival;
borrow = delayDiff(data_arrival, enable_arrival, this);
if (delayLessEqual(borrow, max_borrow, this))
required = data_arrival;
else {
borrow = max_borrow;
required = enable_arrival + max_borrow;
required = delaySum(enable_arrival, max_borrow, this);
}
time_given_to_startpoint = borrow + open_uncertainty + open_crpr;
time_given_to_startpoint = delaySum(delaySum(borrow,
open_uncertainty,
this),
open_crpr, this);
// Cycle accounting for required time is with respect to the
// data clock zeroth cycle. The data departs the latch
// with respect to the enable clock zeroth cycle.
float data_shift_to_enable_clk = acct->sourceTimeOffset(check_role)
- acct->targetTimeOffset(check_role);
adjusted_data_arrival = required + data_shift_to_enable_clk;
adjusted_data_arrival = delaySum(required, data_shift_to_enable_clk, this);
}
}
else if (disable_path) {
required = max_delay + search_->clkPathArrival(disable_path) - margin;
required = delayDiff(delaySum(max_delay,
search_->clkPathArrival(disable_path),
this),
margin, this);
// Borrow cannot be determined without enable path.
borrow = 0.0;
adjusted_data_arrival = data_arrival;
@ -176,7 +184,7 @@ Latches::latchBorrowInfo(const Path *data_path,
const ClockEdge *enable_clk_edge = enable_path->clkEdge(this);
const ClockEdge *disable_clk_edge = disable_path->clkEdge(this);
bool is_pulse_clk = enable_path->clkInfo(this)->isPulseClk();
nom_pulse_width = is_pulse_clk ? 0.0F : enable_clk_edge->pulseWidth();
nom_pulse_width = is_pulse_clk ? 0.0 : enable_clk_edge->pulseWidth();
open_uncertainty = PathEnd::checkClkUncertainty(data_clk_edge, enable_clk_edge,
enable_path,
TimingRole::latchSetup(), sdc);
@ -190,14 +198,14 @@ Latches::latchBorrowInfo(const Path *data_path,
CheckCrpr *check_crpr = search_->checkCrpr();
open_crpr = check_crpr->checkCrpr(data_path, enable_path);
Crpr close_crpr = check_crpr->checkCrpr(data_path, disable_path);
crpr_diff = open_crpr - close_crpr;
crpr_diff = delayDiff(open_crpr, close_crpr, this);
open_latency = PathEnd::checkTgtClkDelay(enable_path, enable_clk_edge,
TimingRole::setup(), this);
Arrival close_latency = PathEnd::checkTgtClkDelay(disable_path,
disable_clk_edge,
TimingRole::latchSetup(),
this);
latency_diff = open_latency - close_latency;
latency_diff = delayDiff(open_latency, close_latency, this);
}
float borrow_limit;
sdc->latchBorrowLimit(data_path->pin(this), disable_path->pin(this),
@ -206,8 +214,9 @@ Latches::latchBorrowInfo(const Path *data_path,
if (borrow_limit_exists)
max_borrow = borrow_limit;
else
max_borrow = nom_pulse_width - delayAsFloat(latency_diff)
- delayAsFloat(crpr_diff) - delayAsFloat(margin);
max_borrow = delayDiff(nom_pulse_width,
delaySum(delaySum(latency_diff, crpr_diff, this),
margin, this), this);
}
else {
nom_pulse_width = 0.0;
@ -349,7 +358,7 @@ Latches::latchOutArrival(const Path *data_path,
if (!(excpt && excpt->isFalse())) {
arc_delay = search_->deratedDelay(data_vertex, d_q_arc, d_q_edge,
false, min_max, dcalc_ap, sdc);
q_arrival = data_path->arrival() + arc_delay;
q_arrival = delaySum(data_path->arrival(), arc_delay, this);
// Copy the data tag but remove the drprClkPath.
// Levelization does not traverse latch D->Q edges, so in some cases
// level(Q) < level(D)
@ -405,7 +414,7 @@ Latches::latchOutArrival(const Path *data_path,
// Latch is transparent when data arrives.
arc_delay = search_->deratedDelay(data_vertex, d_q_arc, d_q_edge,
false, min_max, dcalc_ap, sdc);
q_arrival = adjusted_data_arrival + arc_delay;
q_arrival = delaySum(adjusted_data_arrival, arc_delay, this);
// Tag switcheroo - data passing thru gets latch enable tag.
// States and path ap come from Q, everything else from enable.
Path *crpr_clk_path = crprActive(mode) ? enable_path : nullptr;

View File

@ -281,9 +281,9 @@ MakeEndTimingArcs::visit(PathEnd *path_end)
Arrival data_delay = src_path->arrival();
Delay clk_latency = path_end->targetClkDelay(sta_);
ArcDelay check_margin = path_end->margin(sta_);
Delay margin = min_max == MinMax::max()
? data_delay - clk_latency + check_margin
: clk_latency - data_delay + check_margin;
Delay margin = (min_max == MinMax::max())
? delaySum(delayDiff(data_delay, clk_latency, sta_), check_margin, sta_)
: delaySum(delayDiff(clk_latency, data_delay, sta_), check_margin, sta_);
float delay1 = delayAsFloat(margin, MinMax::max(), sta_);
debugPrint(debug, "make_timing_model", 2, "%s -> %s clock %s %s %s %s",
input_rf_->shortName(),
@ -605,10 +605,10 @@ MakeTimingModel::makeScalarCheckModel(float value,
TablePtr table = std::make_shared<Table>(value);
TableTemplate *tbl_template =
library_->findTableTemplate("scalar", TableTemplateType::delay);
TableModel *table_model = new TableModel(table, tbl_template,
scale_factor_type, rf);
CheckTableModel *check_model = new CheckTableModel(cell_, table_model);
return check_model;
TableModel *check_table = new TableModel(table, tbl_template, scale_factor_type, rf);
TableModels *check_tables = new TableModels(check_table);
CheckTableModel *check = new CheckTableModel(cell_, check_tables);
return check;
}
TimingModel *
@ -622,9 +622,12 @@ MakeTimingModel::makeGateModelScalar(Delay delay,
library_->findTableTemplate("scalar", TableTemplateType::delay);
TableModel *delay_model = new TableModel(delay_table, tbl_template,
ScaleFactorType::cell, rf);
TableModels *delay_models = new TableModels(delay_model);
TableModel *slew_model = new TableModel(slew_table, tbl_template,
ScaleFactorType::cell, rf);
GateTableModel *gate_model = new GateTableModel(cell_, delay_model, slew_model);
TableModels *slew_models = new TableModels(slew_model);
GateTableModel *gate_model = new GateTableModel(cell_, delay_models, slew_models,
nullptr, nullptr);
return gate_model;
}
@ -637,7 +640,9 @@ MakeTimingModel::makeGateModelScalar(Delay delay,
library_->findTableTemplate("scalar", TableTemplateType::delay);
TableModel *delay_model = new TableModel(delay_table, tbl_template,
ScaleFactorType::cell, rf);
GateTableModel *gate_model = new GateTableModel(cell_, delay_model, nullptr);
TableModels *models = new TableModels(delay_model);
GateTableModel *gate_model = new GateTableModel(cell_, models, nullptr,
nullptr, nullptr);
return gate_model;
}
@ -674,12 +679,11 @@ MakeTimingModel::makeGateModelTable(const Pin *output_pin,
float output_load_cap = graph_delay_calc_->loadCap(output_pin,
scene_,
min_max_);
ArcDelay drvr_self_delay;
Slew drvr_self_slew;
drvr_gate_model->gateDelay(pvt, in_slew1, output_load_cap, false,
float drvr_self_delay, drvr_self_slew;
drvr_gate_model->gateDelay(pvt, in_slew1, output_load_cap,
drvr_self_delay, drvr_self_slew);
const TableModel *drvr_table = drvr_gate_model->delayModel();
const TableModel *drvr_table = drvr_gate_model->delayModels()->model();
const TableTemplate *drvr_template = drvr_table->tblTemplate();
const TableAxis *drvr_load_axis = loadCapacitanceAxis(drvr_table);
if (drvr_load_axis) {
@ -689,13 +693,13 @@ MakeTimingModel::makeGateModelTable(const Pin *output_pin,
for (size_t i = 0; i < drvr_axis_values.size(); i++) {
float load_cap = drvr_axis_values[i];
// get slew from driver input pin
ArcDelay gate_delay;
Slew gate_slew;
drvr_gate_model->gateDelay(pvt, in_slew1, load_cap, false,
float gate_delay, gate_slew;
drvr_gate_model->gateDelay(pvt, in_slew1, load_cap,
gate_delay, gate_slew);
// Remove the self delay driving the output pin net load cap.
load_values->push_back(delayAsFloat(delay + gate_delay
- drvr_self_delay));
load_values->push_back(delayAsFloat(delay)
+ gate_delay
- drvr_self_delay);
slew_values->push_back(delayAsFloat(gate_slew));
}
@ -711,10 +715,14 @@ MakeTimingModel::makeGateModelTable(const Pin *output_pin,
load_axis);
TableModel *delay_model = new TableModel(delay_table, model_template,
ScaleFactorType::cell, rf);
TableModels *delay_models = new TableModels(delay_model);
TableModel *slew_model = new TableModel(slew_table, model_template,
ScaleFactorType::cell, rf);
GateTableModel *gate_model = new GateTableModel(cell_, delay_model,
slew_model);
TableModels *slew_models = new TableModels(slew_model);
GateTableModel *gate_model = new GateTableModel(cell_,
delay_models,
slew_models,
nullptr, nullptr);
return gate_model;
}
}

View File

@ -75,7 +75,7 @@ Path::Path(Vertex *vertex,
Path::Path(Vertex *vertex,
Tag *tag,
Arrival arrival,
const Arrival &arrival,
Path *prev_path,
Edge *prev_edge,
TimingArc *prev_arc,
@ -99,7 +99,7 @@ Path::Path(Vertex *vertex,
Path::Path(Vertex *vertex,
Tag *tag,
Arrival arrival,
const Arrival &arrival,
Path *prev_path,
Edge *prev_edge,
TimingArc *prev_arc,
@ -124,7 +124,7 @@ Path::Path(Vertex *vertex,
void
Path::init(Vertex *vertex,
Arrival arrival,
const Arrival &arrival,
const StaState *sta)
{
const Graph *graph = sta->graph();
@ -155,7 +155,7 @@ Path::init(Vertex *vertex,
void
Path::init(Vertex *vertex,
Tag *tag,
Arrival arrival,
const Arrival &arrival,
const StaState *sta)
{
const Graph *graph = sta->graph();
@ -171,7 +171,7 @@ Path::init(Vertex *vertex,
void
Path::init(Vertex *vertex,
Tag *tag,
Arrival arrival,
const Arrival &arrival,
Path *prev_path,
Edge *prev_edge,
TimingArc *prev_arc,
@ -330,7 +330,7 @@ Path::pathAnalysisPtIndex(const StaState *sta) const
return scene(sta)->pathIndex(minMax(sta));
}
Slew
const Slew &
Path::slew(const StaState *sta) const
{
DcalcAPIndex slew_index = scene(sta)->dcalcAnalysisPtIndex(minMax(sta));
@ -365,9 +365,9 @@ Slack
Path::slack(const StaState *sta) const
{
if (minMax(sta) == MinMax::max())
return required_ - arrival_;
return delayDiff(required_, arrival_, sta);
else
return arrival_ - required_;
return delayDiff(arrival_, required_, sta);
}
Path *

View File

@ -102,7 +102,7 @@ PathEnd::sourceClkEdge(const StaState *sta) const
return path_->clkEdge(sta);
}
Arrival
const Arrival &
PathEnd::dataArrivalTime(const StaState *) const
{
return path_->arrival();
@ -111,13 +111,17 @@ PathEnd::dataArrivalTime(const StaState *) const
Arrival
PathEnd::dataArrivalTimeOffset(const StaState *sta) const
{
return dataArrivalTime(sta) + sourceClkOffset(sta);
return delaySum(dataArrivalTime(sta),
sourceClkOffset(sta),
sta);
}
Required
PathEnd::requiredTimeOffset(const StaState *sta) const
{
return requiredTime(sta) + sourceClkOffset(sta);
return delaySum(requiredTime(sta),
sourceClkOffset(sta),
sta);
}
const RiseFall *
@ -259,9 +263,9 @@ Crpr
PathEnd::checkCrpr(const StaState *sta) const
{
if (checkRole(sta)->genericRole() == TimingRole::hold())
return -crpr(sta);
return delayDiff(delay_zero, crpr(sta), sta);
else
return crpr(sta);;
return crpr(sta);
}
Crpr
@ -301,7 +305,7 @@ PathEnd::checkTgtClkDelay(const Path *tgt_clk_path,
Delay insertion, latency;
checkTgtClkDelay(tgt_clk_path, tgt_clk_edge, check_role, sta,
insertion, latency);
return Delay(insertion + latency);
return delaySum(insertion, latency, sta);
}
void
@ -334,7 +338,8 @@ PathEnd::checkTgtClkDelay(const Path *tgt_clk_path,
Delay path_insertion = search->clockInsertion(tgt_clk, tgt_src_pin,
tgt_clk_rf, min_max,
min_max, mode);
latency = delayRemove(clk_arrival - tgt_clk_edge->time(), path_insertion);
latency = delayRemove(delayDiff(clk_arrival, tgt_clk_edge->time(), sta),
path_insertion);
}
else
// Ideal clock.
@ -615,21 +620,25 @@ PathEndClkConstrained::targetClkTime(const StaState *sta) const
Arrival
PathEndClkConstrained::targetClkArrival(const StaState *sta) const
{
return targetClkArrivalNoCrpr(sta)
+ checkCrpr(sta);
return delaySum(targetClkArrivalNoCrpr(sta),
checkCrpr(sta),
sta);
}
Arrival
PathEndClkConstrained::targetClkArrivalNoCrpr(const StaState *sta) const
{
Sdc *sdc = path_->sdc(sta);
return targetClkTime(sta)
+ targetClkDelay(sta)
+ checkClkUncertainty(sourceClkEdge(sta),
targetClkEdge(sta),
targetClkPath(),
checkRole(sta), sdc)
+ targetClkMcpAdjustment(sta);
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);
}
Delay
@ -704,8 +713,9 @@ PathEndClkConstrained::crpr(const StaState *sta) const
Required
PathEndClkConstrained::requiredTime(const StaState *sta) const
{
return requiredTimeNoCrpr(sta)
+ checkCrpr(sta);
return delaySum(requiredTimeNoCrpr(sta),
checkCrpr(sta),
sta);
}
Required
@ -714,9 +724,9 @@ PathEndClkConstrained::requiredTimeNoCrpr(const StaState *sta) const
Arrival tgt_clk_arrival = targetClkArrivalNoCrpr(sta);
ArcDelay check_margin = margin(sta);
if (checkGenericRole(sta) == TimingRole::setup())
return tgt_clk_arrival - check_margin;
return delayDiff(tgt_clk_arrival, check_margin, sta);
else
return tgt_clk_arrival + check_margin;
return delaySum(tgt_clk_arrival, check_margin, sta);
}
Slack
@ -725,9 +735,9 @@ PathEndClkConstrained::slack(const StaState *sta) const
Arrival arrival = dataArrivalTime(sta);
Required required = requiredTime(sta);
if (checkGenericRole(sta) == TimingRole::setup())
return required - arrival;
return delayDiff(required, arrival, sta);
else
return arrival - required;
return delayDiff(arrival, required, sta);
}
int
@ -862,9 +872,9 @@ PathEndClkConstrained::slackNoCrpr(const StaState *sta) const
Arrival arrival = dataArrivalTime(sta);
Required required = requiredTimeNoCrpr(sta);
if (checkGenericRole(sta) == TimingRole::setup())
return required - arrival;
return delayDiff(required, arrival, sta);
else
return arrival - required;
return delayDiff(arrival, required, sta);
}
void
@ -1017,10 +1027,18 @@ PathEndCheck::exceptPathCmp(const PathEnd *path_end,
Delay
PathEndCheck::clkSkew(const StaState *sta)
{
return sourceClkDelay(sta) - targetClkDelay(sta) - crpr(sta)
// Uncertainty decreases slack, but increases skew.
- checkTgtClkUncertainty(clk_path_, clk_path_->clkEdge(sta),
checkRole(sta), sta);
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;
}
Delay
@ -1035,7 +1053,8 @@ PathEndCheck::sourceClkDelay(const StaState *sta) const
Arrival clk_arrival = src_clk_path->arrival();
const ClockEdge *src_clk_edge = src_clk_info->clkEdge();
Delay insertion = sourceClkInsertionDelay(sta);
return delayRemove(clk_arrival - src_clk_edge->time(), insertion);
return delayRemove(delayDiff(clk_arrival, src_clk_edge->time(), sta),
insertion);
}
else
// Ideal clock.
@ -1052,9 +1071,17 @@ PathEndCheck::requiredTimeNoCrpr(const StaState *sta) const
ArcDelay check_margin = margin(sta);
float macro_clk_tree_delay = macroClkTreeDelay(sta);
if (checkGenericRole(sta) == TimingRole::setup())
return tgt_clk_arrival - (check_margin + macro_clk_tree_delay);
return delayDiff(tgt_clk_arrival,
delaySum(check_margin,
macro_clk_tree_delay,
sta),
sta);
else
return tgt_clk_arrival + (check_margin - macro_clk_tree_delay);
return delaySum(tgt_clk_arrival,
delayDiff(check_margin,
macro_clk_tree_delay,
sta),
sta);
}
float
@ -1072,7 +1099,7 @@ PathEndCheck::macroClkTreeDelay(const StaState *sta) const
if (clk_port) {
const MinMax *min_max = clk_path_->minMax(sta);
const RiseFall *rf = clk_path_->transition(sta);
float slew = delayAsFloat(clk_path_->slew(sta));
float slew = delayAsFloat(clk_path_->slew(sta), min_max, sta);
return clk_port->clkTreeDelay(slew, rf, min_max);
}
}
@ -1276,14 +1303,16 @@ PathEndLatchCheck::targetClkWidth(const StaState *sta) const
Arrival enable_arrival = search->clkPathArrival(clk_path_);
const ClkInfo *enable_clk_info = clk_path_->clkInfo(sta);
if (enable_clk_info->isPulseClk())
return disable_arrival - enable_arrival;
return delayDiff(disable_arrival, enable_arrival, sta);
else {
if (delayGreater(enable_arrival, disable_arrival, sta)) {
const Clock *disable_clk = enable_clk_info->clock();
if (disable_clk)
disable_arrival += disable_clk->period();
disable_arrival = delaySum(disable_arrival,
disable_clk->period(),
sta);
}
return disable_arrival - enable_arrival;
return delayDiff(disable_arrival, enable_arrival, sta);
}
}
@ -1416,10 +1445,14 @@ PathEndOutputDelay::targetClkArrivalNoCrpr(const StaState *sta) const
else {
const ClockEdge *tgt_clk_edge = targetClkEdge(sta);
const TimingRole *check_role = checkRole(sta);
return targetClkTime(sta)
+ tgtClkDelay(tgt_clk_edge, check_role, sta)
+ targetClkUncertainty(sta)
+ checkMcpAdjustment(path_, tgt_clk_edge, sta);
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);
}
}
@ -1451,7 +1484,7 @@ PathEndOutputDelay::tgtClkDelay(const ClockEdge *tgt_clk_edge,
Arrival insertion, latency;
tgtClkDelay(tgt_clk_edge, check_role, sta,
insertion, latency);
return insertion + latency;
return delaySum(insertion, latency, sta);
}
void
@ -1691,17 +1724,23 @@ PathEndDataCheck::requiredTimeNoCrpr(const StaState *sta) const
{
Arrival data_clk_arrival = data_clk_path_->arrival();
float data_clk_time = data_clk_path_->clkEdge(sta)->time();
Arrival data_clk_delay = data_clk_arrival - data_clk_time;
Arrival tgt_clk_arrival = targetClkTime(sta)
+ data_clk_delay
+ targetClkUncertainty(sta)
+ targetClkMcpAdjustment(sta);
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);
ArcDelay check_margin = margin(sta);
if (checkGenericRole(sta) == TimingRole::setup())
return tgt_clk_arrival - check_margin;
return delayDiff(tgt_clk_arrival, check_margin, sta);
else
return tgt_clk_arrival + check_margin;
return delaySum(tgt_clk_arrival, check_margin, sta);
}
ArcDelay
@ -1917,7 +1956,7 @@ PathEnd::pathDelaySrcClkOffset(const Path *path,
const ClockEdge *clk_edge = path->clkEdge(sta);
if (clk_edge) {
if (ignoreClkLatency(path, path_delay, sta))
offset = -delayAsFloat(src_clk_arrival);
offset = -delayAsFloat(src_clk_arrival, path->minMax(sta), sta);
else
// Arrival includes src clock edge time that is not counted in the
// path delay.
@ -1960,8 +1999,9 @@ PathEndPathDelay::targetClkArrivalNoCrpr(const StaState *sta) const
{
const ClockEdge *tgt_clk_edge = targetClkEdge(sta);
if (tgt_clk_edge)
return targetClkDelay(sta)
+ targetClkUncertainty(sta);
return delaySum(targetClkDelay(sta),
targetClkUncertainty(sta),
sta);
else if (clk_path_)
return clk_path_->arrival();
else
@ -1979,19 +2019,29 @@ PathEndPathDelay::requiredTime(const StaState *sta) const
{
float delay = path_delay_->delay();
if (path_delay_->ignoreClkLatency()) {
Required src_offset = path_->isClock(sta)
? path_->clkEdge(sta)->time()
: src_clk_arrival_;
return src_offset + delay
+ ((minMax(sta) == MinMax::max()) ? -margin(sta) : margin(sta));
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);
}
else {
Arrival tgt_clk_arrival = targetClkArrival(sta);
float src_clk_offset = sourceClkOffset(sta);
// Path delay includes target clk latency and timing check setup/hold
// margin or external departure at target.
return delay - src_clk_offset + tgt_clk_arrival
+ ((minMax(sta) == MinMax::max()) ? -margin(sta) : margin(sta));
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);
}
}
@ -2073,22 +2123,22 @@ PathEnd::cmpSlack(const PathEnd *path_end1,
{
Slack slack1 = path_end1->slack(sta);
Slack slack2 = path_end2->slack(sta);
if (delayZero(slack1)
&& delayZero(slack2)
if (delayZero(slack1, sta)
&& delayZero(slack2, sta)
&& 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.
if (delayEqual(borrow1, borrow2))
if (delayEqual(borrow1, borrow2, sta))
return 0;
else if (delayGreater(borrow1, borrow2, sta))
return -1;
else
return 1;
}
else if (delayEqual(slack1, slack2))
else if (delayEqual(slack1, slack2, sta))
return 0;
else if (delayLess(slack1, slack2, sta))
return -1;
@ -2104,7 +2154,7 @@ PathEnd::cmpArrival(const PathEnd *path_end1,
Arrival arrival1 = path_end1->dataArrivalTime(sta);
Arrival arrival2 = path_end2->dataArrivalTime(sta);
const MinMax *min_max = path_end1->minMax(sta);
if (delayEqual(arrival1, arrival2))
if (delayEqual(arrival1, arrival2, sta))
return 0;
else if (delayLess(arrival1, arrival2, min_max, sta))
return -1;

View File

@ -511,9 +511,11 @@ PathEnumFaninVisitor::reportDiversion(const Edge *div_edge,
Arrival path_delay = path_enum_->cmp_slack_
? path_end_->slack(this)
: path_end_->dataArrivalTime(this);
Arrival div_delay = path_delay - path_enum_->divSlack(before_div_,
after_div, div_edge,
div_arc);
Arrival div_delay = delayDiff(path_delay,
path_enum_->divSlack(before_div_,
after_div, div_edge,
div_arc),
this);
Path *div_prev = before_div_->prevPath();
report_->reportLine("path_enum: diversion %s %s %s -> %s",
path->to_string(this).c_str(),
@ -580,7 +582,7 @@ PathEnum::divSlack(Path *before_div,
Tag *q_tag;
latches_->latchOutArrival(after_div, div_arc, div_edge,
q_tag, div_delay, div_arrival);
return div_arrival - before_div_arrival;
return delayDiff(div_arrival, before_div_arrival, this);
}
else {
DcalcAPIndex dcalc_ap = before_div->dcalcAnalysisPtIndex(this);
@ -589,8 +591,8 @@ PathEnum::divSlack(Path *before_div,
false, before_div->minMax(this),
dcalc_ap,
before_div->sdc(this));
Arrival div_arrival = search_->clkPathArrival(after_div) + div_delay;
return div_arrival - before_div_arrival;
Arrival div_arrival = delaySum(search_->clkPathArrival(after_div), div_delay, this);
return delayDiff(div_arrival, before_div_arrival, this);
}
}
else {
@ -719,7 +721,7 @@ PathEnum::updatePathHeadDelays(PathSeq &paths,
path->minMax(this),
path->dcalcAnalysisPtIndex(this),
path->sdc(this));
arrival = prev_arrival + arc_delay;
arrival = delaySum(prev_arrival, arc_delay, this);
path->setArrival(arrival);
const Tag *tag = path->tag(this);
const ClkInfo *clk_info = tag->clkInfo();

48
search/PocvMode.cc Normal file
View File

@ -0,0 +1,48 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// 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.
#include "PocvMode.hh"
#include "EnumNameMap.hh"
namespace sta {
static EnumNameMap<PocvMode> pocv_mode_map =
{{PocvMode::scalar, "scalar"},
{PocvMode::normal, "normal"},
{PocvMode::skew_normal, "skew_normal"}};
const char *
pocvModeName(PocvMode mode)
{
return pocv_mode_map.find(mode);
}
PocvMode
findPocvMode(const char *mode_name)
{
return pocv_mode_map.find(mode_name, PocvMode::scalar);
}
} // namespace

View File

@ -1133,7 +1133,7 @@ Properties::edgeDelay(Edge *edge,
if (to_rf == rf) {
for (const Scene *scene : sta_->scenes()) {
DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max);
ArcDelay arc_delay = sta_->arcDelay(edge, arc, ap_index);
const ArcDelay &arc_delay = sta_->arcDelay(edge, arc, ap_index);
if (!delay_exists
|| delayGreater(arc_delay, delay, min_max, sta_)) {
delay = arc_delay;

View File

@ -134,20 +134,18 @@ ReportField::setEnabled(bool enabled)
////////////////////////////////////////////////////////////////
const float ReportPath::field_blank_ = -1.0;
ReportPath::ReportPath(StaState *sta) :
StaState(sta),
format_(ReportPathFormat::full),
no_split_(false),
report_sigmas_(false),
start_end_pt_width_(80),
field_width_extra_(5),
plus_zero_(nullptr),
minus_zero_(nullptr)
{
setDigits(2);
makeFields();
setReportFields(false, false, false, false, false, false, false);
setDigits(2);
setReportFields(false, false, false, false, false, false, false, false);
}
ReportPath::~ReportPath()
@ -158,6 +156,7 @@ ReportPath::~ReportPath()
delete field_capacitance_;
delete field_slew_;
delete field_fanout_;
delete field_variation_;
delete field_src_attr_;
delete field_edge_;
delete field_case_;
@ -169,6 +168,7 @@ ReportPath::~ReportPath()
void
ReportPath::makeFields()
{
// The order corresponds to the default field order.
field_fanout_ = makeField("fanout", "Fanout", 6, false, nullptr, true);
field_capacitance_ = makeField("capacitance", "Cap", 6, false,
units_->capacitanceUnit(), true);
@ -176,6 +176,8 @@ ReportPath::makeFields()
true);
field_incr_ = makeField("incr", "Delay", 6, false, units_->timeUnit(),
true);
field_variation_ = makeField("variation", "Variation", 6, false,
units_->timeUnit(), false);
field_total_ = makeField("total", "Time", 6, false, units_->timeUnit(),
true);
field_edge_ = makeField("edge", "", 1, false, nullptr, true);
@ -243,6 +245,7 @@ ReportPath::setReportFields(bool report_input_pin,
bool report_cap,
bool report_slew,
bool report_fanout,
bool report_variation,
bool report_src_attr)
{
report_input_pin_ = report_input_pin;
@ -252,6 +255,7 @@ ReportPath::setReportFields(bool report_input_pin,
field_capacitance_->setEnabled(report_cap);
field_slew_->setEnabled(report_slew);
field_fanout_->setEnabled(report_fanout);
field_variation_->setEnabled(report_variation);
field_src_attr_->setEnabled(report_src_attr);
// for debug
field_case_->setEnabled(false);
@ -278,12 +282,14 @@ ReportPath::setDigits(int digits)
stringDelete(minus_zero_);
minus_zero_ = stringPrint("-%.*f", digits_, 0.0);
plus_zero_ = stringPrint("%.*f", digits_, 0.0);
}
void
ReportPath::setReportSigmas(bool report)
{
report_sigmas_ = report;
// Numeric field width expands with digits.
int field_width = digits + field_width_extra_;
field_capacitance_->setWidth(field_width);
field_slew_->setWidth(field_width);
field_variation_->setWidth(field_width);
field_incr_->setWidth(field_width);
field_total_->setWidth(field_width);
}
////////////////////////////////////////////////////////////////
@ -556,7 +562,7 @@ ReportPath::reportFull(const PathEndLatchCheck *end) const
end->latchRequired(this, req_time, borrow, adjusted_data_arrival,
time_given_to_startpoint);
// Adjust required to requiredTimeOffset.
req_time += end->sourceClkOffset(this);
req_time = delaySum(req_time, end->sourceClkOffset(this), this);
if (path_delay) {
float delay = path_delay->delay();
reportLine("max_delay", delay, delay, early_late);
@ -630,7 +636,7 @@ ReportPath::reportBorrowing(const PathEndLatchCheck *end,
if (tgt_clk_path->clkInfo(search_)->isPropagated()) {
auto width_msg = stdstrPrint("%s nominal pulse width", tgt_clk_name.c_str());
reportLineTotal(width_msg.c_str(), nom_pulse_width, early_late);
if (!delayZero(latency_diff))
if (!delayZero(latency_diff, this))
reportLineTotalMinus("clock latency difference", latency_diff, early_late);
}
else {
@ -640,18 +646,18 @@ ReportPath::reportBorrowing(const PathEndLatchCheck *end,
ArcDelay margin = end->margin(this);
reportLineTotalMinus("library setup time", margin, early_late);
reportDashLineTotal();
if (!delayZero(crpr_diff))
if (!delayZero(crpr_diff, this))
reportLineTotalMinus("CRPR difference", crpr_diff, early_late);
reportLineTotal("max time borrow", max_borrow, early_late);
}
if (delayGreater(borrow, delay_zero, this)
&& (!fuzzyZero(open_uncertainty)
|| !delayZero(open_crpr))) {
|| !delayZero(open_crpr, this))) {
reportDashLineTotal();
reportLineTotal("actual time borrow", borrow, early_late);
if (!fuzzyZero(open_uncertainty))
reportLineTotal("open edge uncertainty", open_uncertainty, early_late);
if (!delayZero(open_crpr))
if (!delayZero(open_crpr, this))
reportLineTotal("open edge CRPR", open_crpr, early_late);
reportDashLineTotal();
reportLineTotal("time given to startpoint", time_given_to_startpoint, early_late);
@ -720,7 +726,7 @@ ReportPath::reportFull(const PathEndPathDelay *end) const
ArcDelay margin = end->margin(this);
const MinMax *min_max = path_delay->minMax()->asMinMax();
if (min_max == MinMax::max())
margin = -margin;
margin = delayDiff(delay_zero, margin, this);
std::string delay_msg = min_max->to_string() + "_delay";
float delay = path_delay->delay();
@ -734,8 +740,8 @@ ReportPath::reportFull(const PathEndPathDelay *end) const
reportTgtClk(end, delay, 0.0, true);
else {
Arrival tgt_clk_delay = end->targetClkDelay(this);
Arrival tgt_clk_arrival = delay + tgt_clk_delay;
if (!delayZero(tgt_clk_delay))
Arrival tgt_clk_arrival = delaySum(tgt_clk_delay, delay, this);
if (!delayZero(tgt_clk_delay, this))
reportLine(clkNetworkDelayIdealProp(isPropagated(tgt_clk_path)),
tgt_clk_delay, tgt_clk_arrival, early_late);
reportClkUncertainty(end, tgt_clk_arrival);
@ -924,10 +930,11 @@ ReportPath::reportFull(const PathEndDataCheck *end) const
PathExpanded clk_expanded(data_clk_path, this);
float src_offset = end->sourceClkOffset(this);
Delay clk_delay = end->targetClkDelay(this);
const MinMax *min_max = data_clk_path->minMax(this);
Arrival clk_arrival = end->targetClkArrival(this);
const ClockEdge *tgt_clk_edge = end->targetClkEdge(this);
float prev = delayAsFloat(clk_arrival) + src_offset;
float offset = prev - delayAsFloat(clk_delay) - tgt_clk_edge->time();
float prev = delayAsFloat(clk_arrival, min_max, this) + src_offset;
float offset = prev - delayAsFloat(clk_delay, min_max, this) - tgt_clk_edge->time();
// Delay to startpoint is already included.
reportPath6(data_clk_path, clk_expanded, clk_expanded.startIndex(),
true, false, prev, offset);
@ -1397,13 +1404,15 @@ ReportPath::reportVerbose(const MinPulseWidthCheck &check) const
float close_clk_time = close_clk_edge->time() + close_offset;
auto close_clk_msg = stdstrPrint("clock %s (%s edge)", close_clk_name, close_rise_fall);
reportLine(close_clk_msg.c_str(), close_clk_time, close_clk_time, close_el);
Arrival close_arrival = check.closeArrival(this) + close_offset;
Arrival close_arrival = delaySum(check.closeArrival(this), close_offset, this);
reportLine(clk_ideal_prop, check.closeDelay(this), close_arrival, close_el);
reportLine(pin_name, delay_zero, close_arrival, close_el);
if (variables_->crprEnabled()) {
Crpr pessimism = check.checkCrpr(this);
close_arrival += pessimism;
close_arrival = delaySum(close_arrival, pessimism, this);
reportLine("clock reconvergence pessimism", pessimism, close_arrival, close_el);
}
reportLine("close edge arrival time", close_arrival, close_el);
@ -1578,7 +1587,7 @@ ReportPath::reportShort(const MaxSkewCheck &check) const
reportDescription(what.c_str(), line);
const EarlyLate *early_late = EarlyLate::early();
reportSpaceFieldDelay(check.maxSkew(this), early_late, line);
reportSpaceFieldDelay(check.skew(), early_late, line);
reportSpaceFieldDelay(check.skew(this), early_late, line);
reportSpaceSlack(check.slack(this), line);
report_->reportLineString(line);
}
@ -1607,7 +1616,7 @@ ReportPath::reportVerbose(const MaxSkewCheck &check) const
reportDashLine();
reportLine("allowable skew", check.maxSkew(this), EarlyLate::early());
reportLine("actual skew", check.skew(), EarlyLate::late());
reportLine("actual skew", check.skew(this), EarlyLate::late());
reportDashLine();
reportSlack(check.slack(this));
}
@ -1625,7 +1634,9 @@ ReportPath::reportSkewClkPath(const char *arrival_msg,
std::string clk_name = clkName(clk, clk_end_rf != clk_rf);
float clk_time = clk_edge->time();
const Arrival &clk_arrival = search_->clkPathArrival(clk_path);
Arrival clk_delay = clk_arrival - clk_time;
Arrival clk_delay = delayDiff(clk_arrival,
clk_time,
this);
const MinMax *min_max = clk_path->minMax(this);
Vertex *clk_vertex = clk_path->vertex(this);
reportClkLine(clk, clk_name.c_str(), clk_end_rf, clk_time, min_max);
@ -2066,15 +2077,19 @@ ReportPath::reportSrcClkAndPath(const Path *path,
const Path *clk_path = expanded.clkPath();
const RiseFall *clk_end_rf;
if (clk_path) {
clk_end_time = search_->clkPathArrival(clk_path) + time_offset;
clk_delay = clk_end_time - clk_time;
clk_end_time = delaySum(search_->clkPathArrival(clk_path),
time_offset,
this);
clk_delay = delayDiff(clk_end_time,
clk_time,
this);
clk_end_rf = clk_path->transition(this);
}
else {
// Path from input port or clk used as data.
clk_end_rf = clk_rf;
clk_delay = clk_insertion + clk_latency;
clk_end_time = clk_time + clk_delay;
clk_delay = delaySum(clk_insertion, clk_latency, this);
clk_end_time = delaySum(clk_time, clk_delay, this);
const Path *first_path = expanded.startPath();
const InputDelay *input_delay = pathInputDelay(first_path);
@ -2086,8 +2101,12 @@ ReportPath::reportSrcClkAndPath(const Path *path,
pathInputDelayRefPath(first_path, input_delay, ref_path);
if (!ref_path.isNull()) {
const Arrival &ref_end_time = ref_path.arrival();
clk_delay = ref_end_time - clk_time;
clk_end_time = ref_end_time + time_offset;
clk_delay = delayDiff(ref_end_time,
clk_time,
this);
clk_end_time = delaySum(ref_end_time,
time_offset,
this);
input_has_ref_path = true;
}
}
@ -2127,8 +2146,10 @@ ReportPath::reportSrcClkAndPath(const Path *path,
reportPath1(path, expanded, true, time_offset);
else {
Arrival clk_arrival = clk_end_time;
Arrival end_arrival = path->arrival() + time_offset;
Delay clk_delay = end_arrival - clk_arrival;
Arrival end_arrival = delaySum(path->arrival(),
time_offset,
this);
Delay clk_delay = delayDiff(end_arrival, clk_arrival, this);
reportLine("clock network delay", clk_delay,
end_arrival, early_late);
Vertex *end_vertex = path->vertex(this);
@ -2187,7 +2208,7 @@ ReportPath::reportTgtClk(const PathEnd *end,
bool is_prop) const
{
const ClockEdge *clk_edge = end->targetClkEdge(this);
Clock *clk = clk_edge->clock();
const Clock *clk = clk_edge->clock();
const RiseFall *clk_rf = clk_edge->transition();
const RiseFall *clk_end_rf = end->targetClkEndTrans(this);
std::string clk_name = clkName(clk, clk_end_rf != clk_rf);
@ -2196,7 +2217,7 @@ ReportPath::reportTgtClk(const PathEnd *end,
+ end->targetClkMcpAdjustment(this)
+ src_offset;
Arrival clk_delay = end->targetClkDelay(this);
Arrival clk_arrival = clk_time + clk_delay;
Arrival clk_arrival = delaySum(clk_delay, clk_time, this);
const MinMax *min_max = end->path()->tgtClkMinMax(this);
const Path *clk_path = end->targetClkPath();
reportClkLine(clk, clk_name.c_str(), clk_end_rf, prev_time, clk_time, min_max);
@ -2225,7 +2246,7 @@ ReportPath::reportTgtClk(const PathEnd *end,
}
else {
// Output departure.
Arrival clk_arrival = clk_time + clk_delay;
Arrival clk_arrival = delaySum(clk_time, clk_delay, this);
reportLine(clkNetworkDelayIdealProp(clk->isPropagated()),
clk_delay, clk_arrival, min_max);
}
@ -2241,9 +2262,11 @@ ReportPath::reportTgtClk(const PathEnd *end,
if (clk_path) {
Vertex *clk_vertex = clk_path->vertex(this);
reportLine(descriptionField(clk_vertex).c_str(),
prev_time
+ end->targetClkArrival(this)
+ end->sourceClkOffset(this),
delaySum(delaySum(prev_time,
end->targetClkArrival(this),
this),
end->sourceClkOffset(this),
this),
min_max, clk_end_rf);
}
}
@ -2264,7 +2287,7 @@ ReportPath::tgtClkInsertionOffet(const Path *clk_path,
min_max, min_max, mode);
Arrival tgt_insertion = search_->clockInsertion(clk, src_pin, clk_rf,
min_max, early_late, mode);
return delayAsFloat(tgt_insertion - path_insertion);
return delayAsFloat(delayDiff(tgt_insertion, path_insertion, this));
}
bool
@ -2327,11 +2350,18 @@ ReportPath::reportClkLine(const Clock *clk,
const char *rise_fall = asRiseFall(clk_rf);
auto clk_msg = stdstrPrint("clock %s (%s edge)", clk_name, rise_fall);
if (clk->isPropagated())
reportLine(clk_msg.c_str(), clk_time - prev_time, clk_time, min_max);
reportLine(clk_msg.c_str(),
delayDiff(clk_time, prev_time, this),
clk_time,
min_max);
else {
// Report ideal clock slew.
float clk_slew = clk->slew(clk_rf, min_max);
reportLine(clk_msg.c_str(), clk_slew, clk_time - prev_time, clk_time, min_max);
reportLine(clk_msg.c_str(),
clk_slew,
delayDiff(clk_time, prev_time, this),
clk_time,
min_max);
}
}
@ -2433,13 +2463,16 @@ ReportPath::reportClkSrcLatency(Arrival insertion,
float clk_time,
const EarlyLate *early_late) const
{
reportLine("clock source latency", insertion, clk_time + insertion, early_late);
Arrival clk_arrival = delaySum(clk_time,
insertion,
this);
reportLine("clock source latency", insertion, clk_arrival, early_late);
}
void
ReportPath::reportPathLine(const Path *path,
Arrival incr,
Arrival time,
const Delay &incr,
const Arrival &time,
const char *line_case) const
{
Vertex *vertex = path->vertex(this);
@ -2461,7 +2494,7 @@ ReportPath::reportPathLine(const Path *path,
if (is_driver && field_capacitance_->enabled())
cap = graph_delay_calc_->loadCap(pin, rf, scene, min_max);
reportLine(what.c_str(), cap, slew, field_blank_,
incr, time, false, early_late, rf, src_attr,
incr, field_blank_, time, false, early_late, rf, src_attr,
line_case);
}
@ -2474,13 +2507,16 @@ ReportPath::reportRequired(const PathEnd *end,
float macro_clk_tree_delay = end->macroClkTreeDelay(this);
ArcDelay margin = end->margin(this);
if (end->minMax(this) == MinMax::min()) {
margin = -margin;
margin = delayDiff(delay_zero, margin, this);
macro_clk_tree_delay = -macro_clk_tree_delay;
}
if (macro_clk_tree_delay != 0.0)
reportLine("macro clock tree delay", -macro_clk_tree_delay,
req_time + margin, early_late);
reportLine(margin_msg.c_str(), -margin, req_time, early_late);
delaySum(req_time, margin, this), early_late);
reportLine(margin_msg.c_str(),
delayDiff(delay_zero, margin, this),
req_time,
early_late);
reportLine("data required time", req_time, early_late);
reportDashLine();
}
@ -2531,7 +2567,7 @@ ReportPath::reportCommonClkPessimism(const PathEnd *end,
{
if (variables_->crprEnabled()) {
Crpr pessimism = end->checkCrpr(this);
clk_arrival += pessimism;
clk_arrival = delaySum(clk_arrival, pessimism, this);
reportLine("clock reconvergence pessimism", pessimism, clk_arrival,
end->clkEarlyLate(this));
}
@ -2543,11 +2579,15 @@ ReportPath::reportClkUncertainty(const PathEnd *end,
{
const EarlyLate *early_late = end->clkEarlyLate(this);
float uncertainty = end->targetNonInterClkUncertainty(this);
clk_arrival += uncertainty;
clk_arrival = delaySum(clk_arrival,
uncertainty,
this);
if (uncertainty != 0.0)
reportLine("clock uncertainty", uncertainty, clk_arrival, early_late);
float inter_uncertainty = end->interClkUncertainty(this);
clk_arrival += inter_uncertainty;
clk_arrival = delaySum(clk_arrival,
inter_uncertainty,
this);
if (inter_uncertainty != 0.0)
reportLine("inter-clock uncertainty", inter_uncertainty,
clk_arrival, early_late);
@ -2659,7 +2699,9 @@ ReportPath::reportPath4(const Path *path,
reportPath5(latch_enable_path, enable_expanded, skip_first_path,
propagated_clk, report_clk_path, time_offset);
}
Arrival time = latch_enable_time + latch_time_given;
Arrival time = delaySum(latch_enable_time,
latch_time_given,
this);
Arrival incr = latch_time_given;
if (delayGreaterEqual(incr, 0.0, this))
reportLine("time given to startpoint", incr, time, early_late);
@ -2668,7 +2710,10 @@ ReportPath::reportPath4(const Path *path,
// Override latch D arrival with enable + given.
reportPathLine(expanded.path(0), delay_zero, time, "latch_D");
reportPath6(path, expanded, 1, propagated_clk, report_clk_path,
latch_enable_time + latch_time_given, time_offset);
delaySum(latch_enable_time,
latch_time_given,
this),
time_offset);
}
}
else
@ -2689,7 +2734,9 @@ ReportPath::reportPath5(const Path *path,
if (skip_first_path) {
path_first_index = 1;
const Path *start = expanded.path(0);
prev_time = start->arrival() + time_offset;
prev_time = delaySum(start->arrival(),
time_offset,
this);
}
reportPath6(path, expanded, path_first_index, propagated_clk,
report_clk_path, prev_time, time_offset);
@ -2717,7 +2764,7 @@ ReportPath::reportPath6(const Path *path,
const TimingArc *prev_arc = path1->prevArc(this);
Vertex *vertex = path1->vertex(this);
Pin *pin = vertex->pin();
Arrival time = path1->arrival() + time_offset;
Arrival time = delaySum(path1->arrival(), time_offset, this);
Delay incr = 0.0;
const char *line_case = nullptr;
bool is_clk_start = path1->vertex(this) == clk_start;
@ -2746,7 +2793,9 @@ ReportPath::reportPath6(const Path *path,
// The delay calculator annotates wire delays on the edges
// from the input to the loads. Report the wire delay on the
// input pin instead.
Arrival next_time = next_path->arrival() + time_offset;
Arrival next_time = delaySum(next_path->arrival(),
time_offset,
this);
incr = delayIncr(next_time, time, min_max);
time = next_time;
line_case = "input_drive";
@ -2755,7 +2804,7 @@ ReportPath::reportPath6(const Path *path,
if (!propagated_clk)
// Clock latency at path endpoint in case latency was set
// on a clock pin other than the clock source.
time = search_->clkPathArrival(path1) + time_offset;
time = delaySum(search_->clkPathArrival(path1), time_offset, this);
incr = 0.0;
line_case = "clk_first";
}
@ -2772,7 +2821,9 @@ ReportPath::reportPath6(const Path *path,
if (!propagated_clk) {
// Ideal clock.
const ClockEdge *src_clk_edge = path->clkEdge(this);
time = search_->clkPathArrival(path1) + time_offset;
time = delaySum(search_->clkPathArrival(path1),
time_offset,
this);
if (src_clk_edge) {
Clock *src_clk = src_clk_edge->clock();
const RiseFall *src_clk_rf = src_clk_edge->transition();
@ -2803,6 +2854,8 @@ ReportPath::reportPath6(const Path *path,
}
if (vertex->isDriver(network_)) {
// Report delay arc pocv variation between input and driver.
reportVariation(path1);
float cap = field_blank_;
float fanout = field_blank_;
if (field_capacitance_->enabled())
@ -2811,13 +2864,13 @@ ReportPath::reportPath6(const Path *path,
fanout = drvrFanout(vertex, scene, min_max);
const std::string what = descriptionField(vertex);
reportLine(what.c_str(), cap, slew, fanout,
incr, time, false, min_max, rf, src_attr,
incr, field_blank_, time, false, min_max, rf, src_attr,
line_case);
if (report_net_) {
const std::string what2 = descriptionNet(pin);
reportLine(what2.c_str(), field_blank_, field_blank_, field_blank_,
field_blank_, field_blank_, false, min_max,
field_blank_, field_blank_, field_blank_, false, min_max,
nullptr, src_attr, "");
}
prev_time = time;
@ -2830,7 +2883,7 @@ ReportPath::reportPath6(const Path *path,
|| is_clk_start) {
const std::string what = descriptionField(vertex);
reportLine(what.c_str(), field_blank_, slew, field_blank_,
incr, time, false, min_max, rf, src_attr,
incr, field_blank_, time, false, min_max, rf, src_attr,
line_case);
prev_time = time;
}
@ -2841,6 +2894,59 @@ ReportPath::reportPath6(const Path *path,
}
}
void
ReportPath::reportVariation(const Path *path) const
{
if (field_variation_->enabled()) {
const Edge *prev_edge = path->prevEdge(this);
if (prev_edge) {
const TimingArc *prev_arc = path->prevArc(this);
const MinMax *min_max = path->minMax(this);
DcalcAPIndex slew_index = path->dcalcAnalysisPtIndex(this);
const ArcDelay &arc_delay=graph_->arcDelay(prev_edge, prev_arc,slew_index);
switch (variables_->pocvMode()) {
case PocvMode::normal: {
float std_dev = arc_delay.stdDev();
reportLine("sigma", field_blank_, field_blank_, field_blank_,
field_blank_, std_dev, field_blank_, true, min_max, nullptr,
"", nullptr);
break;
}
case PocvMode::skew_normal: {
float mean = arc_delay.mean();
reportLine("mean", field_blank_, field_blank_, field_blank_,
field_blank_, mean, field_blank_, true, min_max, nullptr,
"", nullptr);
float mean_shift = arc_delay.meanShift();
reportLine("mean_shift", field_blank_, field_blank_, field_blank_,
field_blank_, mean_shift, field_blank_, true, min_max, nullptr,
"", nullptr);
float std_dev = arc_delay.stdDev();
reportLine("std_dev", field_blank_, field_blank_, field_blank_,
field_blank_, std_dev, field_blank_, true, min_max, nullptr,
"", nullptr);
// skewness is dimensionless, so scale it to the field's time units.
float skewness = arc_delay.skewness() * units_->timeUnit()->scale();
reportLine("skewness", field_blank_, field_blank_, field_blank_,
field_blank_, skewness, field_blank_, true, min_max, nullptr,
"", nullptr);
break;
}
default:
break;
}
}
}
}
Delay
ReportPath::delayIncr(const Delay &time,
const Delay &prev,
const MinMax *min_max) const
{
return delayAsFloat(time, min_max, this) - delayAsFloat(prev, min_max, this);
}
void
ReportPath::reportHierPinsThru(const Path *path) const
{
@ -2850,24 +2956,13 @@ ReportPath::reportHierPinsThru(const Path *path) const
for (const Pin *hpin : hierPinsThruEdge(prev_edge, network_, graph_)) {
const std::string what = descriptionField(hpin);
reportLine(what.c_str(), field_blank_, field_blank_, field_blank_,
field_blank_, field_blank_, false, path->minMax(this),
field_blank_, field_blank_, field_blank_, false, path->minMax(this),
nullptr, "", "");
}
}
}
}
Delay
ReportPath::delayIncr(Delay time,
Delay prev,
const MinMax *min_max) const
{
if (report_sigmas_)
return delayRemove(time, prev);
else
return delayAsFloat(time, min_max, this) - delayAsFloat(prev, min_max, this);
}
bool
ReportPath::nextArcAnnotated(const Path *next_path,
size_t next_index,
@ -2974,7 +3069,9 @@ ReportPath::reportInputExternalDelay(const Path *first_path,
const Pin *first_pin = first_path->pin(graph_);
if (!pathFromClkPin(first_path, first_pin)) {
const RiseFall *rf = first_path->transition(this);
Arrival time = first_path->arrival() + time_offset;
Arrival time = delaySum(first_path->arrival(),
time_offset,
this);
const EarlyLate *early_late = first_path->minMax(this);
InputDelay *input_delay = pathInputDelay(first_path);
if (input_delay) {
@ -3054,7 +3151,7 @@ ReportPath::reportLine(const char *what,
Delay total,
const EarlyLate *early_late) const
{
reportLine(what, field_blank_, field_blank_, field_blank_,
reportLine(what, field_blank_, field_blank_, field_blank_, field_blank_,
field_blank_, total, false, early_late, nullptr,
"", nullptr);
}
@ -3066,8 +3163,8 @@ ReportPath::reportLineNegative(const char *what,
const EarlyLate *early_late) const
{
reportLine(what, field_blank_, field_blank_, field_blank_,
field_blank_, total, true, early_late, nullptr,
"", nullptr);
field_blank_, field_blank_, total, true /* tota_with_minus */,
early_late, nullptr, "", nullptr);
}
// Report total, and transition suffix.
@ -3078,55 +3175,56 @@ ReportPath::reportLine(const char *what,
const RiseFall *rf) const
{
reportLine(what, field_blank_, field_blank_, field_blank_,
field_blank_, total, false, early_late, rf, "",
field_blank_, field_blank_, total, false, early_late, rf, "",
nullptr);
}
// Report increment, and total.
void
ReportPath::reportLine(const char *what,
Delay incr,
Delay total,
const Delay &incr,
const Delay &total,
const EarlyLate *early_late) const
{
reportLine(what, field_blank_, field_blank_, field_blank_,
incr, total, false, early_late, nullptr, "",
incr, field_blank_, total, false, early_late, nullptr, "",
nullptr);
}
// Report increment, total, and transition suffix.
void
ReportPath::reportLine(const char *what,
Delay incr,
Delay total,
const Delay &incr,
const Delay &total,
const EarlyLate *early_late,
const RiseFall *rf) const
{
reportLine(what, field_blank_, field_blank_, field_blank_,
incr, total, false, early_late, rf, "",
incr, field_blank_, total, false, early_late, rf, "",
nullptr);
}
// Report slew, increment, and total.
void
ReportPath::reportLine(const char *what,
Slew slew,
Delay incr,
Delay total,
const Slew &slew,
const Delay &incr,
const Delay &total,
const EarlyLate *early_late) const
{
reportLine(what, field_blank_, slew, field_blank_,
incr, total, false, early_late, nullptr,
incr, field_blank_, total, false, early_late, nullptr,
"", nullptr);
}
void
ReportPath::reportLine(const char *what,
float cap,
Slew slew,
const Slew &slew,
float fanout,
Delay incr,
Delay total,
const Delay &incr,
float variation,
const Delay &total,
bool total_with_minus,
const EarlyLate *early_late,
const RiseFall *rf,
@ -3159,6 +3257,8 @@ ReportPath::reportLine(const char *what,
reportFieldDelay(slew, early_late, field, line);
else if (field == field_incr_)
reportFieldDelay(incr, early_late, field, line);
else if (field == field_variation_)
reportFieldDelay(variation, early_late, field, line);
else if (field == field_total_) {
if (total_with_minus)
reportFieldDelayMinus(total, early_late, field, line);
@ -3171,6 +3271,8 @@ ReportPath::reportLine(const char *what,
else
reportFieldBlank(field, line);
}
else if (field == field_variation_)
reportFieldBlank(field, line);
else if (field == field_src_attr_) {
if (src_attr != "")
reportField(src_attr.c_str(), field, line);
@ -3195,7 +3297,7 @@ ReportPath::reportLine(const char *what,
// Only the total field.
void
ReportPath::reportLineTotal(const char *what,
Delay incr,
const Delay &incr,
const EarlyLate *early_late) const
{
reportLineTotal1(what, incr, false, early_late);
@ -3204,7 +3306,7 @@ ReportPath::reportLineTotal(const char *what,
// Only the total field and always with leading minus sign.
void
ReportPath::reportLineTotalMinus(const char *what,
Delay decr,
const Delay &decr,
const EarlyLate *early_late) const
{
reportLineTotal1(what, decr, true, early_late);
@ -3212,7 +3314,7 @@ ReportPath::reportLineTotalMinus(const char *what,
void
ReportPath::reportLineTotal1(const char *what,
Delay incr,
const Delay &incr,
bool incr_with_minus,
const EarlyLate *early_late) const
{
@ -3287,7 +3389,7 @@ ReportPath::reportSpaceFieldTime(float value,
}
void
ReportPath::reportSpaceFieldDelay(Delay value,
ReportPath::reportSpaceFieldDelay(const Delay &value,
const EarlyLate *early_late,
std::string &line) const
{
@ -3296,11 +3398,11 @@ ReportPath::reportSpaceFieldDelay(Delay value,
}
void
ReportPath::reportTotalDelay(Delay value,
ReportPath::reportTotalDelay(const Delay &value,
const EarlyLate *early_late,
std::string &line) const
{
const char *str = delayAsString(value, early_late, this, digits_);
const char *str = delayAsString(value, early_late, digits_, this);
if (stringEq(str, minus_zero_))
// Filter "-0.00" fields.
str = plus_zero_;
@ -3309,7 +3411,7 @@ ReportPath::reportTotalDelay(Delay value,
// Total time always with leading minus sign.
void
ReportPath::reportFieldDelayMinus(Delay value,
ReportPath::reportFieldDelayMinus(const Delay &value,
const EarlyLate *early_late,
const ReportField *field,
std::string &line) const
@ -3317,10 +3419,9 @@ ReportPath::reportFieldDelayMinus(Delay value,
if (delayAsFloat(value) == field_blank_)
reportFieldBlank(field, line);
else {
const char *str = report_sigmas_
? delayAsString(-value, this, digits_)
// Opposite min/max for negative value.
: delayAsString(-value, early_late->opposite(), this, digits_);
// Opposite min/max for negative value.
const char *str = delayAsString(delayDiff(delay_zero, value, this),
early_late->opposite(), digits_, this);
if (stringEq(str, plus_zero_))
// Force leading minus sign.
str = minus_zero_;
@ -3329,17 +3430,15 @@ ReportPath::reportFieldDelayMinus(Delay value,
}
void
ReportPath::reportFieldDelay(Delay value,
ReportPath::reportFieldDelay(const Delay &value,
const EarlyLate *early_late,
const ReportField *field,
std::string &line) const
{
if (delayAsFloat(value) == field_blank_)
if (value.mean() == field_blank_)
reportFieldBlank(field, line);
else {
const char *str = report_sigmas_
? delayAsString(value, this, digits_)
: delayAsString(value, early_late, this, digits_);
const char *str = delayAsString(value, early_late, digits_, this);
if (stringEq(str, minus_zero_))
// Filter "-0.00" fields.
str = plus_zero_;

View File

@ -56,12 +56,11 @@ public:
bool report_cap,
bool report_slew,
bool report_fanout,
bool report_variation,
bool report_src_attr);
int digits() const { return digits_; }
void setDigits(int digits);
void setNoSplit(bool no_split);
bool reportSigmas() const { return report_sigmas_; }
void setReportSigmas(bool report);
ReportField *findField(const char *name) const;
// Header above reportPathEnd results.
@ -267,8 +266,8 @@ protected:
float clk_time,
const EarlyLate *early_late) const;
void reportPathLine(const Path *path,
Delay incr,
Arrival time,
const Delay &incr,
const Arrival &time,
const char *line_case) const;
void reportCommonClkPessimism(const PathEnd *end,
Arrival &clk_arrival) const ;
@ -331,6 +330,7 @@ protected:
bool report_clk_path,
Arrival prev_time,
float time_offset) const;
void reportVariation(const Path *path) const;
void reportHierPinsThru(const Path *path) const;
void reportInputExternalDelay(const Path *path,
float time_offset) const;
@ -345,38 +345,39 @@ protected:
const EarlyLate *early_late,
const RiseFall *rf) const;
void reportLine(const char *what,
Delay incr,
Delay total,
const Delay &incr,
const Delay &total,
const EarlyLate *early_late) const;
void reportLine(const char *what,
Delay incr,
Delay total,
const Delay &incr,
const Delay &total,
const EarlyLate *early_late,
const RiseFall *rf) const;
void reportLine(const char *what,
Slew slew,
Delay incr,
Delay total,
const Slew &slew,
const Delay &incr,
const Delay &total,
const EarlyLate *early_late) const;
void reportLine(const char *what,
float cap,
Slew slew,
const Slew &slew,
float fanout,
Delay incr,
Delay total,
const Delay &incr,
float variation,
const Delay &total,
bool total_with_minus,
const EarlyLate *early_late,
const RiseFall *rf,
std::string src_attr,
const char *line_case) const;
void reportLineTotal(const char *what,
Delay incr,
const Delay &incr,
const EarlyLate *early_late) const;
void reportLineTotalMinus(const char *what,
Delay decr,
const Delay &decr,
const EarlyLate *early_late) const;
void reportLineTotal1(const char *what,
Delay incr,
const Delay &incr,
bool incr_with_minus,
const EarlyLate *early_late) const;
void reportDashLineTotal() const;
@ -391,17 +392,17 @@ protected:
std::string &result) const;
void reportSpaceFieldTime(float value,
std::string &result) const;
void reportSpaceFieldDelay(Delay value,
void reportSpaceFieldDelay(const Delay &value,
const EarlyLate *early_late,
std::string &result) const;
void reportFieldDelayMinus(Delay value,
void reportFieldDelayMinus(const Delay &value,
const EarlyLate *early_late,
const ReportField *field,
std::string &result) const;
void reportTotalDelay(Delay value,
void reportTotalDelay(const Delay &value,
const EarlyLate *early_late,
std::string &result) const;
void reportFieldDelay(Delay value,
void reportFieldDelay(const Delay &value,
const EarlyLate *early_late,
const ReportField *field,
std::string &result) const;
@ -465,8 +466,8 @@ protected:
Path &ref_path) const;
const char *asRisingFalling(const RiseFall *rf) const;
const char *asRiseFall(const RiseFall *rf) const;
Delay delayIncr(Delay time,
Delay prev,
Delay delayIncr(const Delay &time,
const Delay &prev,
const MinMax *min_max) const;
// Path options.
@ -477,7 +478,6 @@ protected:
bool report_net_;
bool no_split_;
int digits_;
bool report_sigmas_;
int start_end_pt_width_;
@ -487,15 +487,15 @@ protected:
ReportField *field_capacitance_;
ReportField *field_slew_;
ReportField *field_fanout_;
ReportField *field_variation_;
ReportField *field_src_attr_;
ReportField *field_edge_;
ReportField *field_case_;
static constexpr float field_blank_ = -1;
int field_width_extra_;
const char *plus_zero_;
const char *minus_zero_;
static const float field_blank_;
static const float field_skip_;
};
class ReportField

View File

@ -1334,7 +1334,7 @@ Search::arrivalsChanged(Vertex *vertex,
Path *path2 = tag_bldr->tagMatchPath(tag1);
if (path2 == nullptr
|| path1->tag(this) != path2->tag(this)
|| !delayEqual(path1->arrival(), path2->arrival())
|| !delayEqual(path1->arrival(), path2->arrival(), this)
|| path1->prevEdge(this) != path2->prevEdge(this)
|| path1->prevArc(this) != path2->prevArc(this)
|| path1->prevPath() != path2->prevPath())
@ -1420,8 +1420,8 @@ ArrivalVisitor::pruneCrprArrivals()
const ClkInfo *clk_info_no_crpr = path_no_crpr->clkInfo(this);
Arrival max_crpr = crpr->maxCrpr(clk_info_no_crpr);
Arrival max_arrival_max_crpr = (min_max == MinMax::max())
? max_arrival - max_crpr
: max_arrival + max_crpr;
? delayDiff(max_arrival, max_crpr, this)
: delaySum(max_arrival, max_crpr, this);
debugPrint(debug_, "search", 4, " cmp %s %s - %s = %s",
tag->to_string(this).c_str(),
delayAsString(max_arrival, this),
@ -1622,7 +1622,7 @@ Search::seedClkArrival(const Pin *pin,
sdc->exceptionFromClkStates(pin,rf,clk,rf,min_max,states);
Tag *tag = findTag(scene, rf, min_max, clk_info, true, nullptr, false,
states, true, nullptr);
Arrival arrival(clk_edge->time() + insertion);
Arrival arrival = delaySum(insertion, clk_edge->time(), this);
tag_bldr->setArrival(tag, arrival);
}
@ -1639,7 +1639,7 @@ Search::seedClkDataArrival(const Pin *pin,
Tag *tag = clkDataTag(pin, clk, rf, clk_edge, insertion, min_max, scene);
if (tag) {
// Data arrivals include insertion delay.
Arrival arrival(clk_edge->time() + insertion);
Arrival arrival = delaySum(insertion, clk_edge->time(), this);
tag_bldr->setArrival(tag, arrival);
}
}
@ -1878,8 +1878,8 @@ Search::inputDelayRefPinArrival(Path *ref_path,
Clock *clk = clk_edge->clock();
if (clk->isPropagated()) {
const ClkInfo *clk_info = ref_path->clkInfo(this);
ref_arrival = delayAsFloat(ref_path->arrival());
ref_insertion = delayAsFloat(clk_info->insertion());
ref_arrival = delayAsFloat(ref_path->arrival(), min_max, this);
ref_insertion = delayAsFloat(clk_info->insertion(), min_max, this);
ref_latency = clk_info->latency();
}
else {
@ -2186,13 +2186,12 @@ PathVisitor::visitFromPath(const Pin *from_pin,
true, min_max,
dcalc_ap,
sdc);
bool arc_delay_min_max_eq =
fuzzyEqual(delayAsFloat(arc_delay), delayAsFloat(arc_delay_opp));
bool arc_delay_min_max_eq = delayEqual(arc_delay, arc_delay_opp, this);
to_tag = search_->thruClkTag(from_path, from_vertex, from_tag, true,
edge, to_rf, arc_delay_min_max_eq,
min_max, scene);
if (to_tag)
to_arrival = from_arrival + arc_delay;
if (to_tag)
to_arrival = delaySum(from_arrival, arc_delay, this);
}
}
}
@ -2210,7 +2209,9 @@ PathVisitor::visitFromPath(const Pin *from_pin,
const LibertyCell *inst_cell = clk_port->libertyCell();
if (inst_cell->isMacro()) {
float slew = delayAsFloat(from_path->slew(this));
arc_delay -= clk_port->clkTreeDelay(slew, from_rf, min_max);
arc_delay = delayDiff(arc_delay,
clk_port->clkTreeDelay(slew, from_rf, min_max),
this);
}
}
@ -2237,7 +2238,7 @@ PathVisitor::visitFromPath(const Pin *from_pin,
to_tag = search_->thruTag(to_tag, edge, to_rf, tag_cache_);
from_arrival = search_->clkPathArrival(from_path, from_clk_info,
clk_edge, min_max);
to_arrival = from_arrival + arc_delay;
to_arrival = delaySum(from_arrival, arc_delay, this);
}
else
to_tag = nullptr;
@ -2309,7 +2310,7 @@ PathVisitor::visitFromPath(const Pin *from_pin,
to_propagates_clk, edge, to_rf,
arc_delay_min_max_eq,
min_max, scene);
to_arrival = from_arrival + arc_delay;
to_arrival = delaySum(from_arrival, arc_delay, this);
}
}
else {
@ -2317,8 +2318,8 @@ PathVisitor::visitFromPath(const Pin *from_pin,
|| sdc->isPathDelayInternalToBreak(from_pin))) {
arc_delay = search_->deratedDelay(from_vertex, arc, edge, false,
min_max, dcalc_ap, sdc);
if (!delayInf(arc_delay)) {
to_arrival = from_arrival + arc_delay;
if (!delayInf(arc_delay, this)) {
to_arrival = delaySum(from_arrival, arc_delay, this);
to_tag = search_->thruTag(from_tag, edge, to_rf, tag_cache_);
}
}
@ -2355,11 +2356,11 @@ Search::clkPathArrival(const Path *clk_path,
&& !clk_info->isPropagated()) {
// Ideal clock, apply ideal insertion delay and latency.
const EarlyLate *early_late = min_max;
return clk_edge->time()
+ clockInsertion(clk_edge->clock(), clk_info->clkSrc(),
clk_edge->transition(), min_max,
early_late, scene->mode())
+ clk_info->latency();
Arrival insertion = clockInsertion(clk_edge->clock(), clk_info->clkSrc(),
clk_edge->transition(), min_max,
early_late, scene->mode());
return delaySum(delaySum(insertion, clk_edge->time(), this),
clk_info->latency(), this);
}
else
return clk_path->arrival();
@ -3166,8 +3167,8 @@ Search::deratedDelay(const Vertex *from_vertex,
const Sdc *sdc)
{
float derate = timingDerate(from_vertex, arc, edge, is_clk, sdc, min_max);
ArcDelay delay = graph_->arcDelay(edge, arc, dcalc_ap);
return delay * derate;
const ArcDelay &delay = graph_->arcDelay(edge, arc, dcalc_ap);
return delayProduct(delay, derate, this);;
}
float
@ -3568,9 +3569,9 @@ RequiredCmp::requiredsSave(Vertex *vertex,
while (path_iter.hasNext()) {
Path *path = path_iter.next();
size_t path_index = path->pathIndex(sta);
Required req = requireds_[path_index];
Required &prev_req = path->required();
bool changed = !delayEqual(prev_req, req);
const Required req = requireds_[path_index];
const Required &prev_req = path->required();
bool changed = !delayEqual(prev_req, req, sta);
debugPrint(debug, "search", 3, "required %s save %s -> %s%s",
path->to_string(sta).c_str(),
delayAsString(prev_req, sta),
@ -3669,8 +3670,8 @@ RequiredVisitor::visitFromToPath(const Pin *,
if (to_tag_group && to_tag_group->hasTag(to_tag)) {
size_t to_path_index = to_tag_group->pathIndex(to_tag);
Path &to_path = to_vertex->paths()[to_path_index];
Required &to_required = to_path.required();
Required from_required = to_required - arc_delay;
const Required &to_required = to_path.required();
Required from_required = delayDiff(to_required, arc_delay, this);
debugPrint(debug_, "search", 3, " to tag %2u: %s",
to_tag->index(),
to_tag->to_string(this).c_str());
@ -3694,7 +3695,7 @@ RequiredVisitor::visitFromToPath(const Pin *,
Tag *to_path_tag = to_path->tag(this);
if (Tag::matchNoCrpr(to_path_tag, to_tag)) {
Required to_required = to_path->required();
Required from_required = to_required - arc_delay;
Required from_required = delayDiff(to_required, arc_delay, this);
debugPrint(debug_, "search", 3, " to tag %2u: %s",
to_path_tag->index(),
to_path_tag->to_string(this).c_str());
@ -3873,14 +3874,14 @@ Slack
Search::totalNegativeSlack(const MinMax *min_max)
{
tnsPreamble();
Slack tns = 0.0;
DelayDbl tns = 0.0;
for (Scene *scene : scenes_) {
size_t path_index = scene->pathIndex(min_max);
Slack tns1 = tns_[path_index];
DelayDbl tns1 = tns_[path_index];
if (delayLess(tns1, tns, this))
tns = tns1;
}
return tns;
return delayDblAsDelay(tns);
}
Slack
@ -3889,7 +3890,7 @@ Search::totalNegativeSlack(const Scene *scene,
{
tnsPreamble();
PathAPIndex path_ap_index = scene->pathIndex(min_max);
return tns_[path_ap_index];
return delayDblAsDelay(tns_[path_ap_index]);
}
void
@ -3976,7 +3977,7 @@ Search::tnsIncr(Vertex *vertex,
debugPrint(debug_, "tns", 3, "tns+ %s %s",
delayAsString(slack, this),
vertex->to_string(this).c_str());
tns_[path_ap_index] += slack;
delayIncr(tns_[path_ap_index], slack, this);
if (tns_slacks_[path_ap_index].contains(vertex))
report_->critical(1513, "tns incr existing vertex");
tns_slacks_[path_ap_index][vertex] = slack;
@ -3995,7 +3996,7 @@ Search::tnsDecr(Vertex *vertex,
debugPrint(debug_, "tns", 3, "tns- %s %s",
delayAsString(slack, this),
vertex->to_string(this).c_str());
tns_[path_ap_index] -= slack;
delayDecr(tns_[path_ap_index], slack, this);
tns_slacks_[path_ap_index].erase(vertex);
}
}

View File

@ -39,6 +39,7 @@
#include "Bfs.hh"
#include "Scene.hh"
#include "Sta.hh"
#include "StaConfig.hh"
using namespace sta;
@ -155,26 +156,29 @@ find_requireds()
Sta::sta()->findRequireds();
}
Slack
float
total_negative_slack_cmd(const MinMax *min_max)
{
return Sta::sta()->totalNegativeSlack(min_max);
Sta *sta = Sta::sta();
return delayAsFloat(sta->totalNegativeSlack(min_max), min_max, sta);
}
Slack
float
total_negative_slack_scene_cmd(const Scene *scene,
const MinMax *min_max)
{
return Sta::sta()->totalNegativeSlack(scene, min_max);
Sta *sta = Sta::sta();
return delayAsFloat(sta->totalNegativeSlack(scene, min_max), min_max, sta);
}
Slack
float
worst_slack_cmd(const MinMax *min_max)
{
Sta *sta = Sta::sta();
Slack worst_slack;
Vertex *worst_vertex;
Sta::sta()->worstSlack(min_max, worst_slack, worst_vertex);
return worst_slack;
sta->worstSlack(min_max, worst_slack, worst_vertex);
return delayAsFloat(worst_slack, min_max, sta);
}
Vertex *
@ -186,14 +190,15 @@ worst_slack_vertex(const MinMax *min_max)
return worst_vertex;;
}
Slack
float
worst_slack_scene(const Scene *scene,
const MinMax *min_max)
{
Sta *sta = Sta::sta();
Slack worst_slack;
Vertex *worst_vertex;
Sta::sta()->worstSlack(scene, min_max, worst_slack, worst_vertex);
return worst_slack;
sta->worstSlack(scene, min_max, worst_slack, worst_vertex);
return delayAsFloat(worst_slack, min_max, sta);
}
Path *
@ -224,7 +229,7 @@ vertex_worst_slack_path(Vertex *vertex,
return sta->vertexWorstSlackPath(vertex, min_max);
}
Slack
float
endpoint_slack(const Pin *pin,
const char *path_group_name,
const MinMax *min_max)
@ -233,7 +238,7 @@ endpoint_slack(const Pin *pin,
sta->ensureLibLinked();
if (sta->isGroupPathName(path_group_name, sta->cmdSdc())) {
Slack slack = sta->endpointSlack(pin, std::string(path_group_name), min_max);
return sta->units()->timeUnit()->staToUser(delayAsFloat(slack));
return sta->units()->timeUnit()->staToUser(delayAsFloat(slack, min_max, sta));
}
else {
sta->report()->error(1577, "%s is not a known path group name.",
@ -407,6 +412,7 @@ set_report_path_fields(bool report_input_pin,
bool report_cap,
bool report_slew,
bool report_fanout,
bool report_variation,
bool report_src_attr)
{
Sta::sta()->setReportPathFields(report_input_pin,
@ -415,6 +421,7 @@ set_report_path_fields(bool report_input_pin,
report_cap,
report_slew,
report_fanout,
report_variation,
report_src_attr);
}
@ -432,18 +439,6 @@ set_report_path_field_properties(const char *field_name,
sta->report()->warn(1575, "unknown report path field %s", field_name);
}
void
set_report_path_field_width(const char *field_name,
int width)
{
Sta *sta = Sta::sta();
ReportField *field = sta->findReportPathField(field_name);
if (field)
field->setWidth(width);
else
sta->report()->warn(1576, "unknown report path field %s", field_name);
}
void
set_report_path_digits(int digits)
{
@ -456,12 +451,6 @@ set_report_path_no_split(bool no_split)
Sta::sta()->setReportPathNoSplit(no_split);
}
void
set_report_path_sigmas(bool report_sigmas)
{
Sta::sta()->setReportPathSigmas(report_sigmas);
}
void
report_path_cmd(Path *path)
{
@ -480,25 +469,28 @@ report_path_ends(PathEndSeq *ends)
void
report_arrival_wrt_clks(const Pin *pin,
const Scene *scene,
bool report_variance,
int digits)
{
Sta::sta()->reportArrivalWrtClks(pin, scene, digits);
Sta::sta()->reportArrivalWrtClks(pin, scene, report_variance, digits);
}
void
report_required_wrt_clks(const Pin *pin,
const Scene *scene,
bool report_variance,
int digits)
{
Sta::sta()->reportRequiredWrtClks(pin, scene, digits);
Sta::sta()->reportRequiredWrtClks(pin, scene, report_variance, digits);
}
void
report_slack_wrt_clks(const Pin *pin,
const Scene *scene,
bool report_variance,
int digits)
{
Sta::sta()->reportSlackWrtClks(pin, scene, digits);
Sta::sta()->reportSlackWrtClks(pin, scene, report_variance, digits);
}
////////////////////////////////////////////////////////////////
@ -518,7 +510,9 @@ float
worst_clk_skew_cmd(const SetupHold *setup_hold,
bool include_internal_latency)
{
return Sta::sta()->findWorstClkSkew(setup_hold, include_internal_latency);
Sta *sta = Sta::sta();
Delay skew = sta->findWorstClkSkew(setup_hold, include_internal_latency);
return delayAsFloat(skew, MinMax::max(), sta);
}
////////////////////////////////////////////////////////////////
@ -571,7 +565,7 @@ report_max_skew_checks(const Net *net,
////////////////////////////////////////////////////////////////
Slack
float
find_clk_min_period(const Clock *clk,
bool ignore_port_paths)
{
@ -963,39 +957,37 @@ set_crpr_mode(const char *mode)
{
Sta *sta = Sta::sta();
if (stringEq(mode, "same_pin"))
Sta::sta()->setCrprMode(CrprMode::same_pin);
sta->setCrprMode(CrprMode::same_pin);
else if (stringEq(mode, "same_transition"))
Sta::sta()->setCrprMode(CrprMode::same_transition);
sta->setCrprMode(CrprMode::same_transition);
else
sta->report()->critical(1573, "unknown common clk pessimism mode.");
sta->report()->error(1573, "unknown common clk pessimism mode.");
}
bool
pocv_enabled()
const char *
pocv_mode()
{
return Sta::sta()->pocvEnabled();
return pocvModeName(Sta::sta()->pocvMode());
}
void
set_pocv_enabled(bool enabled)
set_pocv_mode(const char *mode_name)
{
#if !SSTA
if (enabled)
Sta::sta()->report()->error(1574, "POCV support requires compilation with SSTA=1.");
#endif
return Sta::sta()->setPocvEnabled(enabled);
Sta *sta = Sta::sta();
PocvMode mode = findPocvMode(mode_name);
sta->setPocvMode(mode);
}
float
pocv_sigma_factor()
pocv_quantile()
{
return Sta::sta()->sigmaFactor();
return Sta::sta()->pocvQuantile();
}
void
set_pocv_sigma_factor(float factor)
set_pocv_quantile(float quantile)
{
Sta::sta()->setSigmaFactor(factor);
Sta::sta()->setPocvQuantile(quantile);
}
bool
@ -1141,58 +1133,83 @@ Vertex *vertex() { return self->vertex(Sta::sta()); }
Path *path() { return self->path(); }
RiseFall *end_transition()
{ return const_cast<RiseFall*>(self->path()->transition(Sta::sta())); }
Slack slack() { return self->slack(Sta::sta()); }
ArcDelay margin() { return self->margin(Sta::sta()); }
Required data_required_time() { return self->requiredTimeOffset(Sta::sta()); }
Arrival data_arrival_time() { return self->dataArrivalTimeOffset(Sta::sta()); }
float
slack()
{
Sta *sta = Sta::sta();
return delayAsFloat(self->slack(sta), self->minMax(sta), sta);
}
float
margin()
{
Sta *sta = Sta::sta();
return delayAsFloat(self->margin(sta), self->minMax(sta), sta);
}
float
data_required_time()
{
Sta *sta = Sta::sta();
return delayAsFloat(self->requiredTimeOffset(sta), self->minMax(sta), sta);
}
float
data_arrival_time()
{
Sta *sta = Sta::sta();
return delayAsFloat(self->dataArrivalTimeOffset(sta), self->minMax(sta), sta);
}
float
target_clk_delay()
{
Sta *sta = Sta::sta();
return delayAsFloat(self->targetClkDelay(sta), self->minMax(sta), sta);
}
float
source_clk_latency()
{
Sta *sta = Sta::sta();
return delayAsFloat(self->sourceClkLatency(sta), self->minMax(sta), sta);
}
float
clk_skew()
{
Sta *sta = Sta::sta();
return delayAsFloat(self->clkSkew(sta), self->minMax(sta), sta);
}
const TimingRole *check_role() { return self->checkRole(Sta::sta()); }
MinMax *min_max() { return const_cast<MinMax*>(self->minMax(Sta::sta())); }
float source_clk_offset() { return self->sourceClkOffset(Sta::sta()); }
Arrival source_clk_latency() { return self->sourceClkLatency(Sta::sta()); }
Arrival source_clk_insertion_delay()
{ return self->sourceClkInsertionDelay(Sta::sta()); }
const Clock *target_clk() { return self->targetClk(Sta::sta()); }
const ClockEdge *target_clk_edge() { return self->targetClkEdge(Sta::sta()); }
Path *target_clk_path() { return self->targetClkPath(); }
float target_clk_time() { return self->targetClkTime(Sta::sta()); }
float target_clk_offset() { return self->targetClkOffset(Sta::sta()); }
float target_clk_mcp_adjustment()
{ return self->targetClkMcpAdjustment(Sta::sta()); }
Arrival target_clk_delay() { return self->targetClkDelay(Sta::sta()); }
Arrival target_clk_insertion_delay()
{ return self->targetClkInsertionDelay(Sta::sta()); }
float target_clk_uncertainty()
{ return self->targetNonInterClkUncertainty(Sta::sta()); }
float inter_clk_uncertainty()
{ return self->interClkUncertainty(Sta::sta()); }
Arrival target_clk_arrival() { return self->targetClkArrival(Sta::sta()); }
bool path_delay_margin_is_external()
{ return self->pathDelayMarginIsExternal();}
Crpr check_crpr() { return self->checkCrpr(Sta::sta()); }
RiseFall *target_clk_end_trans()
{ return const_cast<RiseFall*>(self->targetClkEndTrans(Sta::sta())); }
Delay clk_skew() { return self->clkSkew(Sta::sta()); }
}
%extend Path {
float
arrival()
{
return delayAsFloat(self->arrival());
Sta *sta = Sta::sta();
return delayAsFloat(self->arrival(), self->minMax(sta), sta);
}
float
required()
{
return delayAsFloat(self->required());
Sta *sta = Sta::sta();
return delayAsFloat(self->required(), self->minMax(sta), sta);
}
float
slack()
{
Sta *sta = Sta::sta();
return delayAsFloat(self->slack(sta));
return delayAsFloat(self->slack(sta), self->minMax(sta), sta);
}
const Pin *

View File

@ -683,7 +683,6 @@ proc_redirect report_path {
proc parse_report_path_options { cmd args_var default_format
unknown_key_is_error } {
variable path_options
variable report_path_field_width_extra
global sta_report_default_digits
upvar 1 $args_var args
@ -691,7 +690,7 @@ proc parse_report_path_options { cmd args_var default_format
unset path_options
}
parse_key_args $cmd args path_options {-format -digits -fields} \
path_options {-no_line_splits -report_sigmas} $unknown_key_is_error
path_options {-no_line_splits} $unknown_key_is_error
set format $default_format
if [info exists path_options(-format)] {
@ -712,24 +711,8 @@ proc parse_report_path_options { cmd args_var default_format
check_positive_integer "-digits" $digits
}
set report_sigmas [info exists path_options(-report_sigmas)]
set_report_path_sigmas $report_sigmas
set path_options(num_fmt) "%.${digits}f"
set_report_path_digits $digits
# Numeric field width expands with digits.
set field_width [expr $digits + $report_path_field_width_extra]
if { $report_sigmas } {
set delay_field_width [expr $field_width * 3 + $report_path_field_width_extra]
} else {
set delay_field_width $field_width
}
foreach field {total incr} {
set_report_path_field_width $field $delay_field_width
}
foreach field {capacitance slew} {
set_report_path_field_width $field $field_width
}
set report_input_pin 0
set report_hier_pins 0
@ -737,6 +720,7 @@ proc parse_report_path_options { cmd args_var default_format
set report_net 0
set report_slew 0
set report_fanout 0
set report_variation 0
set report_src_attr 0
if { [info exists path_options(-fields)] } {
foreach field $path_options(-fields) {
@ -752,6 +736,8 @@ proc parse_report_path_options { cmd args_var default_format
set report_slew 1
} elseif { [string match "fanout" $field] } {
set report_fanout 1
} elseif { [string match "variation" $field] } {
set report_variation 1
} elseif { [string match "src*" $field] } {
set report_src_attr 1
} else {
@ -759,20 +745,21 @@ proc parse_report_path_options { cmd args_var default_format
}
}
}
set_report_path_fields $report_input_pin $report_hier_pins $report_net \
$report_cap $report_slew $report_fanout $report_src_attr
$report_cap $report_slew $report_fanout $report_variation $report_src_attr
set_report_path_no_split [info exists path_options(-no_line_splits)]
}
################################################################
define_cmd_args "report_arrival" {[-scene scene] [-digits digits] pin}
define_cmd_args "report_arrival" {[-scene scene] [-report_variance] [-digits digits] pin}
proc report_arrival { args } {
global sta_report_default_digits
parse_key_args "report_arrival" args keys {-scene -digits} flags {}
parse_key_args "report_arrival" args keys {-scene -digits} flags {-report_variance}
check_argc_eq1 "report_arrival" $args
set pin [get_port_pin_error "pin" [lindex $args 0]]
@ -783,17 +770,18 @@ proc report_arrival { args } {
} else {
set digits $sta_report_default_digits
}
report_arrival_wrt_clks $pin $scene $digits
set report_variance [info exists flags(-report_variance)]
report_arrival_wrt_clks $pin $scene $report_variance $digits
}
################################################################
define_cmd_args "report_required" {[-scene scene] [-digits digits] pin}
define_cmd_args "report_required" {[-scene scene] [-report_variance] [-digits digits] pin}
proc report_required { args } {
global sta_report_default_digits
parse_key_args "report_required" args keys {-scene -digits} flags {}
parse_key_args "report_required" args keys {-scene -digits} flags {-report_variance}
check_argc_eq1 "report_required" $args
set pin [get_port_pin_error "pin" [lindex $args 0]]
@ -804,17 +792,18 @@ proc report_required { args } {
} else {
set digits $sta_report_default_digits
}
report_required_wrt_clks $pin $scene $digits
set report_variance [info exists flags(-report_variance)]
report_required_wrt_clks $pin $scene $report_variance $digits
}
################################################################
define_cmd_args "report_slack" {[-scene scene] [-digits digits] pin}
define_cmd_args "report_slack" {[-scene scene] [-report_variance] [-digits digits] pin}
proc report_slack { args } {
global sta_report_default_digits
parse_key_args "report_slack" args keys {-scene -digits} flags {}
parse_key_args "report_slack" args keys {-scene -digits} flags {-report_variance}
check_argc_eq1 "report_slack" $args
set pin [get_port_pin_error "pin" [lindex $args 0]]
@ -825,7 +814,8 @@ proc report_slack { args } {
} else {
set digits $sta_report_default_digits
}
report_slack_wrt_clks $pin $scene $digits
set report_variance [info exists flags(-report_variance)]
report_slack_wrt_clks $pin $scene $report_variance $digits
}
################################################################

View File

@ -87,6 +87,9 @@
#include "MakeTimingModel.hh"
#include "parasitics/ConcreteParasitics.hh"
#include "spice/WritePathSpice.hh"
#include "DelayScalar.hh"
#include "DelayNormal.hh"
#include "DelaySkewNormal.hh"
namespace sta {
@ -300,6 +303,7 @@ Sta::makeComponents()
makePower();
makeClkSkews();
makeCheckTiming();
delay_ops_ = new DelayOpsScalar();
setCmdNamespace1(CmdNamespace::sdc);
setThreadCount1(defaultThreadCount());
@ -526,6 +530,7 @@ Sta::~Sta()
delete equiv_cells_;
delete dispatch_queue_;
delete variables_;
delete delay_ops_;
deleteContents(parasitics_name_map_);
deleteContents(modes_);
deleteContents(scenes_);
@ -2262,25 +2267,47 @@ Sta::setCrprMode(CrprMode mode)
variables_->setCrprMode(mode);
}
bool
Sta::pocvEnabled() const
PocvMode
Sta::pocvMode() const
{
return variables_->pocvEnabled();
return variables_->pocvMode();
}
void
Sta::setPocvEnabled(bool enabled)
Sta::setPocvMode(PocvMode mode)
{
if (enabled != variables_->pocvEnabled())
if (mode != variables_->pocvMode()) {
variables_->setPocvMode(mode);
delete delay_ops_;
switch (mode) {
case PocvMode::scalar:
default:
delay_ops_ = new DelayOpsScalar();
break;
case PocvMode::normal:
delay_ops_ = new DelayOpsNormal();
break;
case PocvMode::skew_normal:
delay_ops_ = new DelayOpsSkewNormal();
break;
}
updateComponentsState();
delaysInvalid();
variables_->setPocvEnabled(enabled);
}
}
float
Sta::pocvQuantile()
{
return variables_->pocvQuantile();
}
void
Sta::setSigmaFactor(float factor)
Sta::setPocvQuantile(float quantile)
{
if (!fuzzyEqual(factor, sigma_factor_)) {
sigma_factor_ = factor;
if (!fuzzyEqual(quantile, variables_->pocvQuantile())) {
variables_->setPocvQuantile(quantile);
search_->arrivalsInvalid();
updateComponentsState();
}
@ -2739,11 +2766,12 @@ Sta::setReportPathFields(bool report_input_pin,
bool report_cap,
bool report_slew,
bool report_fanout,
bool report_variation,
bool report_src_attr)
{
report_path_->setReportFields(report_input_pin, report_hier_pins, report_net,
report_cap, report_slew, report_fanout,
report_src_attr);
report_variation, report_src_attr);
}
ReportField *
@ -2764,12 +2792,6 @@ Sta::setReportPathNoSplit(bool no_split)
report_path_->setNoSplit(no_split);
}
void
Sta::setReportPathSigmas(bool report_sigmas)
{
report_path_->setReportSigmas(report_sigmas);
}
void
Sta::reportPathEnd(PathEnd *end)
{
@ -2811,7 +2833,7 @@ Sta::reportClkSkew(ConstClockSeq &clks,
include_internal_latency, digits);
}
float
Delay
Sta::findWorstClkSkew(const SetupHold *setup_hold,
bool include_internal_latency)
{
@ -3246,10 +3268,11 @@ Sta::endpointSlack(const Pin *pin,
void
Sta::reportArrivalWrtClks(const Pin *pin,
const Scene *scene,
bool report_variance,
int digits)
{
searchPreamble();
reportDelaysWrtClks(pin, scene, digits, false,
reportDelaysWrtClks(pin, scene, report_variance, digits, false,
[] (const Path *path) {
return path->arrival();
});
@ -3258,9 +3281,10 @@ Sta::reportArrivalWrtClks(const Pin *pin,
void
Sta::reportRequiredWrtClks(const Pin *pin,
const Scene *scene,
bool report_variance,
int digits)
{
reportDelaysWrtClks(pin, scene, digits, true,
reportDelaysWrtClks(pin, scene, report_variance, digits, true,
[] (const Path *path) {
return path->required();
});
@ -3269,9 +3293,10 @@ Sta::reportRequiredWrtClks(const Pin *pin,
void
Sta::reportSlackWrtClks(const Pin *pin,
const Scene *scene,
bool report_variance,
int digits)
{
reportDelaysWrtClks(pin, scene, digits, true,
reportDelaysWrtClks(pin, scene, report_variance, digits, true,
[this] (const Path *path) {
return path->slack(this);
});
@ -3280,6 +3305,7 @@ Sta::reportSlackWrtClks(const Pin *pin,
void
Sta::reportDelaysWrtClks(const Pin *pin,
const Scene *scene,
bool report_variance,
int digits,
bool find_required,
PathDelayFunc get_path_delay)
@ -3288,14 +3314,17 @@ Sta::reportDelaysWrtClks(const Pin *pin,
Vertex *vertex, *bidir_vertex;
graph_->pinVertices(pin, vertex, bidir_vertex);
if (vertex)
reportDelaysWrtClks(vertex, scene, digits, find_required, get_path_delay);
reportDelaysWrtClks(vertex, scene, report_variance, digits,
find_required, get_path_delay);
if (bidir_vertex)
reportDelaysWrtClks(vertex, scene, digits, find_required, get_path_delay);
reportDelaysWrtClks(vertex, scene, report_variance, digits,
find_required, get_path_delay);
}
void
Sta::reportDelaysWrtClks(Vertex *vertex,
const Scene *scene,
bool report_variance,
int digits,
bool find_required,
PathDelayFunc get_path_delay)
@ -3305,13 +3334,15 @@ Sta::reportDelaysWrtClks(Vertex *vertex,
else
search_->findArrivals(vertex->level());
const Sdc *sdc = scene->sdc();
reportDelaysWrtClks(vertex, nullptr, scene, digits, get_path_delay);
reportDelaysWrtClks(vertex, nullptr, scene, report_variance, digits, get_path_delay);
const ClockEdge *default_clk_edge = sdc->defaultArrivalClock()->edge(RiseFall::rise());
reportDelaysWrtClks(vertex, default_clk_edge, scene, digits, get_path_delay);
reportDelaysWrtClks(vertex, default_clk_edge, scene, report_variance,
digits, get_path_delay);
for (const Clock *clk : sdc->sortedClocks()) {
for (const RiseFall *rf : RiseFall::range()) {
const ClockEdge *clk_edge = clk->edge(rf);
reportDelaysWrtClks(vertex, clk_edge, scene, digits, get_path_delay);
reportDelaysWrtClks(vertex, clk_edge, scene, report_variance, digits,
get_path_delay);
}
}
}
@ -3320,6 +3351,7 @@ void
Sta::reportDelaysWrtClks(Vertex *vertex,
const ClockEdge *clk_edge,
const Scene *scene,
bool report_variance,
int digits,
PathDelayFunc get_path_delay)
{
@ -3335,13 +3367,13 @@ Sta::reportDelaysWrtClks(Vertex *vertex,
report_->reportLine("%s r %s:%s f %s:%s",
clk_name.c_str(),
formatDelay(RiseFall::rise(), MinMax::min(),
delays, digits).c_str(),
delays, report_variance, digits).c_str(),
formatDelay(RiseFall::rise(), MinMax::max(),
delays, digits).c_str(),
delays, report_variance, digits).c_str(),
formatDelay(RiseFall::fall(), MinMax::min(),
delays, digits).c_str(),
delays, report_variance, digits).c_str(),
formatDelay(RiseFall::fall(), MinMax::max(),
delays, digits).c_str());
delays, report_variance, digits).c_str());
}
}
@ -3360,7 +3392,7 @@ Sta::findDelaysWrtClks(Vertex *vertex,
const MinMax *min_max = path->minMax(this);
const ClockEdge *path_clk_edge = path->clkEdge(this);
if (path_clk_edge == clk_edge
&& !delayInf(delay))
&& !delayInf(delay, this))
delays.mergeValue(rf, min_max, delay, this);
}
return delays;
@ -3370,13 +3402,14 @@ std::string
Sta::formatDelay(const RiseFall *rf,
const MinMax *min_max,
const RiseFallMinMaxDelay &delays,
bool report_variance,
int digits)
{
Delay delay;
bool exists;
delays.value(rf, min_max, delay, exists);
if (exists)
return delayAsString(delay, this, digits);
return delayAsString(delay, min_max, report_variance, digits, this);
else
return "---";
}
@ -3439,7 +3472,7 @@ MinPeriodEndVisitor::visit(PathEnd *path_end)
|| !(network->isTopLevelPort(path->pin(sta_))
|| pathIsFromInputPort(path_end)))) {
Slack slack = path_end->slack(sta_);
float period = clk_->period() - delayAsFloat(slack);
float period = clk_->period() - delayAsFloat(slack, MinMax::min(), sta_);
min_period_ = std::max(min_period_, period);
}
}
@ -3589,7 +3622,7 @@ Sta::setIncrementalDelayTolerance(float tol)
graph_delay_calc_->setIncrementalDelayTolerance(tol);
}
ArcDelay
const ArcDelay&
Sta::arcDelay(Edge *edge,
TimingArc *arc,
DcalcAPIndex ap_index)
@ -3684,7 +3717,7 @@ Sta::ensureGraph()
void
Sta::makeGraph()
{
graph_ = new Graph(this, 2, dcalcAnalysisPtCount());
graph_ = new Graph(this, dcalcAnalysisPtCount());
graph_->makeGraph();
}
@ -5535,12 +5568,12 @@ Sta::reportSlewChecks(const Net *net,
if (verbose)
report_path_->reportLimitVerbose(report_path_->fieldSlew(),
check.pin(), check.edge(),
delayAsFloat(check.slew()),
delayAsFloat(check.slew(), min_max, this),
check.limit(), check.slack(),
check.scene(), min_max);
else
report_path_->reportLimitShort(report_path_->fieldSlew(), check.pin(),
delayAsFloat(check.slew()),
delayAsFloat(check.slew(), min_max, this),
check.limit(), check.slack());
}
report_->reportLine("");

View File

@ -49,11 +49,11 @@ StaState::StaState() :
arc_delay_calc_(nullptr),
graph_delay_calc_(nullptr),
search_(nullptr),
delay_ops_(nullptr),
latches_(nullptr),
variables_(nullptr),
thread_count_(1),
dispatch_queue_(nullptr),
sigma_factor_(1.0)
dispatch_queue_(nullptr)
{
}

View File

@ -166,7 +166,7 @@ WorstSlack::initQueue(PathAPIndex path_ap_index)
slack_threshold_ = slack_init_;
for(Vertex *vertex : search_->endpoints()) {
Slack slack = search_->wnsSlack(vertex, path_ap_index);
if (!delayEqual(slack, slack_init_)) {
if (!delayEqual(slack, slack_init_, this)) {
if (delayLess(slack, worst_slack_, this))
setWorstSlack(vertex, slack);
if (delayLessEqual(slack, slack_threshold_, this))
@ -177,8 +177,8 @@ WorstSlack::initQueue(PathAPIndex path_ap_index)
}
}
debugPrint(debug_, "wns", 3, "threshold %s",
delayAsString(slack_threshold_, this));
// checkQueue();
delayAsString(slack_threshold_, MinMax::max(), this));
//checkQueue();
}
void
@ -199,7 +199,7 @@ WorstSlack::sortQueue(PathAPIndex path_ap_index)
Vertex *threshold_vertex = vertices[threshold_index];
slack_threshold_ = search_->wnsSlack(threshold_vertex, path_ap_index);
debugPrint(debug_, "wns", 3, "threshold %s",
delayAsString(slack_threshold_, this));
delayAsString(slack_threshold_, MinMax::max(), this));
// Reinsert vertices with slack < threshold.
queue_->clear();
@ -281,7 +281,7 @@ WorstSlack::updateWorstSlack(Vertex *vertex,
// Mark worst slack as unknown (updated by findWorstSlack().
worst_vertex_ = nullptr;
if (!delayEqual(slack, slack_init_)
if (!delayEqual(slack, slack_init_, this)
&& delayLessEqual(slack, slack_threshold_, this)) {
debugPrint(debug_, "wns", 3, "insert %s %s",
vertex->to_string(this).c_str(),

View File

@ -484,7 +484,7 @@ WriteSpice::slewAxisMinValue(const TimingArc *arc)
{
GateTableModel *gate_model = arc->gateTableModel(scene_, min_max_);
if (gate_model) {
const TableModel *model = gate_model->delayModel();
const TableModel *model = gate_model->delayModels()->model();
const TableAxis *axis1 = model->axis1();
TableAxisVariable var1 = axis1->variable();
if (var1 == TableAxisVariable::input_transition_time

View File

@ -1198,32 +1198,8 @@ using namespace sta;
Tcl_SetObjResult(interp, obj);
}
%typemap(out) Delay {
Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1)));
}
%typemap(out) Arrival {
Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1)));
}
%typemap(out) Required {
Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1)));
}
%typemap(out) Slack {
Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1)));
}
%typemap(out) ArcDelay {
Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1)));
}
%typemap(out) Slew {
Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1)));
}
%typemap(out) Crpr {
Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1)));
%typemap(in) StringSet* {
$1 = tclListSetConstChar($input, interp);
}
%typemap(out) Mode* {

View File

@ -170,7 +170,7 @@ tclArcDcalcArg(ArcDcalcArg &gate,
obj = Tcl_NewStringObj(to_edge, strlen(to_edge));
Tcl_ListObjAppendElement(interp, list, obj);
const char *input_delay = delayAsString(gate.inputDelay(), sta, 3);
const char *input_delay = delayAsString(gate.inputDelay(), sta);
obj = Tcl_NewStringObj(input_delay, strlen(input_delay));
Tcl_ListObjAppendElement(interp, list, obj);

View File

@ -152,16 +152,42 @@ proc trace_propagate_gated_clock_enable { name1 name2 op } {
propagate_gated_clock_enable set_propagate_gated_clock_enable
}
trace variable ::sta_pocv_enabled "rw" \
sta::trace_pocv_enabled
trace variable ::sta_pocv_mode "rw" \
sta::trace_pocv_mode
proc trace_pocv_enabled { name1 name2 op } {
trace_boolean_var $op ::sta_pocv_enabled \
pocv_enabled set_pocv_enabled
proc trace_pocv_mode { name1 name2 op } {
global sta_pocv_mode
if { $op == "r" } {
set sta_pocv_mode [pocv_mode]
} elseif { $op == "w" } {
if { $sta_pocv_mode == "scalar" \
|| $sta_pocv_mode == "normal" \
|| $sta_pocv_mode == "skew_normal" } {
set_pocv_mode $sta_pocv_mode
} else {
sta_error 593 "sta_pocv_mode must be scalar, normal, or skew_normal."
}
}
}
# Report path numeric field width is digits + extra.
set report_path_field_width_extra 5
trace variable ::sta_pocv_quantile "rw" \
sta::trace_pocv_quantile
proc trace_pocv_quantile { name1 name2 op } {
global sta_pocv_quantile
if { $op == "r" } {
set sta_pocv_quantile [pocv_quantile]
} elseif { $op == "w" } {
if { [string is double $sta_pocv_quantile] \
&& $sta_pocv_quantile >= 0.0 } {
set_pocv_quantile $sta_pocv_quantile
} else {
sta_error 594 "sta_pocv_quantile must be a positive floating point number."
}
}
}
################################################################

View File

@ -6,6 +6,4 @@
#cmakedefine ZLIB_FOUND
#define SSTA ${SSTA}
#define TCL_READLINE ${TCL_READLINE}

View File

@ -1032,7 +1032,7 @@ VerilogDclBus::VerilogDclBus(PortDirection *dir,
int
VerilogDclBus::size() const
{
return abs(to_index_ - from_index_) + 1;
return std::abs(to_index_ - from_index_) + 1;
}
VerilogDclArg::VerilogDclArg(const std::string &net_name) :