lvf squish
Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
parent
0a5b95a523
commit
d6e7b4256c
|
|
@ -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}")
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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++) {
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 "";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 "";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 "";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
----------
|
||||
|
||||
|
|
|
|||
7081
doc/OpenSTA.fodt
7081
doc/OpenSTA.fodt
File diff suppressed because it is too large
Load Diff
BIN
doc/OpenSTA.pdf
BIN
doc/OpenSTA.pdf
Binary file not shown.
|
|
@ -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
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
@ -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)
|
||||
126
graph/Graph.cc
126
graph/Graph.cc
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ""
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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++;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_)));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_; }
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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_) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 *
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
179
search/Search.i
179
search/Search.i
|
|
@ -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 *
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
################################################################
|
||||
|
|
|
|||
105
search/Sta.cc
105
search/Sta.cc
|
|
@ -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("");
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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* {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
################################################################
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,4 @@
|
|||
|
||||
#cmakedefine ZLIB_FOUND
|
||||
|
||||
#define SSTA ${SSTA}
|
||||
|
||||
#define TCL_READLINE ${TCL_READLINE}
|
||||
|
|
|
|||
|
|
@ -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) :
|
||||
|
|
|
|||
Loading…
Reference in New Issue