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)
|
cmake_policy(SET CMP0086 NEW)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
project(STA VERSION 3.0.0
|
project(STA VERSION 3.0.1
|
||||||
LANGUAGES CXX
|
LANGUAGES CXX
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -82,13 +82,17 @@ endif()
|
||||||
set(STA_SOURCE
|
set(STA_SOURCE
|
||||||
app/StaMain.cc
|
app/StaMain.cc
|
||||||
|
|
||||||
dcalc/ArcDelayCalc.cc
|
|
||||||
dcalc/ArcDcalcWaveforms.cc
|
dcalc/ArcDcalcWaveforms.cc
|
||||||
|
dcalc/ArcDelayCalc.cc
|
||||||
dcalc/ArnoldiDelayCalc.cc
|
dcalc/ArnoldiDelayCalc.cc
|
||||||
dcalc/ArnoldiReduce.cc
|
dcalc/ArnoldiReduce.cc
|
||||||
dcalc/CcsCeffDelayCalc.cc
|
dcalc/CcsCeffDelayCalc.cc
|
||||||
|
dcalc/Delay.cc
|
||||||
dcalc/DelayCalc.cc
|
dcalc/DelayCalc.cc
|
||||||
dcalc/DelayCalcBase.cc
|
dcalc/DelayCalcBase.cc
|
||||||
|
dcalc/DelayNormal.cc
|
||||||
|
dcalc/DelayScalar.cc
|
||||||
|
dcalc/DelaySkewNormal.cc
|
||||||
dcalc/DmpCeff.cc
|
dcalc/DmpCeff.cc
|
||||||
dcalc/DmpDelayCalc.cc
|
dcalc/DmpDelayCalc.cc
|
||||||
dcalc/FindRoot.cc
|
dcalc/FindRoot.cc
|
||||||
|
|
@ -99,9 +103,6 @@ set(STA_SOURCE
|
||||||
dcalc/PrimaDelayCalc.cc
|
dcalc/PrimaDelayCalc.cc
|
||||||
dcalc/UnitDelayCalc.cc
|
dcalc/UnitDelayCalc.cc
|
||||||
|
|
||||||
graph/DelayFloat.cc
|
|
||||||
graph/DelayNormal1.cc
|
|
||||||
graph/DelayNormal2.cc
|
|
||||||
graph/Graph.cc
|
graph/Graph.cc
|
||||||
graph/GraphCmp.cc
|
graph/GraphCmp.cc
|
||||||
|
|
||||||
|
|
@ -199,6 +200,7 @@ set(STA_SOURCE
|
||||||
search/PathEnum.cc
|
search/PathEnum.cc
|
||||||
search/PathExpanded.cc
|
search/PathExpanded.cc
|
||||||
search/PathGroup.cc
|
search/PathGroup.cc
|
||||||
|
search/PocvMode.cc
|
||||||
search/Property.cc
|
search/Property.cc
|
||||||
search/ReportPath.cc
|
search/ReportPath.cc
|
||||||
search/Search.cc
|
search/Search.cc
|
||||||
|
|
@ -403,11 +405,6 @@ find_package(Eigen3 REQUIRED)
|
||||||
|
|
||||||
include(cmake/FindCUDD.cmake)
|
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 a header file to pass some of the CMake settings
|
||||||
configure_file(${STA_HOME}/util/StaConfig.hh.cmake
|
configure_file(${STA_HOME}/util/StaConfig.hh.cmake
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/include/sta/StaConfig.hh
|
${CMAKE_CURRENT_BINARY_DIR}/include/sta/StaConfig.hh
|
||||||
|
|
@ -554,7 +551,7 @@ endif()
|
||||||
|
|
||||||
# common to gcc/clang
|
# common to gcc/clang
|
||||||
set(CXX_FLAGS -Wall -Wextra -pedantic -Wcast-qual -Wredundant-decls
|
set(CXX_FLAGS -Wall -Wextra -pedantic -Wcast-qual -Wredundant-decls
|
||||||
-Wformat-security -Werror=misleading-indentation)
|
-Wformat-security -Werror=misleading-indentation -Wundef)
|
||||||
|
|
||||||
if(ENABLE_TSAN)
|
if(ENABLE_TSAN)
|
||||||
message(STATUS "Thread sanitizer: ${ENABLE_TSAN}")
|
message(STATUS "Thread sanitizer: ${ENABLE_TSAN}")
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,8 @@ ArcDcalcWaveforms::inputWaveform(ArcDcalcArg &dcalc_arg,
|
||||||
library->supplyVoltage("VDD", vdd, vdd_exists);
|
library->supplyVoltage("VDD", vdd, vdd_exists);
|
||||||
if (!vdd_exists)
|
if (!vdd_exists)
|
||||||
report->error(1751, "VDD not defined in library %s", library->name());
|
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.
|
// Delay time axis.
|
||||||
FloatSeq time_values;
|
FloatSeq time_values;
|
||||||
for (float time : in_waveform.axis1()->values())
|
for (float time : in_waveform.axis1()->values())
|
||||||
|
|
|
||||||
|
|
@ -257,18 +257,18 @@ ArcDcalcResult::ArcDcalcResult(size_t load_count) :
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ArcDcalcResult::setGateDelay(ArcDelay gate_delay)
|
ArcDcalcResult::setGateDelay(const ArcDelay &gate_delay)
|
||||||
{
|
{
|
||||||
gate_delay_ = gate_delay;
|
gate_delay_ = gate_delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ArcDcalcResult::setDrvrSlew(Slew drvr_slew)
|
ArcDcalcResult::setDrvrSlew(const Slew &drvr_slew)
|
||||||
{
|
{
|
||||||
drvr_slew_ = drvr_slew;
|
drvr_slew_ = drvr_slew;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArcDelay
|
const ArcDelay &
|
||||||
ArcDcalcResult::wireDelay(size_t load_idx) const
|
ArcDcalcResult::wireDelay(size_t load_idx) const
|
||||||
{
|
{
|
||||||
return wire_delays_[load_idx];
|
return wire_delays_[load_idx];
|
||||||
|
|
@ -276,7 +276,7 @@ ArcDcalcResult::wireDelay(size_t load_idx) const
|
||||||
|
|
||||||
void
|
void
|
||||||
ArcDcalcResult::setWireDelay(size_t load_idx,
|
ArcDcalcResult::setWireDelay(size_t load_idx,
|
||||||
ArcDelay wire_delay)
|
const ArcDelay &wire_delay)
|
||||||
{
|
{
|
||||||
wire_delays_[load_idx] = wire_delay;
|
wire_delays_[load_idx] = wire_delay;
|
||||||
}
|
}
|
||||||
|
|
@ -288,7 +288,7 @@ ArcDcalcResult::setLoadCount(size_t load_count)
|
||||||
load_slews_.resize(load_count);
|
load_slews_.resize(load_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
Slew
|
const Slew &
|
||||||
ArcDcalcResult::loadSlew(size_t load_idx) const
|
ArcDcalcResult::loadSlew(size_t load_idx) const
|
||||||
{
|
{
|
||||||
return load_slews_[load_idx];
|
return load_slews_[load_idx];
|
||||||
|
|
@ -296,7 +296,7 @@ ArcDcalcResult::loadSlew(size_t load_idx) const
|
||||||
|
|
||||||
void
|
void
|
||||||
ArcDcalcResult::setLoadSlew(size_t load_idx,
|
ArcDcalcResult::setLoadSlew(size_t load_idx,
|
||||||
Slew load_slew)
|
const Slew &load_slew)
|
||||||
{
|
{
|
||||||
load_slews_[load_idx] = load_slew;
|
load_slews_[load_idx] = load_slew;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -237,7 +237,6 @@ private:
|
||||||
ArnoldiReduce *reduce_;
|
ArnoldiReduce *reduce_;
|
||||||
delay_work *delay_work_;
|
delay_work *delay_work_;
|
||||||
std::vector<rcmodel*> unsaved_parasitics_;
|
std::vector<rcmodel*> unsaved_parasitics_;
|
||||||
bool pocv_enabled_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ArcDelayCalc *
|
ArcDelayCalc *
|
||||||
|
|
@ -397,7 +396,6 @@ ArnoldiDelayCalc::gateDelay(const Pin *drvr_pin,
|
||||||
ConcreteParasitic *cparasitic =
|
ConcreteParasitic *cparasitic =
|
||||||
reinterpret_cast<ConcreteParasitic*>(const_cast<Parasitic*>(parasitic));
|
reinterpret_cast<ConcreteParasitic*>(const_cast<Parasitic*>(parasitic));
|
||||||
rcmodel_ = dynamic_cast<rcmodel*>(cparasitic);
|
rcmodel_ = dynamic_cast<rcmodel*>(cparasitic);
|
||||||
pocv_enabled_ = variables_->pocvEnabled();
|
|
||||||
GateTableModel *table_model = arc->gateTableModel(scene, min_max);
|
GateTableModel *table_model = arc->gateTableModel(scene, min_max);
|
||||||
if (table_model && rcmodel_) {
|
if (table_model && rcmodel_) {
|
||||||
const Pvt *pvt = pinPvt(drvr_pin, scene, min_max);
|
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);
|
auto load_idx_itr = load_pin_index_map.find(load_pin);
|
||||||
if (load_idx_itr != load_pin_index_map.end()) {
|
if (load_idx_itr != load_pin_index_map.end()) {
|
||||||
size_t load_idx = load_idx_itr->second;
|
size_t load_idx = load_idx_itr->second;
|
||||||
ArcDelay wire_delay = _delayV[i] - _delayV[0];
|
double wire_delay = _delayV[i] - _delayV[0];
|
||||||
Slew load_slew = _slewV[i];
|
double load_slew = _slewV[i];
|
||||||
thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew);
|
thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew);
|
||||||
dcalc_result.setWireDelay(load_idx, wire_delay);
|
dcalc_result.setWireDelay(load_idx, wire_delay);
|
||||||
dcalc_result.setLoadSlew(load_idx, load_slew);
|
dcalc_result.setLoadSlew(load_idx, load_slew);
|
||||||
|
|
@ -1325,9 +1323,8 @@ ArnoldiDelayCalc::ra_get_r(delay_work *D,
|
||||||
float c1;
|
float c1;
|
||||||
double tlohi,r;
|
double tlohi,r;
|
||||||
c1 = ctot;
|
c1 = ctot;
|
||||||
ArcDelay d1;
|
float d1, s1;
|
||||||
Slew s1;
|
tab->table->gateDelay(tab->pvt, tab->in_slew, c1, d1, s1);
|
||||||
tab->table->gateDelay(tab->pvt, tab->in_slew, c1, pocv_enabled_, d1, s1);
|
|
||||||
tlohi = slew_derate*delayAsFloat(s1);
|
tlohi = slew_derate*delayAsFloat(s1);
|
||||||
r = tlohi/(c_log*c1);
|
r = tlohi/(c_log*c1);
|
||||||
if (rdelay>0.0 && r > rdelay)
|
if (rdelay>0.0 && r > rdelay)
|
||||||
|
|
@ -1346,9 +1343,8 @@ ArnoldiDelayCalc::ra_get_s(delay_work *D,
|
||||||
double c_log = con->vlg;
|
double c_log = con->vlg;
|
||||||
double c_smin = con->smin;
|
double c_smin = con->smin;
|
||||||
double tlohi,smin,s;
|
double tlohi,smin,s;
|
||||||
ArcDelay d1;
|
float d1, s1;
|
||||||
Slew s1;
|
tab->table->gateDelay(tab->pvt, tab->in_slew, c, d1, s1);
|
||||||
tab->table->gateDelay(tab->pvt, tab->in_slew, c, pocv_enabled_, d1, s1);
|
|
||||||
tlohi = slew_derate*delayAsFloat(s1);
|
tlohi = slew_derate*delayAsFloat(s1);
|
||||||
smin = r*c*c_smin; // c_smin = ra_hinv((1-vhi)/vhi-log(vhi)) + log(vhi);
|
smin = r*c*c_smin; // c_smin = ra_hinv((1-vhi)/vhi-log(vhi)) + log(vhi);
|
||||||
if (c_log*r*c >= tlohi) {
|
if (c_log*r*c >= tlohi) {
|
||||||
|
|
@ -1378,10 +1374,9 @@ ArnoldiDelayCalc::ra_rdelay_1(timing_table *tab,
|
||||||
float c2 = 0.5*c1;
|
float c2 = 0.5*c1;
|
||||||
if (c1==c2)
|
if (c1==c2)
|
||||||
return 0.0;
|
return 0.0;
|
||||||
ArcDelay d1, d2;
|
float d1, d2, s1, s2;
|
||||||
Slew s1, s2;
|
tab->table->gateDelay(tab->pvt, tab->in_slew, c1, d1, s1);
|
||||||
tab->table->gateDelay(tab->pvt, tab->in_slew, c1, pocv_enabled_, d1, s1);
|
tab->table->gateDelay(tab->pvt, tab->in_slew, c2, d2, s2);
|
||||||
tab->table->gateDelay(tab->pvt, tab->in_slew, c2, pocv_enabled_, d2, s2);
|
|
||||||
double dt50 = delayAsFloat(d1)-delayAsFloat(d2);
|
double dt50 = delayAsFloat(d1)-delayAsFloat(d2);
|
||||||
if (dt50 <= 0.0)
|
if (dt50 <= 0.0)
|
||||||
return 0.0;
|
return 0.0;
|
||||||
|
|
@ -1402,8 +1397,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
|
||||||
double vlo = con->vlo;
|
double vlo = con->vlo;
|
||||||
double ctot = mod->ctot;
|
double ctot = mod->ctot;
|
||||||
double ceff,tlohi,t50_sy,r,s,t50_sr,rdelay;
|
double ceff,tlohi,t50_sy,r,s,t50_sr,rdelay;
|
||||||
ArcDelay df;
|
float df, sf;
|
||||||
Slew sf;
|
|
||||||
|
|
||||||
debugPrint(debug_, "arnoldi", 1, "ctot=%s",
|
debugPrint(debug_, "arnoldi", 1, "ctot=%s",
|
||||||
units_->capacitanceUnit()->asString(ctot));
|
units_->capacitanceUnit()->asString(ctot));
|
||||||
|
|
@ -1432,7 +1426,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
|
||||||
units_->timeUnit()->asString(s));
|
units_->timeUnit()->asString(s));
|
||||||
thix = ra_solve_for_t(p,s,vhi);
|
thix = ra_solve_for_t(p,s,vhi);
|
||||||
tlox = ra_solve_for_t(p,s,vlo);
|
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",
|
debugPrint(debug_, "arnoldi", 1, "table slew (in_slew %s ctot %s) = %s",
|
||||||
units_->timeUnit()->asString(tab->in_slew),
|
units_->timeUnit()->asString(tab->in_slew),
|
||||||
units_->capacitanceUnit()->asString(ctot),
|
units_->capacitanceUnit()->asString(ctot),
|
||||||
|
|
@ -1443,8 +1437,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
|
||||||
units_->timeUnit()->asString(tlox-thix));
|
units_->timeUnit()->asString(tlox-thix));
|
||||||
}
|
}
|
||||||
ceff = ctot;
|
ceff = ctot;
|
||||||
tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, pocv_enabled_,
|
tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, df, sf);
|
||||||
df, sf);
|
|
||||||
t50_sy = delayAsFloat(df);
|
t50_sy = delayAsFloat(df);
|
||||||
t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5);
|
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_->timeUnit()->asString(ceff_time),
|
||||||
units_->capacitanceUnit()->asString(ceff));
|
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_sy = delayAsFloat(df);
|
||||||
t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5);
|
t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5);
|
||||||
for (j=0;j<mod->n;j++) {
|
for (j=0;j<mod->n;j++) {
|
||||||
|
|
|
||||||
|
|
@ -113,14 +113,12 @@ CcsCeffDelayCalc::gateDelay(const Pin *drvr_pin,
|
||||||
vh_ = drvr_library->slewUpperThreshold(drvr_rf_) * vdd_;
|
vh_ = drvr_library->slewUpperThreshold(drvr_rf_) * vdd_;
|
||||||
|
|
||||||
drvr_cell->ensureVoltageWaveforms(scenes_);
|
drvr_cell->ensureVoltageWaveforms(scenes_);
|
||||||
in_slew_ = delayAsFloat(in_slew);
|
|
||||||
output_waveforms_ = output_waveforms;
|
output_waveforms_ = output_waveforms;
|
||||||
ref_time_ = output_waveforms_->referenceTime(in_slew_);
|
ref_time_ = output_waveforms_->referenceTime(in_slew_);
|
||||||
debugPrint(debug_, "ccs_dcalc", 1, "%s %s",
|
debugPrint(debug_, "ccs_dcalc", 1, "%s %s",
|
||||||
drvr_cell->name(),
|
drvr_cell->name(),
|
||||||
drvr_rf_->shortName());
|
drvr_rf_->shortName());
|
||||||
ArcDelay gate_delay;
|
double gate_delay, drvr_slew;
|
||||||
Slew drvr_slew;
|
|
||||||
gateDelaySlew(drvr_library, drvr_rf_, 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);
|
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,
|
CcsCeffDelayCalc::gateDelaySlew(const LibertyLibrary *drvr_library,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
// Return values.
|
// Return values.
|
||||||
ArcDelay &gate_delay,
|
double &gate_delay,
|
||||||
Slew &drvr_slew)
|
double &drvr_slew)
|
||||||
{
|
{
|
||||||
initRegions(drvr_library, rf);
|
initRegions(drvr_library, rf);
|
||||||
findCsmWaveform();
|
findCsmWaveform();
|
||||||
|
|
@ -145,7 +143,7 @@ CcsCeffDelayCalc::gateDelaySlew(const LibertyLibrary *drvr_library,
|
||||||
"gate_delay %s drvr_slew %s (initial)",
|
"gate_delay %s drvr_slew %s (initial)",
|
||||||
delayAsString(gate_delay, this),
|
delayAsString(gate_delay, this),
|
||||||
delayAsString(drvr_slew, this));
|
delayAsString(drvr_slew, this));
|
||||||
float prev_drvr_slew = delayAsFloat(drvr_slew);
|
float prev_drvr_slew = drvr_slew;
|
||||||
constexpr int max_iterations = 5;
|
constexpr int max_iterations = 5;
|
||||||
for (int iter = 0; iter < max_iterations; iter++) {
|
for (int iter = 0; iter < max_iterations; iter++) {
|
||||||
debugPrint(debug_, "ccs_dcalc", 2, "iteration %d", 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",
|
"gate_delay %s drvr_slew %s",
|
||||||
delayAsString(gate_delay, this),
|
delayAsString(gate_delay, this),
|
||||||
delayAsString(drvr_slew, 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;
|
break;
|
||||||
prev_drvr_slew = delayAsFloat(drvr_slew);
|
prev_drvr_slew = drvr_slew;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -309,8 +307,8 @@ CcsCeffDelayCalc::findCsmWaveform()
|
||||||
ArcDcalcResult
|
ArcDcalcResult
|
||||||
CcsCeffDelayCalc::makeResult(const LibertyLibrary *drvr_library,
|
CcsCeffDelayCalc::makeResult(const LibertyLibrary *drvr_library,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
ArcDelay &gate_delay,
|
double &gate_delay,
|
||||||
Slew &drvr_slew,
|
double &drvr_slew,
|
||||||
const LoadPinIndexMap &load_pin_index_map)
|
const LoadPinIndexMap &load_pin_index_map)
|
||||||
{
|
{
|
||||||
ArcDcalcResult dcalc_result(load_pin_index_map.size());
|
ArcDcalcResult dcalc_result(load_pin_index_map.size());
|
||||||
|
|
@ -322,8 +320,7 @@ CcsCeffDelayCalc::makeResult(const LibertyLibrary *drvr_library,
|
||||||
dcalc_result.setDrvrSlew(drvr_slew);
|
dcalc_result.setDrvrSlew(drvr_slew);
|
||||||
|
|
||||||
for (const auto &[load_pin, load_idx] : load_pin_index_map) {
|
for (const auto &[load_pin, load_idx] : load_pin_index_map) {
|
||||||
ArcDelay wire_delay;
|
double wire_delay, load_slew;
|
||||||
Slew load_slew;
|
|
||||||
loadDelaySlew(load_pin, drvr_library, rf, drvr_slew, 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.setWireDelay(load_idx, wire_delay);
|
||||||
dcalc_result.setLoadSlew(load_idx, load_slew);
|
dcalc_result.setLoadSlew(load_idx, load_slew);
|
||||||
|
|
@ -335,13 +332,14 @@ void
|
||||||
CcsCeffDelayCalc::loadDelaySlew(const Pin *load_pin,
|
CcsCeffDelayCalc::loadDelaySlew(const Pin *load_pin,
|
||||||
const LibertyLibrary *drvr_library,
|
const LibertyLibrary *drvr_library,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
Slew &drvr_slew,
|
double &drvr_slew,
|
||||||
// Return values.
|
// Return values.
|
||||||
ArcDelay &wire_delay,
|
double &wire_delay,
|
||||||
Slew &load_slew)
|
double &load_slew)
|
||||||
{
|
{
|
||||||
wire_delay = 0.0;
|
wire_delay = 0.0;
|
||||||
load_slew = drvr_slew;
|
load_slew = drvr_slew;
|
||||||
|
|
||||||
bool elmore_exists = false;
|
bool elmore_exists = false;
|
||||||
float elmore = 0.0;
|
float elmore = 0.0;
|
||||||
if (parasitic_
|
if (parasitic_
|
||||||
|
|
@ -351,7 +349,7 @@ CcsCeffDelayCalc::loadDelaySlew(const Pin *load_pin,
|
||||||
if (elmore_exists &&
|
if (elmore_exists &&
|
||||||
(elmore == 0.0
|
(elmore == 0.0
|
||||||
// Elmore delay is small compared to driver slew.
|
// Elmore delay is small compared to driver slew.
|
||||||
|| elmore < delayAsFloat(drvr_slew) * 1e-3)) {
|
|| elmore < drvr_slew * 1e-3)) {
|
||||||
wire_delay = elmore;
|
wire_delay = elmore;
|
||||||
load_slew = drvr_slew;
|
load_slew = drvr_slew;
|
||||||
}
|
}
|
||||||
|
|
@ -363,11 +361,11 @@ CcsCeffDelayCalc::loadDelaySlew(const Pin *load_pin,
|
||||||
|
|
||||||
void
|
void
|
||||||
CcsCeffDelayCalc::loadDelaySlew(const Pin *load_pin,
|
CcsCeffDelayCalc::loadDelaySlew(const Pin *load_pin,
|
||||||
Slew &drvr_slew,
|
double &drvr_slew,
|
||||||
float elmore,
|
float elmore,
|
||||||
// Return values.
|
// Return values.
|
||||||
ArcDelay &delay,
|
double &delay,
|
||||||
Slew &slew)
|
double &slew)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i <= region_count_; i++) {
|
for (size_t i = 0; i <= region_count_; i++) {
|
||||||
region_ramp_times_[i] = region_times_[i];
|
region_ramp_times_[i] = region_times_[i];
|
||||||
|
|
|
||||||
|
|
@ -73,29 +73,29 @@ protected:
|
||||||
void gateDelaySlew(const LibertyLibrary *drvr_library,
|
void gateDelaySlew(const LibertyLibrary *drvr_library,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
// Return values.
|
// Return values.
|
||||||
ArcDelay &gate_delay,
|
double &gate_delay,
|
||||||
Slew &drvr_slew);
|
double &drvr_slew);
|
||||||
void initRegions(const LibertyLibrary *drvr_library,
|
void initRegions(const LibertyLibrary *drvr_library,
|
||||||
const RiseFall *rf);
|
const RiseFall *rf);
|
||||||
void findCsmWaveform();
|
void findCsmWaveform();
|
||||||
ArcDcalcResult makeResult(const LibertyLibrary *drvr_library,
|
ArcDcalcResult makeResult(const LibertyLibrary *drvr_library,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
ArcDelay &gate_delay,
|
double &gate_delay,
|
||||||
Slew &drvr_slew,
|
double &drvr_slew,
|
||||||
const LoadPinIndexMap &load_pin_index_map);
|
const LoadPinIndexMap &load_pin_index_map);
|
||||||
void loadDelaySlew(const Pin *load_pin,
|
void loadDelaySlew(const Pin *load_pin,
|
||||||
const LibertyLibrary *drvr_library,
|
const LibertyLibrary *drvr_library,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
Slew &drvr_slew,
|
double &drvr_slew,
|
||||||
// Return values.
|
// Return values.
|
||||||
ArcDelay &wire_delay,
|
double &wire_delay,
|
||||||
Slew &load_slew);
|
double &load_slew);
|
||||||
void loadDelaySlew(const Pin *load_pin,
|
void loadDelaySlew(const Pin *load_pin,
|
||||||
Slew &drvr_slew,
|
double &drvr_slew,
|
||||||
float elmore,
|
float elmore,
|
||||||
// Return values.
|
// Return values.
|
||||||
ArcDelay &delay,
|
double &delay,
|
||||||
Slew &slew);
|
double &slew);
|
||||||
double findVlTime(double v,
|
double findVlTime(double v,
|
||||||
double elmore);
|
double elmore);
|
||||||
bool makeWaveformPreamble(const Pin *in_pin,
|
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" \
|
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 } {
|
proc report_slews { args } {
|
||||||
global sta_report_default_digits
|
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
|
check_argc_eq1 "report_slews" $args
|
||||||
|
|
||||||
set scenes [parse_scenes_or_all keys]
|
set scenes [parse_scenes_or_all keys]
|
||||||
set pin [get_port_pin_error "pin" [lindex $args 0]]
|
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] {
|
foreach vertex [$pin vertices] {
|
||||||
set rise_min [format_time [$vertex slew_scenes rise $scenes min] $digits]
|
set rise_min [$vertex slew_scenes_string rise $scenes min $report_variance $digits]
|
||||||
set rise_max [format_time [$vertex slew_scenes rise $scenes max] $digits]
|
set rise_max [$vertex slew_scenes_string rise $scenes max $report_variance $digits]
|
||||||
set fall_min [format_time [$vertex slew_scenes fall $scenes min] $digits]
|
set fall_min [$vertex slew_scenes_string fall $scenes min $report_variance $digits]
|
||||||
set fall_max [format_time [$vertex slew_scenes fall $scenes max] $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"
|
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
|
void
|
||||||
DelayCalcBase::dspfWireDelaySlew(const Pin *load_pin,
|
DelayCalcBase::dspfWireDelaySlew(const Pin *load_pin,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
Slew drvr_slew,
|
double drvr_slew,
|
||||||
float elmore,
|
float elmore,
|
||||||
ArcDelay &wire_delay,
|
double &wire_delay,
|
||||||
Slew &load_slew)
|
double &load_slew)
|
||||||
{
|
{
|
||||||
|
|
||||||
LibertyLibrary *load_library = thresholdLibrary(load_pin);
|
LibertyLibrary *load_library = thresholdLibrary(load_pin);
|
||||||
|
|
@ -107,8 +107,8 @@ void
|
||||||
DelayCalcBase::thresholdAdjust(const Pin *load_pin,
|
DelayCalcBase::thresholdAdjust(const Pin *load_pin,
|
||||||
const LibertyLibrary *drvr_library,
|
const LibertyLibrary *drvr_library,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
ArcDelay &load_delay,
|
double &wire_delay,
|
||||||
Slew &load_slew)
|
double &load_slew)
|
||||||
{
|
{
|
||||||
LibertyLibrary *load_library = thresholdLibrary(load_pin);
|
LibertyLibrary *load_library = thresholdLibrary(load_pin);
|
||||||
if (load_library
|
if (load_library
|
||||||
|
|
@ -118,11 +118,11 @@ DelayCalcBase::thresholdAdjust(const Pin *load_pin,
|
||||||
float load_vth = load_library->inputThreshold(rf);
|
float load_vth = load_library->inputThreshold(rf);
|
||||||
float drvr_slew_delta = drvr_library->slewUpperThreshold(rf)
|
float drvr_slew_delta = drvr_library->slewUpperThreshold(rf)
|
||||||
- drvr_library->slewLowerThreshold(rf);
|
- drvr_library->slewLowerThreshold(rf);
|
||||||
float load_delay_delta =
|
float wire_delay_delta =
|
||||||
delayAsFloat(load_slew) * ((load_vth - drvr_vth) / drvr_slew_delta);
|
delayAsFloat(load_slew) * ((load_vth - drvr_vth) / drvr_slew_delta);
|
||||||
load_delay += (rf == RiseFall::rise())
|
wire_delay += (rf == RiseFall::rise())
|
||||||
? load_delay_delta
|
? wire_delay_delta
|
||||||
: -load_delay_delta;
|
: -wire_delay_delta;
|
||||||
float load_slew_delta = load_library->slewUpperThreshold(rf)
|
float load_slew_delta = load_library->slewUpperThreshold(rf)
|
||||||
- load_library->slewLowerThreshold(rf);
|
- load_library->slewLowerThreshold(rf);
|
||||||
float drvr_slew_derate = drvr_library->slewDerateFromLibrary();
|
float drvr_slew_derate = drvr_library->slewDerateFromLibrary();
|
||||||
|
|
@ -162,9 +162,8 @@ DelayCalcBase::checkDelay(const Pin *check_pin,
|
||||||
float from_slew1 = delayAsFloat(from_slew);
|
float from_slew1 = delayAsFloat(from_slew);
|
||||||
float to_slew1 = delayAsFloat(to_slew);
|
float to_slew1 = delayAsFloat(to_slew);
|
||||||
return model->checkDelay(pinPvt(check_pin, scene, min_max),
|
return model->checkDelay(pinPvt(check_pin, scene, min_max),
|
||||||
from_slew1, to_slew1,
|
from_slew1, to_slew1, related_out_cap,
|
||||||
related_out_cap,
|
min_max, variables_->pocvMode());
|
||||||
variables_->pocvEnabled());
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return delay_zero;
|
return delay_zero;
|
||||||
|
|
@ -187,8 +186,8 @@ DelayCalcBase::reportCheckDelay(const Pin *check_pin,
|
||||||
float to_slew1 = delayAsFloat(to_slew);
|
float to_slew1 = delayAsFloat(to_slew);
|
||||||
return model->reportCheckDelay(pinPvt(check_pin, scene, min_max),
|
return model->reportCheckDelay(pinPvt(check_pin, scene, min_max),
|
||||||
from_slew1, from_slew_annotation,
|
from_slew1, from_slew_annotation,
|
||||||
to_slew1, related_out_cap, false,
|
to_slew1, related_out_cap, min_max,
|
||||||
digits);
|
PocvMode::scalar, digits);
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,16 +72,16 @@ protected:
|
||||||
void thresholdAdjust(const Pin *load_pin,
|
void thresholdAdjust(const Pin *load_pin,
|
||||||
const LibertyLibrary *drvr_library,
|
const LibertyLibrary *drvr_library,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
ArcDelay &load_delay,
|
double &load_delay,
|
||||||
Slew &load_slew);
|
double &load_slew);
|
||||||
// Helper function for input ports driving dspf parasitic.
|
// Helper function for input ports driving dspf parasitic.
|
||||||
void dspfWireDelaySlew(const Pin *load_pin,
|
void dspfWireDelaySlew(const Pin *load_pin,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
Slew drvr_slew,
|
double drvr_slew,
|
||||||
float elmore,
|
float elmore,
|
||||||
// Return values.
|
// Return values.
|
||||||
ArcDelay &wire_delay,
|
double &wire_delay,
|
||||||
Slew &load_slew);
|
double &load_slew);
|
||||||
const Pvt *pinPvt(const Pin *pin,
|
const Pvt *pinPvt(const Pin *pin,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
const MinMax *min_max);
|
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 in_slew,
|
||||||
double c2,
|
double c2,
|
||||||
double c1,
|
double c1,
|
||||||
const Pvt *pvt,
|
const Pvt *pvt);
|
||||||
bool pocv_enabled);
|
|
||||||
static void
|
static void
|
||||||
newtonRaphson(const int max_iter,
|
newtonRaphson(const int max_iter,
|
||||||
double x[],
|
double x[],
|
||||||
|
|
@ -143,8 +142,8 @@ public:
|
||||||
virtual void loadDelaySlew(const Pin *load_pin,
|
virtual void loadDelaySlew(const Pin *load_pin,
|
||||||
double elmore,
|
double elmore,
|
||||||
// Return values.
|
// Return values.
|
||||||
ArcDelay &delay,
|
double &delay,
|
||||||
Slew &slew);
|
double &slew);
|
||||||
double ceff() { return ceff_; }
|
double ceff() { return ceff_; }
|
||||||
|
|
||||||
// Given x_ as a vector of input parameters, fill fvec_ with the
|
// Given x_ as a vector of input parameters, fill fvec_ with the
|
||||||
|
|
@ -348,13 +347,10 @@ DmpAlg::gateCapDelaySlew(double ceff,
|
||||||
double &delay,
|
double &delay,
|
||||||
double &slew)
|
double &slew)
|
||||||
{
|
{
|
||||||
ArcDelay model_delay;
|
float model_delay, model_slew;
|
||||||
Slew model_slew;
|
gate_model_->gateDelay(pvt_, in_slew_, ceff, model_delay, model_slew);
|
||||||
gate_model_->gateDelay(pvt_, in_slew_, ceff,
|
delay = model_delay;
|
||||||
variables_->pocvEnabled(),
|
slew = model_slew;
|
||||||
model_delay, model_slew);
|
|
||||||
delay = delayAsFloat(model_delay);
|
|
||||||
slew = delayAsFloat(model_slew);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -543,8 +539,8 @@ DmpAlg::showVo()
|
||||||
void
|
void
|
||||||
DmpAlg::loadDelaySlew(const Pin *,
|
DmpAlg::loadDelaySlew(const Pin *,
|
||||||
double elmore,
|
double elmore,
|
||||||
ArcDelay &delay,
|
double &delay,
|
||||||
Slew &slew)
|
double &slew)
|
||||||
{
|
{
|
||||||
if (!driver_valid_
|
if (!driver_valid_
|
||||||
|| elmore == 0.0
|
|| elmore == 0.0
|
||||||
|
|
@ -700,8 +696,8 @@ public:
|
||||||
void loadDelaySlew(const Pin *,
|
void loadDelaySlew(const Pin *,
|
||||||
double elmore,
|
double elmore,
|
||||||
// Return values.
|
// Return values.
|
||||||
ArcDelay &delay,
|
double &delay,
|
||||||
Slew &slew) override;
|
double &slew) override;
|
||||||
void evalDmpEqns() override;
|
void evalDmpEqns() override;
|
||||||
double voCrossingUpperBound() override;
|
double voCrossingUpperBound() override;
|
||||||
|
|
||||||
|
|
@ -753,8 +749,8 @@ DmpCap::gateDelaySlew(// Return values.
|
||||||
void
|
void
|
||||||
DmpCap::loadDelaySlew(const Pin *,
|
DmpCap::loadDelaySlew(const Pin *,
|
||||||
double elmore,
|
double elmore,
|
||||||
ArcDelay &delay,
|
double &delay,
|
||||||
Slew &slew)
|
double &slew)
|
||||||
{
|
{
|
||||||
delay = elmore;
|
delay = elmore;
|
||||||
slew = drvr_slew_;
|
slew = drvr_slew_;
|
||||||
|
|
@ -1498,21 +1494,36 @@ DmpCeffDelayCalc::gateDelay(const Pin *drvr_pin,
|
||||||
parasitics_->piModel(parasitic, c2, rpi, c1);
|
parasitics_->piModel(parasitic, c2, rpi, c1);
|
||||||
if (std::isnan(c2) || std::isnan(c1) || std::isnan(rpi))
|
if (std::isnan(c2) || std::isnan(c1) || std::isnan(rpi))
|
||||||
report_->error(1040, "parasitic Pi model has NaNs.");
|
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);
|
table_model, rf, in_slew1, c2, rpi, c1);
|
||||||
double gate_delay, drvr_slew;
|
double gate_delay, drvr_slew;
|
||||||
gateDelaySlew(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());
|
ArcDcalcResult dcalc_result(load_pin_index_map.size());
|
||||||
dcalc_result.setGateDelay(gate_delay);
|
dcalc_result.setGateDelay(gate_delay2);
|
||||||
dcalc_result.setDrvrSlew(drvr_slew);
|
dcalc_result.setDrvrSlew(drvr_slew2);
|
||||||
|
|
||||||
for (const auto &[load_pin, load_idx] : load_pin_index_map) {
|
for (const auto &[load_pin, load_idx] : load_pin_index_map) {
|
||||||
ArcDelay wire_delay;
|
double wire_delay;
|
||||||
Slew load_slew;
|
double load_slew;
|
||||||
loadDelaySlew(load_pin, drvr_slew, rf, drvr_library, parasitic,
|
loadDelaySlew(load_pin, drvr_slew, rf, drvr_library, parasitic,
|
||||||
wire_delay, load_slew);
|
wire_delay, load_slew);
|
||||||
dcalc_result.setWireDelay(load_idx, wire_delay);
|
// Copy pocv params from driver.
|
||||||
dcalc_result.setLoadSlew(load_idx, load_slew);
|
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;
|
return dcalc_result;
|
||||||
}
|
}
|
||||||
|
|
@ -1543,8 +1554,7 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library,
|
||||||
{
|
{
|
||||||
double rd = 0.0;
|
double rd = 0.0;
|
||||||
if (gate_model) {
|
if (gate_model) {
|
||||||
rd = gateModelRd(drvr_cell, gate_model, rf, in_slew, c2, c1,
|
rd = gateModelRd(drvr_cell, gate_model, rf, in_slew, c2, c1, pvt);
|
||||||
pvt, variables_->pocvEnabled());
|
|
||||||
// Zero Rd means the table is constant and thus independent of load cap.
|
// Zero Rd means the table is constant and thus independent of load cap.
|
||||||
if (rd < 1e-2
|
if (rd < 1e-2
|
||||||
// Rpi is small compared to Rd, which makes the load capacitive.
|
// Rpi is small compared to Rd, which makes the load capacitive.
|
||||||
|
|
@ -1612,14 +1622,12 @@ DmpCeffDelayCalc::reportGateDelay(const Pin *drvr_pin,
|
||||||
else
|
else
|
||||||
c_eff = load_cap;
|
c_eff = load_cap;
|
||||||
if (model) {
|
if (model) {
|
||||||
const Unit *time_unit = units->timeUnit();
|
|
||||||
float in_slew1 = delayAsFloat(in_slew);
|
float in_slew1 = delayAsFloat(in_slew);
|
||||||
result += model->reportGateDelay(pinPvt(drvr_pin, scene, min_max),
|
result += model->reportGateDelay(pinPvt(drvr_pin, scene, min_max),
|
||||||
in_slew1, c_eff,
|
in_slew1, c_eff, min_max,
|
||||||
variables_->pocvEnabled(), digits);
|
variables_->pocvMode(), digits);
|
||||||
result += "Driver waveform slew = ";
|
result += "Driver waveform slew = ";
|
||||||
float drvr_slew = delayAsFloat(dcalc_result.drvrSlew());
|
result += delayAsString(dcalc_result.drvrSlew(), min_max, digits, this);
|
||||||
result += time_unit->asString(drvr_slew, digits);
|
|
||||||
result += '\n';
|
result += '\n';
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -1632,18 +1640,15 @@ gateModelRd(const LibertyCell *cell,
|
||||||
double in_slew,
|
double in_slew,
|
||||||
double c2,
|
double c2,
|
||||||
double c1,
|
double c1,
|
||||||
const Pvt *pvt,
|
const Pvt *pvt)
|
||||||
bool pocv_enabled)
|
|
||||||
{
|
{
|
||||||
float cap1 = c1 + c2;
|
float cap1 = c1 + c2;
|
||||||
float cap2 = cap1 + 1e-15;
|
float cap2 = cap1 + 1e-15;
|
||||||
ArcDelay d1, d2;
|
float d1, d2, s1, s2;
|
||||||
Slew s1, s2;
|
gate_model->gateDelay(pvt, in_slew, cap1, d1, s1);
|
||||||
gate_model->gateDelay(pvt, in_slew, cap1, pocv_enabled, d1, s1);
|
gate_model->gateDelay(pvt, in_slew, cap2, d2, s2);
|
||||||
gate_model->gateDelay(pvt, in_slew, cap2, pocv_enabled, d2, s2);
|
|
||||||
double vth = cell->libertyLibrary()->outputThreshold(rf);
|
double vth = cell->libertyLibrary()->outputThreshold(rf);
|
||||||
float rd = -std::log(vth) * std::abs(delayAsFloat(d1) - delayAsFloat(d2))
|
float rd = -std::log(vth) * std::abs(d1 - d2) / (cap2 - cap1);
|
||||||
/ (cap2 - cap1);
|
|
||||||
return rd;
|
return rd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1658,8 +1663,8 @@ DmpCeffDelayCalc::gateDelaySlew(// Return values.
|
||||||
void
|
void
|
||||||
DmpCeffDelayCalc::loadDelaySlewElmore(const Pin *load_pin,
|
DmpCeffDelayCalc::loadDelaySlewElmore(const Pin *load_pin,
|
||||||
double elmore,
|
double elmore,
|
||||||
ArcDelay &delay,
|
double &delay,
|
||||||
Slew &slew)
|
double &slew)
|
||||||
{
|
{
|
||||||
if (dmp_alg_)
|
if (dmp_alg_)
|
||||||
dmp_alg_->loadDelaySlew(load_pin, elmore, delay, slew);
|
dmp_alg_->loadDelaySlew(load_pin, elmore, delay, slew);
|
||||||
|
|
|
||||||
|
|
@ -69,15 +69,15 @@ protected:
|
||||||
const LibertyLibrary *drvr_library,
|
const LibertyLibrary *drvr_library,
|
||||||
const Parasitic *parasitic,
|
const Parasitic *parasitic,
|
||||||
// Return values.
|
// Return values.
|
||||||
ArcDelay &wire_delay,
|
double &wire_delay,
|
||||||
Slew &load_slew) = 0;
|
double &load_slew) = 0;
|
||||||
void gateDelaySlew(// Return values.
|
void gateDelaySlew(// Return values.
|
||||||
double &delay,
|
double &delay,
|
||||||
double &slew);
|
double &slew);
|
||||||
void loadDelaySlewElmore(const Pin *load_pin,
|
void loadDelaySlewElmore(const Pin *load_pin,
|
||||||
double elmore,
|
double elmore,
|
||||||
ArcDelay &delay,
|
double &delay,
|
||||||
Slew &slew);
|
double &slew);
|
||||||
// Select the appropriate special case Dartu/Menezes/Pileggi algorithm.
|
// Select the appropriate special case Dartu/Menezes/Pileggi algorithm.
|
||||||
void setCeffAlgorithm(const LibertyLibrary *library,
|
void setCeffAlgorithm(const LibertyLibrary *library,
|
||||||
const LibertyCell *cell,
|
const LibertyCell *cell,
|
||||||
|
|
|
||||||
|
|
@ -59,8 +59,8 @@ protected:
|
||||||
const LibertyLibrary *drvr_library,
|
const LibertyLibrary *drvr_library,
|
||||||
const Parasitic *parasitic,
|
const Parasitic *parasitic,
|
||||||
// Return values.
|
// Return values.
|
||||||
ArcDelay &wire_delay,
|
double &wire_delay,
|
||||||
Slew &load_slew) override;
|
double &load_slew) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
ArcDelayCalc *
|
ArcDelayCalc *
|
||||||
|
|
@ -93,8 +93,8 @@ DmpCeffElmoreDelayCalc::inputPortDelay(const Pin *,
|
||||||
ArcDcalcResult dcalc_result(load_pin_index_map.size());
|
ArcDcalcResult dcalc_result(load_pin_index_map.size());
|
||||||
LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
|
LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
|
||||||
for (auto [load_pin, load_idx] : load_pin_index_map) {
|
for (auto [load_pin, load_idx] : load_pin_index_map) {
|
||||||
ArcDelay wire_delay = 0.0;
|
double wire_delay = 0.0;
|
||||||
Slew load_slew = in_slew;
|
double load_slew = in_slew;
|
||||||
bool elmore_exists = false;
|
bool elmore_exists = false;
|
||||||
float elmore = 0.0;
|
float elmore = 0.0;
|
||||||
if (parasitic)
|
if (parasitic)
|
||||||
|
|
@ -116,8 +116,8 @@ DmpCeffElmoreDelayCalc::loadDelaySlew(const Pin *load_pin,
|
||||||
const LibertyLibrary *drvr_library,
|
const LibertyLibrary *drvr_library,
|
||||||
const Parasitic *parasitic,
|
const Parasitic *parasitic,
|
||||||
// Return values.
|
// Return values.
|
||||||
ArcDelay &wire_delay,
|
double &wire_delay,
|
||||||
Slew &load_slew)
|
double &load_slew)
|
||||||
{
|
{
|
||||||
wire_delay = 0.0;
|
wire_delay = 0.0;
|
||||||
load_slew = drvr_slew;
|
load_slew = drvr_slew;
|
||||||
|
|
@ -143,14 +143,14 @@ public:
|
||||||
Parasitic *findParasitic(const Pin *drvr_pin,
|
Parasitic *findParasitic(const Pin *drvr_pin,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
const MinMax *min_max) override;
|
const MinMax *min_max) override;
|
||||||
ArcDcalcResult inputPortDelay(const Pin *port_pin,
|
ArcDcalcResult inputPortDelay(const Pin *port_pin,
|
||||||
float in_slew,
|
float in_slew,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
const Parasitic *parasitic,
|
const Parasitic *parasitic,
|
||||||
const LoadPinIndexMap &load_pin_index_map,
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
const MinMax *min_max) override;
|
const MinMax *min_max) override;
|
||||||
ArcDcalcResult gateDelay(const Pin *drvr_pin,
|
ArcDcalcResult gateDelay(const Pin *drvr_pin,
|
||||||
const TimingArc *arc,
|
const TimingArc *arc,
|
||||||
const Slew &in_slew,
|
const Slew &in_slew,
|
||||||
|
|
@ -158,7 +158,7 @@ public:
|
||||||
const Parasitic *parasitic,
|
const Parasitic *parasitic,
|
||||||
const LoadPinIndexMap &load_pin_index_map,
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
const MinMax *min_max) override;
|
const MinMax *min_max) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void loadDelaySlew(const Pin *load_pin,
|
void loadDelaySlew(const Pin *load_pin,
|
||||||
|
|
@ -167,14 +167,14 @@ private:
|
||||||
const LibertyLibrary *drvr_library,
|
const LibertyLibrary *drvr_library,
|
||||||
const Parasitic *parasitic,
|
const Parasitic *parasitic,
|
||||||
// Return values.
|
// Return values.
|
||||||
ArcDelay &wire_delay,
|
double &wire_delay,
|
||||||
Slew &load_slew) override;
|
double &load_slew) override;
|
||||||
void loadDelay(double drvr_slew,
|
void loadDelay(double drvr_slew,
|
||||||
Parasitic *pole_residue,
|
Parasitic *pole_residue,
|
||||||
double p1,
|
double p1,
|
||||||
double k1,
|
double k1,
|
||||||
ArcDelay &wire_delay,
|
double &wire_delay,
|
||||||
Slew &load_slew);
|
double &load_slew);
|
||||||
float loadDelay(double vth,
|
float loadDelay(double vth,
|
||||||
double p1,
|
double p1,
|
||||||
double p2,
|
double p2,
|
||||||
|
|
@ -267,8 +267,8 @@ DmpCeffTwoPoleDelayCalc::inputPortDelay(const Pin *,
|
||||||
{
|
{
|
||||||
const Parasitics *parasitics = scene->parasitics(min_max);
|
const Parasitics *parasitics = scene->parasitics(min_max);
|
||||||
ArcDcalcResult dcalc_result(load_pin_index_map.size());
|
ArcDcalcResult dcalc_result(load_pin_index_map.size());
|
||||||
ArcDelay wire_delay = 0.0;
|
double wire_delay = 0.0;
|
||||||
Slew load_slew = in_slew;
|
double load_slew = in_slew;
|
||||||
LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
|
LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
|
||||||
for (const auto [load_pin, load_idx] : load_pin_index_map) {
|
for (const auto [load_pin, load_idx] : load_pin_index_map) {
|
||||||
if (parasitics->isPiPoleResidue(parasitic)) {
|
if (parasitics->isPiPoleResidue(parasitic)) {
|
||||||
|
|
@ -323,8 +323,8 @@ DmpCeffTwoPoleDelayCalc::loadDelaySlew(const Pin *load_pin,
|
||||||
const LibertyLibrary *drvr_library,
|
const LibertyLibrary *drvr_library,
|
||||||
const Parasitic *parasitic,
|
const Parasitic *parasitic,
|
||||||
// Return values.
|
// Return values.
|
||||||
ArcDelay &wire_delay,
|
double &wire_delay,
|
||||||
Slew &load_slew)
|
double &load_slew)
|
||||||
{
|
{
|
||||||
parasitic_is_pole_residue_ = parasitics_->isPiPoleResidue(parasitic);
|
parasitic_is_pole_residue_ = parasitics_->isPiPoleResidue(parasitic);
|
||||||
// Should handle PiElmore parasitic.
|
// Should handle PiElmore parasitic.
|
||||||
|
|
@ -362,12 +362,12 @@ DmpCeffTwoPoleDelayCalc::loadDelay(double drvr_slew,
|
||||||
double p1,
|
double p1,
|
||||||
double k1,
|
double k1,
|
||||||
// Return values.
|
// Return values.
|
||||||
ArcDelay &wire_delay,
|
double &wire_delay,
|
||||||
Slew &load_slew)
|
double &load_slew)
|
||||||
{
|
{
|
||||||
ComplexFloat pole2, residue2;
|
ComplexFloat pole2, residue2;
|
||||||
parasitics_->poleResidue(pole_residue, 1, pole2, residue2);
|
parasitics_->poleResidue(pole_residue, 1, pole2, residue2);
|
||||||
if (!delayZero(drvr_slew)
|
if (!delayZero(drvr_slew, this)
|
||||||
&& pole2.imag() == 0.0
|
&& pole2.imag() == 0.0
|
||||||
&& residue2.imag() == 0.0) {
|
&& residue2.imag() == 0.0) {
|
||||||
double p2 = pole2.real();
|
double p2 = pole2.real();
|
||||||
|
|
|
||||||
|
|
@ -646,17 +646,17 @@ GraphDelayCalc::findInputArcDelay(const Pin *drvr_pin,
|
||||||
ArcDcalcResult intrinsic_result =
|
ArcDcalcResult intrinsic_result =
|
||||||
arc_delay_calc_->gateDelay(drvr_pin, arc, Slew(from_slew), 0.0, nullptr,
|
arc_delay_calc_->gateDelay(drvr_pin, arc, Slew(from_slew), 0.0, nullptr,
|
||||||
load_pin_index_map, scene, min_max);
|
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,
|
ArcDcalcResult gate_result = arc_delay_calc_->gateDelay(drvr_pin, arc,
|
||||||
Slew(from_slew), load_cap,
|
Slew(from_slew), load_cap,
|
||||||
parasitic,
|
parasitic,
|
||||||
load_pin_index_map,
|
load_pin_index_map,
|
||||||
scene, min_max);
|
scene, min_max);
|
||||||
ArcDelay gate_delay = gate_result.gateDelay();
|
const ArcDelay &gate_delay = gate_result.gateDelay();
|
||||||
Slew gate_slew = gate_result.drvrSlew();
|
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,
|
debugPrint(debug_, "delay_calc", 3,
|
||||||
" gate delay = %s intrinsic = %s slew = %s",
|
" gate delay = %s intrinsic = %s slew = %s",
|
||||||
delayAsString(gate_delay, this),
|
delayAsString(gate_delay, this),
|
||||||
|
|
@ -729,9 +729,8 @@ GraphDelayCalc::loadSlews(LoadPinIndexMap &load_pin_index_map)
|
||||||
Vertex *load_vertex = graph_->pinLoadVertex(pin);
|
Vertex *load_vertex = graph_->pinLoadVertex(pin);
|
||||||
SlewSeq &slews = load_slews[index];;
|
SlewSeq &slews = load_slews[index];;
|
||||||
slews.resize(slew_count);
|
slews.resize(slew_count);
|
||||||
Slew *vertex_slews = load_vertex->slews();
|
|
||||||
for (size_t i = 0; i < slew_count; i++)
|
for (size_t i = 0; i < slew_count; i++)
|
||||||
slews[i] = vertex_slews[i];
|
slews[i] = graph_->slew(load_vertex, i);
|
||||||
}
|
}
|
||||||
return load_slews;
|
return load_slews;
|
||||||
}
|
}
|
||||||
|
|
@ -744,9 +743,9 @@ GraphDelayCalc::loadSlewsChanged(DrvrLoadSlews &load_slews_prev,
|
||||||
for (auto const [pin, index] : load_pin_index_map) {
|
for (auto const [pin, index] : load_pin_index_map) {
|
||||||
Vertex *load_vertex = graph_->pinLoadVertex(pin);
|
Vertex *load_vertex = graph_->pinLoadVertex(pin);
|
||||||
SlewSeq &slews_prev = load_slews_prev[index];;
|
SlewSeq &slews_prev = load_slews_prev[index];;
|
||||||
const Slew *slews = load_vertex->slews();
|
|
||||||
for (size_t i = 0; i < slew_count; i++) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -915,19 +914,18 @@ GraphDelayCalc::initLoadSlews(Vertex *drvr_vertex)
|
||||||
Edge *wire_edge = edge_iter.next();
|
Edge *wire_edge = edge_iter.next();
|
||||||
if (wire_edge->isWire()) {
|
if (wire_edge->isWire()) {
|
||||||
Vertex *load_vertex = wire_edge->to(graph_);
|
Vertex *load_vertex = wire_edge->to(graph_);
|
||||||
|
|
||||||
for (Scene *scene : scenes_) {
|
for (Scene *scene : scenes_) {
|
||||||
for (const MinMax *min_max : MinMax::range()) {
|
for (const MinMax *min_max : MinMax::range()) {
|
||||||
DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max);
|
DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max);
|
||||||
Slew slew_init_value(min_max->initValue());
|
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))
|
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
|
bool
|
||||||
|
|
@ -965,12 +963,12 @@ GraphDelayCalc::initRootSlews(Vertex *vertex)
|
||||||
for (Scene *scene : scenes_) {
|
for (Scene *scene : scenes_) {
|
||||||
for (const MinMax *min_max : MinMax::range()) {
|
for (const MinMax *min_max : MinMax::range()) {
|
||||||
DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max);
|
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))
|
if (!vertex->slewAnnotated(rf, min_max))
|
||||||
graph_->setSlew(vertex, rf, ap_index, default_slew);
|
graph_->setSlew(vertex, rf, ap_index, default_slew);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -1195,8 +1193,8 @@ GraphDelayCalc::annotateDelaysSlews(Edge *edge,
|
||||||
bool
|
bool
|
||||||
GraphDelayCalc::annotateDelaySlew(Edge *edge,
|
GraphDelayCalc::annotateDelaySlew(Edge *edge,
|
||||||
const TimingArc *arc,
|
const TimingArc *arc,
|
||||||
ArcDelay &gate_delay,
|
const ArcDelay &gate_delay,
|
||||||
Slew &gate_slew,
|
const Slew &gate_slew,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
const MinMax *min_max)
|
const MinMax *min_max)
|
||||||
{
|
{
|
||||||
|
|
@ -1258,8 +1256,8 @@ GraphDelayCalc::annotateLoadDelays(Vertex *drvr_vertex,
|
||||||
Vertex *load_vertex = wire_edge->to(graph_);
|
Vertex *load_vertex = wire_edge->to(graph_);
|
||||||
Pin *load_pin = load_vertex->pin();
|
Pin *load_pin = load_vertex->pin();
|
||||||
size_t load_idx = load_pin_index_map[load_pin];
|
size_t load_idx = load_pin_index_map[load_pin];
|
||||||
ArcDelay wire_delay = dcalc_result.wireDelay(load_idx);
|
const ArcDelay &wire_delay = dcalc_result.wireDelay(load_idx);
|
||||||
Slew load_slew = dcalc_result.loadSlew(load_idx);
|
const Slew &load_slew = dcalc_result.loadSlew(load_idx);
|
||||||
debugPrint(debug_, "delay_calc", 3,
|
debugPrint(debug_, "delay_calc", 3,
|
||||||
" %s load delay = %s slew = %s",
|
" %s load delay = %s slew = %s",
|
||||||
load_vertex->to_string(this).c_str(),
|
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
|
// annotate the same wire edges so they must be combined
|
||||||
// rather than set.
|
// rather than set.
|
||||||
const ArcDelay &delay = graph_->wireArcDelay(wire_edge, drvr_rf, ap_index);
|
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
|
if (!merge
|
||||||
|| delayGreater(wire_delay_extra, delay, min_max, this)) {
|
|| delayGreater(wire_delay_extra, delay, min_max, this)) {
|
||||||
graph_->setWireArcDelay(wire_edge, drvr_rf, ap_index, wire_delay_extra);
|
graph_->setWireArcDelay(wire_edge, drvr_rf, ap_index, wire_delay_extra);
|
||||||
|
|
|
||||||
|
|
@ -118,7 +118,7 @@ LumpedCapDelayCalc::inputPortDelay(const Pin *,
|
||||||
const MinMax *)
|
const MinMax *)
|
||||||
{
|
{
|
||||||
const LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
|
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
|
ArcDcalcResult
|
||||||
|
|
@ -139,16 +139,22 @@ LumpedCapDelayCalc::gateDelay(const Pin *drvr_pin,
|
||||||
const RiseFall *rf = arc->toEdge()->asRiseFall();
|
const RiseFall *rf = arc->toEdge()->asRiseFall();
|
||||||
const LibertyLibrary *drvr_library = arc->to()->libertyLibrary();
|
const LibertyLibrary *drvr_library = arc->to()->libertyLibrary();
|
||||||
if (model) {
|
if (model) {
|
||||||
ArcDelay gate_delay;
|
float gate_delay, drvr_slew;
|
||||||
Slew drvr_slew;
|
|
||||||
float in_slew1 = delayAsFloat(in_slew);
|
float in_slew1 = delayAsFloat(in_slew);
|
||||||
// NaNs cause seg faults during table lookup.
|
// 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");
|
report_->error(1350, "gate delay input variable is NaN");
|
||||||
model->gateDelay(pinPvt(drvr_pin, scene, min_max), in_slew1, load_cap,
|
const Pvt *pvt = pinPvt(drvr_pin, scene, min_max);
|
||||||
variables_->pocvEnabled(),
|
model->gateDelay(pvt, in_slew1, load_cap, gate_delay, drvr_slew);
|
||||||
gate_delay, drvr_slew);
|
|
||||||
return makeResult(drvr_library, rf, gate_delay, drvr_slew, load_pin_index_map);
|
// 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
|
else
|
||||||
return makeResult(drvr_library, rf, delay_zero, delay_zero, load_pin_index_map);
|
return makeResult(drvr_library, rf, delay_zero, delay_zero, load_pin_index_map);
|
||||||
|
|
@ -157,17 +163,18 @@ LumpedCapDelayCalc::gateDelay(const Pin *drvr_pin,
|
||||||
ArcDcalcResult
|
ArcDcalcResult
|
||||||
LumpedCapDelayCalc::makeResult(const LibertyLibrary *drvr_library,
|
LumpedCapDelayCalc::makeResult(const LibertyLibrary *drvr_library,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
ArcDelay gate_delay,
|
const ArcDelay &gate_delay,
|
||||||
Slew drvr_slew,
|
const Slew &drvr_slew,
|
||||||
const LoadPinIndexMap &load_pin_index_map)
|
const LoadPinIndexMap &load_pin_index_map)
|
||||||
{
|
{
|
||||||
ArcDcalcResult dcalc_result(load_pin_index_map.size());
|
ArcDcalcResult dcalc_result(load_pin_index_map.size());
|
||||||
dcalc_result.setGateDelay(gate_delay);
|
dcalc_result.setGateDelay(gate_delay);
|
||||||
dcalc_result.setDrvrSlew(drvr_slew);
|
dcalc_result.setDrvrSlew(drvr_slew);
|
||||||
|
|
||||||
|
double drvr_slew1 = delayAsFloat(drvr_slew);
|
||||||
for (const auto [load_pin, load_idx] : load_pin_index_map) {
|
for (const auto [load_pin, load_idx] : load_pin_index_map) {
|
||||||
ArcDelay wire_delay = 0.0;
|
double wire_delay = 0.0;
|
||||||
Slew load_slew = drvr_slew;
|
double load_slew = drvr_slew1;
|
||||||
thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew);
|
thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew);
|
||||||
dcalc_result.setWireDelay(load_idx, wire_delay);
|
dcalc_result.setWireDelay(load_idx, wire_delay);
|
||||||
dcalc_result.setLoadSlew(load_idx, load_slew);
|
dcalc_result.setLoadSlew(load_idx, load_slew);
|
||||||
|
|
@ -190,7 +197,8 @@ LumpedCapDelayCalc::reportGateDelay(const Pin *check_pin,
|
||||||
if (model) {
|
if (model) {
|
||||||
float in_slew1 = delayAsFloat(in_slew);
|
float in_slew1 = delayAsFloat(in_slew);
|
||||||
return model->reportGateDelay(pinPvt(check_pin, scene, min_max),
|
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 "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -74,8 +74,8 @@ public:
|
||||||
protected:
|
protected:
|
||||||
ArcDcalcResult makeResult(const LibertyLibrary *drvr_library,
|
ArcDcalcResult makeResult(const LibertyLibrary *drvr_library,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
ArcDelay gate_delay,
|
const ArcDelay &gate_delay,
|
||||||
Slew drvr_slew,
|
const Slew &drvr_slew,
|
||||||
const LoadPinIndexMap &load_pin_index_map);
|
const LoadPinIndexMap &load_pin_index_map);
|
||||||
|
|
||||||
using ArcDelayCalc::reduceParasitic;
|
using ArcDelayCalc::reduceParasitic;
|
||||||
|
|
|
||||||
|
|
@ -88,13 +88,13 @@ ParallelDelayCalc::gateDelaysParallel(ArcDcalcArgSeq &dcalc_args,
|
||||||
load_pin_index_map, scene, min_max);
|
load_pin_index_map, scene, min_max);
|
||||||
ArcDelay gate_delay = gate_result.gateDelay();
|
ArcDelay gate_delay = gate_result.gateDelay();
|
||||||
Slew drvr_slew = gate_result.drvrSlew();
|
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;
|
load_delays[drvr_idx] = load_delay;
|
||||||
|
|
||||||
if (!delayZero(load_delay))
|
if (!delayZero(load_delay, this))
|
||||||
load_delay_sum += 1.0 / load_delay;
|
delayIncr(load_delay_sum, delayDiv(1.0, load_delay, this), this);
|
||||||
if (!delayZero(drvr_slew))
|
if (!delayZero(drvr_slew, this))
|
||||||
slew_sum += 1.0 / drvr_slew;
|
delayIncr(slew_sum, delayDiv(1.0, drvr_slew, this), this);
|
||||||
|
|
||||||
dcalc_result.setLoadCount(load_pin_index_map.size());
|
dcalc_result.setLoadCount(load_pin_index_map.size());
|
||||||
for (const auto &[load_pin, load_idx] : load_pin_index_map) {
|
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
|
? delay_zero
|
||||||
: 1.0 / load_delay_sum;
|
: delayDiv(1.0, load_delay_sum, this);
|
||||||
ArcDelay drvr_slew = delayZero(slew_sum) ? delay_zero : 1.0 / slew_sum;
|
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++) {
|
for (size_t drvr_idx = 0; drvr_idx < drvr_count; drvr_idx++) {
|
||||||
ArcDcalcResult &dcalc_result = dcalc_results[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);
|
dcalc_result.setDrvrSlew(drvr_slew);
|
||||||
}
|
}
|
||||||
return dcalc_results;
|
return dcalc_results;
|
||||||
|
|
|
||||||
|
|
@ -166,8 +166,8 @@ PrimaDelayCalc::inputPortDelay(const Pin *drvr_pin,
|
||||||
for (auto load_pin_index : load_pin_index_map) {
|
for (auto load_pin_index : load_pin_index_map) {
|
||||||
const Pin *load_pin = load_pin_index.first;
|
const Pin *load_pin = load_pin_index.first;
|
||||||
size_t load_idx = load_pin_index.second;
|
size_t load_idx = load_pin_index.second;
|
||||||
ArcDelay wire_delay = 0.0;
|
double wire_delay = 0.0;
|
||||||
Slew load_slew = in_slew;
|
double load_slew = in_slew;
|
||||||
bool elmore_exists = false;
|
bool elmore_exists = false;
|
||||||
float elmore = 0.0;
|
float elmore = 0.0;
|
||||||
if (pi_elmore)
|
if (pi_elmore)
|
||||||
|
|
@ -722,8 +722,8 @@ PrimaDelayCalc::dcalcResults()
|
||||||
size_t drvr_node = pin_node_map_[drvr_pin];
|
size_t drvr_node = pin_node_map_[drvr_pin];
|
||||||
ThresholdTimes &drvr_times = threshold_times_[drvr_node];
|
ThresholdTimes &drvr_times = threshold_times_[drvr_node];
|
||||||
float ref_time = output_waveforms_[drvr_idx]->referenceTime(dcalc_arg.inSlewFlt());
|
float ref_time = output_waveforms_[drvr_idx]->referenceTime(dcalc_arg.inSlewFlt());
|
||||||
ArcDelay gate_delay = drvr_times[threshold_vth] - ref_time;
|
double gate_delay = drvr_times[threshold_vth] - ref_time;
|
||||||
Slew drvr_slew = std::abs(drvr_times[threshold_vh] - drvr_times[threshold_vl]);
|
double drvr_slew = std::abs(drvr_times[threshold_vh] - drvr_times[threshold_vl]);
|
||||||
dcalc_result.setGateDelay(gate_delay);
|
dcalc_result.setGateDelay(gate_delay);
|
||||||
dcalc_result.setDrvrSlew(drvr_slew);
|
dcalc_result.setDrvrSlew(drvr_slew);
|
||||||
debugPrint(debug_, "ccs_dcalc", 2,
|
debugPrint(debug_, "ccs_dcalc", 2,
|
||||||
|
|
@ -739,8 +739,8 @@ PrimaDelayCalc::dcalcResults()
|
||||||
size_t load_node = pin_node_map_[load_pin];
|
size_t load_node = pin_node_map_[load_pin];
|
||||||
ThresholdTimes &wire_times = threshold_times_[load_node];
|
ThresholdTimes &wire_times = threshold_times_[load_node];
|
||||||
ThresholdTimes &drvr_times = threshold_times_[drvr_node];
|
ThresholdTimes &drvr_times = threshold_times_[drvr_node];
|
||||||
ArcDelay wire_delay = wire_times[threshold_vth] - drvr_times[threshold_vth];
|
double wire_delay = wire_times[threshold_vth] - drvr_times[threshold_vth];
|
||||||
Slew load_slew = std::abs(wire_times[threshold_vh] - wire_times[threshold_vl]);
|
double load_slew = std::abs(wire_times[threshold_vh] - wire_times[threshold_vl]);
|
||||||
debugPrint(debug_, "ccs_dcalc", 2,
|
debugPrint(debug_, "ccs_dcalc", 2,
|
||||||
"load %s %s delay %s slew %s",
|
"load %s %s delay %s slew %s",
|
||||||
network_->pathName(load_pin),
|
network_->pathName(load_pin),
|
||||||
|
|
@ -920,7 +920,8 @@ PrimaDelayCalc::reportGateDelay(const Pin *drvr_pin,
|
||||||
if (model) {
|
if (model) {
|
||||||
float in_slew1 = delayAsFloat(in_slew);
|
float in_slew1 = delayAsFloat(in_slew);
|
||||||
return model->reportGateDelay(pinPvt(drvr_pin, scene, min_max),
|
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 "";
|
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
|
the std containers. The member functions are now templated functions found
|
||||||
in ContainerHelpers.hh.
|
in ContainerHelpers.hh.
|
||||||
|
|
||||||
|
The Graph slew_rf_count option is no longer supported.
|
||||||
|
|
||||||
Release 2.6.2 2025/03/30
|
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.
|
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
|
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
|
leaf instance timing models have corresponding edges in the graph
|
||||||
between pins on the instance.
|
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
|
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 "PortDirection.hh"
|
||||||
#include "Network.hh"
|
#include "Network.hh"
|
||||||
#include "FuncExpr.hh"
|
#include "FuncExpr.hh"
|
||||||
|
#include "Variables.hh"
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
||||||
|
|
@ -46,12 +47,10 @@ namespace sta {
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Graph::Graph(StaState *sta,
|
Graph::Graph(StaState *sta,
|
||||||
int slew_rf_count,
|
|
||||||
DcalcAPIndex ap_count) :
|
DcalcAPIndex ap_count) :
|
||||||
StaState(sta),
|
StaState(sta),
|
||||||
vertices_(nullptr),
|
vertices_(nullptr),
|
||||||
edges_(nullptr),
|
edges_(nullptr),
|
||||||
slew_rf_count_(slew_rf_count),
|
|
||||||
ap_count_(ap_count),
|
ap_count_(ap_count),
|
||||||
period_check_annotations_(nullptr),
|
period_check_annotations_(nullptr),
|
||||||
reg_clk_vertices_(makeVertexSet(this))
|
reg_clk_vertices_(makeVertexSet(this))
|
||||||
|
|
@ -583,15 +582,31 @@ Graph::slew(const Vertex *vertex,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
DcalcAPIndex ap_index)
|
DcalcAPIndex ap_index)
|
||||||
{
|
{
|
||||||
if (slew_rf_count_) {
|
size_t slew_index = ap_index * RiseFall::index_count + rf->index();
|
||||||
const Slew *slews = vertex->slews();
|
const float *slews_flt = vertex->slewsFloat();
|
||||||
size_t slew_index = (slew_rf_count_ == 1)
|
if (variables_->pocvEnabled()) {
|
||||||
? ap_index
|
const Slew *slews = std::bit_cast<const Slew*>(slews_flt);
|
||||||
: ap_index*slew_rf_count_+rf->index();
|
|
||||||
return slews[slew_index];
|
return slews[slew_index];
|
||||||
}
|
}
|
||||||
else {
|
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;
|
return slew;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -602,18 +617,15 @@ Graph::setSlew(Vertex *vertex,
|
||||||
DcalcAPIndex ap_index,
|
DcalcAPIndex ap_index,
|
||||||
const Slew &slew)
|
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();
|
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;
|
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);
|
edges_->destroy(edge);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArcDelay
|
const ArcDelay &
|
||||||
Graph::arcDelay(const Edge *edge,
|
Graph::arcDelay(const Edge *edge,
|
||||||
const TimingArc *arc,
|
const TimingArc *arc,
|
||||||
DcalcAPIndex ap_index) const
|
DcalcAPIndex ap_index) const
|
||||||
{
|
{
|
||||||
ArcDelay *delays = edge->arcDelays();
|
|
||||||
size_t index = arc->index() * ap_count_ + ap_index;
|
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
|
void
|
||||||
Graph::setArcDelay(Edge *edge,
|
Graph::setArcDelay(Edge *edge,
|
||||||
const TimingArc *arc,
|
const TimingArc *arc,
|
||||||
DcalcAPIndex ap_index,
|
DcalcAPIndex ap_index,
|
||||||
ArcDelay delay)
|
const ArcDelay &delay)
|
||||||
{
|
{
|
||||||
ArcDelay *arc_delays = edge->arcDelays();
|
|
||||||
size_t index = arc->index() * ap_count_ + ap_index;
|
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 &
|
const ArcDelay &
|
||||||
|
|
@ -691,9 +717,17 @@ Graph::wireArcDelay(const Edge *edge,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
DcalcAPIndex ap_index)
|
DcalcAPIndex ap_index)
|
||||||
{
|
{
|
||||||
ArcDelay *delays = edge->arcDelays();
|
|
||||||
size_t index = rf->index() * ap_count_ + ap_index;
|
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
|
void
|
||||||
|
|
@ -702,9 +736,15 @@ Graph::setWireArcDelay(Edge *edge,
|
||||||
DcalcAPIndex ap_index,
|
DcalcAPIndex ap_index,
|
||||||
const ArcDelay &delay)
|
const ArcDelay &delay)
|
||||||
{
|
{
|
||||||
ArcDelay *delays = edge->arcDelays();
|
|
||||||
size_t index = rf->index() * ap_count_ + ap_index;
|
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)
|
Graph::initSlews(Vertex *vertex)
|
||||||
{
|
{
|
||||||
size_t slew_count = slewCount();
|
size_t slew_count = slewCount();
|
||||||
Slew *slews = new Slew[slew_count];
|
if (variables_->pocvEnabled()) {
|
||||||
vertex->setSlews(slews);
|
float *slews = std::bit_cast<float*>(new Slew[slew_count]{});
|
||||||
for (size_t i = 0; i < slew_count; i++)
|
vertex->setSlews(slews);
|
||||||
slews[i] = 0.0;
|
}
|
||||||
|
else {
|
||||||
|
float *slews = new float[slew_count]{};
|
||||||
|
vertex->setSlews(slews);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
Graph::slewCount()
|
Graph::slewCount()
|
||||||
{
|
{
|
||||||
return slew_rf_count_ * ap_count_;
|
return RiseFall::index_count * ap_count_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -805,10 +849,14 @@ Graph::initArcDelays(Edge *edge)
|
||||||
{
|
{
|
||||||
size_t arc_count = edge->timingArcSet()->arcCount();
|
size_t arc_count = edge->timingArcSet()->arcCount();
|
||||||
size_t delay_count = arc_count * ap_count_;
|
size_t delay_count = arc_count * ap_count_;
|
||||||
ArcDelay *arc_delays = new ArcDelay[delay_count];
|
if (variables_->pocvEnabled()) {
|
||||||
edge->setArcDelays(arc_delays);
|
float *delays = std::bit_cast<float*>(new ArcDelay[delay_count]{});
|
||||||
for (size_t i = 0; i < delay_count; i++)
|
edge->setArcDelays(delays);
|
||||||
arc_delays[i] = 0.0;
|
}
|
||||||
|
else {
|
||||||
|
float *delays = new float[delay_count]{};
|
||||||
|
edge->setArcDelays(delays);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
@ -1040,7 +1088,7 @@ Vertex::setVisited2(bool visited)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Vertex::setSlews(Slew *slews)
|
Vertex::setSlews(float *slews)
|
||||||
{
|
{
|
||||||
delete [] slews_;
|
delete [] slews_;
|
||||||
slews_ = slews;
|
slews_ = slews;
|
||||||
|
|
@ -1251,10 +1299,10 @@ Edge::setTimingArcSet(TimingArcSet *set)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Edge::setArcDelays(ArcDelay *arc_delays)
|
Edge::setArcDelays(float *delays)
|
||||||
{
|
{
|
||||||
delete [] arc_delays_;
|
delete [] arc_delays_;
|
||||||
arc_delays_ = arc_delays;
|
arc_delays_ = delays;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
||||||
|
|
@ -132,21 +132,24 @@ bool is_bidirect_driver() { return self->isBidirectDriver(); }
|
||||||
int level() { return Sta::sta()->vertexLevel(self); }
|
int level() { return Sta::sta()->vertexLevel(self); }
|
||||||
int tag_group_index() { return self->tagGroupIndex(); }
|
int tag_group_index() { return self->tagGroupIndex(); }
|
||||||
|
|
||||||
Slew
|
float
|
||||||
slew(const RiseFallBoth *rf,
|
slew(const RiseFallBoth *rf,
|
||||||
const MinMax *min_max)
|
const MinMax *min_max)
|
||||||
{
|
{
|
||||||
Sta *sta = Sta::sta();
|
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
|
std::string
|
||||||
slew_scenes(const RiseFallBoth *rf,
|
slew_scenes_string(const RiseFallBoth *rf,
|
||||||
const SceneSeq scenes,
|
const SceneSeq scenes,
|
||||||
const MinMax *min_max)
|
const MinMax *min_max,
|
||||||
|
bool report_variance,
|
||||||
|
int digits)
|
||||||
{
|
{
|
||||||
Sta *sta = Sta::sta();
|
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 *
|
VertexOutEdgeIterator *
|
||||||
|
|
@ -223,22 +226,29 @@ arc_delays(TimingArc *arc)
|
||||||
{
|
{
|
||||||
Sta *sta = Sta::sta();
|
Sta *sta = Sta::sta();
|
||||||
FloatSeq delays;
|
FloatSeq delays;
|
||||||
DcalcAPIndex ap_count = sta->dcalcAnalysisPtCount();
|
for (Scene *scene : sta->scenes()) {
|
||||||
for (DcalcAPIndex ap_index = 0; ap_index < ap_count; ap_index++)
|
for (const MinMax *min_max : MinMax::range()) {
|
||||||
delays.push_back(delayAsFloat(sta->arcDelay(self, arc, ap_index)));
|
DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max);
|
||||||
|
delays.push_back(delayAsFloat(sta->arcDelay(self, arc, ap_index), min_max, sta));
|
||||||
|
}
|
||||||
|
}
|
||||||
return delays;
|
return delays;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringSeq
|
StringSeq
|
||||||
arc_delay_strings(TimingArc *arc,
|
arc_delay_strings(TimingArc *arc,
|
||||||
|
bool report_variance,
|
||||||
int digits)
|
int digits)
|
||||||
{
|
{
|
||||||
Sta *sta = Sta::sta();
|
Sta *sta = Sta::sta();
|
||||||
StringSeq delays;
|
StringSeq delays;
|
||||||
DcalcAPIndex ap_count = sta->dcalcAnalysisPtCount();
|
for (Scene *scene : sta->scenes()) {
|
||||||
for (DcalcAPIndex ap_index = 0; ap_index < ap_count; ap_index++)
|
for (const MinMax *min_max : MinMax::range()) {
|
||||||
delays.push_back(delayAsString(sta->arcDelay(self, arc, ap_index),
|
DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max);
|
||||||
sta, digits));
|
delays.push_back(delayAsString(sta->arcDelay(self, arc, ap_index),
|
||||||
|
min_max, report_variance, digits, sta));
|
||||||
|
}
|
||||||
|
}
|
||||||
return delays;
|
return delays;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -255,8 +265,9 @@ arc_delay(TimingArc *arc,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
const MinMax *min_max)
|
const MinMax *min_max)
|
||||||
{
|
{
|
||||||
|
Sta *sta = Sta::sta();
|
||||||
DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max);
|
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
|
std::string
|
||||||
|
|
|
||||||
|
|
@ -26,51 +26,64 @@
|
||||||
|
|
||||||
namespace eval sta {
|
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 } {
|
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
|
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)] } {
|
if { [info exists keys(-from)] && [info exists keys(-to)] } {
|
||||||
set from_pin [get_port_pin_error "from_pin" $keys(-from)]
|
set from_pin [get_port_pin_error "from_pin" $keys(-from)]
|
||||||
set to_pin [get_port_pin_error "to_pin" $keys(-to)]
|
set to_pin [get_port_pin_error "to_pin" $keys(-to)]
|
||||||
foreach from_vertex [$from_pin vertices] {
|
foreach from_vertex [$from_pin vertices] {
|
||||||
foreach to_vertex [$to_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)] {
|
} elseif [info exists keys(-from)] {
|
||||||
set from_pin [get_port_pin_error "from_pin" $keys(-from)]
|
set from_pin [get_port_pin_error "from_pin" $keys(-from)]
|
||||||
foreach from_vertex [$from_pin vertices] {
|
foreach from_vertex [$from_pin vertices] {
|
||||||
report_edges_ $from_vertex out_edge_iterator \
|
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)] {
|
} elseif [info exists keys(-to)] {
|
||||||
set to_pin [get_port_pin_error "to_pin" $keys(-to)]
|
set to_pin [get_port_pin_error "to_pin" $keys(-to)]
|
||||||
foreach to_vertex [$to_pin vertices] {
|
foreach to_vertex [$to_pin vertices] {
|
||||||
report_edges_ $to_vertex in_edge_iterator \
|
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]
|
set iter [$from_vertex out_edge_iterator]
|
||||||
while {[$iter has_next]} {
|
while {[$iter has_next]} {
|
||||||
set edge [$iter next]
|
set edge [$iter next]
|
||||||
if { [$edge to] == $to_vertex } {
|
if { [$edge to] == $to_vertex } {
|
||||||
if { [$edge role] == "wire" } {
|
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 {
|
} else {
|
||||||
report_edge_ $edge vertex_port_name vertex_port_name
|
report_edge_ $edge vertex_port_name vertex_port_name $digits $report_variance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$iter finish
|
$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.
|
# First report edges internal to the device.
|
||||||
set device_header 0
|
set device_header 0
|
||||||
set iter [$vertex $iter_proc]
|
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
|
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
|
$iter finish
|
||||||
|
|
@ -94,15 +107,14 @@ proc report_edges_ { vertex iter_proc wire_from_name_proc wire_to_name_proc } {
|
||||||
while {[$iter has_next]} {
|
while {[$iter has_next]} {
|
||||||
set edge [$iter next]
|
set edge [$iter next]
|
||||||
if { [$edge role] == "wire" } {
|
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
|
$iter finish
|
||||||
}
|
}
|
||||||
|
|
||||||
proc report_edge_ { edge vertex_from_name_proc vertex_to_name_proc } {
|
proc report_edge_ { edge vertex_from_name_proc vertex_to_name_proc \
|
||||||
global sta_report_default_digits
|
digits report_variance } {
|
||||||
|
|
||||||
set latch_enable [$edge latch_d_to_q_en]
|
set latch_enable [$edge latch_d_to_q_en]
|
||||||
if { $latch_enable != "" } {
|
if { $latch_enable != "" } {
|
||||||
set latch_enable " enable $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] {
|
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 delays_fmt [format_delays $delays]
|
||||||
set disable_reason ""
|
set disable_reason ""
|
||||||
if { [timing_arc_disabled $edge $arc] } {
|
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.
|
# Separate delay list elements with colons.
|
||||||
proc format_delays { values } {
|
proc format_delays { values } {
|
||||||
set result ""
|
set result ""
|
||||||
|
|
|
||||||
|
|
@ -119,15 +119,15 @@ public:
|
||||||
ArcDcalcResult(size_t load_count);
|
ArcDcalcResult(size_t load_count);
|
||||||
void setLoadCount(size_t load_count);
|
void setLoadCount(size_t load_count);
|
||||||
ArcDelay &gateDelay() { return gate_delay_; }
|
ArcDelay &gateDelay() { return gate_delay_; }
|
||||||
void setGateDelay(ArcDelay gate_delay);
|
void setGateDelay(const ArcDelay &gate_delay);
|
||||||
Slew &drvrSlew() { return drvr_slew_; }
|
Slew &drvrSlew() { return drvr_slew_; }
|
||||||
void setDrvrSlew(Slew drvr_slew);
|
void setDrvrSlew(const Slew &drvr_slew);
|
||||||
ArcDelay wireDelay(size_t load_idx) const;
|
const ArcDelay &wireDelay(size_t load_idx) const;
|
||||||
void setWireDelay(size_t load_idx,
|
void setWireDelay(size_t load_idx,
|
||||||
ArcDelay wire_delay);
|
const ArcDelay &wire_delay);
|
||||||
Slew loadSlew(size_t load_idx) const;
|
const Slew &loadSlew(size_t load_idx) const;
|
||||||
void setLoadSlew(size_t load_idx,
|
void setLoadSlew(size_t load_idx,
|
||||||
Slew load_slew);
|
const Slew &load_slew);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ArcDelay gate_delay_;
|
ArcDelay gate_delay_;
|
||||||
|
|
|
||||||
|
|
@ -24,27 +24,326 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "StaConfig.hh"
|
#include <array>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
// IWYU pragma: begin_exports
|
#include "StaConfig.hh"
|
||||||
#if (SSTA == 1)
|
#include "MinMax.hh"
|
||||||
// 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
|
|
||||||
|
|
||||||
namespace sta {
|
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 ArcDelay = Delay;
|
||||||
using Slew = Delay;
|
using Slew = Delay;
|
||||||
using Arrival = Delay;
|
using Arrival = Delay;
|
||||||
using Required = Delay;
|
using Required = Delay;
|
||||||
using Slack = 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
|
} // 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
|
class Graph : public StaState
|
||||||
{
|
{
|
||||||
public:
|
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,
|
Graph(StaState *sta,
|
||||||
int slew_rf_count,
|
|
||||||
DcalcAPIndex ap_count);
|
DcalcAPIndex ap_count);
|
||||||
void makeGraph();
|
void makeGraph();
|
||||||
~Graph();
|
~Graph();
|
||||||
|
|
@ -100,6 +94,8 @@ public:
|
||||||
const Slew &slew(const Vertex *vertex,
|
const Slew &slew(const Vertex *vertex,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
DcalcAPIndex ap_index);
|
DcalcAPIndex ap_index);
|
||||||
|
const Slew &slew(const Vertex *vertex,
|
||||||
|
size_t index);
|
||||||
void setSlew(Vertex *vertex,
|
void setSlew(Vertex *vertex,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
DcalcAPIndex ap_index,
|
DcalcAPIndex ap_index,
|
||||||
|
|
@ -128,13 +124,13 @@ public:
|
||||||
Edge *&edge,
|
Edge *&edge,
|
||||||
const TimingArc *&arc) const;
|
const TimingArc *&arc) const;
|
||||||
|
|
||||||
ArcDelay arcDelay(const Edge *edge,
|
const ArcDelay &arcDelay(const Edge *edge,
|
||||||
const TimingArc *arc,
|
const TimingArc *arc,
|
||||||
DcalcAPIndex ap_index) const;
|
DcalcAPIndex ap_index) const;
|
||||||
void setArcDelay(Edge *edge,
|
void setArcDelay(Edge *edge,
|
||||||
const TimingArc *arc,
|
const TimingArc *arc,
|
||||||
DcalcAPIndex ap_index,
|
DcalcAPIndex ap_index,
|
||||||
ArcDelay delay);
|
const ArcDelay &delay);
|
||||||
// Alias for arcDelays using library wire arcs.
|
// Alias for arcDelays using library wire arcs.
|
||||||
const ArcDelay &wireArcDelay(const Edge *edge,
|
const ArcDelay &wireArcDelay(const Edge *edge,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
|
|
@ -222,7 +218,6 @@ protected:
|
||||||
// driver/source (top level input, instance pin output) vertex
|
// driver/source (top level input, instance pin output) vertex
|
||||||
// in pin_bidirect_drvr_vertex_map
|
// in pin_bidirect_drvr_vertex_map
|
||||||
PinVertexMap pin_bidirect_drvr_vertex_map_;
|
PinVertexMap pin_bidirect_drvr_vertex_map_;
|
||||||
int slew_rf_count_;
|
|
||||||
DcalcAPIndex ap_count_;
|
DcalcAPIndex ap_count_;
|
||||||
// Sdf period check annotations.
|
// Sdf period check annotations.
|
||||||
PeriodCheckAnnotations *period_check_annotations_;
|
PeriodCheckAnnotations *period_check_annotations_;
|
||||||
|
|
@ -258,8 +253,6 @@ public:
|
||||||
[[nodiscard]] bool isRoot() const{ return level_ == 0; }
|
[[nodiscard]] bool isRoot() const{ return level_ == 0; }
|
||||||
[[nodiscard]] bool hasFanin() const;
|
[[nodiscard]] bool hasFanin() const;
|
||||||
[[nodiscard]] bool hasFanout() const;
|
[[nodiscard]] bool hasFanout() const;
|
||||||
Slew *slews() { return slews_; }
|
|
||||||
const Slew *slews() const { return slews_; }
|
|
||||||
Path *paths() const { return paths_; }
|
Path *paths() const { return paths_; }
|
||||||
Path *makePaths(uint32_t count);
|
Path *makePaths(uint32_t count);
|
||||||
void setPaths(Path *paths);
|
void setPaths(Path *paths);
|
||||||
|
|
@ -298,14 +291,18 @@ protected:
|
||||||
bool is_bidirect_drvr,
|
bool is_bidirect_drvr,
|
||||||
bool is_reg_clk);
|
bool is_reg_clk);
|
||||||
void clear();
|
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_;
|
Pin *pin_;
|
||||||
EdgeId in_edges_; // Edges to this vertex.
|
EdgeId in_edges_; // Edges to this vertex.
|
||||||
EdgeId out_edges_; // Edges from this vertex.
|
EdgeId out_edges_; // Edges from this vertex.
|
||||||
|
|
||||||
// Delay calc
|
// Delay calc
|
||||||
Slew *slews_;
|
float *slews_;
|
||||||
// Search
|
// Search
|
||||||
Path *paths_;
|
Path *paths_;
|
||||||
|
|
||||||
|
|
@ -356,8 +353,9 @@ public:
|
||||||
TimingSense sense() const;
|
TimingSense sense() const;
|
||||||
TimingArcSet *timingArcSet() const { return arc_set_; }
|
TimingArcSet *timingArcSet() const { return arc_set_; }
|
||||||
void setTimingArcSet(TimingArcSet *set);
|
void setTimingArcSet(TimingArcSet *set);
|
||||||
ArcDelay *arcDelays() const { return arc_delays_; }
|
float *arcDelays() { return arc_delays_; }
|
||||||
void setArcDelays(ArcDelay *arc_delays);
|
const float *arcDelays() const { return arc_delays_; }
|
||||||
|
void setArcDelays(float *delays);
|
||||||
bool delay_Annotation_Is_Incremental() const {return delay_annotation_is_incremental_;};
|
bool delay_Annotation_Is_Incremental() const {return delay_annotation_is_incremental_;};
|
||||||
void setDelayAnnotationIsIncremental(bool is_incr);
|
void setDelayAnnotationIsIncremental(bool is_incr);
|
||||||
// Edge is disabled to break combinational loops.
|
// Edge is disabled to break combinational loops.
|
||||||
|
|
@ -398,7 +396,7 @@ protected:
|
||||||
EdgeId vertex_in_link_; // Vertex in edges list.
|
EdgeId vertex_in_link_; // Vertex in edges list.
|
||||||
EdgeId vertex_out_next_; // Vertex out edges doubly linked list.
|
EdgeId vertex_out_next_; // Vertex out edges doubly linked list.
|
||||||
EdgeId vertex_out_prev_;
|
EdgeId vertex_out_prev_;
|
||||||
ArcDelay *arc_delays_;
|
float *arc_delays_;
|
||||||
union {
|
union {
|
||||||
uintptr_t bits_;
|
uintptr_t bits_;
|
||||||
std::vector<bool> *seq_;
|
std::vector<bool> *seq_;
|
||||||
|
|
|
||||||
|
|
@ -245,8 +245,8 @@ protected:
|
||||||
|
|
||||||
bool annotateDelaySlew(Edge *edge,
|
bool annotateDelaySlew(Edge *edge,
|
||||||
const TimingArc *arc,
|
const TimingArc *arc,
|
||||||
ArcDelay &gate_delay,
|
const ArcDelay &gate_delay,
|
||||||
Slew &gate_slew,
|
const Slew &gate_slew,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
const MinMax *min_max);
|
const MinMax *min_max);
|
||||||
bool annotateLoadDelays(Vertex *drvr_vertex,
|
bool annotateLoadDelays(Vertex *drvr_vertex,
|
||||||
|
|
|
||||||
|
|
@ -33,44 +33,11 @@
|
||||||
|
|
||||||
namespace sta {
|
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
|
class InternalPowerModel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
InternalPowerModel(TableModel *model);
|
InternalPowerModel();
|
||||||
~InternalPowerModel();
|
InternalPowerModel(std::shared_ptr<TableModel> model);
|
||||||
float power(const LibertyCell *cell,
|
float power(const LibertyCell *cell,
|
||||||
const Pvt *pvt,
|
const Pvt *pvt,
|
||||||
float in_slew,
|
float in_slew,
|
||||||
|
|
@ -80,7 +47,7 @@ public:
|
||||||
float in_slew,
|
float in_slew,
|
||||||
float load_cap,
|
float load_cap,
|
||||||
int digits) const;
|
int digits) const;
|
||||||
const TableModel *model() const { return model_; }
|
const TableModel *model() const { return model_.get(); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void findAxisValues(float in_slew,
|
void findAxisValues(float in_slew,
|
||||||
|
|
@ -95,7 +62,36 @@ protected:
|
||||||
bool checkAxes(const TableModel *model);
|
bool checkAxes(const TableModel *model);
|
||||||
bool checkAxis(const TableAxis *axis);
|
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
|
} // namespace
|
||||||
|
|
|
||||||
|
|
@ -589,7 +589,7 @@ public:
|
||||||
LibertyPort *related_port,
|
LibertyPort *related_port,
|
||||||
LibertyPort *related_pg_pin,
|
LibertyPort *related_pg_pin,
|
||||||
const std::shared_ptr<FuncExpr> &when,
|
const std::shared_ptr<FuncExpr> &when,
|
||||||
InternalPowerModels &models);
|
const InternalPowerModels &models);
|
||||||
void makeLeakagePower(LibertyPort *related_pg_port,
|
void makeLeakagePower(LibertyPort *related_pg_port,
|
||||||
FuncExpr *when,
|
FuncExpr *when,
|
||||||
float power);
|
float power);
|
||||||
|
|
|
||||||
|
|
@ -37,14 +37,22 @@ public:
|
||||||
void gateDelay(const Pvt *pvt,
|
void gateDelay(const Pvt *pvt,
|
||||||
float in_slew,
|
float in_slew,
|
||||||
float load_cap,
|
float load_cap,
|
||||||
bool pocv_enabled,
|
|
||||||
// Return values.
|
// Return values.
|
||||||
ArcDelay &gate_delay,
|
float &gate_delay,
|
||||||
Slew &drvr_slew) const override;
|
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,
|
std::string reportGateDelay(const Pvt *pvt,
|
||||||
float in_slew,
|
float in_slew,
|
||||||
float load_cap,
|
float load_cap,
|
||||||
bool pocv_enabled,
|
const MinMax *min_max,
|
||||||
|
PocvMode pocv_mode,
|
||||||
int digits) const override;
|
int digits) const override;
|
||||||
float driveResistance(const Pvt *pvt) const override;
|
float driveResistance(const Pvt *pvt) const override;
|
||||||
|
|
||||||
|
|
@ -64,13 +72,15 @@ public:
|
||||||
float from_slew,
|
float from_slew,
|
||||||
float to_slew,
|
float to_slew,
|
||||||
float related_out_cap,
|
float related_out_cap,
|
||||||
bool pocv_enabled) const override;
|
const MinMax *min_max,
|
||||||
|
PocvMode pocv_mode) const override;
|
||||||
std::string reportCheckDelay(const Pvt *pvt,
|
std::string reportCheckDelay(const Pvt *pvt,
|
||||||
float from_slew,
|
float from_slew,
|
||||||
const char *from_slew_annotation,
|
const char *from_slew_annotation,
|
||||||
float to_slew,
|
float to_slew,
|
||||||
float related_out_cap,
|
float related_out_cap,
|
||||||
bool pocv_enabled,
|
const MinMax *min_max,
|
||||||
|
PocvMode pocv_mode,
|
||||||
int digits) const override;
|
int digits) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
||||||
|
|
@ -45,14 +45,14 @@ public:
|
||||||
const StaState *sta);
|
const StaState *sta);
|
||||||
Path(Vertex *vertex,
|
Path(Vertex *vertex,
|
||||||
Tag *tag,
|
Tag *tag,
|
||||||
Arrival arrival,
|
const Arrival &arrival,
|
||||||
Path *prev_path,
|
Path *prev_path,
|
||||||
Edge *prev_edge,
|
Edge *prev_edge,
|
||||||
TimingArc *prev_arc,
|
TimingArc *prev_arc,
|
||||||
const StaState *sta);
|
const StaState *sta);
|
||||||
Path(Vertex *vertex,
|
Path(Vertex *vertex,
|
||||||
Tag *tag,
|
Tag *tag,
|
||||||
Arrival arrival,
|
const Arrival &arrival,
|
||||||
Path *prev_path,
|
Path *prev_path,
|
||||||
Edge *prev_edge,
|
Edge *prev_edge,
|
||||||
TimingArc *prev_arc,
|
TimingArc *prev_arc,
|
||||||
|
|
@ -62,11 +62,11 @@ public:
|
||||||
bool isNull() const;
|
bool isNull() const;
|
||||||
// prev_path null
|
// prev_path null
|
||||||
void init(Vertex *vertex,
|
void init(Vertex *vertex,
|
||||||
Arrival arrival,
|
const Arrival &arrival,
|
||||||
const StaState *sta);
|
const StaState *sta);
|
||||||
void init(Vertex *vertex,
|
void init(Vertex *vertex,
|
||||||
Tag *tag,
|
Tag *tag,
|
||||||
Arrival arrival,
|
const Arrival &arrival,
|
||||||
Path *prev_path,
|
Path *prev_path,
|
||||||
Edge *prev_edge,
|
Edge *prev_edge,
|
||||||
TimingArc *prev_arc,
|
TimingArc *prev_arc,
|
||||||
|
|
@ -76,7 +76,7 @@ public:
|
||||||
const StaState *sta);
|
const StaState *sta);
|
||||||
void init(Vertex *vertex,
|
void init(Vertex *vertex,
|
||||||
Tag *tag,
|
Tag *tag,
|
||||||
Arrival arrival,
|
const Arrival &arrival,
|
||||||
const StaState *sta);
|
const StaState *sta);
|
||||||
|
|
||||||
Vertex *vertex(const StaState *sta) const;
|
Vertex *vertex(const StaState *sta) const;
|
||||||
|
|
@ -98,14 +98,12 @@ public:
|
||||||
const MinMax *minMax(const StaState *sta) const;
|
const MinMax *minMax(const StaState *sta) const;
|
||||||
PathAPIndex pathAnalysisPtIndex(const StaState *sta) const;
|
PathAPIndex pathAnalysisPtIndex(const StaState *sta) const;
|
||||||
DcalcAPIndex dcalcAnalysisPtIndex(const StaState *sta) const;
|
DcalcAPIndex dcalcAnalysisPtIndex(const StaState *sta) const;
|
||||||
Arrival &arrival() { return arrival_; }
|
|
||||||
const Arrival &arrival() const { return arrival_; }
|
const Arrival &arrival() const { return arrival_; }
|
||||||
void setArrival(Arrival arrival);
|
void setArrival(Arrival arrival);
|
||||||
Required &required() { return required_; }
|
|
||||||
const Required &required() const {return required_; }
|
const Required &required() const {return required_; }
|
||||||
void setRequired(const Required &required);
|
void setRequired(const Required &required);
|
||||||
Slack slack(const StaState *sta) const;
|
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.
|
// This takes the same time as prevPath and prevArc combined.
|
||||||
Path *prevPath() const;
|
Path *prevPath() const;
|
||||||
void setPrevPath(Path *prev_path);
|
void setPrevPath(Path *prev_path);
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ public:
|
||||||
virtual const char *typeName() const = 0;
|
virtual const char *typeName() const = 0;
|
||||||
virtual int exceptPathCmp(const PathEnd *path_end,
|
virtual int exceptPathCmp(const PathEnd *path_end,
|
||||||
const StaState *sta) const;
|
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 time with source clock offset.
|
||||||
Arrival dataArrivalTimeOffset(const StaState *sta) const;
|
Arrival dataArrivalTimeOffset(const StaState *sta) const;
|
||||||
virtual Required requiredTime(const StaState *sta) const = 0;
|
virtual Required requiredTime(const StaState *sta) const = 0;
|
||||||
|
|
|
||||||
|
|
@ -22,19 +22,15 @@
|
||||||
//
|
//
|
||||||
// This notice may not be removed or altered from any source distribution.
|
// This notice may not be removed or altered from any source distribution.
|
||||||
|
|
||||||
#include "Machine.hh"
|
#pragma once
|
||||||
#include "StringUtil.hh"
|
|
||||||
#include "Units.hh"
|
|
||||||
#include "StaState.hh"
|
|
||||||
#include "Delay.hh"
|
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
||||||
|
enum class PocvMode { scalar, normal, skew_normal };
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
delayAsString(const Delay &delay,
|
pocvModeName(PocvMode mode);
|
||||||
const StaState *sta)
|
PocvMode
|
||||||
{
|
findPocvMode(const char *mode_name);
|
||||||
return delayAsString(delay, sta, sta->units()->timeUnit()->digits());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
@ -982,11 +982,11 @@ public:
|
||||||
bool report_cap,
|
bool report_cap,
|
||||||
bool report_slew,
|
bool report_slew,
|
||||||
bool report_fanout,
|
bool report_fanout,
|
||||||
|
bool report_variation,
|
||||||
bool report_src_attr);
|
bool report_src_attr);
|
||||||
ReportField *findReportPathField(const char *name);
|
ReportField *findReportPathField(const char *name);
|
||||||
void setReportPathDigits(int digits);
|
void setReportPathDigits(int digits);
|
||||||
void setReportPathNoSplit(bool no_split);
|
void setReportPathNoSplit(bool no_split);
|
||||||
void setReportPathSigmas(bool report_sigmas);
|
|
||||||
void reportPathEnd(PathEnd *end);
|
void reportPathEnd(PathEnd *end);
|
||||||
void reportPathEnds(PathEndSeq *ends);
|
void reportPathEnds(PathEndSeq *ends);
|
||||||
ReportPath *reportPath() { return report_path_; }
|
ReportPath *reportPath() { return report_path_; }
|
||||||
|
|
@ -998,7 +998,7 @@ public:
|
||||||
const SetupHold *setup_hold,
|
const SetupHold *setup_hold,
|
||||||
bool include_internal_latency,
|
bool include_internal_latency,
|
||||||
int digits);
|
int digits);
|
||||||
float findWorstClkSkew(const SetupHold *setup_hold,
|
Delay findWorstClkSkew(const SetupHold *setup_hold,
|
||||||
bool include_internal_latency);
|
bool include_internal_latency);
|
||||||
|
|
||||||
void reportClkLatency(ConstClockSeq &clks,
|
void reportClkLatency(ConstClockSeq &clks,
|
||||||
|
|
@ -1126,12 +1126,15 @@ public:
|
||||||
|
|
||||||
void reportArrivalWrtClks(const Pin *pin,
|
void reportArrivalWrtClks(const Pin *pin,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
|
bool report_variance,
|
||||||
int digits);
|
int digits);
|
||||||
void reportRequiredWrtClks(const Pin *pin,
|
void reportRequiredWrtClks(const Pin *pin,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
|
bool report_variance,
|
||||||
int digits);
|
int digits);
|
||||||
void reportSlackWrtClks(const Pin *pin,
|
void reportSlackWrtClks(const Pin *pin,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
|
bool report_variance,
|
||||||
int digits);
|
int digits);
|
||||||
|
|
||||||
Slew slew(Vertex *vertex,
|
Slew slew(Vertex *vertex,
|
||||||
|
|
@ -1139,9 +1142,9 @@ public:
|
||||||
const SceneSeq &scenes,
|
const SceneSeq &scenes,
|
||||||
const MinMax *min_max);
|
const MinMax *min_max);
|
||||||
|
|
||||||
ArcDelay arcDelay(Edge *edge,
|
const ArcDelay &arcDelay(Edge *edge,
|
||||||
TimingArc *arc,
|
TimingArc *arc,
|
||||||
DcalcAPIndex ap_index);
|
DcalcAPIndex ap_index);
|
||||||
// True if the timing arc has been back-annotated.
|
// True if the timing arc has been back-annotated.
|
||||||
bool arcDelayAnnotated(Edge *edge,
|
bool arcDelayAnnotated(Edge *edge,
|
||||||
TimingArc *arc,
|
TimingArc *arc,
|
||||||
|
|
@ -1403,12 +1406,13 @@ public:
|
||||||
// TCL variable sta_crpr_mode.
|
// TCL variable sta_crpr_mode.
|
||||||
CrprMode crprMode() const;
|
CrprMode crprMode() const;
|
||||||
void setCrprMode(CrprMode mode);
|
void setCrprMode(CrprMode mode);
|
||||||
// TCL variable sta_pocv_enabled.
|
// TCL variable sta_pocv_mode.
|
||||||
// Parametric on chip variation (statisical sta).
|
// Parametric on chip variation (statisical sta).
|
||||||
bool pocvEnabled() const;
|
PocvMode pocvMode() const;
|
||||||
void setPocvEnabled(bool enabled);
|
void setPocvMode(PocvMode mode);
|
||||||
// Number of std deviations from mean to use for normal distributions.
|
// 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.
|
// TCL variable sta_propagate_gated_clock_enable.
|
||||||
// Propagate gated clock enable arrivals.
|
// Propagate gated clock enable arrivals.
|
||||||
bool propagateGatedClockEnable() const;
|
bool propagateGatedClockEnable() const;
|
||||||
|
|
@ -1505,17 +1509,20 @@ protected:
|
||||||
|
|
||||||
void reportDelaysWrtClks(const Pin *pin,
|
void reportDelaysWrtClks(const Pin *pin,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
|
bool report_variance,
|
||||||
int digits,
|
int digits,
|
||||||
bool find_required,
|
bool find_required,
|
||||||
PathDelayFunc get_path_delay);
|
PathDelayFunc get_path_delay);
|
||||||
void reportDelaysWrtClks(Vertex *vertex,
|
void reportDelaysWrtClks(Vertex *vertex,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
|
bool report_variance,
|
||||||
int digits,
|
int digits,
|
||||||
bool find_required,
|
bool find_required,
|
||||||
PathDelayFunc get_path_delay);
|
PathDelayFunc get_path_delay);
|
||||||
void reportDelaysWrtClks(Vertex *vertex,
|
void reportDelaysWrtClks(Vertex *vertex,
|
||||||
const ClockEdge *clk_edge,
|
const ClockEdge *clk_edge,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
|
bool report_variance,
|
||||||
int digits,
|
int digits,
|
||||||
PathDelayFunc get_path_delay);
|
PathDelayFunc get_path_delay);
|
||||||
RiseFallMinMaxDelay findDelaysWrtClks(Vertex *vertex,
|
RiseFallMinMaxDelay findDelaysWrtClks(Vertex *vertex,
|
||||||
|
|
@ -1525,6 +1532,7 @@ protected:
|
||||||
std::string formatDelay(const RiseFall *rf,
|
std::string formatDelay(const RiseFall *rf,
|
||||||
const MinMax *min_max,
|
const MinMax *min_max,
|
||||||
const RiseFallMinMaxDelay &delays,
|
const RiseFallMinMaxDelay &delays,
|
||||||
|
bool report_variance,
|
||||||
int digits);
|
int digits);
|
||||||
|
|
||||||
void connectDrvrPinAfter(Vertex *vertex);
|
void connectDrvrPinAfter(Vertex *vertex);
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ class GraphDelayCalc;
|
||||||
class Latches;
|
class Latches;
|
||||||
class DispatchQueue;
|
class DispatchQueue;
|
||||||
class Variables;
|
class Variables;
|
||||||
|
class DelayOps;
|
||||||
|
|
||||||
using ModeSeq = std::vector<Mode*>;
|
using ModeSeq = std::vector<Mode*>;
|
||||||
using ModeSet = std::set<Mode*>;
|
using ModeSet = std::set<Mode*>;
|
||||||
|
|
@ -96,10 +97,10 @@ public:
|
||||||
GraphDelayCalc *graphDelayCalc() const { return graph_delay_calc_; }
|
GraphDelayCalc *graphDelayCalc() const { return graph_delay_calc_; }
|
||||||
Search *search() { return search_; }
|
Search *search() { return search_; }
|
||||||
Search *search() const { return search_; }
|
Search *search() const { return search_; }
|
||||||
|
const DelayOps *delayOps() const { return delay_ops_; }
|
||||||
Latches *latches() { return latches_; }
|
Latches *latches() { return latches_; }
|
||||||
Latches *latches() const { return latches_; }
|
Latches *latches() const { return latches_; }
|
||||||
unsigned threadCount() const { return thread_count_; }
|
unsigned threadCount() const { return thread_count_; }
|
||||||
float sigmaFactor() const { return sigma_factor_; }
|
|
||||||
bool crprActive(const Mode *mode) const;
|
bool crprActive(const Mode *mode) const;
|
||||||
Variables *variables() { return variables_; }
|
Variables *variables() { return variables_; }
|
||||||
const Variables *variables() const { return variables_; }
|
const Variables *variables() const { return variables_; }
|
||||||
|
|
@ -133,11 +134,11 @@ protected:
|
||||||
ArcDelayCalc *arc_delay_calc_;
|
ArcDelayCalc *arc_delay_calc_;
|
||||||
GraphDelayCalc *graph_delay_calc_;
|
GraphDelayCalc *graph_delay_calc_;
|
||||||
Search *search_;
|
Search *search_;
|
||||||
|
DelayOps *delay_ops_;
|
||||||
Latches *latches_;
|
Latches *latches_;
|
||||||
Variables *variables_;
|
Variables *variables_;
|
||||||
int thread_count_;
|
int thread_count_;
|
||||||
DispatchQueue *dispatch_queue_;
|
DispatchQueue *dispatch_queue_;
|
||||||
float sigma_factor_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
||||||
|
|
@ -33,12 +33,14 @@
|
||||||
#include "Transition.hh"
|
#include "Transition.hh"
|
||||||
#include "LibertyClass.hh"
|
#include "LibertyClass.hh"
|
||||||
#include "TimingModel.hh"
|
#include "TimingModel.hh"
|
||||||
|
#include "Variables.hh"
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
||||||
class Unit;
|
class Unit;
|
||||||
class Units;
|
class Units;
|
||||||
class Report;
|
class Report;
|
||||||
|
class TableModels;
|
||||||
class Table;
|
class Table;
|
||||||
class TableModel;
|
class TableModel;
|
||||||
class TableAxis;
|
class TableAxis;
|
||||||
|
|
@ -63,43 +65,41 @@ class GateTableModel : public GateTimingModel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GateTableModel(LibertyCell *cell,
|
GateTableModel(LibertyCell *cell,
|
||||||
TableModel *delay_model,
|
TableModels *delay_models,
|
||||||
TableModelsEarlyLate delay_sigma_models,
|
TableModels *slew_models,
|
||||||
TableModel *slew_model,
|
|
||||||
TableModelsEarlyLate slew_sigma_models,
|
|
||||||
ReceiverModelPtr receiver_model,
|
ReceiverModelPtr receiver_model,
|
||||||
OutputWaveforms *output_waveforms);
|
OutputWaveforms *output_waveforms);
|
||||||
GateTableModel(LibertyCell *cell,
|
GateTableModel(LibertyCell *cell,
|
||||||
TableModel *delay_model,
|
TableModels *delay_models,
|
||||||
TableModel *slew_model);
|
TableModels *slew_models);
|
||||||
~GateTableModel() override;
|
~GateTableModel() override;
|
||||||
void gateDelay(const Pvt *pvt,
|
void gateDelay(const Pvt *pvt,
|
||||||
float in_slew,
|
float in_slew,
|
||||||
float load_cap,
|
float load_cap,
|
||||||
bool pocv_enabled,
|
|
||||||
// Return values.
|
// Return values.
|
||||||
ArcDelay &gate_delay,
|
float &gate_delay,
|
||||||
Slew &drvr_slew) const override;
|
float &drvr_slew) const override;
|
||||||
// deprecated 2024-01-07
|
// Fill in pocv parameters in gate_delay, drvr_slew.
|
||||||
// related_out_cap arg removed.
|
void gateDelayPocv(const Pvt *pvt,
|
||||||
void gateDelay(const Pvt *pvt,
|
float in_slew,
|
||||||
float in_slew,
|
float load_cap,
|
||||||
float load_cap,
|
const MinMax *min_max,
|
||||||
float related_out_cap,
|
PocvMode pocv_mode,
|
||||||
bool pocv_enabled,
|
// Return values.
|
||||||
ArcDelay &gate_delay,
|
ArcDelay &gate_delay,
|
||||||
Slew &drvr_slew) const __attribute__ ((deprecated));
|
Slew &drvr_slew) const override;
|
||||||
std::string reportGateDelay(const Pvt *pvt,
|
std::string reportGateDelay(const Pvt *pvt,
|
||||||
float in_slew,
|
float in_slew,
|
||||||
float load_cap,
|
float load_cap,
|
||||||
bool pocv_enabled,
|
const MinMax *min_max,
|
||||||
|
PocvMode pocv_mode,
|
||||||
int digits) const override;
|
int digits) const override;
|
||||||
float driveResistance(const Pvt *pvt) const override;
|
float driveResistance(const Pvt *pvt) const override;
|
||||||
|
|
||||||
const TableModel *delayModel() const { return delay_model_.get(); }
|
const TableModels *delayModels() const { return delay_models_.get(); }
|
||||||
const TableModel *slewModel() const { return slew_model_.get(); }
|
const TableModel *delayModel() const;
|
||||||
const TableModel *delaySigmaModel(const EarlyLate *el) const;
|
const TableModels *slewModels() const { return slew_models_.get(); }
|
||||||
const TableModel *slewSigmaModel(const EarlyLate *el) const;
|
const TableModel *slewModel() const;
|
||||||
const ReceiverModel *receiverModel() const { return receiver_model_.get(); }
|
const ReceiverModel *receiverModel() const { return receiver_model_.get(); }
|
||||||
OutputWaveforms *outputWaveforms() const { return output_waveforms_.get(); }
|
OutputWaveforms *outputWaveforms() const { return output_waveforms_.get(); }
|
||||||
// Check the axes before making the model.
|
// Check the axes before making the model.
|
||||||
|
|
@ -138,10 +138,8 @@ protected:
|
||||||
float &axis_value3) const;
|
float &axis_value3) const;
|
||||||
static bool checkAxis(const TableAxis *axis);
|
static bool checkAxis(const TableAxis *axis);
|
||||||
|
|
||||||
std::unique_ptr<TableModel> delay_model_;
|
std::unique_ptr<TableModels> delay_models_;
|
||||||
TableModelsEarlyLate delay_sigma_models_;
|
std::unique_ptr<TableModels> slew_models_;
|
||||||
std::unique_ptr<TableModel> slew_model_;
|
|
||||||
TableModelsEarlyLate slew_sigma_models_;
|
|
||||||
ReceiverModelPtr receiver_model_;
|
ReceiverModelPtr receiver_model_;
|
||||||
std::unique_ptr<OutputWaveforms> output_waveforms_;
|
std::unique_ptr<OutputWaveforms> output_waveforms_;
|
||||||
};
|
};
|
||||||
|
|
@ -150,25 +148,24 @@ class CheckTableModel : public CheckTimingModel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CheckTableModel(LibertyCell *cell,
|
CheckTableModel(LibertyCell *cell,
|
||||||
TableModel *model,
|
TableModels *check_models);
|
||||||
TableModelsEarlyLate sigma_models);
|
|
||||||
CheckTableModel(LibertyCell *cell,
|
|
||||||
TableModel *model);
|
|
||||||
~CheckTableModel() override;
|
~CheckTableModel() override;
|
||||||
ArcDelay checkDelay(const Pvt *pvt,
|
ArcDelay checkDelay(const Pvt *pvt,
|
||||||
float from_slew,
|
float from_slew,
|
||||||
float to_slew,
|
float to_slew,
|
||||||
float related_out_cap,
|
float related_out_cap,
|
||||||
bool pocv_enabled) const override;
|
const MinMax *min_max,
|
||||||
|
PocvMode pocv_mode) const override;
|
||||||
std::string reportCheckDelay(const Pvt *pvt,
|
std::string reportCheckDelay(const Pvt *pvt,
|
||||||
float from_slew,
|
float from_slew,
|
||||||
const char *from_slew_annotation,
|
const char *from_slew_annotation,
|
||||||
float to_slew,
|
float to_slew,
|
||||||
float related_out_cap,
|
float related_out_cap,
|
||||||
bool pocv_enabled,
|
const MinMax *min_max,
|
||||||
|
PocvMode pocv_mode,
|
||||||
int digits) const override;
|
int digits) const override;
|
||||||
const TableModel *model() const { return model_.get(); }
|
const TableModels *checkModels() const { return check_models_.get(); }
|
||||||
const TableModel *sigmaModel(const EarlyLate *el) const;
|
const TableModel *checkModel() const;
|
||||||
|
|
||||||
// Check the axes before making the model.
|
// Check the axes before making the model.
|
||||||
// Return true if the model axes are supported.
|
// Return true if the model axes are supported.
|
||||||
|
|
@ -202,8 +199,7 @@ protected:
|
||||||
int digits) const;
|
int digits) const;
|
||||||
static bool checkAxis(const TableAxis *axis);
|
static bool checkAxis(const TableAxis *axis);
|
||||||
|
|
||||||
std::unique_ptr<TableModel> model_;
|
std::unique_ptr<TableModels> check_models_;
|
||||||
TableModelsEarlyLate sigma_models_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class TableAxis
|
class TableAxis
|
||||||
|
|
@ -311,6 +307,8 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void clear();
|
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,
|
std::string reportValueOrder0(const char *result_name,
|
||||||
const char *comment1,
|
const char *comment1,
|
||||||
const Unit *table_unit,
|
const Unit *table_unit,
|
||||||
|
|
@ -408,6 +406,34 @@ protected:
|
||||||
bool is_scaled_:1;
|
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
|
class ReceiverModel
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@
|
||||||
|
|
||||||
#include "Delay.hh"
|
#include "Delay.hh"
|
||||||
#include "LibertyClass.hh"
|
#include "LibertyClass.hh"
|
||||||
|
#include "Variables.hh"
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
||||||
|
|
@ -52,14 +53,23 @@ public:
|
||||||
virtual void gateDelay(const Pvt *pvt,
|
virtual void gateDelay(const Pvt *pvt,
|
||||||
float in_slew,
|
float in_slew,
|
||||||
float load_cap,
|
float load_cap,
|
||||||
bool pocv_enabled,
|
|
||||||
// Return values.
|
// Return values.
|
||||||
ArcDelay &gate_delay,
|
float &gate_delay,
|
||||||
Slew &drvr_slew) const = 0;
|
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,
|
virtual std::string reportGateDelay(const Pvt *pvt,
|
||||||
float in_slew,
|
float in_slew,
|
||||||
float load_cap,
|
float load_cap,
|
||||||
bool pocv_enabled,
|
const MinMax *min_max,
|
||||||
|
PocvMode pocv_mode,
|
||||||
int digits) const = 0;
|
int digits) const = 0;
|
||||||
virtual float driveResistance(const Pvt *pvt) const = 0;
|
virtual float driveResistance(const Pvt *pvt) const = 0;
|
||||||
};
|
};
|
||||||
|
|
@ -74,13 +84,15 @@ public:
|
||||||
float from_slew,
|
float from_slew,
|
||||||
float to_slew,
|
float to_slew,
|
||||||
float related_out_cap,
|
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,
|
virtual std::string reportCheckDelay(const Pvt *pvt,
|
||||||
float from_slew,
|
float from_slew,
|
||||||
const char *from_slew_annotation,
|
const char *from_slew_annotation,
|
||||||
float to_slew,
|
float to_slew,
|
||||||
float related_out_cap,
|
float related_out_cap,
|
||||||
bool pocv_enabled,
|
const MinMax *min_max,
|
||||||
|
PocvMode pocv_mode,
|
||||||
int digits) const = 0;
|
int digits) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "PocvMode.hh"
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
||||||
enum class CrprMode { same_pin, same_transition };
|
enum class CrprMode { same_pin, same_transition };
|
||||||
|
|
@ -72,8 +74,11 @@ public:
|
||||||
// TCL variable sta_input_port_default_clock.
|
// TCL variable sta_input_port_default_clock.
|
||||||
bool useDefaultArrivalClock() { return use_default_arrival_clock_; }
|
bool useDefaultArrivalClock() { return use_default_arrival_clock_; }
|
||||||
void setUseDefaultArrivalClock(bool enable);
|
void setUseDefaultArrivalClock(bool enable);
|
||||||
bool pocvEnabled() const { return pocv_enabled_; }
|
bool pocvEnabled() const;
|
||||||
void setPocvEnabled(bool enabled);
|
PocvMode pocvMode() const { return pocv_mode_; }
|
||||||
|
void setPocvMode(PocvMode mode);
|
||||||
|
float pocvQuantile() const { return pocv_quantile_; }
|
||||||
|
void setPocvQuantile(float quartile);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool crpr_enabled_;
|
bool crpr_enabled_;
|
||||||
|
|
@ -88,7 +93,8 @@ private:
|
||||||
bool dynamic_loop_breaking_;
|
bool dynamic_loop_breaking_;
|
||||||
bool propagate_all_clks_;
|
bool propagate_all_clks_;
|
||||||
bool use_default_arrival_clock_;
|
bool use_default_arrival_clock_;
|
||||||
bool pocv_enabled_;
|
PocvMode pocv_mode_;
|
||||||
|
float pocv_quantile_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ InternalPower::InternalPower(LibertyPort *port,
|
||||||
LibertyPort *related_port,
|
LibertyPort *related_port,
|
||||||
LibertyPort *related_pg_pin,
|
LibertyPort *related_pg_pin,
|
||||||
const std::shared_ptr<FuncExpr> &when,
|
const std::shared_ptr<FuncExpr> &when,
|
||||||
InternalPowerModels &models) :
|
const InternalPowerModels &models) :
|
||||||
port_(port),
|
port_(port),
|
||||||
related_port_(related_port),
|
related_port_(related_port),
|
||||||
related_pg_pin_(related_pg_pin),
|
related_pg_pin_(related_pg_pin),
|
||||||
|
|
@ -52,36 +52,32 @@ InternalPower::libertyCell() const
|
||||||
return port_->libertyCell();
|
return port_->libertyCell();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const InternalPowerModel &
|
||||||
|
InternalPower::model(const RiseFall *rf) const
|
||||||
|
{
|
||||||
|
return models_[rf->index()];
|
||||||
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
InternalPower::power(const RiseFall *rf,
|
InternalPower::power(const RiseFall *rf,
|
||||||
const Pvt *pvt,
|
const Pvt *pvt,
|
||||||
float in_slew,
|
float in_slew,
|
||||||
float load_cap) const
|
float load_cap) const
|
||||||
{
|
{
|
||||||
const std::shared_ptr<InternalPowerModel> &model = models_[rf->index()];
|
const InternalPowerModel &model = models_[rf->index()];
|
||||||
if (model)
|
return model.power(libertyCell(), pvt, in_slew, load_cap);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
InternalPowerModel::InternalPowerModel(TableModel *model) :
|
InternalPowerModel::InternalPowerModel() :
|
||||||
model_(model)
|
model_(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
InternalPowerModel::~InternalPowerModel()
|
InternalPowerModel::InternalPowerModel(std::shared_ptr<TableModel> model) :
|
||||||
|
model_(model)
|
||||||
{
|
{
|
||||||
delete model_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
|
|
|
||||||
|
|
@ -1262,7 +1262,7 @@ LibertyCell::makeInternalPower(LibertyPort *port,
|
||||||
LibertyPort *related_port,
|
LibertyPort *related_port,
|
||||||
LibertyPort *related_pg_pin,
|
LibertyPort *related_pg_pin,
|
||||||
const std::shared_ptr<FuncExpr> &when,
|
const std::shared_ptr<FuncExpr> &when,
|
||||||
InternalPowerModels &models)
|
const InternalPowerModels &models)
|
||||||
{
|
{
|
||||||
internal_powers_.emplace_back(port, related_port, related_pg_pin, when, models);
|
internal_powers_.emplace_back(port, related_port, related_pg_pin, when, models);
|
||||||
port_internal_powers_[port].push_back(internal_powers_.size() - 1);
|
port_internal_powers_[port].push_back(internal_powers_.size() - 1);
|
||||||
|
|
|
||||||
|
|
@ -2122,80 +2122,76 @@ LibertyReader::makeTableModels(LibertyCell *cell,
|
||||||
{
|
{
|
||||||
bool found_model = false;
|
bool found_model = false;
|
||||||
for (const RiseFall *rf : RiseFall::range()) {
|
for (const RiseFall *rf : RiseFall::range()) {
|
||||||
std::string delay_attr_name = "cell_" + rf->to_string();
|
TableModel *delay_model = readTableModel(timing_group,
|
||||||
TableModel *delay = readGateTableModel(timing_group, delay_attr_name.c_str(), rf,
|
"cell_" + rf->to_string(),
|
||||||
TableTemplateType::delay, time_scale_,
|
rf, TableTemplateType::delay,
|
||||||
ScaleFactorType::cell);
|
time_scale_,
|
||||||
std::string transition_attr_name = rf->to_string() + "_transition";
|
ScaleFactorType::cell,
|
||||||
TableModel *transition = readGateTableModel(timing_group,
|
GateTableModel::checkAxes);
|
||||||
transition_attr_name.c_str(),
|
TableModel *slew_model = readTableModel(timing_group,
|
||||||
rf, TableTemplateType::delay,
|
rf->to_string() + "_transition",
|
||||||
time_scale_,
|
rf, TableTemplateType::delay,
|
||||||
ScaleFactorType::transition);
|
time_scale_,
|
||||||
if (delay || transition) {
|
ScaleFactorType::transition,
|
||||||
std::string delay_sigma_attr_name = "ocv_sigma_cell_" + rf->to_string();
|
GateTableModel::checkAxes);
|
||||||
TableModelsEarlyLate delay_sigmas =
|
if (delay_model || slew_model) {
|
||||||
readEarlyLateTableModels(timing_group,
|
TableModels *delay_models = new TableModels(delay_model);
|
||||||
delay_sigma_attr_name.c_str(),
|
readLvfModels(timing_group,
|
||||||
rf, TableTemplateType::delay,
|
"ocv_sigma_cell_" + rf->to_string(),
|
||||||
time_scale_,
|
"ocv_std_dev_cell_" + rf->to_string(),
|
||||||
ScaleFactorType::unknown);
|
"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()
|
TableModels *slew_models = new TableModels(slew_model);
|
||||||
+ "_transition";
|
readLvfModels(timing_group,
|
||||||
TableModelsEarlyLate slew_sigmas =
|
"ocv_sigma_" + rf->to_string() + "_transition",
|
||||||
readEarlyLateTableModels(timing_group,
|
"ocv_std_dev_" + rf->to_string() + "_transition",
|
||||||
slew_sigma_attr_name.c_str(),
|
"ocv_mean_shift_" + rf->to_string() + "_transition",
|
||||||
rf, TableTemplateType::delay,
|
"ocv_skewness_" + rf->to_string() + "_transition",
|
||||||
time_scale_,
|
rf, slew_models, GateTableModel::checkAxes);
|
||||||
ScaleFactorType::unknown);
|
|
||||||
|
|
||||||
ReceiverModelPtr receiver_model = readReceiverCapacitance(timing_group, rf);
|
ReceiverModelPtr receiver_model = readReceiverCapacitance(timing_group, rf);
|
||||||
OutputWaveforms *output_waveforms = readOutputWaveforms(timing_group, rf);
|
OutputWaveforms *output_waveforms = readOutputWaveforms(timing_group, rf);
|
||||||
|
|
||||||
timing_attrs->setModel(rf, new GateTableModel(cell, delay,
|
timing_attrs->setModel(rf, new GateTableModel(cell, delay_models,
|
||||||
std::move(delay_sigmas),
|
slew_models,
|
||||||
transition,
|
|
||||||
std::move(slew_sigmas),
|
|
||||||
receiver_model,
|
receiver_model,
|
||||||
output_waveforms));
|
output_waveforms));
|
||||||
TimingType timing_type = timing_attrs->timingType();
|
TimingType timing_type = timing_attrs->timingType();
|
||||||
if (isGateTimingType(timing_type)) {
|
if (isGateTimingType(timing_type)) {
|
||||||
if (transition == nullptr)
|
if (slew_model == nullptr)
|
||||||
libWarn(1210, timing_group, "missing %s_transition.", rf->name());
|
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());
|
libWarn(1211, timing_group, "missing cell_%s.", rf->name());
|
||||||
}
|
}
|
||||||
found_model = true;
|
found_model = true;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
std::string constraint_attr_name = rf->to_string() + "_constraint";
|
std::string constraint_attr_name = rf->to_string() + "_constraint";
|
||||||
ScaleFactorType scale_factor_type =
|
ScaleFactorType scale_factor_type =
|
||||||
timingTypeScaleFactorType(timing_attrs->timingType());
|
timingTypeScaleFactorType(timing_attrs->timingType());
|
||||||
TableModel *constraint = readCheckTableModel(timing_group,
|
TableModel *check_model = readTableModel(timing_group,
|
||||||
constraint_attr_name.c_str(),
|
constraint_attr_name.c_str(),
|
||||||
rf, TableTemplateType::delay,
|
rf, TableTemplateType::delay,
|
||||||
time_scale_, scale_factor_type);
|
time_scale_, scale_factor_type,
|
||||||
if (constraint) {
|
CheckTableModel::checkAxes);
|
||||||
std::string constraint_sigma_attr_name = "ocv_sigma_" + rf->to_string()
|
if (check_model) {
|
||||||
+ "_constraint";
|
TableModels *check_models = new TableModels(check_model);
|
||||||
TableModelsEarlyLate constraint_sigmas =
|
readLvfModels(timing_group,
|
||||||
readEarlyLateTableModels(timing_group,
|
"ocv_sigma_" + rf->to_string() + "_constraint",
|
||||||
constraint_sigma_attr_name.c_str(),
|
"ocv_std_dev_" + rf->to_string() + "_constraint",
|
||||||
rf, TableTemplateType::delay,
|
"ocv_mean_shift_" + rf->to_string() + "_constraint",
|
||||||
time_scale_,
|
"ocv_skewness_" + rf->to_string() + "_constraint",
|
||||||
ScaleFactorType::unknown);
|
rf, check_models, CheckTableModel::checkAxes);
|
||||||
timing_attrs->setModel(rf, new CheckTableModel(cell, constraint,
|
timing_attrs->setModel(rf, new CheckTableModel(cell, check_models));
|
||||||
std::move(constraint_sigmas)));
|
found_model = true;
|
||||||
found_model = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!found_model)
|
if (!found_model)
|
||||||
libWarn(1311, timing_group, "no table models found in timing group.");
|
libWarn(1311, timing_group, "no table models found in timing group.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
LibertyReader::isGateTimingType(TimingType timing_type)
|
LibertyReader::isGateTimingType(TimingType timing_type)
|
||||||
{
|
{
|
||||||
|
|
@ -2215,41 +2211,66 @@ LibertyReader::isGateTimingType(TimingType timing_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
TableModel *
|
TableModel *
|
||||||
LibertyReader::readGateTableModel(const LibertyGroup *timing_group,
|
LibertyReader::readTableModel(const LibertyGroup *timing_group,
|
||||||
const char *table_group_name,
|
const std::string &table_group_name,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
TableTemplateType template_type,
|
TableTemplateType template_type,
|
||||||
float scale,
|
float scale,
|
||||||
ScaleFactorType scale_factor_type)
|
ScaleFactorType scale_factor_type,
|
||||||
|
const std::function<bool(TableModel *model)> check_axes)
|
||||||
{
|
{
|
||||||
const LibertyGroup *table_group = timing_group->findSubgroup(table_group_name);
|
const LibertyGroup *table_group = timing_group->findSubgroup(table_group_name);
|
||||||
if (table_group) {
|
if (table_group)
|
||||||
TableModel *model = readTableModel(table_group, rf, template_type, scale,
|
return readTableModel(table_group, rf, template_type, scale,
|
||||||
scale_factor_type);
|
scale_factor_type, check_axes);
|
||||||
if (model && !GateTableModel::checkAxes(model))
|
|
||||||
libWarn(1251, table_group, "unsupported model axis.");
|
|
||||||
return model;
|
|
||||||
}
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
TableModel *
|
void
|
||||||
LibertyReader::readCheckTableModel(const LibertyGroup *timing_group,
|
LibertyReader::readLvfModels(const LibertyGroup *timing_group,
|
||||||
const char *table_group_name,
|
const std::string &sigma_group_name,
|
||||||
const RiseFall *rf,
|
const std::string &std_dev_group_name,
|
||||||
TableTemplateType template_type,
|
const std::string &mean_shift_group_name,
|
||||||
float scale,
|
const std::string &skewness_group_name,
|
||||||
ScaleFactorType scale_factor_type)
|
const RiseFall *rf,
|
||||||
|
TableModels *table_models,
|
||||||
|
const std::function<bool(TableModel *model)> check_axes)
|
||||||
{
|
{
|
||||||
const LibertyGroup *table_group = timing_group->findSubgroup(table_group_name);
|
TableModelsEarlyLate sigmas =
|
||||||
if (table_group) {
|
readEarlyLateTableModels(timing_group,
|
||||||
TableModel *model = readTableModel(table_group, rf, template_type, scale,
|
sigma_group_name.c_str(),
|
||||||
scale_factor_type);
|
rf, TableTemplateType::delay,
|
||||||
if (model && !CheckTableModel::checkAxes(model))
|
time_scale_,
|
||||||
libWarn(1252, table_group, "unsupported model axis.");
|
ScaleFactorType::unknown,
|
||||||
return model;
|
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
|
TableModelsEarlyLate
|
||||||
|
|
@ -2258,12 +2279,13 @@ LibertyReader::readEarlyLateTableModels(const LibertyGroup *timing_group,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
TableTemplateType template_type,
|
TableTemplateType template_type,
|
||||||
float scale,
|
float scale,
|
||||||
ScaleFactorType scale_factor_type)
|
ScaleFactorType scale_factor_type,
|
||||||
|
const std::function<bool(TableModel *model)> check_axes)
|
||||||
{
|
{
|
||||||
TableModelsEarlyLate models{};
|
TableModelsEarlyLate models{};
|
||||||
for (const LibertyGroup *table_group : timing_group->findSubgroups(table_group_name)) {
|
for (const LibertyGroup *table_group : timing_group->findSubgroups(table_group_name)) {
|
||||||
TableModel *model = readTableModel(table_group, rf, template_type, scale,
|
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");
|
const std::string *early_late = table_group->findAttrString("sigma_type");
|
||||||
if (early_late == nullptr
|
if (early_late == nullptr
|
||||||
|| *early_late == "early_and_late") {
|
|| *early_late == "early_and_late") {
|
||||||
|
|
@ -2274,9 +2296,6 @@ LibertyReader::readEarlyLateTableModels(const LibertyGroup *timing_group,
|
||||||
models[EarlyLate::early()->index()] = model;
|
models[EarlyLate::early()->index()] = model;
|
||||||
else if (*early_late == "late")
|
else if (*early_late == "late")
|
||||||
models[EarlyLate::late()->index()] = model;
|
models[EarlyLate::late()->index()] = model;
|
||||||
|
|
||||||
//if (model && !GateTableModel::checkAxes(model))
|
|
||||||
// libWarn(1182, table_group, "unsupported model axis.");
|
|
||||||
}
|
}
|
||||||
return models;
|
return models;
|
||||||
}
|
}
|
||||||
|
|
@ -2445,7 +2464,8 @@ LibertyReader::readTableModel(const LibertyGroup *table_group,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
TableTemplateType template_type,
|
TableTemplateType template_type,
|
||||||
float scale,
|
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();
|
const char *template_name = table_group->firstName();
|
||||||
if (library_ && template_name) {
|
if (library_ && template_name) {
|
||||||
|
|
@ -2456,6 +2476,9 @@ LibertyReader::readTableModel(const LibertyGroup *table_group,
|
||||||
if (table) {
|
if (table) {
|
||||||
TableModel *table_model = new TableModel(table, tbl_template,
|
TableModel *table_model = new TableModel(table, tbl_template,
|
||||||
scale_factor_type, rf);
|
scale_factor_type, rf);
|
||||||
|
if (!check_axes(table_model)) {
|
||||||
|
libWarn(1251, table_group, "unsupported model axis.");
|
||||||
|
}
|
||||||
return table_model;
|
return table_model;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2682,7 +2705,7 @@ LibertyReader::readInternalPowerGroups(LibertyCell *cell,
|
||||||
FuncExpr *when1 = readFuncExpr(cell, ipwr_group, "when");
|
FuncExpr *when1 = readFuncExpr(cell, ipwr_group, "when");
|
||||||
if (when1)
|
if (when1)
|
||||||
when = std::shared_ptr<FuncExpr>(when1);
|
when = std::shared_ptr<FuncExpr>(when1);
|
||||||
InternalPowerModels models;
|
InternalPowerModels models{};
|
||||||
// rise/fall_power group
|
// rise/fall_power group
|
||||||
for (const RiseFall *rf : RiseFall::range()) {
|
for (const RiseFall *rf : RiseFall::range()) {
|
||||||
std::string pwr_attr_name = rf->to_string() + "_power";
|
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,
|
TableModel *model = readTableModel(pwr_group, rf, TableTemplateType::power,
|
||||||
energyScale(),
|
energyScale(),
|
||||||
ScaleFactorType::internal_power);
|
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)
|
// power group (rise/fall power are the same)
|
||||||
|
|
@ -2701,9 +2726,11 @@ LibertyReader::readInternalPowerGroups(LibertyCell *cell,
|
||||||
TableTemplateType::power,
|
TableTemplateType::power,
|
||||||
energyScale(),
|
energyScale(),
|
||||||
ScaleFactorType::internal_power);
|
ScaleFactorType::internal_power);
|
||||||
auto pwr_model = std::make_shared<InternalPowerModel>(model);
|
std::shared_ptr<TableModel> table_model(model);
|
||||||
for (const RiseFall *rf : RiseFall::range())
|
for (const RiseFall *rf : RiseFall::range()) {
|
||||||
|
InternalPowerModel pwr_model(table_model);
|
||||||
models[rf->index()] = pwr_model;
|
models[rf->index()] = pwr_model;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (related_ports.empty())
|
if (related_ports.empty())
|
||||||
cell->makeInternalPower(port, nullptr, related_pg_port, when, models);
|
cell->makeInternalPower(port, nullptr, related_pg_port, when, models);
|
||||||
|
|
@ -2792,9 +2819,9 @@ LibertyReader::makeScalarCheckModel(LibertyCell *cell,
|
||||||
library_->findTableTemplate("scalar", TableTemplateType::delay);
|
library_->findTableTemplate("scalar", TableTemplateType::delay);
|
||||||
TableModel *table_model = new TableModel(table, tbl_template,
|
TableModel *table_model = new TableModel(table, tbl_template,
|
||||||
scale_factor_type, rf);
|
scale_factor_type, rf);
|
||||||
TableModelsEarlyLate sigmas{};
|
|
||||||
CheckTableModel *check_model = new CheckTableModel(cell, table_model,
|
TableModels *check_models = new TableModels(table_model);
|
||||||
std::move(sigmas));
|
TimingModel *check_model = new CheckTableModel(cell, check_models);
|
||||||
return check_model;
|
return check_model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3713,7 +3740,7 @@ PortNameBitIterator::init(const char *port_name)
|
||||||
range_bit_ = from;
|
range_bit_ = from;
|
||||||
findRangeBusNameNext();
|
findRangeBusNameNext();
|
||||||
}
|
}
|
||||||
size_ = abs(from - to) + 1;
|
size_ = std::abs(from - to) + 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
visitor_->libWarn(1294, line_, "port %s not found.", port_name);
|
visitor_->libWarn(1294, line_, "port %s not found.", port_name);
|
||||||
|
|
|
||||||
|
|
@ -232,25 +232,21 @@ protected:
|
||||||
const LibertyPortSeq &ports,
|
const LibertyPortSeq &ports,
|
||||||
const LibertyGroup *port_group);
|
const LibertyGroup *port_group);
|
||||||
bool isGateTimingType(TimingType timing_type);
|
bool isGateTimingType(TimingType timing_type);
|
||||||
TableModel *readGateTableModel(const LibertyGroup *timing_group,
|
TableModel *readTableModel(const LibertyGroup *timing_group,
|
||||||
const char *table_group_name,
|
const std::string &table_group_name,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
TableTemplateType template_type,
|
TableTemplateType template_type,
|
||||||
float scale,
|
float scale,
|
||||||
ScaleFactorType scale_factor_type);
|
ScaleFactorType scale_factor_type,
|
||||||
|
const std::function<bool(TableModel *model)> check_axes);
|
||||||
TableModelsEarlyLate
|
TableModelsEarlyLate
|
||||||
readEarlyLateTableModels(const LibertyGroup *timing_group,
|
readEarlyLateTableModels(const LibertyGroup *timing_group,
|
||||||
const char *table_group_name,
|
const char *table_group_name,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
TableTemplateType template_type,
|
TableTemplateType template_type,
|
||||||
float scale,
|
float scale,
|
||||||
ScaleFactorType scale_factor_type);
|
ScaleFactorType scale_factor_type,
|
||||||
TableModel *readCheckTableModel(const LibertyGroup *timing_group,
|
const std::function<bool(TableModel *model)> check_axes);
|
||||||
const char *table_group_name,
|
|
||||||
const RiseFall *rf,
|
|
||||||
TableTemplateType template_type,
|
|
||||||
float scale,
|
|
||||||
ScaleFactorType scale_factor_type);
|
|
||||||
ReceiverModelPtr readReceiverCapacitance(const LibertyGroup *timing_group,
|
ReceiverModelPtr readReceiverCapacitance(const LibertyGroup *timing_group,
|
||||||
const RiseFall *rf);
|
const RiseFall *rf);
|
||||||
void readReceiverCapacitance(const LibertyGroup *timing_group,
|
void readReceiverCapacitance(const LibertyGroup *timing_group,
|
||||||
|
|
@ -268,7 +264,9 @@ protected:
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
TableTemplateType template_type,
|
TableTemplateType template_type,
|
||||||
float scale,
|
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,
|
TablePtr readTableModel(const LibertyGroup *table_group,
|
||||||
const TableTemplate *tbl_template,
|
const TableTemplate *tbl_template,
|
||||||
float scale);
|
float scale);
|
||||||
|
|
@ -281,6 +279,14 @@ protected:
|
||||||
void makeTableModels(LibertyCell *cell,
|
void makeTableModels(LibertyCell *cell,
|
||||||
const LibertyGroup *timing_group,
|
const LibertyGroup *timing_group,
|
||||||
TimingArcAttrsPtr timing_attrs);
|
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,
|
TableAxisPtr makeTableAxis(const LibertyGroup *table_group,
|
||||||
const char *index_attr_name,
|
const char *index_attr_name,
|
||||||
|
|
|
||||||
|
|
@ -466,13 +466,14 @@ LibertyWriter::writeTimingModels(const TimingArc *arc,
|
||||||
const TableModel *slew_model = gate_model->slewModel();
|
const TableModel *slew_model = gate_model->slewModel();
|
||||||
if (slew_model) {
|
if (slew_model) {
|
||||||
const std::string &slew_template_name = slew_model->tblTemplate()->name();
|
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);
|
writeTableModel(slew_model);
|
||||||
fprintf(stream_, " }\n");
|
fprintf(stream_, " }\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (check_model) {
|
else if (check_model) {
|
||||||
const TableModel *model = check_model->model();
|
const TableModel *model = check_model->checkModel();
|
||||||
const std::string &template_name = model->tblTemplate()->name();
|
const std::string &template_name = model->tblTemplate()->name();
|
||||||
fprintf(stream_, " %s_constraint(%s) {\n", rf->name(), template_name.c_str());
|
fprintf(stream_, " %s_constraint(%s) {\n", rf->name(), template_name.c_str());
|
||||||
writeTableModel(model);
|
writeTableModel(model);
|
||||||
|
|
|
||||||
|
|
@ -42,20 +42,32 @@ void
|
||||||
GateLinearModel::gateDelay(const Pvt *,
|
GateLinearModel::gateDelay(const Pvt *,
|
||||||
float,
|
float,
|
||||||
float load_cap,
|
float load_cap,
|
||||||
bool,
|
|
||||||
// return values
|
// return values
|
||||||
ArcDelay &gate_delay,
|
float &gate_delay,
|
||||||
Slew &drvr_slew) const
|
float &drvr_slew) const
|
||||||
{
|
{
|
||||||
gate_delay = intrinsic_ + resistance_ * load_cap;
|
gate_delay = intrinsic_ + resistance_ * load_cap;
|
||||||
drvr_slew = 0.0;
|
drvr_slew = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
GateLinearModel::gateDelayPocv(const Pvt *,
|
||||||
|
float,
|
||||||
|
float,
|
||||||
|
const MinMax *,
|
||||||
|
PocvMode,
|
||||||
|
// return values
|
||||||
|
ArcDelay &,
|
||||||
|
Slew &) const
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
GateLinearModel::reportGateDelay(const Pvt *,
|
GateLinearModel::reportGateDelay(const Pvt *,
|
||||||
float,
|
float,
|
||||||
float load_cap,
|
float load_cap,
|
||||||
bool,
|
const MinMax *,
|
||||||
|
PocvMode,
|
||||||
int digits) const
|
int digits) const
|
||||||
{
|
{
|
||||||
const LibertyLibrary *library = cell_->libertyLibrary();
|
const LibertyLibrary *library = cell_->libertyLibrary();
|
||||||
|
|
@ -98,7 +110,8 @@ CheckLinearModel::checkDelay(const Pvt *,
|
||||||
float,
|
float,
|
||||||
float,
|
float,
|
||||||
float,
|
float,
|
||||||
bool) const
|
const MinMax *,
|
||||||
|
PocvMode) const
|
||||||
{
|
{
|
||||||
return intrinsic_;
|
return intrinsic_;
|
||||||
}
|
}
|
||||||
|
|
@ -109,7 +122,8 @@ CheckLinearModel::reportCheckDelay(const Pvt *,
|
||||||
const char *,
|
const char *,
|
||||||
float,
|
float,
|
||||||
float,
|
float,
|
||||||
bool,
|
const MinMax *,
|
||||||
|
PocvMode,
|
||||||
int digits) const
|
int digits) const
|
||||||
{
|
{
|
||||||
const LibertyLibrary *library = cell_->libertyLibrary();
|
const LibertyLibrary *library = cell_->libertyLibrary();
|
||||||
|
|
|
||||||
|
|
@ -38,8 +38,6 @@ namespace sta {
|
||||||
size_t
|
size_t
|
||||||
findValueIndex(float value,
|
findValueIndex(float value,
|
||||||
const FloatSeq *values);
|
const FloatSeq *values);
|
||||||
static void
|
|
||||||
sigmaModelsDelete(TableModelsEarlyLate &models);
|
|
||||||
static std::string
|
static std::string
|
||||||
reportPvt(const LibertyCell *cell,
|
reportPvt(const LibertyCell *cell,
|
||||||
const Pvt *pvt,
|
const Pvt *pvt,
|
||||||
|
|
@ -53,139 +51,189 @@ TimingModel::TimingModel(LibertyCell *cell) :
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
GateTableModel::GateTableModel(LibertyCell *cell,
|
GateTableModel::GateTableModel(LibertyCell *cell,
|
||||||
TableModel *delay_model,
|
TableModels *delay_models,
|
||||||
TableModelsEarlyLate delay_sigma_models,
|
TableModels *slew_models,
|
||||||
TableModel *slew_model,
|
|
||||||
TableModelsEarlyLate slew_sigma_models,
|
|
||||||
ReceiverModelPtr receiver_model,
|
ReceiverModelPtr receiver_model,
|
||||||
OutputWaveforms *output_waveforms) :
|
OutputWaveforms *output_waveforms) :
|
||||||
GateTimingModel(cell),
|
GateTimingModel(cell),
|
||||||
delay_model_(delay_model),
|
delay_models_(delay_models),
|
||||||
delay_sigma_models_(std::move(delay_sigma_models)),
|
slew_models_(slew_models),
|
||||||
slew_model_(slew_model),
|
|
||||||
slew_sigma_models_(std::move(slew_sigma_models)),
|
|
||||||
receiver_model_(receiver_model),
|
receiver_model_(receiver_model),
|
||||||
output_waveforms_(output_waveforms)
|
output_waveforms_(output_waveforms)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
GateTableModel::GateTableModel(LibertyCell *cell,
|
GateTableModel::GateTableModel(LibertyCell *cell,
|
||||||
TableModel *delay_model,
|
TableModels *delay_models,
|
||||||
TableModel *slew_model) :
|
TableModels *slew_models) :
|
||||||
GateTimingModel(cell),
|
GateTimingModel(cell),
|
||||||
delay_model_(delay_model),
|
delay_models_(delay_models),
|
||||||
delay_sigma_models_{},
|
slew_models_(slew_models),
|
||||||
slew_model_(slew_model),
|
|
||||||
slew_sigma_models_{},
|
|
||||||
receiver_model_(nullptr),
|
receiver_model_(nullptr),
|
||||||
output_waveforms_(nullptr)
|
output_waveforms_(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
GateTableModel::~GateTableModel()
|
GateTableModel::~GateTableModel() = default;
|
||||||
|
|
||||||
|
const TableModel *
|
||||||
|
GateTableModel::delayModel() const
|
||||||
{
|
{
|
||||||
sigmaModelsDelete(slew_sigma_models_);
|
return delay_models_ ? delay_models_->model() : nullptr;
|
||||||
sigmaModelsDelete(delay_sigma_models_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
const TableModel *
|
||||||
sigmaModelsDelete(TableModelsEarlyLate &models)
|
GateTableModel::slewModel() const
|
||||||
{
|
{
|
||||||
TableModel *early_model = models[EarlyLate::earlyIndex()];
|
return slew_models_ ? slew_models_->model() : nullptr;;
|
||||||
TableModel *late_model = models[EarlyLate::lateIndex()];
|
|
||||||
if (early_model == late_model)
|
|
||||||
delete early_model;
|
|
||||||
else {
|
|
||||||
delete early_model;
|
|
||||||
delete late_model;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
GateTableModel::setIsScaled(bool is_scaled)
|
GateTableModel::setIsScaled(bool is_scaled)
|
||||||
{
|
{
|
||||||
if (delay_model_)
|
if (delay_models_)
|
||||||
delay_model_->setIsScaled(is_scaled);
|
delay_models_->model()->setIsScaled(is_scaled);
|
||||||
if (slew_model_)
|
if (slew_models_)
|
||||||
slew_model_->setIsScaled(is_scaled);
|
slew_models_->model()->setIsScaled(is_scaled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
GateTableModel::gateDelay(const Pvt *pvt,
|
GateTableModel::gateDelay(const Pvt *pvt,
|
||||||
float in_slew,
|
float in_slew,
|
||||||
float load_cap,
|
float load_cap,
|
||||||
bool pocv_enabled,
|
|
||||||
// return values
|
// return values
|
||||||
ArcDelay &gate_delay,
|
float &gate_delay,
|
||||||
Slew &drvr_slew) const
|
float &drvr_slew) const
|
||||||
{
|
{
|
||||||
float delay = findValue(pvt, delay_model_.get(), in_slew, load_cap, 0.0);
|
if (delay_models_)
|
||||||
float sigma_early = 0.0;
|
gate_delay = findValue(pvt, delay_models_->model(), in_slew, load_cap, 0.0);
|
||||||
float sigma_late = 0.0;
|
else
|
||||||
if (pocv_enabled && delay_sigma_models_[EarlyLate::earlyIndex()])
|
gate_delay = 0.0;
|
||||||
sigma_early = findValue(pvt, delay_sigma_models_[EarlyLate::earlyIndex()],
|
if (slew_models_)
|
||||||
in_slew, load_cap, 0.0);
|
drvr_slew = findValue(pvt, slew_models_->model(), in_slew, load_cap, 0.0);
|
||||||
if (pocv_enabled && delay_sigma_models_[EarlyLate::lateIndex()])
|
else
|
||||||
sigma_late = findValue(pvt, delay_sigma_models_[EarlyLate::lateIndex()],
|
drvr_slew = 0.0;
|
||||||
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);
|
|
||||||
// Clip negative slews to zero.
|
// Clip negative slews to zero.
|
||||||
if (slew < 0.0)
|
if (drvr_slew < 0.0)
|
||||||
slew = 0.0;
|
drvr_slew = 0.0;
|
||||||
drvr_slew = makeDelay(slew, sigma_early, sigma_late);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
GateTableModel::gateDelay(const Pvt *pvt,
|
GateTableModel::gateDelayPocv(const Pvt *pvt,
|
||||||
float in_slew,
|
float in_slew,
|
||||||
float load_cap,
|
float load_cap,
|
||||||
float,
|
const MinMax *min_max,
|
||||||
bool pocv_enabled,
|
PocvMode pocv_mode,
|
||||||
ArcDelay &gate_delay,
|
// return values
|
||||||
Slew &drvr_slew) const
|
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
|
std::string
|
||||||
GateTableModel::reportGateDelay(const Pvt *pvt,
|
GateTableModel::reportGateDelay(const Pvt *pvt,
|
||||||
float in_slew,
|
float in_slew,
|
||||||
float load_cap,
|
float load_cap,
|
||||||
bool pocv_enabled,
|
const MinMax *min_max,
|
||||||
|
PocvMode pocv_mode,
|
||||||
int digits) const
|
int digits) const
|
||||||
{
|
{
|
||||||
std::string result = reportPvt(cell_, pvt, digits);
|
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);
|
load_cap, 0.0, digits);
|
||||||
if (pocv_enabled && delay_sigma_models_[EarlyLate::earlyIndex()])
|
if (pocv_mode != PocvMode::scalar) {
|
||||||
result += reportTableLookup("Delay sigma(early)", pvt,
|
if (delay_models_->sigma(min_max))
|
||||||
delay_sigma_models_[EarlyLate::earlyIndex()],
|
result += reportTableLookup("Delay sigma(early)", pvt,
|
||||||
in_slew, load_cap, 0.0, digits);
|
delay_models_->sigma(min_max),
|
||||||
if (pocv_enabled && delay_sigma_models_[EarlyLate::lateIndex()])
|
in_slew, load_cap, 0.0, digits);
|
||||||
result += reportTableLookup("Delay sigma(late)", pvt,
|
if (delay_models_->sigma(EarlyLate::late()))
|
||||||
delay_sigma_models_[EarlyLate::lateIndex()],
|
result += reportTableLookup("Delay sigma(late)", pvt,
|
||||||
in_slew, load_cap, 0.0, digits);
|
delay_models_->sigma(min_max),
|
||||||
result += '\n';
|
in_slew, load_cap, 0.0, digits);
|
||||||
result += reportTableLookup("Slew", pvt, slew_model_.get(), in_slew,
|
result += '\n';
|
||||||
load_cap, 9.0, digits);
|
|
||||||
if (pocv_enabled && slew_sigma_models_[EarlyLate::earlyIndex()])
|
result += reportTableLookup("Slew", pvt, slew_models_->model(), in_slew,
|
||||||
result += reportTableLookup("Slew sigma(early)", pvt,
|
load_cap, 9.0, digits);
|
||||||
slew_sigma_models_[EarlyLate::earlyIndex()],
|
|
||||||
in_slew, load_cap, 0.0, digits);
|
if (slew_models_->sigma(EarlyLate::early()))
|
||||||
if (pocv_enabled && slew_sigma_models_[EarlyLate::lateIndex()])
|
result += reportTableLookup("Slew sigma(early)", pvt,
|
||||||
result += reportTableLookup("Slew sigma(late)", pvt,
|
slew_models_->sigma(min_max),
|
||||||
slew_sigma_models_[EarlyLate::lateIndex()],
|
in_slew, load_cap, 0.0, digits);
|
||||||
in_slew, load_cap, 0.0, digits);
|
if (slew_models_->sigma(EarlyLate::late()))
|
||||||
float drvr_slew = findValue(pvt, slew_model_.get(), in_slew, load_cap, 0.0);
|
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)
|
if (drvr_slew < 0.0)
|
||||||
result += "Negative slew clipped to 0.0\n";
|
result += "Negative slew clipped to 0.0\n";
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -284,46 +332,30 @@ GateTableModel::driveResistance(const Pvt *pvt) const
|
||||||
return slew / cap;
|
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
|
void
|
||||||
GateTableModel::maxCapSlew(float in_slew,
|
GateTableModel::maxCapSlew(float in_slew,
|
||||||
const Pvt *pvt,
|
const Pvt *pvt,
|
||||||
float &slew,
|
float &slew,
|
||||||
float &cap) const
|
float &cap) const
|
||||||
{
|
{
|
||||||
if (!slew_model_) {
|
TableModel *model = slew_models_->model();
|
||||||
cap = 1.0;
|
const TableAxis *axis1 = model->axis1();
|
||||||
slew = 0.0;
|
const TableAxis *axis2 = model->axis2();
|
||||||
return;
|
const TableAxis *axis3 = model->axis3();
|
||||||
}
|
|
||||||
const TableAxis *axis1 = slew_model_->axis1();
|
|
||||||
const TableAxis *axis2 = slew_model_->axis2();
|
|
||||||
const TableAxis *axis3 = slew_model_->axis3();
|
|
||||||
if (axis1
|
if (axis1
|
||||||
&& axis1->variable() == TableAxisVariable::total_output_net_capacitance) {
|
&& axis1->variable() == TableAxisVariable::total_output_net_capacitance) {
|
||||||
cap = axis1->axisValue(axis1->size() - 1);
|
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
|
else if (axis2
|
||||||
&& axis2->variable()==TableAxisVariable::total_output_net_capacitance) {
|
&& axis2->variable()==TableAxisVariable::total_output_net_capacitance) {
|
||||||
cap = axis2->axisValue(axis2->size() - 1);
|
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
|
else if (axis3
|
||||||
&& axis3->variable()==TableAxisVariable::total_output_net_capacitance) {
|
&& axis3->variable()==TableAxisVariable::total_output_net_capacitance) {
|
||||||
cap = axis3->axisValue(axis3->size() - 1);
|
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 {
|
else {
|
||||||
// Table not dependent on capacitance.
|
// Table not dependent on capacitance.
|
||||||
|
|
@ -416,38 +448,24 @@ ReceiverModel::checkAxes(const TableModel *table)
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
CheckTableModel::CheckTableModel(LibertyCell *cell,
|
CheckTableModel::CheckTableModel(LibertyCell *cell,
|
||||||
TableModel *model,
|
TableModels *check_models) :
|
||||||
TableModelsEarlyLate sigma_models) :
|
|
||||||
CheckTimingModel(cell),
|
CheckTimingModel(cell),
|
||||||
model_(model),
|
check_models_(check_models)
|
||||||
sigma_models_(std::move(sigma_models))
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckTableModel::CheckTableModel(LibertyCell *cell,
|
CheckTableModel::~CheckTableModel() = default;
|
||||||
TableModel *model) :
|
|
||||||
CheckTimingModel(cell),
|
|
||||||
model_(model),
|
|
||||||
sigma_models_{}
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
CheckTableModel::~CheckTableModel()
|
const TableModel *
|
||||||
|
CheckTableModel::checkModel() const
|
||||||
{
|
{
|
||||||
sigmaModelsDelete(sigma_models_);
|
return check_models_ ? check_models_->model() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CheckTableModel::setIsScaled(bool is_scaled)
|
CheckTableModel::setIsScaled(bool is_scaled)
|
||||||
{
|
{
|
||||||
if (model_)
|
check_models_->model()->setIsScaled(is_scaled);
|
||||||
model_->setIsScaled(is_scaled);
|
|
||||||
}
|
|
||||||
|
|
||||||
const TableModel *
|
|
||||||
CheckTableModel::sigmaModel(const EarlyLate *el) const
|
|
||||||
{
|
|
||||||
return sigma_models_[el->index()];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ArcDelay
|
ArcDelay
|
||||||
|
|
@ -455,22 +473,51 @@ CheckTableModel::checkDelay(const Pvt *pvt,
|
||||||
float from_slew,
|
float from_slew,
|
||||||
float to_slew,
|
float to_slew,
|
||||||
float related_out_cap,
|
float related_out_cap,
|
||||||
bool pocv_enabled) const
|
const MinMax *min_max,
|
||||||
|
PocvMode pocv_mode) const
|
||||||
{
|
{
|
||||||
if (model_) {
|
ArcDelay check_delay;
|
||||||
float mean = findValue(pvt, model_.get(), from_slew, to_slew, related_out_cap);
|
if (check_models_) {
|
||||||
float sigma_early = 0.0;
|
float margin = findValue(pvt, check_models_->model(), from_slew,
|
||||||
float sigma_late = 0.0;
|
to_slew, related_out_cap);
|
||||||
if (pocv_enabled && sigma_models_[EarlyLate::earlyIndex()])
|
check_delay.setMean(margin);
|
||||||
sigma_early = findValue(pvt, sigma_models_[EarlyLate::earlyIndex()],
|
|
||||||
from_slew, to_slew, related_out_cap);
|
switch (pocv_mode) {
|
||||||
if (pocv_enabled && sigma_models_[EarlyLate::lateIndex()])
|
case PocvMode::normal: {
|
||||||
sigma_late = findValue(pvt, sigma_models_[EarlyLate::lateIndex()],
|
TableModel *std_dev_model = check_models_->stdDev();
|
||||||
from_slew, to_slew, related_out_cap);
|
if (std_dev_model == nullptr)
|
||||||
return makeDelay(mean, sigma_early, sigma_late);
|
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 check_delay;
|
||||||
return 0.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
|
|
@ -496,22 +543,28 @@ CheckTableModel::reportCheckDelay(const Pvt *pvt,
|
||||||
const char *from_slew_annotation,
|
const char *from_slew_annotation,
|
||||||
float to_slew,
|
float to_slew,
|
||||||
float related_out_cap,
|
float related_out_cap,
|
||||||
bool pocv_enabled,
|
const MinMax *min_max,
|
||||||
|
PocvMode pocv_mode,
|
||||||
int digits) const
|
int digits) const
|
||||||
{
|
{
|
||||||
std::string result = reportTableDelay("Check", pvt, model_.get(),
|
std::string result = reportTableDelay("Check", pvt, check_models_->model(),
|
||||||
from_slew, from_slew_annotation, to_slew,
|
from_slew, from_slew_annotation, to_slew,
|
||||||
related_out_cap, digits);
|
related_out_cap, digits);
|
||||||
if (pocv_enabled && sigma_models_[EarlyLate::earlyIndex()])
|
switch (pocv_mode) {
|
||||||
result += reportTableDelay("Check sigma early", pvt,
|
case PocvMode::normal:
|
||||||
sigma_models_[EarlyLate::earlyIndex()],
|
case PocvMode::skew_normal: {
|
||||||
from_slew, from_slew_annotation, to_slew,
|
TableModel *check_table = check_models_->stdDev();
|
||||||
related_out_cap, digits);
|
if (check_table == nullptr)
|
||||||
if (pocv_enabled && sigma_models_[EarlyLate::lateIndex()])
|
check_table = check_models_->sigma(min_max);
|
||||||
result += reportTableDelay("Check sigma late", pvt,
|
if (check_table)
|
||||||
sigma_models_[EarlyLate::lateIndex()],
|
result += reportTableDelay("Check sigma", pvt, check_table,
|
||||||
from_slew, from_slew_annotation, to_slew,
|
from_slew, from_slew_annotation, to_slew,
|
||||||
related_out_cap, digits);
|
related_out_cap, digits);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -530,10 +583,11 @@ CheckTableModel::reportTableDelay(const char *result_name,
|
||||||
findAxisValues(from_slew, to_slew, related_out_cap,
|
findAxisValues(from_slew, to_slew, related_out_cap,
|
||||||
axis_value1, axis_value2, axis_value3);
|
axis_value1, axis_value2, axis_value3);
|
||||||
std::string result = reportPvt(cell_, pvt, digits);
|
std::string result = reportPvt(cell_, pvt, digits);
|
||||||
result += model_->reportValue(result_name, cell_, pvt,
|
const Unit *time_unit = cell_->libertyLibrary()->units()->timeUnit();
|
||||||
axis_value1, from_slew_annotation, axis_value2,
|
result += check_models_->model()->reportValue(result_name, cell_, pvt,
|
||||||
axis_value3,
|
axis_value1, from_slew_annotation,
|
||||||
cell_->libertyLibrary()->units()->timeUnit(), digits);
|
axis_value2, axis_value3,
|
||||||
|
time_unit, digits);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
|
|
@ -548,31 +602,32 @@ CheckTableModel::findAxisValues(float from_slew,
|
||||||
float &axis_value2,
|
float &axis_value2,
|
||||||
float &axis_value3) const
|
float &axis_value3) const
|
||||||
{
|
{
|
||||||
switch (model_->order()) {
|
TableModel *model = check_models_->model();
|
||||||
|
switch (model->order()) {
|
||||||
case 0:
|
case 0:
|
||||||
axis_value1 = 0.0;
|
axis_value1 = 0.0;
|
||||||
axis_value2 = 0.0;
|
axis_value2 = 0.0;
|
||||||
axis_value3 = 0.0;
|
axis_value3 = 0.0;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
axis_value1 = axisValue(model_->axis1(), from_slew, to_slew,
|
axis_value1 = axisValue(model->axis1(), from_slew, to_slew,
|
||||||
related_out_cap);
|
related_out_cap);
|
||||||
axis_value2 = 0.0;
|
axis_value2 = 0.0;
|
||||||
axis_value3 = 0.0;
|
axis_value3 = 0.0;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
axis_value1 = axisValue(model_->axis1(), from_slew, to_slew,
|
axis_value1 = axisValue(model->axis1(), from_slew, to_slew,
|
||||||
related_out_cap);
|
related_out_cap);
|
||||||
axis_value2 = axisValue(model_->axis2(), from_slew, to_slew,
|
axis_value2 = axisValue(model->axis2(), from_slew, to_slew,
|
||||||
related_out_cap);
|
related_out_cap);
|
||||||
axis_value3 = 0.0;
|
axis_value3 = 0.0;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
axis_value1 = axisValue(model_->axis1(), from_slew, to_slew,
|
axis_value1 = axisValue(model->axis1(), from_slew, to_slew,
|
||||||
related_out_cap);
|
related_out_cap);
|
||||||
axis_value2 = axisValue(model_->axis2(), from_slew, to_slew,
|
axis_value2 = axisValue(model->axis2(), from_slew, to_slew,
|
||||||
related_out_cap);
|
related_out_cap);
|
||||||
axis_value3 = axisValue(model_->axis3(), from_slew, to_slew,
|
axis_value3 = axisValue(model->axis3(), from_slew, to_slew,
|
||||||
related_out_cap);
|
related_out_cap);
|
||||||
break;
|
break;
|
||||||
default:
|
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() :
|
TableModel::TableModel() :
|
||||||
table_(nullptr),
|
table_(nullptr),
|
||||||
tbl_template_(nullptr),
|
tbl_template_(nullptr),
|
||||||
|
|
@ -959,51 +1083,65 @@ Table::findValue(float axis_value1,
|
||||||
return value_;
|
return value_;
|
||||||
if (order_ == 1)
|
if (order_ == 1)
|
||||||
return findValue(axis_value1);
|
return findValue(axis_value1);
|
||||||
if (order_ == 2) {
|
if (order_ == 2)
|
||||||
size_t size1 = axis1_->size();
|
return findValueOrder2(axis_value1, axis_value2);
|
||||||
size_t size2 = axis2_->size();
|
else
|
||||||
if (size1 == 1) {
|
return findValueOrder3(axis_value1, axis_value2, axis_value3);
|
||||||
if (size2 == 1)
|
}
|
||||||
return value(0, 0);
|
|
||||||
size_t axis_index2 = axis2_->findAxisIndex(axis_value2);
|
float
|
||||||
double x2 = axis_value2;
|
Table::findValueOrder2(float axis_value1,
|
||||||
double y00 = value(0, axis_index2);
|
float axis_value2) const
|
||||||
double x2l = axis2_->axisValue(axis_index2);
|
{
|
||||||
double x2u = axis2_->axisValue(axis_index2 + 1);
|
size_t size1 = axis1_->size();
|
||||||
double dx2 = (x2 - x2l) / (x2u - x2l);
|
size_t size2 = axis2_->size();
|
||||||
double y01 = value(0, axis_index2 + 1);
|
if (size1 == 1) {
|
||||||
return (1 - dx2) * y00 + dx2 * y01;
|
if (size2 == 1)
|
||||||
}
|
return value(0, 0);
|
||||||
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);
|
size_t axis_index2 = axis2_->findAxisIndex(axis_value2);
|
||||||
double x1 = axis_value1;
|
|
||||||
double x2 = axis_value2;
|
double x2 = axis_value2;
|
||||||
double y00 = value(axis_index1, axis_index2);
|
double y00 = value(0, 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 x2l = axis2_->axisValue(axis_index2);
|
||||||
double x2u = axis2_->axisValue(axis_index2 + 1);
|
double x2u = axis2_->axisValue(axis_index2 + 1);
|
||||||
double dx2 = (x2 - x2l) / (x2u - x2l);
|
double dx2 = (x2 - x2l) / (x2u - x2l);
|
||||||
double y01 = value(axis_index1, axis_index2 + 1);
|
double y01 = value(0, axis_index2 + 1);
|
||||||
return (1 - dx1) * (1 - dx2) * y00
|
return (1 - dx2) * y00 + dx2 * y01;
|
||||||
+ dx1 * (1 - dx2) * y10
|
|
||||||
+ dx1 * dx2 * y11
|
|
||||||
+ (1 - dx1) * 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_index1 = axis1_->findAxisIndex(axis_value1);
|
||||||
size_t axis_index2 = axis2_->findAxisIndex(axis_value2);
|
size_t axis_index2 = axis2_->findAxisIndex(axis_value2);
|
||||||
size_t axis_index3 = axis3_->findAxisIndex(axis_value3);
|
size_t axis_index3 = axis3_->findAxisIndex(axis_value3);
|
||||||
|
|
|
||||||
|
|
@ -152,9 +152,8 @@ TimingArc::intrinsicDelay() const
|
||||||
{
|
{
|
||||||
GateTimingModel *model = dynamic_cast<GateTimingModel*>(model_);
|
GateTimingModel *model = dynamic_cast<GateTimingModel*>(model_);
|
||||||
if (model) {
|
if (model) {
|
||||||
ArcDelay arc_delay;
|
float arc_delay, slew;
|
||||||
Slew slew;
|
model->gateDelay(nullptr, 0.0, 0.0, arc_delay, slew);
|
||||||
model->gateDelay(nullptr, 0.0, 0.0, false, arc_delay, slew);
|
|
||||||
return arc_delay;
|
return arc_delay;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -1173,7 +1173,7 @@ Power::findInputInternalPower(const Pin *pin,
|
||||||
int rf_count = 0;
|
int rf_count = 0;
|
||||||
for (const RiseFall *rf : RiseFall::range()) {
|
for (const RiseFall *rf : RiseFall::range()) {
|
||||||
float slew = getSlew(vertex, rf, scene);
|
float slew = getSlew(vertex, rf, scene);
|
||||||
if (!delayInf(slew)) {
|
if (!delayInf(slew, this)) {
|
||||||
float table_energy = pwr->power(rf, pvt, slew, load_cap);
|
float table_energy = pwr->power(rf, pvt, slew, load_cap);
|
||||||
energy += table_energy;
|
energy += table_energy;
|
||||||
rf_count++;
|
rf_count++;
|
||||||
|
|
@ -1238,17 +1238,18 @@ Power::getMinRfSlew(const Pin *pin)
|
||||||
graph_->pinVertices(pin, vertex, bidir_vertex);
|
graph_->pinVertices(pin, vertex, bidir_vertex);
|
||||||
if (vertex) {
|
if (vertex) {
|
||||||
const MinMax *min_max = MinMax::min();
|
const MinMax *min_max = MinMax::min();
|
||||||
Slew mm_slew = min_max->initValue();
|
float mm_slew = min_max->initValue();
|
||||||
for (DcalcAPIndex ap_index = 0;
|
for (DcalcAPIndex ap_index = 0;
|
||||||
ap_index < dcalcAnalysisPtCount();
|
ap_index < dcalcAnalysisPtCount();
|
||||||
ap_index++) {
|
ap_index++) {
|
||||||
const Slew &slew1 = graph_->slew(vertex, RiseFall::rise(), ap_index);
|
const Slew &slew1 = graph_->slew(vertex, RiseFall::rise(), ap_index);
|
||||||
const Slew &slew2 = graph_->slew(vertex, RiseFall::fall(), ap_index);
|
const Slew &slew2 = graph_->slew(vertex, RiseFall::fall(), ap_index);
|
||||||
Slew slew = delayAsFloat(slew1 + slew2) / 2.0;
|
float slew_avg = (delayAsFloat(slew1, min_max, this)
|
||||||
if (delayGreater(slew, mm_slew, min_max, this))
|
+ delayAsFloat(slew2, min_max, this)) / 2.0;
|
||||||
mm_slew = slew;
|
if (delayGreater(slew_avg, mm_slew, min_max, this))
|
||||||
|
mm_slew = slew_avg;
|
||||||
}
|
}
|
||||||
return delayAsFloat(mm_slew);
|
return mm_slew;
|
||||||
}
|
}
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
@ -1343,7 +1344,7 @@ Power::findOutputInternalPower(const LibertyPort *to_port,
|
||||||
float slew = from_vertex
|
float slew = from_vertex
|
||||||
? getSlew(from_vertex, from_rf, scene)
|
? getSlew(from_vertex, from_rf, scene)
|
||||||
: 0.0;
|
: 0.0;
|
||||||
if (!delayInf(slew)) {
|
if (!delayInf(slew, this)) {
|
||||||
float table_energy = pwr->power(to_rf, pvt, slew, load_cap);
|
float table_energy = pwr->power(to_rf, pvt, slew, load_cap);
|
||||||
energy += table_energy;
|
energy += table_energy;
|
||||||
rf_count++;
|
rf_count++;
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,8 @@ Variables::Variables() :
|
||||||
dynamic_loop_breaking_(false),
|
dynamic_loop_breaking_(false),
|
||||||
propagate_all_clks_(false),
|
propagate_all_clks_(false),
|
||||||
use_default_arrival_clock_(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;
|
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
|
} // namespace
|
||||||
|
|
|
||||||
|
|
@ -735,7 +735,7 @@ SdfReader::setEdgeArcDelays(Edge *edge,
|
||||||
if (value_ptr) {
|
if (value_ptr) {
|
||||||
ArcDelay delay;
|
ArcDelay delay;
|
||||||
if (in_incremental_)
|
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
|
else
|
||||||
delay = *value_ptr;
|
delay = *value_ptr;
|
||||||
graph_->setArcDelay(edge, arc, arc_delay_index, delay);
|
graph_->setArcDelay(edge, arc, arc_delay_index, delay);
|
||||||
|
|
@ -784,7 +784,7 @@ SdfReader::setEdgeArcDelaysCondUse(Edge *edge,
|
||||||
&& triple_index != null_index_) {
|
&& triple_index != null_index_) {
|
||||||
ArcDelay delay(*value);
|
ArcDelay delay(*value);
|
||||||
if (!is_incremental_only_ && in_incremental_)
|
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)) {
|
else if (graph_->arcDelayAnnotated(edge, arc, arc_delay_index)) {
|
||||||
ArcDelay prev_value = graph_->arcDelay(edge, arc, arc_delay_index);
|
ArcDelay prev_value = graph_->arcDelay(edge, arc, arc_delay_index);
|
||||||
if (delayGreater(prev_value, delay, min_max, this))
|
if (delayGreater(prev_value, delay, min_max, this))
|
||||||
|
|
|
||||||
|
|
@ -430,11 +430,11 @@ SdfWriter::writeArcDelays(Edge *edge)
|
||||||
TimingArcSet *arc_set = edge->timingArcSet();
|
TimingArcSet *arc_set = edge->timingArcSet();
|
||||||
for (TimingArc *arc : arc_set->arcs()) {
|
for (TimingArc *arc : arc_set->arcs()) {
|
||||||
const RiseFall *rf = arc->toEdge()->asRiseFall();
|
const RiseFall *rf = arc->toEdge()->asRiseFall();
|
||||||
ArcDelay min_delay = graph_->arcDelay(edge, arc, arc_delay_min_index_);
|
const ArcDelay &min_delay = graph_->arcDelay(edge, arc, arc_delay_min_index_);
|
||||||
delays.setValue(rf, MinMax::min(), delayAsFloat(min_delay));
|
delays.setValue(rf, MinMax::min(), delayAsFloat(min_delay, MinMax::min(), this));
|
||||||
|
|
||||||
ArcDelay max_delay = graph_->arcDelay(edge, arc, arc_delay_max_index_);
|
const ArcDelay &max_delay = graph_->arcDelay(edge, arc, arc_delay_max_index_);
|
||||||
delays.setValue(rf, MinMax::max(), delayAsFloat(max_delay));
|
delays.setValue(rf, MinMax::max(), delayAsFloat(max_delay, MinMax::max(), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (delays.hasValue(RiseFall::rise(), MinMax::min())
|
if (delays.hasValue(RiseFall::rise(), MinMax::min())
|
||||||
|
|
@ -527,8 +527,10 @@ SdfWriter::writeTimingChecks(const Instance *inst,
|
||||||
TimingArc *arc;
|
TimingArc *arc;
|
||||||
graph_->minPulseWidthArc(vertex, hi_low, edge, arc);
|
graph_->minPulseWidthArc(vertex, hi_low, edge, arc);
|
||||||
if (edge) {
|
if (edge) {
|
||||||
min_width = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_min_index_));
|
min_width = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_min_index_),
|
||||||
max_width = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_max_index_));
|
MinMax::min(), this);
|
||||||
|
max_width = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_max_index_),
|
||||||
|
MinMax::max(), this);
|
||||||
ensureTimingCheckheaders(check_header, inst, inst_header);
|
ensureTimingCheckheaders(check_header, inst, inst_header);
|
||||||
writeWidthCheck(pin, hi_low, min_width, max_width);
|
writeWidthCheck(pin, hi_low, min_width, max_width);
|
||||||
}
|
}
|
||||||
|
|
@ -615,30 +617,37 @@ SdfWriter::writeEdgeCheck(Edge *edge,
|
||||||
if (arcs[clk_rf_index][RiseFall::riseIndex()]
|
if (arcs[clk_rf_index][RiseFall::riseIndex()]
|
||||||
&& arcs[clk_rf_index][RiseFall::fallIndex()]
|
&& arcs[clk_rf_index][RiseFall::fallIndex()]
|
||||||
&& arcs[clk_rf_index][RiseFall::riseIndex()]
|
&& arcs[clk_rf_index][RiseFall::riseIndex()]
|
||||||
&& arcs[clk_rf_index][RiseFall::fallIndex()]
|
&& arcs[clk_rf_index][RiseFall::fallIndex()]) {
|
||||||
&& delayEqual(graph_->arcDelay(edge,
|
float rise_min=delayAsFloat(graph_->arcDelay(edge,
|
||||||
arcs[clk_rf_index][RiseFall::riseIndex()],
|
arcs[clk_rf_index][RiseFall::riseIndex()],
|
||||||
arc_delay_min_index_),
|
arc_delay_min_index_),
|
||||||
graph_->arcDelay(edge,
|
MinMax::min(), this);
|
||||||
arcs[clk_rf_index][RiseFall::fallIndex()],
|
float fall_min=delayAsFloat(graph_->arcDelay(edge,
|
||||||
arc_delay_min_index_))
|
arcs[clk_rf_index][RiseFall::fallIndex()],
|
||||||
&& delayEqual(graph_->arcDelay(edge,
|
arc_delay_min_index_),
|
||||||
arcs[clk_rf_index][RiseFall::riseIndex()],
|
MinMax::min(), this);
|
||||||
arc_delay_max_index_),
|
float rise_max=delayAsFloat(graph_->arcDelay(edge,
|
||||||
graph_->arcDelay(edge,
|
arcs[clk_rf_index][RiseFall::riseIndex()],
|
||||||
arcs[clk_rf_index][RiseFall::fallIndex()],
|
arc_delay_max_index_),
|
||||||
arc_delay_max_index_)))
|
MinMax::max(), this);
|
||||||
// Rise/fall margins are the same, so no data edge specifier is required.
|
float fall_max=delayAsFloat(graph_->arcDelay(edge,
|
||||||
writeCheck(edge, arcs[clk_rf_index][RiseFall::riseIndex()],
|
arcs[clk_rf_index][RiseFall::fallIndex()],
|
||||||
sdf_check, false, true);
|
arc_delay_max_index_),
|
||||||
else {
|
MinMax::max(), this);
|
||||||
if (arcs[clk_rf_index][RiseFall::riseIndex()])
|
if (fuzzyEqual(rise_min, fall_min)
|
||||||
writeCheck(edge, arcs[clk_rf_index][RiseFall::riseIndex()],
|
&& fuzzyEqual(rise_max, fall_max)) {
|
||||||
sdf_check, true, true);
|
// Rise/fall margins are the same, so no data edge specifier is required.
|
||||||
if (arcs[clk_rf_index][RiseFall::fallIndex()])
|
writeCheck(edge, arcs[clk_rf_index][RiseFall::riseIndex()],
|
||||||
writeCheck(edge, arcs[clk_rf_index][RiseFall::fallIndex()],
|
sdf_check, false, true);
|
||||||
sdf_check, true, 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
|
void
|
||||||
|
|
@ -689,9 +698,11 @@ SdfWriter::writeCheck(Edge *edge,
|
||||||
|
|
||||||
gzprintf(stream_, " ");
|
gzprintf(stream_, " ");
|
||||||
|
|
||||||
ArcDelay min_delay = graph_->arcDelay(edge, arc, arc_delay_min_index_);
|
float min_delay = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_min_index_),
|
||||||
ArcDelay max_delay = graph_->arcDelay(edge, arc, arc_delay_max_index_);
|
MinMax::min(), this);
|
||||||
writeSdfTriple(delayAsFloat(min_delay), delayAsFloat(max_delay));
|
float max_delay = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_max_index_),
|
||||||
|
MinMax::max(), this);
|
||||||
|
writeSdfTriple(min_delay, max_delay);
|
||||||
|
|
||||||
gzprintf(stream_, ")\n");
|
gzprintf(stream_, ")\n");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -178,15 +178,15 @@ MaxSkewCheck::maxSkew(const StaState *sta) const
|
||||||
}
|
}
|
||||||
|
|
||||||
Delay
|
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
|
Slack
|
||||||
MaxSkewCheck::slack(const StaState *sta) const
|
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 slack1 = check1.slack(sta_);
|
||||||
Slack slack2 = check2.slack(sta_);
|
Slack slack2 = check2.slack(sta_);
|
||||||
return delayLess(slack1, slack2, sta_)
|
return delayLess(slack1, slack2, sta_)
|
||||||
|| (delayEqual(slack1, slack2)
|
|| (delayEqual(slack1, slack2, sta_)
|
||||||
// Break ties based on constrained pin names.
|
// Break ties based on constrained pin names.
|
||||||
&& sta_->network()->pinLess(check1.clkPin(sta_), check2.clkPin(sta_)));
|
&& sta_->network()->pinLess(check1.clkPin(sta_), check2.clkPin(sta_)));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ public:
|
||||||
Pin *clkPin(const StaState *sta) const;
|
Pin *clkPin(const StaState *sta) const;
|
||||||
const Path *refPath() const { return ref_path_; }
|
const Path *refPath() const { return ref_path_; }
|
||||||
Pin *refPin(const StaState *sta) const;
|
Pin *refPin(const StaState *sta) const;
|
||||||
Delay skew() const;
|
Delay skew(const StaState *sta) const;
|
||||||
ArcDelay maxSkew(const StaState *sta) const;
|
ArcDelay maxSkew(const StaState *sta) const;
|
||||||
Slack slack(const StaState *sta) const;
|
Slack slack(const StaState *sta) const;
|
||||||
TimingArc *checkArc() const { return check_arc_; }
|
TimingArc *checkArc() const { return check_arc_; }
|
||||||
|
|
|
||||||
|
|
@ -198,7 +198,7 @@ MinPeriodSlackLess::operator()(const MinPeriodCheck &check1,
|
||||||
const Pin *pin2 = check2.pin();
|
const Pin *pin2 = check2.pin();
|
||||||
return delayLess(slack1, slack2, sta_)
|
return delayLess(slack1, slack2, sta_)
|
||||||
// Break ties based on pin and clock names.
|
// Break ties based on pin and clock names.
|
||||||
|| (delayEqual(slack1, slack2)
|
|| (delayEqual(slack1, slack2, sta_)
|
||||||
&& (sta_->network()->pinLess(pin1, pin2)
|
&& (sta_->network()->pinLess(pin1, pin2)
|
||||||
|| (pin1 == pin2
|
|| (pin1 == pin2
|
||||||
&& ClockNameLess()(check1.clk(),
|
&& ClockNameLess()(check1.clk(),
|
||||||
|
|
|
||||||
|
|
@ -252,13 +252,13 @@ MinPulseWidthCheck::closeArrival(const StaState *sta) const
|
||||||
Arrival
|
Arrival
|
||||||
MinPulseWidthCheck::openDelay(const StaState *sta) const
|
MinPulseWidthCheck::openDelay(const StaState *sta) const
|
||||||
{
|
{
|
||||||
return openArrival(sta) - openClkEdge(sta)->time();
|
return delayDiff(openArrival(sta), openClkEdge(sta)->time(), sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
Arrival
|
Arrival
|
||||||
MinPulseWidthCheck::closeDelay(const StaState *sta) const
|
MinPulseWidthCheck::closeDelay(const StaState *sta) const
|
||||||
{
|
{
|
||||||
return closeArrival(sta) - closeClkEdge(sta)->time();
|
return delayDiff(closeArrival(sta), closeClkEdge(sta)->time(), sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ClockEdge *
|
const ClockEdge *
|
||||||
|
|
@ -289,9 +289,11 @@ MinPulseWidthCheck::closeOffset(const StaState *sta) const
|
||||||
Arrival
|
Arrival
|
||||||
MinPulseWidthCheck::width(const StaState *sta) const
|
MinPulseWidthCheck::width(const StaState *sta) const
|
||||||
{
|
{
|
||||||
return closeArrival(sta) + closeOffset(sta)
|
Arrival close_with_offset = delaySum(closeArrival(sta),
|
||||||
- open_path_->arrival()
|
closeOffset(sta),
|
||||||
+ checkCrpr(sta);
|
sta);
|
||||||
|
Arrival minus_open = delayDiff(close_with_offset, open_path_->arrival(), sta);
|
||||||
|
return delaySum(minus_open, checkCrpr(sta), sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
|
|
@ -323,6 +325,7 @@ minPulseWidth(const Path *path,
|
||||||
// set_min_pulse_width command.
|
// set_min_pulse_width command.
|
||||||
sdc->minPulseWidth(pin, clk, rf, min_width, exists);
|
sdc->minPulseWidth(pin, clk, rf, min_width, exists);
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
|
const MinMax *min_max = path->minMax(sta);
|
||||||
DcalcAPIndex dcalc_ap = path->dcalcAnalysisPtIndex(sta);
|
DcalcAPIndex dcalc_ap = path->dcalcAnalysisPtIndex(sta);
|
||||||
Vertex *vertex = path->vertex(sta);
|
Vertex *vertex = path->vertex(sta);
|
||||||
Graph *graph = sta->graph();
|
Graph *graph = sta->graph();
|
||||||
|
|
@ -330,7 +333,7 @@ minPulseWidth(const Path *path,
|
||||||
TimingArc *arc;
|
TimingArc *arc;
|
||||||
graph->minPulseWidthArc(vertex, rf, edge, arc);
|
graph->minPulseWidthArc(vertex, rf, edge, arc);
|
||||||
if (edge) {
|
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;
|
exists = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -350,7 +353,7 @@ MinPulseWidthCheck::checkCrpr(const StaState *sta) const
|
||||||
Slack
|
Slack
|
||||||
MinPulseWidthCheck::slack(const StaState *sta) const
|
MinPulseWidthCheck::slack(const StaState *sta) const
|
||||||
{
|
{
|
||||||
return width(sta) - minWidth(sta);
|
return delayDiff(width(sta), minWidth(sta), sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
Scene *
|
Scene *
|
||||||
|
|
@ -375,7 +378,7 @@ MinPulseWidthSlackLess::operator()(const MinPulseWidthCheck &check1,
|
||||||
const Pin *pin1 = check1.pin(sta_);
|
const Pin *pin1 = check1.pin(sta_);
|
||||||
const Pin *pin2 = check2.pin(sta_);
|
const Pin *pin2 = check2.pin(sta_);
|
||||||
return delayLess(slack1, slack2, sta_)
|
return delayLess(slack1, slack2, sta_)
|
||||||
|| (delayEqual(slack1, slack2)
|
|| (delayEqual(slack1, slack2, sta_)
|
||||||
// Break ties for the sake of regression stability.
|
// Break ties for the sake of regression stability.
|
||||||
&& (sta_->network()->pinLess(pin1, pin2)
|
&& (sta_->network()->pinLess(pin1, pin2)
|
||||||
|| (pin1 == pin2
|
|| (pin1 == pin2
|
||||||
|
|
|
||||||
|
|
@ -61,9 +61,9 @@ public:
|
||||||
StaState *sta);
|
StaState *sta);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static float insertionDelay(Path *clk_path,
|
static Delay insertionDelay(Path *clk_path,
|
||||||
StaState *sta);
|
StaState *sta);
|
||||||
static float delay(Path *clk_path,
|
static Delay delay(Path *clk_path,
|
||||||
StaState *sta);
|
StaState *sta);
|
||||||
static float clkTreeDelay(Path *clk_path,
|
static float clkTreeDelay(Path *clk_path,
|
||||||
StaState *sta);
|
StaState *sta);
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ ClkInfo::findHash(const StaState *sta)
|
||||||
hashIncr(hash_, hash_float(uncertainty));
|
hashIncr(hash_, hash_float(uncertainty));
|
||||||
}
|
}
|
||||||
hashIncr(hash_, hash_float(latency_));
|
hashIncr(hash_, hash_float(latency_));
|
||||||
hashIncr(hash_, hash_float(delayAsFloat(insertion_)));
|
hashIncr(hash_, hash_float(insertion_.mean()));
|
||||||
hashIncr(hash_, is_propagated_);
|
hashIncr(hash_, is_propagated_);
|
||||||
hashIncr(hash_, is_gen_clk_src_path_);
|
hashIncr(hash_, is_gen_clk_src_path_);
|
||||||
hashIncr(hash_, is_pulse_clk_);
|
hashIncr(hash_, is_pulse_clk_);
|
||||||
|
|
@ -152,9 +152,10 @@ ClkInfo::to_string(const StaState *sta) const
|
||||||
Network *network = sta->network();
|
Network *network = sta->network();
|
||||||
std::string result;
|
std::string result;
|
||||||
|
|
||||||
|
const MinMax *min_max = minMax();
|
||||||
result += scene_->name();
|
result += scene_->name();
|
||||||
result += "/";
|
result += "/";
|
||||||
result += minMax()->to_string();
|
result += min_max->to_string();
|
||||||
result += " ";
|
result += " ";
|
||||||
|
|
||||||
if (clk_edge_)
|
if (clk_edge_)
|
||||||
|
|
@ -186,7 +187,7 @@ ClkInfo::to_string(const StaState *sta) const
|
||||||
|
|
||||||
if (delayGreater(insertion_, 0.0, sta)) {
|
if (delayGreater(insertion_, 0.0, sta)) {
|
||||||
result += " insert";
|
result += " insert";
|
||||||
result += delayAsString(insertion_, sta);
|
result += delayAsString(insertion_, min_max, sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uncertainties_) {
|
if (uncertainties_) {
|
||||||
|
|
|
||||||
|
|
@ -116,15 +116,15 @@ ClkLatency::reportClkLatency(const Clock *clk,
|
||||||
report_->reportLine(" min max");
|
report_->reportLine(" min max");
|
||||||
|
|
||||||
report_->reportLine("%7s %7s source latency",
|
report_->reportLine("%7s %7s source latency",
|
||||||
delayAsString(insertion_min, this, digits),
|
delayAsString(insertion_min, MinMax::min(), digits, this),
|
||||||
delayAsString(insertion_max, this, digits));
|
delayAsString(insertion_max, MinMax::max(), digits, this));
|
||||||
report_->reportLine("%7s %7s network latency %s",
|
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)));
|
sdc_network_->pathName(path_min.pin(this)));
|
||||||
report_->reportLine("%7s %7s network latency %s",
|
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)));
|
sdc_network_->pathName(path_max.pin(this)));
|
||||||
if (internal_latency_min != 0.0
|
if (internal_latency_min != 0.0
|
||||||
|| internal_latency_max != 0.0)
|
|| internal_latency_max != 0.0)
|
||||||
|
|
@ -133,11 +133,11 @@ ClkLatency::reportClkLatency(const Clock *clk,
|
||||||
time_unit->asString(internal_latency_max, digits));
|
time_unit->asString(internal_latency_max, digits));
|
||||||
report_->reportLine("---------------");
|
report_->reportLine("---------------");
|
||||||
report_->reportLine("%7s %7s latency",
|
report_->reportLine("%7s %7s latency",
|
||||||
delayAsString(latency_min, this, digits),
|
delayAsString(latency_min, MinMax::min(), digits, this),
|
||||||
delayAsString(latency_max, this, digits));
|
delayAsString(latency_max, MinMax::max(), digits, this));
|
||||||
Delay skew = latency_max - latency_min;
|
Delay skew = delayDiff(latency_max, latency_min, this);
|
||||||
report_->reportLine(" %7s skew",
|
report_->reportLine(" %7s skew",
|
||||||
delayAsString(skew, this, digits));
|
delayAsString(skew, MinMax::max(), digits, this));
|
||||||
report_->reportBlankLine();
|
report_->reportBlankLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -255,10 +255,10 @@ ClkDelays::setLatency(const RiseFall *src_rf,
|
||||||
int end_rf_index = end_rf->index();
|
int end_rf_index = end_rf->index();
|
||||||
int mm_index = min_max->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;
|
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;
|
delay_[src_rf_index][end_rf_index][mm_index] = delay1;
|
||||||
|
|
||||||
float internal_latency = 0.0;
|
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;
|
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;
|
latency_[src_rf_index][end_rf_index][mm_index] = latency;
|
||||||
|
|
||||||
path_[src_rf_index][end_rf_index][mm_index] = *path;
|
path_[src_rf_index][end_rf_index][mm_index] = *path;
|
||||||
|
|
@ -279,22 +279,22 @@ ClkDelays::latency(Path *clk_path,
|
||||||
StaState *sta)
|
StaState *sta)
|
||||||
{
|
{
|
||||||
|
|
||||||
float insertion = insertionDelay(clk_path, sta);
|
Delay insertion = insertionDelay(clk_path, sta);
|
||||||
float delay1 = delay(clk_path, sta);
|
Delay delay1 = delay(clk_path, sta);
|
||||||
float lib_clk_delay = clkTreeDelay(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,
|
ClkDelays::delay(Path *clk_path,
|
||||||
StaState *sta)
|
StaState *sta)
|
||||||
{
|
{
|
||||||
Arrival arrival = clk_path->arrival();
|
Arrival arrival = clk_path->arrival();
|
||||||
const ClockEdge *path_clk_edge = clk_path->clkEdge(sta);
|
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,
|
ClkDelays::insertionDelay(Path *clk_path,
|
||||||
StaState *sta)
|
StaState *sta)
|
||||||
{
|
{
|
||||||
|
|
@ -305,8 +305,7 @@ ClkDelays::insertionDelay(Path *clk_path,
|
||||||
const Pin *src_pin = clk_info->clkSrc();
|
const Pin *src_pin = clk_info->clkSrc();
|
||||||
const MinMax *min_max = clk_path->minMax(sta);
|
const MinMax *min_max = clk_path->minMax(sta);
|
||||||
const Mode *mode = clk_path->mode(sta);
|
const Mode *mode = clk_path->mode(sta);
|
||||||
return delayAsFloat(sta->search()->clockInsertion(clk, src_pin, clk_rf, min_max,
|
return sta->search()->clockInsertion(clk, src_pin, clk_rf, min_max, min_max, mode);
|
||||||
min_max, mode));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
|
|
@ -318,7 +317,7 @@ ClkDelays::clkTreeDelay(Path *clk_path,
|
||||||
const LibertyPort *port = sta->network()->libertyPort(pin);
|
const LibertyPort *port = sta->network()->libertyPort(pin);
|
||||||
const MinMax *min_max = clk_path->minMax(sta);
|
const MinMax *min_max = clk_path->minMax(sta);
|
||||||
const RiseFall *rf = clk_path->transition(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);
|
return port->clkTreeDelay(slew, rf, min_max);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -95,16 +95,17 @@ ClkSkews::reportClkSkew(ClkSkew &clk_skew,
|
||||||
Unit *time_unit = units_->timeUnit();
|
Unit *time_unit = units_->timeUnit();
|
||||||
Path *src_path = clk_skew.srcPath();
|
Path *src_path = clk_skew.srcPath();
|
||||||
Path *tgt_path = clk_skew.tgtPath();
|
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 tgt_latency = clk_skew.tgtLatency(this);
|
||||||
float src_internal_clk_latency = clk_skew.srcInternalClkLatency(this);
|
float src_internal_clk_latency = clk_skew.srcInternalClkLatency(this);
|
||||||
float tgt_internal_clk_latency = clk_skew.tgtInternalClkLatency(this);
|
float tgt_internal_clk_latency = clk_skew.tgtInternalClkLatency(this);
|
||||||
float uncertainty = clk_skew.uncertainty(this);
|
float uncertainty = clk_skew.uncertainty(this);
|
||||||
|
|
||||||
if (src_internal_clk_latency != 0.0)
|
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",
|
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)),
|
sdc_network_->pathName(src_path->pin(this)),
|
||||||
src_path->transition(this)->shortName());
|
src_path->transition(this)->shortName());
|
||||||
if (src_internal_clk_latency != 0.0)
|
if (src_internal_clk_latency != 0.0)
|
||||||
|
|
@ -124,15 +125,32 @@ ClkSkews::reportClkSkew(ClkSkew &clk_skew,
|
||||||
report_->reportLine("%7s clock uncertainty",
|
report_->reportLine("%7s clock uncertainty",
|
||||||
time_unit->asString(uncertainty, digits));
|
time_unit->asString(uncertainty, digits));
|
||||||
report_->reportLine("%7s CRPR",
|
report_->reportLine("%7s CRPR",
|
||||||
time_unit->asString(delayAsFloat(-clk_skew.crpr(this)),
|
delayAsString(delayDiff(0.0, clk_skew.crpr(this), this),
|
||||||
digits));
|
MinMax::max(), digits, this));
|
||||||
report_->reportLine("--------------");
|
report_->reportLine("--------------");
|
||||||
report_->reportLine("%7s %s skew",
|
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");
|
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,
|
ClkSkews::findWorstClkSkew(const SceneSeq &scenes,
|
||||||
const SetupHold *setup_hold,
|
const SetupHold *setup_hold,
|
||||||
bool include_internal_latency)
|
bool include_internal_latency)
|
||||||
|
|
@ -143,10 +161,10 @@ ClkSkews::findWorstClkSkew(const SceneSeq &scenes,
|
||||||
clks.push_back(clk);
|
clks.push_back(clk);
|
||||||
}
|
}
|
||||||
findClkSkew(clks, scenes, include_internal_latency);
|
findClkSkew(clks, scenes, include_internal_latency);
|
||||||
float worst_skew = 0.0;
|
Delay worst_skew = 0.0;
|
||||||
for (const auto& [clk, clk_skews] : skews_) {
|
for (const auto& [clk, clk_skews] : skews_) {
|
||||||
float skew = clk_skews[setup_hold->index()].skew();
|
Delay skew = clk_skews[setup_hold->index()].skew();
|
||||||
if (std::abs(skew) > std::abs(worst_skew))
|
if (delayAbsGreater(skew, worst_skew, this))
|
||||||
worst_skew = skew;
|
worst_skew = skew;
|
||||||
}
|
}
|
||||||
return worst_skew;
|
return worst_skew;
|
||||||
|
|
@ -206,10 +224,12 @@ ClkSkews::findClkSkew(ConstClockSeq &clks,
|
||||||
for (int setup_hold_idx : SetupHold::rangeIndex()) {
|
for (int setup_hold_idx : SetupHold::rangeIndex()) {
|
||||||
ClkSkew &final_skew = itr->second[setup_hold_idx];
|
ClkSkew &final_skew = itr->second[setup_hold_idx];
|
||||||
ClkSkew &partial_skew_val = partial_skew[setup_hold_idx];
|
ClkSkew &partial_skew_val = partial_skew[setup_hold_idx];
|
||||||
float partial_skew1 = partial_skew_val.skew();
|
Delay partial_skew1 = partial_skew_val.skew();
|
||||||
float final_skew1 = final_skew.skew();
|
Delay final_skew1 = final_skew.skew();
|
||||||
if (std::abs(partial_skew1) > std::abs(final_skew1)
|
float partial_skew_max = delayAbsMax(partial_skew1, this);
|
||||||
|| (fuzzyEqual(std::abs(partial_skew1), std::abs(final_skew1))
|
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.
|
// Break ties based on source/target path names.
|
||||||
&& ClkSkew::srcTgtPathNameLess(partial_skew_val, final_skew, this)))
|
&& ClkSkew::srcTgtPathNameLess(partial_skew_val, final_skew, this)))
|
||||||
final_skew = partial_skew_val;
|
final_skew = partial_skew_val;
|
||||||
|
|
@ -299,7 +319,8 @@ ClkSkews::findClkSkew(Vertex *src_vertex,
|
||||||
&& src_rf->matches(src_path->transition(this))
|
&& src_rf->matches(src_path->transition(this))
|
||||||
&& clk_set_.contains(src_clk)
|
&& clk_set_.contains(src_clk)
|
||||||
&& scenes_set_.contains(src_scene)) {
|
&& 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);
|
VertexPathIterator tgt_iter(tgt_vertex, this);
|
||||||
while (tgt_iter.hasNext()) {
|
while (tgt_iter.hasNext()) {
|
||||||
Path *tgt_path = tgt_iter.next();
|
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",
|
"%s %s %s -> %s %s %s crpr = %s skew = %s",
|
||||||
network_->pathName(src_path->pin(this)),
|
network_->pathName(src_path->pin(this)),
|
||||||
src_path->transition(this)->shortName(),
|
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)),
|
network_->pathName(tgt_path->pin(this)),
|
||||||
tgt_path->transition(this)->shortName(),
|
tgt_path->transition(this)->shortName(),
|
||||||
time_unit->asString(probe.tgtLatency(this)),
|
time_unit->asString(probe.tgtLatency(this)),
|
||||||
delayAsString(probe.crpr(this), this),
|
delayAsString(probe.crpr(this), this),
|
||||||
time_unit->asString(probe.skew()));
|
delayAsString(probe.skew(), MinMax::max(), this));
|
||||||
if (clk_skew.srcPath() == nullptr
|
if (clk_skew.srcPath() == nullptr
|
||||||
|| std::abs(probe.skew()) > std::abs(clk_skew.skew()))
|
|| delayAbsGreater(probe.skew(), clk_skew.skew(), this))
|
||||||
clk_skew = probe;
|
clk_skew = probe;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -380,10 +401,8 @@ ClkSkew::ClkSkew(Path *src_path,
|
||||||
tgt_path_(tgt_path),
|
tgt_path_(tgt_path),
|
||||||
include_internal_latency_(include_internal_latency)
|
include_internal_latency_(include_internal_latency)
|
||||||
{
|
{
|
||||||
skew_ = srcLatency(sta)
|
skew_ = delayDiff(delaySum(srcLatency(sta), uncertainty(sta), sta),
|
||||||
- tgtLatency(sta)
|
delaySum(tgtLatency(sta), crpr(sta), sta), sta);
|
||||||
- delayAsFloat(crpr(sta))
|
|
||||||
+ uncertainty(sta);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ClkSkew::ClkSkew(const ClkSkew &clk_skew)
|
ClkSkew::ClkSkew(const ClkSkew &clk_skew)
|
||||||
|
|
@ -403,12 +422,11 @@ ClkSkew::operator=(const ClkSkew &clk_skew)
|
||||||
skew_ = clk_skew.skew_;
|
skew_ = clk_skew.skew_;
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
Arrival
|
||||||
ClkSkew::srcLatency(const StaState *sta)
|
ClkSkew::srcLatency(const StaState *sta)
|
||||||
{
|
{
|
||||||
Arrival src_arrival = src_path_->arrival();
|
return delayDiff(delaySum(src_path_->arrival(), clkTreeDelay(src_path_, sta), sta),
|
||||||
return delayAsFloat(src_arrival) - src_path_->clkEdge(sta)->time()
|
src_path_->clkEdge(sta)->time(), sta);
|
||||||
+ clkTreeDelay(src_path_, sta);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
|
|
@ -421,8 +439,8 @@ float
|
||||||
ClkSkew::tgtLatency(const StaState *sta)
|
ClkSkew::tgtLatency(const StaState *sta)
|
||||||
{
|
{
|
||||||
Arrival tgt_arrival = tgt_path_->arrival();
|
Arrival tgt_arrival = tgt_path_->arrival();
|
||||||
return delayAsFloat(tgt_arrival) - tgt_path_->clkEdge(sta)->time()
|
return delayAsFloat(delaySum(delayDiff(tgt_arrival, tgt_path_->clkEdge(sta)->time(),sta),
|
||||||
+ clkTreeDelay(tgt_path_, sta);
|
clkTreeDelay(tgt_path_, sta), sta));
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
|
|
@ -441,7 +459,7 @@ ClkSkew::clkTreeDelay(Path *clk_path,
|
||||||
const LibertyPort *port = sta->network()->libertyPort(pin);
|
const LibertyPort *port = sta->network()->libertyPort(pin);
|
||||||
const MinMax *min_max = clk_path->minMax(sta);
|
const MinMax *min_max = clk_path->minMax(sta);
|
||||||
const RiseFall *rf = clk_path->transition(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);
|
return port->clkTreeDelay(slew, rf, min_max);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -52,13 +52,13 @@ public:
|
||||||
void operator=(const ClkSkew &clk_skew);
|
void operator=(const ClkSkew &clk_skew);
|
||||||
Path *srcPath() { return src_path_; }
|
Path *srcPath() { return src_path_; }
|
||||||
Path *tgtPath() { return tgt_path_; }
|
Path *tgtPath() { return tgt_path_; }
|
||||||
float srcLatency(const StaState *sta);
|
Arrival srcLatency(const StaState *sta);
|
||||||
float tgtLatency(const StaState *sta);
|
float tgtLatency(const StaState *sta);
|
||||||
float srcInternalClkLatency(const StaState *sta);
|
float srcInternalClkLatency(const StaState *sta);
|
||||||
float tgtInternalClkLatency(const StaState *sta);
|
float tgtInternalClkLatency(const StaState *sta);
|
||||||
Crpr crpr(const StaState *sta);
|
Crpr crpr(const StaState *sta);
|
||||||
float uncertainty(const StaState *sta);
|
float uncertainty(const StaState *sta);
|
||||||
float skew() const { return skew_; }
|
Delay skew() const { return skew_; }
|
||||||
static bool srcTgtPathNameLess(ClkSkew &clk_skew1,
|
static bool srcTgtPathNameLess(ClkSkew &clk_skew1,
|
||||||
ClkSkew &clk_skew2,
|
ClkSkew &clk_skew2,
|
||||||
const StaState *sta);
|
const StaState *sta);
|
||||||
|
|
@ -70,7 +70,7 @@ private:
|
||||||
Path *src_path_;
|
Path *src_path_;
|
||||||
Path *tgt_path_;
|
Path *tgt_path_;
|
||||||
bool include_internal_latency_;
|
bool include_internal_latency_;
|
||||||
float skew_;
|
Delay skew_;
|
||||||
};
|
};
|
||||||
|
|
||||||
using ClkSkewMap = std::map<const Clock*, ClkSkew[SetupHold::index_count]>;
|
using ClkSkewMap = std::map<const Clock*, ClkSkew[SetupHold::index_count]>;
|
||||||
|
|
@ -97,7 +97,7 @@ public:
|
||||||
bool include_internal_latency,
|
bool include_internal_latency,
|
||||||
int digits);
|
int digits);
|
||||||
// Find worst clock skew between src/target registers.
|
// Find worst clock skew between src/target registers.
|
||||||
float findWorstClkSkew(const SceneSeq &scenes,
|
Delay findWorstClkSkew(const SceneSeq &scenes,
|
||||||
const SetupHold *setup_hold,
|
const SetupHold *setup_hold,
|
||||||
bool include_internal_latency);
|
bool include_internal_latency);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -273,19 +273,16 @@ CheckCrpr::findCrpr1(const Path *src_clk_path,
|
||||||
if (variables_->pocvEnabled()) {
|
if (variables_->pocvEnabled()) {
|
||||||
// Remove variation on the common path.
|
// Remove variation on the common path.
|
||||||
// Note that the crpr sigma is negative to offset the
|
// Note that the crpr sigma is negative to offset the
|
||||||
// sigma of the common clock path.
|
// std_dev of the common clock path.
|
||||||
const EarlyLate *src_el = src_clk_path->minMax(this);
|
const Arrival &src_arrival = src_clk_path->arrival();
|
||||||
const EarlyLate *tgt_el = tgt_clk_path->minMax(this);
|
const Arrival &tgt_arrival = tgt_clk_path->arrival();
|
||||||
Arrival src_arrival = src_clk_path->arrival();
|
|
||||||
Arrival tgt_arrival = tgt_clk_path->arrival();
|
|
||||||
float src_clk_time = src_clk_path->clkEdge(this)->time();
|
float src_clk_time = src_clk_path->clkEdge(this)->time();
|
||||||
float tgt_clk_time = tgt_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
|
float crpr_mean = std::abs(src_arrival.mean() - src_clk_time
|
||||||
- (delayAsFloat(tgt_arrival) - tgt_clk_time));
|
- (tgt_arrival.mean() - tgt_clk_time));
|
||||||
// Remove the sigma from both source and target path arrivals.
|
// Remove the sigma from both source and target path arrivals.
|
||||||
float crpr_sigma2 = delaySigma2(src_arrival, src_el)
|
float crpr_sigma2 = src_arrival.stdDev2() + tgt_arrival.stdDev2();
|
||||||
+ delaySigma2(tgt_arrival, tgt_el);
|
return makeDelay2(crpr_mean, -crpr_sigma2);
|
||||||
return makeDelay2(crpr_mean, -crpr_sigma2, -crpr_sigma2);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// The source and target edges are different so the crpr
|
// The source and target edges are different so the crpr
|
||||||
|
|
@ -308,8 +305,9 @@ float
|
||||||
CheckCrpr::crprArrivalDiff(const Path *path)
|
CheckCrpr::crprArrivalDiff(const Path *path)
|
||||||
{
|
{
|
||||||
Arrival other_arrival = otherMinMaxArrival(path);
|
Arrival other_arrival = otherMinMaxArrival(path);
|
||||||
float crpr_diff = std::abs(delayAsFloat(path->arrival())
|
const MinMax *min_max = path->minMax(this);
|
||||||
- delayAsFloat(other_arrival));
|
float crpr_diff = std::abs(delayAsFloat(path->arrival(), min_max, this)
|
||||||
|
- delayAsFloat(other_arrival, min_max->opposite(), this));
|
||||||
return crpr_diff;
|
return crpr_diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ Latches::latchRequired(const Path *data_path,
|
||||||
ignore_clk_latency = path_delay->ignoreClkLatency();
|
ignore_clk_latency = path_delay->ignoreClkLatency();
|
||||||
}
|
}
|
||||||
if (ignore_clk_latency) {
|
if (ignore_clk_latency) {
|
||||||
required = max_delay + src_clk_latency;
|
required = delaySum(src_clk_latency, max_delay, this);
|
||||||
borrow = 0.0;
|
borrow = 0.0;
|
||||||
adjusted_data_arrival = data_arrival;
|
adjusted_data_arrival = data_arrival;
|
||||||
time_given_to_startpoint = 0.0;
|
time_given_to_startpoint = 0.0;
|
||||||
|
|
@ -98,13 +98,15 @@ Latches::latchRequired(const Path *data_path,
|
||||||
// checkTgtClkTime
|
// checkTgtClkTime
|
||||||
float tgt_clk_time = path_delay ? 0.0 : acct->requiredTime(check_role);
|
float tgt_clk_time = path_delay ? 0.0 : acct->requiredTime(check_role);
|
||||||
// checkTgtClkArrival broken down into components.
|
// checkTgtClkArrival broken down into components.
|
||||||
Arrival enable_arrival = max_delay
|
Arrival enable_arrival = delaySum(max_delay
|
||||||
+ tgt_clk_time
|
+ tgt_clk_time
|
||||||
+ open_latency
|
+ open_uncertainty
|
||||||
+ open_uncertainty
|
+ PathEnd::checkSetupMcpAdjustment(data_clk_edge,
|
||||||
+ PathEnd::checkSetupMcpAdjustment(data_clk_edge, enable_clk_edge, mcp,
|
enable_clk_edge,
|
||||||
1, sdc)
|
mcp, 1, sdc),
|
||||||
+ open_crpr;
|
open_latency,
|
||||||
|
this);
|
||||||
|
enable_arrival = delaySum(enable_arrival, open_crpr, this);
|
||||||
debugPrint(debug_, "latch", 1, "data %s enable %s",
|
debugPrint(debug_, "latch", 1, "data %s enable %s",
|
||||||
delayAsString(data_arrival, this),
|
delayAsString(data_arrival, this),
|
||||||
delayAsString(enable_arrival, this));
|
delayAsString(enable_arrival, this));
|
||||||
|
|
@ -117,25 +119,31 @@ Latches::latchRequired(const Path *data_path,
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Data arrives while latch is transparent.
|
// Data arrives while latch is transparent.
|
||||||
borrow = data_arrival - enable_arrival;
|
borrow = delayDiff(data_arrival, enable_arrival, this);
|
||||||
if (delayLessEqual(borrow, max_borrow, this))
|
if (delayLessEqual(borrow, max_borrow, this))
|
||||||
required = data_arrival;
|
required = data_arrival;
|
||||||
else {
|
else {
|
||||||
borrow = max_borrow;
|
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
|
// Cycle accounting for required time is with respect to the
|
||||||
// data clock zeroth cycle. The data departs the latch
|
// data clock zeroth cycle. The data departs the latch
|
||||||
// with respect to the enable clock zeroth cycle.
|
// with respect to the enable clock zeroth cycle.
|
||||||
float data_shift_to_enable_clk = acct->sourceTimeOffset(check_role)
|
float data_shift_to_enable_clk = acct->sourceTimeOffset(check_role)
|
||||||
- acct->targetTimeOffset(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) {
|
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 cannot be determined without enable path.
|
||||||
borrow = 0.0;
|
borrow = 0.0;
|
||||||
adjusted_data_arrival = data_arrival;
|
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 *enable_clk_edge = enable_path->clkEdge(this);
|
||||||
const ClockEdge *disable_clk_edge = disable_path->clkEdge(this);
|
const ClockEdge *disable_clk_edge = disable_path->clkEdge(this);
|
||||||
bool is_pulse_clk = enable_path->clkInfo(this)->isPulseClk();
|
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,
|
open_uncertainty = PathEnd::checkClkUncertainty(data_clk_edge, enable_clk_edge,
|
||||||
enable_path,
|
enable_path,
|
||||||
TimingRole::latchSetup(), sdc);
|
TimingRole::latchSetup(), sdc);
|
||||||
|
|
@ -190,14 +198,14 @@ Latches::latchBorrowInfo(const Path *data_path,
|
||||||
CheckCrpr *check_crpr = search_->checkCrpr();
|
CheckCrpr *check_crpr = search_->checkCrpr();
|
||||||
open_crpr = check_crpr->checkCrpr(data_path, enable_path);
|
open_crpr = check_crpr->checkCrpr(data_path, enable_path);
|
||||||
Crpr close_crpr = check_crpr->checkCrpr(data_path, disable_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,
|
open_latency = PathEnd::checkTgtClkDelay(enable_path, enable_clk_edge,
|
||||||
TimingRole::setup(), this);
|
TimingRole::setup(), this);
|
||||||
Arrival close_latency = PathEnd::checkTgtClkDelay(disable_path,
|
Arrival close_latency = PathEnd::checkTgtClkDelay(disable_path,
|
||||||
disable_clk_edge,
|
disable_clk_edge,
|
||||||
TimingRole::latchSetup(),
|
TimingRole::latchSetup(),
|
||||||
this);
|
this);
|
||||||
latency_diff = open_latency - close_latency;
|
latency_diff = delayDiff(open_latency, close_latency, this);
|
||||||
}
|
}
|
||||||
float borrow_limit;
|
float borrow_limit;
|
||||||
sdc->latchBorrowLimit(data_path->pin(this), disable_path->pin(this),
|
sdc->latchBorrowLimit(data_path->pin(this), disable_path->pin(this),
|
||||||
|
|
@ -206,8 +214,9 @@ Latches::latchBorrowInfo(const Path *data_path,
|
||||||
if (borrow_limit_exists)
|
if (borrow_limit_exists)
|
||||||
max_borrow = borrow_limit;
|
max_borrow = borrow_limit;
|
||||||
else
|
else
|
||||||
max_borrow = nom_pulse_width - delayAsFloat(latency_diff)
|
max_borrow = delayDiff(nom_pulse_width,
|
||||||
- delayAsFloat(crpr_diff) - delayAsFloat(margin);
|
delaySum(delaySum(latency_diff, crpr_diff, this),
|
||||||
|
margin, this), this);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
nom_pulse_width = 0.0;
|
nom_pulse_width = 0.0;
|
||||||
|
|
@ -349,7 +358,7 @@ Latches::latchOutArrival(const Path *data_path,
|
||||||
if (!(excpt && excpt->isFalse())) {
|
if (!(excpt && excpt->isFalse())) {
|
||||||
arc_delay = search_->deratedDelay(data_vertex, d_q_arc, d_q_edge,
|
arc_delay = search_->deratedDelay(data_vertex, d_q_arc, d_q_edge,
|
||||||
false, min_max, dcalc_ap, sdc);
|
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.
|
// Copy the data tag but remove the drprClkPath.
|
||||||
// Levelization does not traverse latch D->Q edges, so in some cases
|
// Levelization does not traverse latch D->Q edges, so in some cases
|
||||||
// level(Q) < level(D)
|
// level(Q) < level(D)
|
||||||
|
|
@ -405,7 +414,7 @@ Latches::latchOutArrival(const Path *data_path,
|
||||||
// Latch is transparent when data arrives.
|
// Latch is transparent when data arrives.
|
||||||
arc_delay = search_->deratedDelay(data_vertex, d_q_arc, d_q_edge,
|
arc_delay = search_->deratedDelay(data_vertex, d_q_arc, d_q_edge,
|
||||||
false, min_max, dcalc_ap, sdc);
|
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.
|
// Tag switcheroo - data passing thru gets latch enable tag.
|
||||||
// States and path ap come from Q, everything else from enable.
|
// States and path ap come from Q, everything else from enable.
|
||||||
Path *crpr_clk_path = crprActive(mode) ? enable_path : nullptr;
|
Path *crpr_clk_path = crprActive(mode) ? enable_path : nullptr;
|
||||||
|
|
|
||||||
|
|
@ -281,9 +281,9 @@ MakeEndTimingArcs::visit(PathEnd *path_end)
|
||||||
Arrival data_delay = src_path->arrival();
|
Arrival data_delay = src_path->arrival();
|
||||||
Delay clk_latency = path_end->targetClkDelay(sta_);
|
Delay clk_latency = path_end->targetClkDelay(sta_);
|
||||||
ArcDelay check_margin = path_end->margin(sta_);
|
ArcDelay check_margin = path_end->margin(sta_);
|
||||||
Delay margin = min_max == MinMax::max()
|
Delay margin = (min_max == MinMax::max())
|
||||||
? data_delay - clk_latency + check_margin
|
? delaySum(delayDiff(data_delay, clk_latency, sta_), check_margin, sta_)
|
||||||
: clk_latency - data_delay + check_margin;
|
: delaySum(delayDiff(clk_latency, data_delay, sta_), check_margin, sta_);
|
||||||
float delay1 = delayAsFloat(margin, MinMax::max(), sta_);
|
float delay1 = delayAsFloat(margin, MinMax::max(), sta_);
|
||||||
debugPrint(debug, "make_timing_model", 2, "%s -> %s clock %s %s %s %s",
|
debugPrint(debug, "make_timing_model", 2, "%s -> %s clock %s %s %s %s",
|
||||||
input_rf_->shortName(),
|
input_rf_->shortName(),
|
||||||
|
|
@ -605,10 +605,10 @@ MakeTimingModel::makeScalarCheckModel(float value,
|
||||||
TablePtr table = std::make_shared<Table>(value);
|
TablePtr table = std::make_shared<Table>(value);
|
||||||
TableTemplate *tbl_template =
|
TableTemplate *tbl_template =
|
||||||
library_->findTableTemplate("scalar", TableTemplateType::delay);
|
library_->findTableTemplate("scalar", TableTemplateType::delay);
|
||||||
TableModel *table_model = new TableModel(table, tbl_template,
|
TableModel *check_table = new TableModel(table, tbl_template, scale_factor_type, rf);
|
||||||
scale_factor_type, rf);
|
TableModels *check_tables = new TableModels(check_table);
|
||||||
CheckTableModel *check_model = new CheckTableModel(cell_, table_model);
|
CheckTableModel *check = new CheckTableModel(cell_, check_tables);
|
||||||
return check_model;
|
return check;
|
||||||
}
|
}
|
||||||
|
|
||||||
TimingModel *
|
TimingModel *
|
||||||
|
|
@ -622,9 +622,12 @@ MakeTimingModel::makeGateModelScalar(Delay delay,
|
||||||
library_->findTableTemplate("scalar", TableTemplateType::delay);
|
library_->findTableTemplate("scalar", TableTemplateType::delay);
|
||||||
TableModel *delay_model = new TableModel(delay_table, tbl_template,
|
TableModel *delay_model = new TableModel(delay_table, tbl_template,
|
||||||
ScaleFactorType::cell, rf);
|
ScaleFactorType::cell, rf);
|
||||||
|
TableModels *delay_models = new TableModels(delay_model);
|
||||||
TableModel *slew_model = new TableModel(slew_table, tbl_template,
|
TableModel *slew_model = new TableModel(slew_table, tbl_template,
|
||||||
ScaleFactorType::cell, rf);
|
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;
|
return gate_model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -637,7 +640,9 @@ MakeTimingModel::makeGateModelScalar(Delay delay,
|
||||||
library_->findTableTemplate("scalar", TableTemplateType::delay);
|
library_->findTableTemplate("scalar", TableTemplateType::delay);
|
||||||
TableModel *delay_model = new TableModel(delay_table, tbl_template,
|
TableModel *delay_model = new TableModel(delay_table, tbl_template,
|
||||||
ScaleFactorType::cell, rf);
|
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;
|
return gate_model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -674,12 +679,11 @@ MakeTimingModel::makeGateModelTable(const Pin *output_pin,
|
||||||
float output_load_cap = graph_delay_calc_->loadCap(output_pin,
|
float output_load_cap = graph_delay_calc_->loadCap(output_pin,
|
||||||
scene_,
|
scene_,
|
||||||
min_max_);
|
min_max_);
|
||||||
ArcDelay drvr_self_delay;
|
float drvr_self_delay, drvr_self_slew;
|
||||||
Slew drvr_self_slew;
|
drvr_gate_model->gateDelay(pvt, in_slew1, output_load_cap,
|
||||||
drvr_gate_model->gateDelay(pvt, in_slew1, output_load_cap, false,
|
|
||||||
drvr_self_delay, drvr_self_slew);
|
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 TableTemplate *drvr_template = drvr_table->tblTemplate();
|
||||||
const TableAxis *drvr_load_axis = loadCapacitanceAxis(drvr_table);
|
const TableAxis *drvr_load_axis = loadCapacitanceAxis(drvr_table);
|
||||||
if (drvr_load_axis) {
|
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++) {
|
for (size_t i = 0; i < drvr_axis_values.size(); i++) {
|
||||||
float load_cap = drvr_axis_values[i];
|
float load_cap = drvr_axis_values[i];
|
||||||
// get slew from driver input pin
|
// get slew from driver input pin
|
||||||
ArcDelay gate_delay;
|
float gate_delay, gate_slew;
|
||||||
Slew gate_slew;
|
drvr_gate_model->gateDelay(pvt, in_slew1, load_cap,
|
||||||
drvr_gate_model->gateDelay(pvt, in_slew1, load_cap, false,
|
|
||||||
gate_delay, gate_slew);
|
gate_delay, gate_slew);
|
||||||
// Remove the self delay driving the output pin net load cap.
|
// Remove the self delay driving the output pin net load cap.
|
||||||
load_values->push_back(delayAsFloat(delay + gate_delay
|
load_values->push_back(delayAsFloat(delay)
|
||||||
- drvr_self_delay));
|
+ gate_delay
|
||||||
|
- drvr_self_delay);
|
||||||
slew_values->push_back(delayAsFloat(gate_slew));
|
slew_values->push_back(delayAsFloat(gate_slew));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -711,10 +715,14 @@ MakeTimingModel::makeGateModelTable(const Pin *output_pin,
|
||||||
load_axis);
|
load_axis);
|
||||||
TableModel *delay_model = new TableModel(delay_table, model_template,
|
TableModel *delay_model = new TableModel(delay_table, model_template,
|
||||||
ScaleFactorType::cell, rf);
|
ScaleFactorType::cell, rf);
|
||||||
|
TableModels *delay_models = new TableModels(delay_model);
|
||||||
TableModel *slew_model = new TableModel(slew_table, model_template,
|
TableModel *slew_model = new TableModel(slew_table, model_template,
|
||||||
ScaleFactorType::cell, rf);
|
ScaleFactorType::cell, rf);
|
||||||
GateTableModel *gate_model = new GateTableModel(cell_, delay_model,
|
TableModels *slew_models = new TableModels(slew_model);
|
||||||
slew_model);
|
GateTableModel *gate_model = new GateTableModel(cell_,
|
||||||
|
delay_models,
|
||||||
|
slew_models,
|
||||||
|
nullptr, nullptr);
|
||||||
return gate_model;
|
return gate_model;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ Path::Path(Vertex *vertex,
|
||||||
|
|
||||||
Path::Path(Vertex *vertex,
|
Path::Path(Vertex *vertex,
|
||||||
Tag *tag,
|
Tag *tag,
|
||||||
Arrival arrival,
|
const Arrival &arrival,
|
||||||
Path *prev_path,
|
Path *prev_path,
|
||||||
Edge *prev_edge,
|
Edge *prev_edge,
|
||||||
TimingArc *prev_arc,
|
TimingArc *prev_arc,
|
||||||
|
|
@ -99,7 +99,7 @@ Path::Path(Vertex *vertex,
|
||||||
|
|
||||||
Path::Path(Vertex *vertex,
|
Path::Path(Vertex *vertex,
|
||||||
Tag *tag,
|
Tag *tag,
|
||||||
Arrival arrival,
|
const Arrival &arrival,
|
||||||
Path *prev_path,
|
Path *prev_path,
|
||||||
Edge *prev_edge,
|
Edge *prev_edge,
|
||||||
TimingArc *prev_arc,
|
TimingArc *prev_arc,
|
||||||
|
|
@ -124,7 +124,7 @@ Path::Path(Vertex *vertex,
|
||||||
|
|
||||||
void
|
void
|
||||||
Path::init(Vertex *vertex,
|
Path::init(Vertex *vertex,
|
||||||
Arrival arrival,
|
const Arrival &arrival,
|
||||||
const StaState *sta)
|
const StaState *sta)
|
||||||
{
|
{
|
||||||
const Graph *graph = sta->graph();
|
const Graph *graph = sta->graph();
|
||||||
|
|
@ -155,7 +155,7 @@ Path::init(Vertex *vertex,
|
||||||
void
|
void
|
||||||
Path::init(Vertex *vertex,
|
Path::init(Vertex *vertex,
|
||||||
Tag *tag,
|
Tag *tag,
|
||||||
Arrival arrival,
|
const Arrival &arrival,
|
||||||
const StaState *sta)
|
const StaState *sta)
|
||||||
{
|
{
|
||||||
const Graph *graph = sta->graph();
|
const Graph *graph = sta->graph();
|
||||||
|
|
@ -171,7 +171,7 @@ Path::init(Vertex *vertex,
|
||||||
void
|
void
|
||||||
Path::init(Vertex *vertex,
|
Path::init(Vertex *vertex,
|
||||||
Tag *tag,
|
Tag *tag,
|
||||||
Arrival arrival,
|
const Arrival &arrival,
|
||||||
Path *prev_path,
|
Path *prev_path,
|
||||||
Edge *prev_edge,
|
Edge *prev_edge,
|
||||||
TimingArc *prev_arc,
|
TimingArc *prev_arc,
|
||||||
|
|
@ -330,7 +330,7 @@ Path::pathAnalysisPtIndex(const StaState *sta) const
|
||||||
return scene(sta)->pathIndex(minMax(sta));
|
return scene(sta)->pathIndex(minMax(sta));
|
||||||
}
|
}
|
||||||
|
|
||||||
Slew
|
const Slew &
|
||||||
Path::slew(const StaState *sta) const
|
Path::slew(const StaState *sta) const
|
||||||
{
|
{
|
||||||
DcalcAPIndex slew_index = scene(sta)->dcalcAnalysisPtIndex(minMax(sta));
|
DcalcAPIndex slew_index = scene(sta)->dcalcAnalysisPtIndex(minMax(sta));
|
||||||
|
|
@ -365,9 +365,9 @@ Slack
|
||||||
Path::slack(const StaState *sta) const
|
Path::slack(const StaState *sta) const
|
||||||
{
|
{
|
||||||
if (minMax(sta) == MinMax::max())
|
if (minMax(sta) == MinMax::max())
|
||||||
return required_ - arrival_;
|
return delayDiff(required_, arrival_, sta);
|
||||||
else
|
else
|
||||||
return arrival_ - required_;
|
return delayDiff(arrival_, required_, sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
Path *
|
Path *
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ PathEnd::sourceClkEdge(const StaState *sta) const
|
||||||
return path_->clkEdge(sta);
|
return path_->clkEdge(sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
Arrival
|
const Arrival &
|
||||||
PathEnd::dataArrivalTime(const StaState *) const
|
PathEnd::dataArrivalTime(const StaState *) const
|
||||||
{
|
{
|
||||||
return path_->arrival();
|
return path_->arrival();
|
||||||
|
|
@ -111,13 +111,17 @@ PathEnd::dataArrivalTime(const StaState *) const
|
||||||
Arrival
|
Arrival
|
||||||
PathEnd::dataArrivalTimeOffset(const StaState *sta) const
|
PathEnd::dataArrivalTimeOffset(const StaState *sta) const
|
||||||
{
|
{
|
||||||
return dataArrivalTime(sta) + sourceClkOffset(sta);
|
return delaySum(dataArrivalTime(sta),
|
||||||
|
sourceClkOffset(sta),
|
||||||
|
sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
Required
|
Required
|
||||||
PathEnd::requiredTimeOffset(const StaState *sta) const
|
PathEnd::requiredTimeOffset(const StaState *sta) const
|
||||||
{
|
{
|
||||||
return requiredTime(sta) + sourceClkOffset(sta);
|
return delaySum(requiredTime(sta),
|
||||||
|
sourceClkOffset(sta),
|
||||||
|
sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
const RiseFall *
|
const RiseFall *
|
||||||
|
|
@ -259,9 +263,9 @@ Crpr
|
||||||
PathEnd::checkCrpr(const StaState *sta) const
|
PathEnd::checkCrpr(const StaState *sta) const
|
||||||
{
|
{
|
||||||
if (checkRole(sta)->genericRole() == TimingRole::hold())
|
if (checkRole(sta)->genericRole() == TimingRole::hold())
|
||||||
return -crpr(sta);
|
return delayDiff(delay_zero, crpr(sta), sta);
|
||||||
else
|
else
|
||||||
return crpr(sta);;
|
return crpr(sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
Crpr
|
Crpr
|
||||||
|
|
@ -301,7 +305,7 @@ PathEnd::checkTgtClkDelay(const Path *tgt_clk_path,
|
||||||
Delay insertion, latency;
|
Delay insertion, latency;
|
||||||
checkTgtClkDelay(tgt_clk_path, tgt_clk_edge, check_role, sta,
|
checkTgtClkDelay(tgt_clk_path, tgt_clk_edge, check_role, sta,
|
||||||
insertion, latency);
|
insertion, latency);
|
||||||
return Delay(insertion + latency);
|
return delaySum(insertion, latency, sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -334,7 +338,8 @@ PathEnd::checkTgtClkDelay(const Path *tgt_clk_path,
|
||||||
Delay path_insertion = search->clockInsertion(tgt_clk, tgt_src_pin,
|
Delay path_insertion = search->clockInsertion(tgt_clk, tgt_src_pin,
|
||||||
tgt_clk_rf, min_max,
|
tgt_clk_rf, min_max,
|
||||||
min_max, mode);
|
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
|
else
|
||||||
// Ideal clock.
|
// Ideal clock.
|
||||||
|
|
@ -615,21 +620,25 @@ PathEndClkConstrained::targetClkTime(const StaState *sta) const
|
||||||
Arrival
|
Arrival
|
||||||
PathEndClkConstrained::targetClkArrival(const StaState *sta) const
|
PathEndClkConstrained::targetClkArrival(const StaState *sta) const
|
||||||
{
|
{
|
||||||
return targetClkArrivalNoCrpr(sta)
|
return delaySum(targetClkArrivalNoCrpr(sta),
|
||||||
+ checkCrpr(sta);
|
checkCrpr(sta),
|
||||||
|
sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
Arrival
|
Arrival
|
||||||
PathEndClkConstrained::targetClkArrivalNoCrpr(const StaState *sta) const
|
PathEndClkConstrained::targetClkArrivalNoCrpr(const StaState *sta) const
|
||||||
{
|
{
|
||||||
Sdc *sdc = path_->sdc(sta);
|
Sdc *sdc = path_->sdc(sta);
|
||||||
return targetClkTime(sta)
|
Arrival clk_arrival = delaySum(targetClkDelay(sta),
|
||||||
+ targetClkDelay(sta)
|
targetClkTime(sta),
|
||||||
+ checkClkUncertainty(sourceClkEdge(sta),
|
sta);
|
||||||
targetClkEdge(sta),
|
float uncertainty = checkClkUncertainty(sourceClkEdge(sta),
|
||||||
targetClkPath(),
|
targetClkEdge(sta),
|
||||||
checkRole(sta), sdc)
|
targetClkPath(),
|
||||||
+ targetClkMcpAdjustment(sta);
|
checkRole(sta),
|
||||||
|
sdc);
|
||||||
|
return delaySum(delaySum(clk_arrival, uncertainty, sta),
|
||||||
|
targetClkMcpAdjustment(sta), sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
Delay
|
Delay
|
||||||
|
|
@ -704,8 +713,9 @@ PathEndClkConstrained::crpr(const StaState *sta) const
|
||||||
Required
|
Required
|
||||||
PathEndClkConstrained::requiredTime(const StaState *sta) const
|
PathEndClkConstrained::requiredTime(const StaState *sta) const
|
||||||
{
|
{
|
||||||
return requiredTimeNoCrpr(sta)
|
return delaySum(requiredTimeNoCrpr(sta),
|
||||||
+ checkCrpr(sta);
|
checkCrpr(sta),
|
||||||
|
sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
Required
|
Required
|
||||||
|
|
@ -714,9 +724,9 @@ PathEndClkConstrained::requiredTimeNoCrpr(const StaState *sta) const
|
||||||
Arrival tgt_clk_arrival = targetClkArrivalNoCrpr(sta);
|
Arrival tgt_clk_arrival = targetClkArrivalNoCrpr(sta);
|
||||||
ArcDelay check_margin = margin(sta);
|
ArcDelay check_margin = margin(sta);
|
||||||
if (checkGenericRole(sta) == TimingRole::setup())
|
if (checkGenericRole(sta) == TimingRole::setup())
|
||||||
return tgt_clk_arrival - check_margin;
|
return delayDiff(tgt_clk_arrival, check_margin, sta);
|
||||||
else
|
else
|
||||||
return tgt_clk_arrival + check_margin;
|
return delaySum(tgt_clk_arrival, check_margin, sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
Slack
|
Slack
|
||||||
|
|
@ -725,9 +735,9 @@ PathEndClkConstrained::slack(const StaState *sta) const
|
||||||
Arrival arrival = dataArrivalTime(sta);
|
Arrival arrival = dataArrivalTime(sta);
|
||||||
Required required = requiredTime(sta);
|
Required required = requiredTime(sta);
|
||||||
if (checkGenericRole(sta) == TimingRole::setup())
|
if (checkGenericRole(sta) == TimingRole::setup())
|
||||||
return required - arrival;
|
return delayDiff(required, arrival, sta);
|
||||||
else
|
else
|
||||||
return arrival - required;
|
return delayDiff(arrival, required, sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
@ -862,9 +872,9 @@ PathEndClkConstrained::slackNoCrpr(const StaState *sta) const
|
||||||
Arrival arrival = dataArrivalTime(sta);
|
Arrival arrival = dataArrivalTime(sta);
|
||||||
Required required = requiredTimeNoCrpr(sta);
|
Required required = requiredTimeNoCrpr(sta);
|
||||||
if (checkGenericRole(sta) == TimingRole::setup())
|
if (checkGenericRole(sta) == TimingRole::setup())
|
||||||
return required - arrival;
|
return delayDiff(required, arrival, sta);
|
||||||
else
|
else
|
||||||
return arrival - required;
|
return delayDiff(arrival, required, sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -1017,10 +1027,18 @@ PathEndCheck::exceptPathCmp(const PathEnd *path_end,
|
||||||
Delay
|
Delay
|
||||||
PathEndCheck::clkSkew(const StaState *sta)
|
PathEndCheck::clkSkew(const StaState *sta)
|
||||||
{
|
{
|
||||||
return sourceClkDelay(sta) - targetClkDelay(sta) - crpr(sta)
|
Delay skew = delayDiff(sourceClkDelay(sta),
|
||||||
// Uncertainty decreases slack, but increases skew.
|
targetClkDelay(sta),
|
||||||
- checkTgtClkUncertainty(clk_path_, clk_path_->clkEdge(sta),
|
sta);
|
||||||
checkRole(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
|
Delay
|
||||||
|
|
@ -1035,7 +1053,8 @@ PathEndCheck::sourceClkDelay(const StaState *sta) const
|
||||||
Arrival clk_arrival = src_clk_path->arrival();
|
Arrival clk_arrival = src_clk_path->arrival();
|
||||||
const ClockEdge *src_clk_edge = src_clk_info->clkEdge();
|
const ClockEdge *src_clk_edge = src_clk_info->clkEdge();
|
||||||
Delay insertion = sourceClkInsertionDelay(sta);
|
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
|
else
|
||||||
// Ideal clock.
|
// Ideal clock.
|
||||||
|
|
@ -1052,9 +1071,17 @@ PathEndCheck::requiredTimeNoCrpr(const StaState *sta) const
|
||||||
ArcDelay check_margin = margin(sta);
|
ArcDelay check_margin = margin(sta);
|
||||||
float macro_clk_tree_delay = macroClkTreeDelay(sta);
|
float macro_clk_tree_delay = macroClkTreeDelay(sta);
|
||||||
if (checkGenericRole(sta) == TimingRole::setup())
|
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
|
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
|
float
|
||||||
|
|
@ -1072,7 +1099,7 @@ PathEndCheck::macroClkTreeDelay(const StaState *sta) const
|
||||||
if (clk_port) {
|
if (clk_port) {
|
||||||
const MinMax *min_max = clk_path_->minMax(sta);
|
const MinMax *min_max = clk_path_->minMax(sta);
|
||||||
const RiseFall *rf = clk_path_->transition(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);
|
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_);
|
Arrival enable_arrival = search->clkPathArrival(clk_path_);
|
||||||
const ClkInfo *enable_clk_info = clk_path_->clkInfo(sta);
|
const ClkInfo *enable_clk_info = clk_path_->clkInfo(sta);
|
||||||
if (enable_clk_info->isPulseClk())
|
if (enable_clk_info->isPulseClk())
|
||||||
return disable_arrival - enable_arrival;
|
return delayDiff(disable_arrival, enable_arrival, sta);
|
||||||
else {
|
else {
|
||||||
if (delayGreater(enable_arrival, disable_arrival, sta)) {
|
if (delayGreater(enable_arrival, disable_arrival, sta)) {
|
||||||
const Clock *disable_clk = enable_clk_info->clock();
|
const Clock *disable_clk = enable_clk_info->clock();
|
||||||
if (disable_clk)
|
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 {
|
else {
|
||||||
const ClockEdge *tgt_clk_edge = targetClkEdge(sta);
|
const ClockEdge *tgt_clk_edge = targetClkEdge(sta);
|
||||||
const TimingRole *check_role = checkRole(sta);
|
const TimingRole *check_role = checkRole(sta);
|
||||||
return targetClkTime(sta)
|
Arrival base = delaySum(targetClkTime(sta),
|
||||||
+ tgtClkDelay(tgt_clk_edge, check_role, sta)
|
tgtClkDelay(tgt_clk_edge, check_role, sta),
|
||||||
+ targetClkUncertainty(sta)
|
sta);
|
||||||
+ checkMcpAdjustment(path_, tgt_clk_edge, 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;
|
Arrival insertion, latency;
|
||||||
tgtClkDelay(tgt_clk_edge, check_role, sta,
|
tgtClkDelay(tgt_clk_edge, check_role, sta,
|
||||||
insertion, latency);
|
insertion, latency);
|
||||||
return insertion + latency;
|
return delaySum(insertion, latency, sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -1691,17 +1724,23 @@ PathEndDataCheck::requiredTimeNoCrpr(const StaState *sta) const
|
||||||
{
|
{
|
||||||
Arrival data_clk_arrival = data_clk_path_->arrival();
|
Arrival data_clk_arrival = data_clk_path_->arrival();
|
||||||
float data_clk_time = data_clk_path_->clkEdge(sta)->time();
|
float data_clk_time = data_clk_path_->clkEdge(sta)->time();
|
||||||
Arrival data_clk_delay = data_clk_arrival - data_clk_time;
|
Arrival data_clk_delay = delayDiff(data_clk_arrival,
|
||||||
Arrival tgt_clk_arrival = targetClkTime(sta)
|
data_clk_time,
|
||||||
+ data_clk_delay
|
sta);
|
||||||
+ targetClkUncertainty(sta)
|
Arrival tgt_clk_arrival =
|
||||||
+ targetClkMcpAdjustment(sta);
|
delaySum(delaySum(targetClkTime(sta),
|
||||||
|
data_clk_delay,
|
||||||
|
sta),
|
||||||
|
delaySum(targetClkUncertainty(sta),
|
||||||
|
targetClkMcpAdjustment(sta),
|
||||||
|
sta),
|
||||||
|
sta);
|
||||||
|
|
||||||
ArcDelay check_margin = margin(sta);
|
ArcDelay check_margin = margin(sta);
|
||||||
if (checkGenericRole(sta) == TimingRole::setup())
|
if (checkGenericRole(sta) == TimingRole::setup())
|
||||||
return tgt_clk_arrival - check_margin;
|
return delayDiff(tgt_clk_arrival, check_margin, sta);
|
||||||
else
|
else
|
||||||
return tgt_clk_arrival + check_margin;
|
return delaySum(tgt_clk_arrival, check_margin, sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArcDelay
|
ArcDelay
|
||||||
|
|
@ -1917,7 +1956,7 @@ PathEnd::pathDelaySrcClkOffset(const Path *path,
|
||||||
const ClockEdge *clk_edge = path->clkEdge(sta);
|
const ClockEdge *clk_edge = path->clkEdge(sta);
|
||||||
if (clk_edge) {
|
if (clk_edge) {
|
||||||
if (ignoreClkLatency(path, path_delay, sta))
|
if (ignoreClkLatency(path, path_delay, sta))
|
||||||
offset = -delayAsFloat(src_clk_arrival);
|
offset = -delayAsFloat(src_clk_arrival, path->minMax(sta), sta);
|
||||||
else
|
else
|
||||||
// Arrival includes src clock edge time that is not counted in the
|
// Arrival includes src clock edge time that is not counted in the
|
||||||
// path delay.
|
// path delay.
|
||||||
|
|
@ -1960,8 +1999,9 @@ PathEndPathDelay::targetClkArrivalNoCrpr(const StaState *sta) const
|
||||||
{
|
{
|
||||||
const ClockEdge *tgt_clk_edge = targetClkEdge(sta);
|
const ClockEdge *tgt_clk_edge = targetClkEdge(sta);
|
||||||
if (tgt_clk_edge)
|
if (tgt_clk_edge)
|
||||||
return targetClkDelay(sta)
|
return delaySum(targetClkDelay(sta),
|
||||||
+ targetClkUncertainty(sta);
|
targetClkUncertainty(sta),
|
||||||
|
sta);
|
||||||
else if (clk_path_)
|
else if (clk_path_)
|
||||||
return clk_path_->arrival();
|
return clk_path_->arrival();
|
||||||
else
|
else
|
||||||
|
|
@ -1979,19 +2019,29 @@ PathEndPathDelay::requiredTime(const StaState *sta) const
|
||||||
{
|
{
|
||||||
float delay = path_delay_->delay();
|
float delay = path_delay_->delay();
|
||||||
if (path_delay_->ignoreClkLatency()) {
|
if (path_delay_->ignoreClkLatency()) {
|
||||||
Required src_offset = path_->isClock(sta)
|
Delay with_delay = path_->isClock(sta)
|
||||||
? path_->clkEdge(sta)->time()
|
? Delay(path_->clkEdge(sta)->time() + delay)
|
||||||
: src_clk_arrival_;
|
: delaySum(src_clk_arrival_, delay, sta);
|
||||||
return src_offset + delay
|
ArcDelay m = margin(sta);
|
||||||
+ ((minMax(sta) == MinMax::max()) ? -margin(sta) : margin(sta));
|
return (minMax(sta) == MinMax::max())
|
||||||
|
? delayDiff(with_delay, m, sta)
|
||||||
|
: delaySum(with_delay, m, sta);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Arrival tgt_clk_arrival = targetClkArrival(sta);
|
Arrival tgt_clk_arrival = targetClkArrival(sta);
|
||||||
float src_clk_offset = sourceClkOffset(sta);
|
float src_clk_offset = sourceClkOffset(sta);
|
||||||
// Path delay includes target clk latency and timing check setup/hold
|
// Path delay includes target clk latency and timing check setup/hold
|
||||||
// margin or external departure at target.
|
// margin or external departure at target.
|
||||||
return delay - src_clk_offset + tgt_clk_arrival
|
Delay base = delaySum(tgt_clk_arrival,
|
||||||
+ ((minMax(sta) == MinMax::max()) ? -margin(sta) : margin(sta));
|
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 slack1 = path_end1->slack(sta);
|
||||||
Slack slack2 = path_end2->slack(sta);
|
Slack slack2 = path_end2->slack(sta);
|
||||||
if (delayZero(slack1)
|
if (delayZero(slack1, sta)
|
||||||
&& delayZero(slack2)
|
&& delayZero(slack2, sta)
|
||||||
&& path_end1->isLatchCheck()
|
&& path_end1->isLatchCheck()
|
||||||
&& path_end2->isLatchCheck()) {
|
&& path_end2->isLatchCheck()) {
|
||||||
Arrival borrow1 = path_end1->borrow(sta);
|
Arrival borrow1 = path_end1->borrow(sta);
|
||||||
Arrival borrow2 = path_end2->borrow(sta);
|
Arrival borrow2 = path_end2->borrow(sta);
|
||||||
// Latch slack is zero if there is borrowing so break ties
|
// Latch slack is zero if there is borrowing so break ties
|
||||||
// based on borrow time.
|
// based on borrow time.
|
||||||
if (delayEqual(borrow1, borrow2))
|
if (delayEqual(borrow1, borrow2, sta))
|
||||||
return 0;
|
return 0;
|
||||||
else if (delayGreater(borrow1, borrow2, sta))
|
else if (delayGreater(borrow1, borrow2, sta))
|
||||||
return -1;
|
return -1;
|
||||||
else
|
else
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else if (delayEqual(slack1, slack2))
|
else if (delayEqual(slack1, slack2, sta))
|
||||||
return 0;
|
return 0;
|
||||||
else if (delayLess(slack1, slack2, sta))
|
else if (delayLess(slack1, slack2, sta))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -2104,7 +2154,7 @@ PathEnd::cmpArrival(const PathEnd *path_end1,
|
||||||
Arrival arrival1 = path_end1->dataArrivalTime(sta);
|
Arrival arrival1 = path_end1->dataArrivalTime(sta);
|
||||||
Arrival arrival2 = path_end2->dataArrivalTime(sta);
|
Arrival arrival2 = path_end2->dataArrivalTime(sta);
|
||||||
const MinMax *min_max = path_end1->minMax(sta);
|
const MinMax *min_max = path_end1->minMax(sta);
|
||||||
if (delayEqual(arrival1, arrival2))
|
if (delayEqual(arrival1, arrival2, sta))
|
||||||
return 0;
|
return 0;
|
||||||
else if (delayLess(arrival1, arrival2, min_max, sta))
|
else if (delayLess(arrival1, arrival2, min_max, sta))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
||||||
|
|
@ -511,9 +511,11 @@ PathEnumFaninVisitor::reportDiversion(const Edge *div_edge,
|
||||||
Arrival path_delay = path_enum_->cmp_slack_
|
Arrival path_delay = path_enum_->cmp_slack_
|
||||||
? path_end_->slack(this)
|
? path_end_->slack(this)
|
||||||
: path_end_->dataArrivalTime(this);
|
: path_end_->dataArrivalTime(this);
|
||||||
Arrival div_delay = path_delay - path_enum_->divSlack(before_div_,
|
Arrival div_delay = delayDiff(path_delay,
|
||||||
after_div, div_edge,
|
path_enum_->divSlack(before_div_,
|
||||||
div_arc);
|
after_div, div_edge,
|
||||||
|
div_arc),
|
||||||
|
this);
|
||||||
Path *div_prev = before_div_->prevPath();
|
Path *div_prev = before_div_->prevPath();
|
||||||
report_->reportLine("path_enum: diversion %s %s %s -> %s",
|
report_->reportLine("path_enum: diversion %s %s %s -> %s",
|
||||||
path->to_string(this).c_str(),
|
path->to_string(this).c_str(),
|
||||||
|
|
@ -580,7 +582,7 @@ PathEnum::divSlack(Path *before_div,
|
||||||
Tag *q_tag;
|
Tag *q_tag;
|
||||||
latches_->latchOutArrival(after_div, div_arc, div_edge,
|
latches_->latchOutArrival(after_div, div_arc, div_edge,
|
||||||
q_tag, div_delay, div_arrival);
|
q_tag, div_delay, div_arrival);
|
||||||
return div_arrival - before_div_arrival;
|
return delayDiff(div_arrival, before_div_arrival, this);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
DcalcAPIndex dcalc_ap = before_div->dcalcAnalysisPtIndex(this);
|
DcalcAPIndex dcalc_ap = before_div->dcalcAnalysisPtIndex(this);
|
||||||
|
|
@ -589,8 +591,8 @@ PathEnum::divSlack(Path *before_div,
|
||||||
false, before_div->minMax(this),
|
false, before_div->minMax(this),
|
||||||
dcalc_ap,
|
dcalc_ap,
|
||||||
before_div->sdc(this));
|
before_div->sdc(this));
|
||||||
Arrival div_arrival = search_->clkPathArrival(after_div) + div_delay;
|
Arrival div_arrival = delaySum(search_->clkPathArrival(after_div), div_delay, this);
|
||||||
return div_arrival - before_div_arrival;
|
return delayDiff(div_arrival, before_div_arrival, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -719,7 +721,7 @@ PathEnum::updatePathHeadDelays(PathSeq &paths,
|
||||||
path->minMax(this),
|
path->minMax(this),
|
||||||
path->dcalcAnalysisPtIndex(this),
|
path->dcalcAnalysisPtIndex(this),
|
||||||
path->sdc(this));
|
path->sdc(this));
|
||||||
arrival = prev_arrival + arc_delay;
|
arrival = delaySum(prev_arrival, arc_delay, this);
|
||||||
path->setArrival(arrival);
|
path->setArrival(arrival);
|
||||||
const Tag *tag = path->tag(this);
|
const Tag *tag = path->tag(this);
|
||||||
const ClkInfo *clk_info = tag->clkInfo();
|
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) {
|
if (to_rf == rf) {
|
||||||
for (const Scene *scene : sta_->scenes()) {
|
for (const Scene *scene : sta_->scenes()) {
|
||||||
DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max);
|
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
|
if (!delay_exists
|
||||||
|| delayGreater(arc_delay, delay, min_max, sta_)) {
|
|| delayGreater(arc_delay, delay, min_max, sta_)) {
|
||||||
delay = arc_delay;
|
delay = arc_delay;
|
||||||
|
|
|
||||||
|
|
@ -134,20 +134,18 @@ ReportField::setEnabled(bool enabled)
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
const float ReportPath::field_blank_ = -1.0;
|
|
||||||
|
|
||||||
ReportPath::ReportPath(StaState *sta) :
|
ReportPath::ReportPath(StaState *sta) :
|
||||||
StaState(sta),
|
StaState(sta),
|
||||||
format_(ReportPathFormat::full),
|
format_(ReportPathFormat::full),
|
||||||
no_split_(false),
|
no_split_(false),
|
||||||
report_sigmas_(false),
|
|
||||||
start_end_pt_width_(80),
|
start_end_pt_width_(80),
|
||||||
|
field_width_extra_(5),
|
||||||
plus_zero_(nullptr),
|
plus_zero_(nullptr),
|
||||||
minus_zero_(nullptr)
|
minus_zero_(nullptr)
|
||||||
{
|
{
|
||||||
setDigits(2);
|
|
||||||
makeFields();
|
makeFields();
|
||||||
setReportFields(false, false, false, false, false, false, false);
|
setDigits(2);
|
||||||
|
setReportFields(false, false, false, false, false, false, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReportPath::~ReportPath()
|
ReportPath::~ReportPath()
|
||||||
|
|
@ -158,6 +156,7 @@ ReportPath::~ReportPath()
|
||||||
delete field_capacitance_;
|
delete field_capacitance_;
|
||||||
delete field_slew_;
|
delete field_slew_;
|
||||||
delete field_fanout_;
|
delete field_fanout_;
|
||||||
|
delete field_variation_;
|
||||||
delete field_src_attr_;
|
delete field_src_attr_;
|
||||||
delete field_edge_;
|
delete field_edge_;
|
||||||
delete field_case_;
|
delete field_case_;
|
||||||
|
|
@ -169,6 +168,7 @@ ReportPath::~ReportPath()
|
||||||
void
|
void
|
||||||
ReportPath::makeFields()
|
ReportPath::makeFields()
|
||||||
{
|
{
|
||||||
|
// The order corresponds to the default field order.
|
||||||
field_fanout_ = makeField("fanout", "Fanout", 6, false, nullptr, true);
|
field_fanout_ = makeField("fanout", "Fanout", 6, false, nullptr, true);
|
||||||
field_capacitance_ = makeField("capacitance", "Cap", 6, false,
|
field_capacitance_ = makeField("capacitance", "Cap", 6, false,
|
||||||
units_->capacitanceUnit(), true);
|
units_->capacitanceUnit(), true);
|
||||||
|
|
@ -176,6 +176,8 @@ ReportPath::makeFields()
|
||||||
true);
|
true);
|
||||||
field_incr_ = makeField("incr", "Delay", 6, false, units_->timeUnit(),
|
field_incr_ = makeField("incr", "Delay", 6, false, units_->timeUnit(),
|
||||||
true);
|
true);
|
||||||
|
field_variation_ = makeField("variation", "Variation", 6, false,
|
||||||
|
units_->timeUnit(), false);
|
||||||
field_total_ = makeField("total", "Time", 6, false, units_->timeUnit(),
|
field_total_ = makeField("total", "Time", 6, false, units_->timeUnit(),
|
||||||
true);
|
true);
|
||||||
field_edge_ = makeField("edge", "", 1, false, nullptr, true);
|
field_edge_ = makeField("edge", "", 1, false, nullptr, true);
|
||||||
|
|
@ -243,6 +245,7 @@ ReportPath::setReportFields(bool report_input_pin,
|
||||||
bool report_cap,
|
bool report_cap,
|
||||||
bool report_slew,
|
bool report_slew,
|
||||||
bool report_fanout,
|
bool report_fanout,
|
||||||
|
bool report_variation,
|
||||||
bool report_src_attr)
|
bool report_src_attr)
|
||||||
{
|
{
|
||||||
report_input_pin_ = report_input_pin;
|
report_input_pin_ = report_input_pin;
|
||||||
|
|
@ -252,6 +255,7 @@ ReportPath::setReportFields(bool report_input_pin,
|
||||||
field_capacitance_->setEnabled(report_cap);
|
field_capacitance_->setEnabled(report_cap);
|
||||||
field_slew_->setEnabled(report_slew);
|
field_slew_->setEnabled(report_slew);
|
||||||
field_fanout_->setEnabled(report_fanout);
|
field_fanout_->setEnabled(report_fanout);
|
||||||
|
field_variation_->setEnabled(report_variation);
|
||||||
field_src_attr_->setEnabled(report_src_attr);
|
field_src_attr_->setEnabled(report_src_attr);
|
||||||
// for debug
|
// for debug
|
||||||
field_case_->setEnabled(false);
|
field_case_->setEnabled(false);
|
||||||
|
|
@ -278,12 +282,14 @@ ReportPath::setDigits(int digits)
|
||||||
stringDelete(minus_zero_);
|
stringDelete(minus_zero_);
|
||||||
minus_zero_ = stringPrint("-%.*f", digits_, 0.0);
|
minus_zero_ = stringPrint("-%.*f", digits_, 0.0);
|
||||||
plus_zero_ = stringPrint("%.*f", digits_, 0.0);
|
plus_zero_ = stringPrint("%.*f", digits_, 0.0);
|
||||||
}
|
|
||||||
|
|
||||||
void
|
// Numeric field width expands with digits.
|
||||||
ReportPath::setReportSigmas(bool report)
|
int field_width = digits + field_width_extra_;
|
||||||
{
|
field_capacitance_->setWidth(field_width);
|
||||||
report_sigmas_ = report;
|
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,
|
end->latchRequired(this, req_time, borrow, adjusted_data_arrival,
|
||||||
time_given_to_startpoint);
|
time_given_to_startpoint);
|
||||||
// Adjust required to requiredTimeOffset.
|
// Adjust required to requiredTimeOffset.
|
||||||
req_time += end->sourceClkOffset(this);
|
req_time = delaySum(req_time, end->sourceClkOffset(this), this);
|
||||||
if (path_delay) {
|
if (path_delay) {
|
||||||
float delay = path_delay->delay();
|
float delay = path_delay->delay();
|
||||||
reportLine("max_delay", delay, delay, early_late);
|
reportLine("max_delay", delay, delay, early_late);
|
||||||
|
|
@ -630,7 +636,7 @@ ReportPath::reportBorrowing(const PathEndLatchCheck *end,
|
||||||
if (tgt_clk_path->clkInfo(search_)->isPropagated()) {
|
if (tgt_clk_path->clkInfo(search_)->isPropagated()) {
|
||||||
auto width_msg = stdstrPrint("%s nominal pulse width", tgt_clk_name.c_str());
|
auto width_msg = stdstrPrint("%s nominal pulse width", tgt_clk_name.c_str());
|
||||||
reportLineTotal(width_msg.c_str(), nom_pulse_width, early_late);
|
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);
|
reportLineTotalMinus("clock latency difference", latency_diff, early_late);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -640,18 +646,18 @@ ReportPath::reportBorrowing(const PathEndLatchCheck *end,
|
||||||
ArcDelay margin = end->margin(this);
|
ArcDelay margin = end->margin(this);
|
||||||
reportLineTotalMinus("library setup time", margin, early_late);
|
reportLineTotalMinus("library setup time", margin, early_late);
|
||||||
reportDashLineTotal();
|
reportDashLineTotal();
|
||||||
if (!delayZero(crpr_diff))
|
if (!delayZero(crpr_diff, this))
|
||||||
reportLineTotalMinus("CRPR difference", crpr_diff, early_late);
|
reportLineTotalMinus("CRPR difference", crpr_diff, early_late);
|
||||||
reportLineTotal("max time borrow", max_borrow, early_late);
|
reportLineTotal("max time borrow", max_borrow, early_late);
|
||||||
}
|
}
|
||||||
if (delayGreater(borrow, delay_zero, this)
|
if (delayGreater(borrow, delay_zero, this)
|
||||||
&& (!fuzzyZero(open_uncertainty)
|
&& (!fuzzyZero(open_uncertainty)
|
||||||
|| !delayZero(open_crpr))) {
|
|| !delayZero(open_crpr, this))) {
|
||||||
reportDashLineTotal();
|
reportDashLineTotal();
|
||||||
reportLineTotal("actual time borrow", borrow, early_late);
|
reportLineTotal("actual time borrow", borrow, early_late);
|
||||||
if (!fuzzyZero(open_uncertainty))
|
if (!fuzzyZero(open_uncertainty))
|
||||||
reportLineTotal("open edge uncertainty", open_uncertainty, early_late);
|
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);
|
reportLineTotal("open edge CRPR", open_crpr, early_late);
|
||||||
reportDashLineTotal();
|
reportDashLineTotal();
|
||||||
reportLineTotal("time given to startpoint", time_given_to_startpoint, early_late);
|
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);
|
ArcDelay margin = end->margin(this);
|
||||||
const MinMax *min_max = path_delay->minMax()->asMinMax();
|
const MinMax *min_max = path_delay->minMax()->asMinMax();
|
||||||
if (min_max == MinMax::max())
|
if (min_max == MinMax::max())
|
||||||
margin = -margin;
|
margin = delayDiff(delay_zero, margin, this);
|
||||||
|
|
||||||
std::string delay_msg = min_max->to_string() + "_delay";
|
std::string delay_msg = min_max->to_string() + "_delay";
|
||||||
float delay = path_delay->delay();
|
float delay = path_delay->delay();
|
||||||
|
|
@ -734,8 +740,8 @@ ReportPath::reportFull(const PathEndPathDelay *end) const
|
||||||
reportTgtClk(end, delay, 0.0, true);
|
reportTgtClk(end, delay, 0.0, true);
|
||||||
else {
|
else {
|
||||||
Arrival tgt_clk_delay = end->targetClkDelay(this);
|
Arrival tgt_clk_delay = end->targetClkDelay(this);
|
||||||
Arrival tgt_clk_arrival = delay + tgt_clk_delay;
|
Arrival tgt_clk_arrival = delaySum(tgt_clk_delay, delay, this);
|
||||||
if (!delayZero(tgt_clk_delay))
|
if (!delayZero(tgt_clk_delay, this))
|
||||||
reportLine(clkNetworkDelayIdealProp(isPropagated(tgt_clk_path)),
|
reportLine(clkNetworkDelayIdealProp(isPropagated(tgt_clk_path)),
|
||||||
tgt_clk_delay, tgt_clk_arrival, early_late);
|
tgt_clk_delay, tgt_clk_arrival, early_late);
|
||||||
reportClkUncertainty(end, tgt_clk_arrival);
|
reportClkUncertainty(end, tgt_clk_arrival);
|
||||||
|
|
@ -924,10 +930,11 @@ ReportPath::reportFull(const PathEndDataCheck *end) const
|
||||||
PathExpanded clk_expanded(data_clk_path, this);
|
PathExpanded clk_expanded(data_clk_path, this);
|
||||||
float src_offset = end->sourceClkOffset(this);
|
float src_offset = end->sourceClkOffset(this);
|
||||||
Delay clk_delay = end->targetClkDelay(this);
|
Delay clk_delay = end->targetClkDelay(this);
|
||||||
|
const MinMax *min_max = data_clk_path->minMax(this);
|
||||||
Arrival clk_arrival = end->targetClkArrival(this);
|
Arrival clk_arrival = end->targetClkArrival(this);
|
||||||
const ClockEdge *tgt_clk_edge = end->targetClkEdge(this);
|
const ClockEdge *tgt_clk_edge = end->targetClkEdge(this);
|
||||||
float prev = delayAsFloat(clk_arrival) + src_offset;
|
float prev = delayAsFloat(clk_arrival, min_max, this) + src_offset;
|
||||||
float offset = prev - delayAsFloat(clk_delay) - tgt_clk_edge->time();
|
float offset = prev - delayAsFloat(clk_delay, min_max, this) - tgt_clk_edge->time();
|
||||||
// Delay to startpoint is already included.
|
// Delay to startpoint is already included.
|
||||||
reportPath6(data_clk_path, clk_expanded, clk_expanded.startIndex(),
|
reportPath6(data_clk_path, clk_expanded, clk_expanded.startIndex(),
|
||||||
true, false, prev, offset);
|
true, false, prev, offset);
|
||||||
|
|
@ -1397,13 +1404,15 @@ ReportPath::reportVerbose(const MinPulseWidthCheck &check) const
|
||||||
float close_clk_time = close_clk_edge->time() + close_offset;
|
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);
|
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);
|
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(clk_ideal_prop, check.closeDelay(this), close_arrival, close_el);
|
||||||
|
|
||||||
reportLine(pin_name, delay_zero, close_arrival, close_el);
|
reportLine(pin_name, delay_zero, close_arrival, close_el);
|
||||||
|
|
||||||
if (variables_->crprEnabled()) {
|
if (variables_->crprEnabled()) {
|
||||||
Crpr pessimism = check.checkCrpr(this);
|
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("clock reconvergence pessimism", pessimism, close_arrival, close_el);
|
||||||
}
|
}
|
||||||
reportLine("close edge arrival time", 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);
|
reportDescription(what.c_str(), line);
|
||||||
const EarlyLate *early_late = EarlyLate::early();
|
const EarlyLate *early_late = EarlyLate::early();
|
||||||
reportSpaceFieldDelay(check.maxSkew(this), early_late, line);
|
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);
|
reportSpaceSlack(check.slack(this), line);
|
||||||
report_->reportLineString(line);
|
report_->reportLineString(line);
|
||||||
}
|
}
|
||||||
|
|
@ -1607,7 +1616,7 @@ ReportPath::reportVerbose(const MaxSkewCheck &check) const
|
||||||
|
|
||||||
reportDashLine();
|
reportDashLine();
|
||||||
reportLine("allowable skew", check.maxSkew(this), EarlyLate::early());
|
reportLine("allowable skew", check.maxSkew(this), EarlyLate::early());
|
||||||
reportLine("actual skew", check.skew(), EarlyLate::late());
|
reportLine("actual skew", check.skew(this), EarlyLate::late());
|
||||||
reportDashLine();
|
reportDashLine();
|
||||||
reportSlack(check.slack(this));
|
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);
|
std::string clk_name = clkName(clk, clk_end_rf != clk_rf);
|
||||||
float clk_time = clk_edge->time();
|
float clk_time = clk_edge->time();
|
||||||
const Arrival &clk_arrival = search_->clkPathArrival(clk_path);
|
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);
|
const MinMax *min_max = clk_path->minMax(this);
|
||||||
Vertex *clk_vertex = clk_path->vertex(this);
|
Vertex *clk_vertex = clk_path->vertex(this);
|
||||||
reportClkLine(clk, clk_name.c_str(), clk_end_rf, clk_time, min_max);
|
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 Path *clk_path = expanded.clkPath();
|
||||||
const RiseFall *clk_end_rf;
|
const RiseFall *clk_end_rf;
|
||||||
if (clk_path) {
|
if (clk_path) {
|
||||||
clk_end_time = search_->clkPathArrival(clk_path) + time_offset;
|
clk_end_time = delaySum(search_->clkPathArrival(clk_path),
|
||||||
clk_delay = clk_end_time - clk_time;
|
time_offset,
|
||||||
|
this);
|
||||||
|
clk_delay = delayDiff(clk_end_time,
|
||||||
|
clk_time,
|
||||||
|
this);
|
||||||
clk_end_rf = clk_path->transition(this);
|
clk_end_rf = clk_path->transition(this);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Path from input port or clk used as data.
|
// Path from input port or clk used as data.
|
||||||
clk_end_rf = clk_rf;
|
clk_end_rf = clk_rf;
|
||||||
clk_delay = clk_insertion + clk_latency;
|
clk_delay = delaySum(clk_insertion, clk_latency, this);
|
||||||
clk_end_time = clk_time + clk_delay;
|
clk_end_time = delaySum(clk_time, clk_delay, this);
|
||||||
|
|
||||||
const Path *first_path = expanded.startPath();
|
const Path *first_path = expanded.startPath();
|
||||||
const InputDelay *input_delay = pathInputDelay(first_path);
|
const InputDelay *input_delay = pathInputDelay(first_path);
|
||||||
|
|
@ -2086,8 +2101,12 @@ ReportPath::reportSrcClkAndPath(const Path *path,
|
||||||
pathInputDelayRefPath(first_path, input_delay, ref_path);
|
pathInputDelayRefPath(first_path, input_delay, ref_path);
|
||||||
if (!ref_path.isNull()) {
|
if (!ref_path.isNull()) {
|
||||||
const Arrival &ref_end_time = ref_path.arrival();
|
const Arrival &ref_end_time = ref_path.arrival();
|
||||||
clk_delay = ref_end_time - clk_time;
|
clk_delay = delayDiff(ref_end_time,
|
||||||
clk_end_time = ref_end_time + time_offset;
|
clk_time,
|
||||||
|
this);
|
||||||
|
clk_end_time = delaySum(ref_end_time,
|
||||||
|
time_offset,
|
||||||
|
this);
|
||||||
input_has_ref_path = true;
|
input_has_ref_path = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2127,8 +2146,10 @@ ReportPath::reportSrcClkAndPath(const Path *path,
|
||||||
reportPath1(path, expanded, true, time_offset);
|
reportPath1(path, expanded, true, time_offset);
|
||||||
else {
|
else {
|
||||||
Arrival clk_arrival = clk_end_time;
|
Arrival clk_arrival = clk_end_time;
|
||||||
Arrival end_arrival = path->arrival() + time_offset;
|
Arrival end_arrival = delaySum(path->arrival(),
|
||||||
Delay clk_delay = end_arrival - clk_arrival;
|
time_offset,
|
||||||
|
this);
|
||||||
|
Delay clk_delay = delayDiff(end_arrival, clk_arrival, this);
|
||||||
reportLine("clock network delay", clk_delay,
|
reportLine("clock network delay", clk_delay,
|
||||||
end_arrival, early_late);
|
end_arrival, early_late);
|
||||||
Vertex *end_vertex = path->vertex(this);
|
Vertex *end_vertex = path->vertex(this);
|
||||||
|
|
@ -2187,7 +2208,7 @@ ReportPath::reportTgtClk(const PathEnd *end,
|
||||||
bool is_prop) const
|
bool is_prop) const
|
||||||
{
|
{
|
||||||
const ClockEdge *clk_edge = end->targetClkEdge(this);
|
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_rf = clk_edge->transition();
|
||||||
const RiseFall *clk_end_rf = end->targetClkEndTrans(this);
|
const RiseFall *clk_end_rf = end->targetClkEndTrans(this);
|
||||||
std::string clk_name = clkName(clk, clk_end_rf != clk_rf);
|
std::string clk_name = clkName(clk, clk_end_rf != clk_rf);
|
||||||
|
|
@ -2196,7 +2217,7 @@ ReportPath::reportTgtClk(const PathEnd *end,
|
||||||
+ end->targetClkMcpAdjustment(this)
|
+ end->targetClkMcpAdjustment(this)
|
||||||
+ src_offset;
|
+ src_offset;
|
||||||
Arrival clk_delay = end->targetClkDelay(this);
|
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 MinMax *min_max = end->path()->tgtClkMinMax(this);
|
||||||
const Path *clk_path = end->targetClkPath();
|
const Path *clk_path = end->targetClkPath();
|
||||||
reportClkLine(clk, clk_name.c_str(), clk_end_rf, prev_time, clk_time, min_max);
|
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 {
|
else {
|
||||||
// Output departure.
|
// Output departure.
|
||||||
Arrival clk_arrival = clk_time + clk_delay;
|
Arrival clk_arrival = delaySum(clk_time, clk_delay, this);
|
||||||
reportLine(clkNetworkDelayIdealProp(clk->isPropagated()),
|
reportLine(clkNetworkDelayIdealProp(clk->isPropagated()),
|
||||||
clk_delay, clk_arrival, min_max);
|
clk_delay, clk_arrival, min_max);
|
||||||
}
|
}
|
||||||
|
|
@ -2241,9 +2262,11 @@ ReportPath::reportTgtClk(const PathEnd *end,
|
||||||
if (clk_path) {
|
if (clk_path) {
|
||||||
Vertex *clk_vertex = clk_path->vertex(this);
|
Vertex *clk_vertex = clk_path->vertex(this);
|
||||||
reportLine(descriptionField(clk_vertex).c_str(),
|
reportLine(descriptionField(clk_vertex).c_str(),
|
||||||
prev_time
|
delaySum(delaySum(prev_time,
|
||||||
+ end->targetClkArrival(this)
|
end->targetClkArrival(this),
|
||||||
+ end->sourceClkOffset(this),
|
this),
|
||||||
|
end->sourceClkOffset(this),
|
||||||
|
this),
|
||||||
min_max, clk_end_rf);
|
min_max, clk_end_rf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2264,7 +2287,7 @@ ReportPath::tgtClkInsertionOffet(const Path *clk_path,
|
||||||
min_max, min_max, mode);
|
min_max, min_max, mode);
|
||||||
Arrival tgt_insertion = search_->clockInsertion(clk, src_pin, clk_rf,
|
Arrival tgt_insertion = search_->clockInsertion(clk, src_pin, clk_rf,
|
||||||
min_max, early_late, mode);
|
min_max, early_late, mode);
|
||||||
return delayAsFloat(tgt_insertion - path_insertion);
|
return delayAsFloat(delayDiff(tgt_insertion, path_insertion, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
@ -2327,11 +2350,18 @@ ReportPath::reportClkLine(const Clock *clk,
|
||||||
const char *rise_fall = asRiseFall(clk_rf);
|
const char *rise_fall = asRiseFall(clk_rf);
|
||||||
auto clk_msg = stdstrPrint("clock %s (%s edge)", clk_name, rise_fall);
|
auto clk_msg = stdstrPrint("clock %s (%s edge)", clk_name, rise_fall);
|
||||||
if (clk->isPropagated())
|
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 {
|
else {
|
||||||
// Report ideal clock slew.
|
// Report ideal clock slew.
|
||||||
float clk_slew = clk->slew(clk_rf, min_max);
|
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,
|
float clk_time,
|
||||||
const EarlyLate *early_late) const
|
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
|
void
|
||||||
ReportPath::reportPathLine(const Path *path,
|
ReportPath::reportPathLine(const Path *path,
|
||||||
Arrival incr,
|
const Delay &incr,
|
||||||
Arrival time,
|
const Arrival &time,
|
||||||
const char *line_case) const
|
const char *line_case) const
|
||||||
{
|
{
|
||||||
Vertex *vertex = path->vertex(this);
|
Vertex *vertex = path->vertex(this);
|
||||||
|
|
@ -2461,7 +2494,7 @@ ReportPath::reportPathLine(const Path *path,
|
||||||
if (is_driver && field_capacitance_->enabled())
|
if (is_driver && field_capacitance_->enabled())
|
||||||
cap = graph_delay_calc_->loadCap(pin, rf, scene, min_max);
|
cap = graph_delay_calc_->loadCap(pin, rf, scene, min_max);
|
||||||
reportLine(what.c_str(), cap, slew, field_blank_,
|
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);
|
line_case);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2474,13 +2507,16 @@ ReportPath::reportRequired(const PathEnd *end,
|
||||||
float macro_clk_tree_delay = end->macroClkTreeDelay(this);
|
float macro_clk_tree_delay = end->macroClkTreeDelay(this);
|
||||||
ArcDelay margin = end->margin(this);
|
ArcDelay margin = end->margin(this);
|
||||||
if (end->minMax(this) == MinMax::min()) {
|
if (end->minMax(this) == MinMax::min()) {
|
||||||
margin = -margin;
|
margin = delayDiff(delay_zero, margin, this);
|
||||||
macro_clk_tree_delay = -macro_clk_tree_delay;
|
macro_clk_tree_delay = -macro_clk_tree_delay;
|
||||||
}
|
}
|
||||||
if (macro_clk_tree_delay != 0.0)
|
if (macro_clk_tree_delay != 0.0)
|
||||||
reportLine("macro clock tree delay", -macro_clk_tree_delay,
|
reportLine("macro clock tree delay", -macro_clk_tree_delay,
|
||||||
req_time + margin, early_late);
|
delaySum(req_time, margin, this), early_late);
|
||||||
reportLine(margin_msg.c_str(), -margin, req_time, early_late);
|
reportLine(margin_msg.c_str(),
|
||||||
|
delayDiff(delay_zero, margin, this),
|
||||||
|
req_time,
|
||||||
|
early_late);
|
||||||
reportLine("data required time", req_time, early_late);
|
reportLine("data required time", req_time, early_late);
|
||||||
reportDashLine();
|
reportDashLine();
|
||||||
}
|
}
|
||||||
|
|
@ -2531,7 +2567,7 @@ ReportPath::reportCommonClkPessimism(const PathEnd *end,
|
||||||
{
|
{
|
||||||
if (variables_->crprEnabled()) {
|
if (variables_->crprEnabled()) {
|
||||||
Crpr pessimism = end->checkCrpr(this);
|
Crpr pessimism = end->checkCrpr(this);
|
||||||
clk_arrival += pessimism;
|
clk_arrival = delaySum(clk_arrival, pessimism, this);
|
||||||
reportLine("clock reconvergence pessimism", pessimism, clk_arrival,
|
reportLine("clock reconvergence pessimism", pessimism, clk_arrival,
|
||||||
end->clkEarlyLate(this));
|
end->clkEarlyLate(this));
|
||||||
}
|
}
|
||||||
|
|
@ -2543,11 +2579,15 @@ ReportPath::reportClkUncertainty(const PathEnd *end,
|
||||||
{
|
{
|
||||||
const EarlyLate *early_late = end->clkEarlyLate(this);
|
const EarlyLate *early_late = end->clkEarlyLate(this);
|
||||||
float uncertainty = end->targetNonInterClkUncertainty(this);
|
float uncertainty = end->targetNonInterClkUncertainty(this);
|
||||||
clk_arrival += uncertainty;
|
clk_arrival = delaySum(clk_arrival,
|
||||||
|
uncertainty,
|
||||||
|
this);
|
||||||
if (uncertainty != 0.0)
|
if (uncertainty != 0.0)
|
||||||
reportLine("clock uncertainty", uncertainty, clk_arrival, early_late);
|
reportLine("clock uncertainty", uncertainty, clk_arrival, early_late);
|
||||||
float inter_uncertainty = end->interClkUncertainty(this);
|
float inter_uncertainty = end->interClkUncertainty(this);
|
||||||
clk_arrival += inter_uncertainty;
|
clk_arrival = delaySum(clk_arrival,
|
||||||
|
inter_uncertainty,
|
||||||
|
this);
|
||||||
if (inter_uncertainty != 0.0)
|
if (inter_uncertainty != 0.0)
|
||||||
reportLine("inter-clock uncertainty", inter_uncertainty,
|
reportLine("inter-clock uncertainty", inter_uncertainty,
|
||||||
clk_arrival, early_late);
|
clk_arrival, early_late);
|
||||||
|
|
@ -2659,7 +2699,9 @@ ReportPath::reportPath4(const Path *path,
|
||||||
reportPath5(latch_enable_path, enable_expanded, skip_first_path,
|
reportPath5(latch_enable_path, enable_expanded, skip_first_path,
|
||||||
propagated_clk, report_clk_path, time_offset);
|
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;
|
Arrival incr = latch_time_given;
|
||||||
if (delayGreaterEqual(incr, 0.0, this))
|
if (delayGreaterEqual(incr, 0.0, this))
|
||||||
reportLine("time given to startpoint", incr, time, early_late);
|
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.
|
// Override latch D arrival with enable + given.
|
||||||
reportPathLine(expanded.path(0), delay_zero, time, "latch_D");
|
reportPathLine(expanded.path(0), delay_zero, time, "latch_D");
|
||||||
reportPath6(path, expanded, 1, propagated_clk, report_clk_path,
|
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
|
else
|
||||||
|
|
@ -2689,7 +2734,9 @@ ReportPath::reportPath5(const Path *path,
|
||||||
if (skip_first_path) {
|
if (skip_first_path) {
|
||||||
path_first_index = 1;
|
path_first_index = 1;
|
||||||
const Path *start = expanded.path(0);
|
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,
|
reportPath6(path, expanded, path_first_index, propagated_clk,
|
||||||
report_clk_path, prev_time, time_offset);
|
report_clk_path, prev_time, time_offset);
|
||||||
|
|
@ -2717,7 +2764,7 @@ ReportPath::reportPath6(const Path *path,
|
||||||
const TimingArc *prev_arc = path1->prevArc(this);
|
const TimingArc *prev_arc = path1->prevArc(this);
|
||||||
Vertex *vertex = path1->vertex(this);
|
Vertex *vertex = path1->vertex(this);
|
||||||
Pin *pin = vertex->pin();
|
Pin *pin = vertex->pin();
|
||||||
Arrival time = path1->arrival() + time_offset;
|
Arrival time = delaySum(path1->arrival(), time_offset, this);
|
||||||
Delay incr = 0.0;
|
Delay incr = 0.0;
|
||||||
const char *line_case = nullptr;
|
const char *line_case = nullptr;
|
||||||
bool is_clk_start = path1->vertex(this) == clk_start;
|
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
|
// The delay calculator annotates wire delays on the edges
|
||||||
// from the input to the loads. Report the wire delay on the
|
// from the input to the loads. Report the wire delay on the
|
||||||
// input pin instead.
|
// 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);
|
incr = delayIncr(next_time, time, min_max);
|
||||||
time = next_time;
|
time = next_time;
|
||||||
line_case = "input_drive";
|
line_case = "input_drive";
|
||||||
|
|
@ -2755,7 +2804,7 @@ ReportPath::reportPath6(const Path *path,
|
||||||
if (!propagated_clk)
|
if (!propagated_clk)
|
||||||
// Clock latency at path endpoint in case latency was set
|
// Clock latency at path endpoint in case latency was set
|
||||||
// on a clock pin other than the clock source.
|
// 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;
|
incr = 0.0;
|
||||||
line_case = "clk_first";
|
line_case = "clk_first";
|
||||||
}
|
}
|
||||||
|
|
@ -2772,7 +2821,9 @@ ReportPath::reportPath6(const Path *path,
|
||||||
if (!propagated_clk) {
|
if (!propagated_clk) {
|
||||||
// Ideal clock.
|
// Ideal clock.
|
||||||
const ClockEdge *src_clk_edge = path->clkEdge(this);
|
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) {
|
if (src_clk_edge) {
|
||||||
Clock *src_clk = src_clk_edge->clock();
|
Clock *src_clk = src_clk_edge->clock();
|
||||||
const RiseFall *src_clk_rf = src_clk_edge->transition();
|
const RiseFall *src_clk_rf = src_clk_edge->transition();
|
||||||
|
|
@ -2803,6 +2854,8 @@ ReportPath::reportPath6(const Path *path,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vertex->isDriver(network_)) {
|
if (vertex->isDriver(network_)) {
|
||||||
|
// Report delay arc pocv variation between input and driver.
|
||||||
|
reportVariation(path1);
|
||||||
float cap = field_blank_;
|
float cap = field_blank_;
|
||||||
float fanout = field_blank_;
|
float fanout = field_blank_;
|
||||||
if (field_capacitance_->enabled())
|
if (field_capacitance_->enabled())
|
||||||
|
|
@ -2811,13 +2864,13 @@ ReportPath::reportPath6(const Path *path,
|
||||||
fanout = drvrFanout(vertex, scene, min_max);
|
fanout = drvrFanout(vertex, scene, min_max);
|
||||||
const std::string what = descriptionField(vertex);
|
const std::string what = descriptionField(vertex);
|
||||||
reportLine(what.c_str(), cap, slew, fanout,
|
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);
|
line_case);
|
||||||
|
|
||||||
if (report_net_) {
|
if (report_net_) {
|
||||||
const std::string what2 = descriptionNet(pin);
|
const std::string what2 = descriptionNet(pin);
|
||||||
reportLine(what2.c_str(), field_blank_, field_blank_, field_blank_,
|
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, "");
|
nullptr, src_attr, "");
|
||||||
}
|
}
|
||||||
prev_time = time;
|
prev_time = time;
|
||||||
|
|
@ -2830,7 +2883,7 @@ ReportPath::reportPath6(const Path *path,
|
||||||
|| is_clk_start) {
|
|| is_clk_start) {
|
||||||
const std::string what = descriptionField(vertex);
|
const std::string what = descriptionField(vertex);
|
||||||
reportLine(what.c_str(), field_blank_, slew, field_blank_,
|
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);
|
line_case);
|
||||||
prev_time = time;
|
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
|
void
|
||||||
ReportPath::reportHierPinsThru(const Path *path) const
|
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_)) {
|
for (const Pin *hpin : hierPinsThruEdge(prev_edge, network_, graph_)) {
|
||||||
const std::string what = descriptionField(hpin);
|
const std::string what = descriptionField(hpin);
|
||||||
reportLine(what.c_str(), field_blank_, field_blank_, field_blank_,
|
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, "", "");
|
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
|
bool
|
||||||
ReportPath::nextArcAnnotated(const Path *next_path,
|
ReportPath::nextArcAnnotated(const Path *next_path,
|
||||||
size_t next_index,
|
size_t next_index,
|
||||||
|
|
@ -2974,7 +3069,9 @@ ReportPath::reportInputExternalDelay(const Path *first_path,
|
||||||
const Pin *first_pin = first_path->pin(graph_);
|
const Pin *first_pin = first_path->pin(graph_);
|
||||||
if (!pathFromClkPin(first_path, first_pin)) {
|
if (!pathFromClkPin(first_path, first_pin)) {
|
||||||
const RiseFall *rf = first_path->transition(this);
|
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);
|
const EarlyLate *early_late = first_path->minMax(this);
|
||||||
InputDelay *input_delay = pathInputDelay(first_path);
|
InputDelay *input_delay = pathInputDelay(first_path);
|
||||||
if (input_delay) {
|
if (input_delay) {
|
||||||
|
|
@ -3054,7 +3151,7 @@ ReportPath::reportLine(const char *what,
|
||||||
Delay total,
|
Delay total,
|
||||||
const EarlyLate *early_late) const
|
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,
|
field_blank_, total, false, early_late, nullptr,
|
||||||
"", nullptr);
|
"", nullptr);
|
||||||
}
|
}
|
||||||
|
|
@ -3066,8 +3163,8 @@ ReportPath::reportLineNegative(const char *what,
|
||||||
const EarlyLate *early_late) const
|
const EarlyLate *early_late) const
|
||||||
{
|
{
|
||||||
reportLine(what, field_blank_, field_blank_, field_blank_,
|
reportLine(what, field_blank_, field_blank_, field_blank_,
|
||||||
field_blank_, total, true, early_late, nullptr,
|
field_blank_, field_blank_, total, true /* tota_with_minus */,
|
||||||
"", nullptr);
|
early_late, nullptr, "", nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Report total, and transition suffix.
|
// Report total, and transition suffix.
|
||||||
|
|
@ -3078,55 +3175,56 @@ ReportPath::reportLine(const char *what,
|
||||||
const RiseFall *rf) const
|
const RiseFall *rf) const
|
||||||
{
|
{
|
||||||
reportLine(what, field_blank_, field_blank_, field_blank_,
|
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);
|
nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Report increment, and total.
|
// Report increment, and total.
|
||||||
void
|
void
|
||||||
ReportPath::reportLine(const char *what,
|
ReportPath::reportLine(const char *what,
|
||||||
Delay incr,
|
const Delay &incr,
|
||||||
Delay total,
|
const Delay &total,
|
||||||
const EarlyLate *early_late) const
|
const EarlyLate *early_late) const
|
||||||
{
|
{
|
||||||
reportLine(what, field_blank_, field_blank_, field_blank_,
|
reportLine(what, field_blank_, field_blank_, field_blank_,
|
||||||
incr, total, false, early_late, nullptr, "",
|
incr, field_blank_, total, false, early_late, nullptr, "",
|
||||||
nullptr);
|
nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Report increment, total, and transition suffix.
|
// Report increment, total, and transition suffix.
|
||||||
void
|
void
|
||||||
ReportPath::reportLine(const char *what,
|
ReportPath::reportLine(const char *what,
|
||||||
Delay incr,
|
const Delay &incr,
|
||||||
Delay total,
|
const Delay &total,
|
||||||
const EarlyLate *early_late,
|
const EarlyLate *early_late,
|
||||||
const RiseFall *rf) const
|
const RiseFall *rf) const
|
||||||
{
|
{
|
||||||
reportLine(what, field_blank_, field_blank_, field_blank_,
|
reportLine(what, field_blank_, field_blank_, field_blank_,
|
||||||
incr, total, false, early_late, rf, "",
|
incr, field_blank_, total, false, early_late, rf, "",
|
||||||
nullptr);
|
nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Report slew, increment, and total.
|
// Report slew, increment, and total.
|
||||||
void
|
void
|
||||||
ReportPath::reportLine(const char *what,
|
ReportPath::reportLine(const char *what,
|
||||||
Slew slew,
|
const Slew &slew,
|
||||||
Delay incr,
|
const Delay &incr,
|
||||||
Delay total,
|
const Delay &total,
|
||||||
const EarlyLate *early_late) const
|
const EarlyLate *early_late) const
|
||||||
{
|
{
|
||||||
reportLine(what, field_blank_, slew, field_blank_,
|
reportLine(what, field_blank_, slew, field_blank_,
|
||||||
incr, total, false, early_late, nullptr,
|
incr, field_blank_, total, false, early_late, nullptr,
|
||||||
"", nullptr);
|
"", nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ReportPath::reportLine(const char *what,
|
ReportPath::reportLine(const char *what,
|
||||||
float cap,
|
float cap,
|
||||||
Slew slew,
|
const Slew &slew,
|
||||||
float fanout,
|
float fanout,
|
||||||
Delay incr,
|
const Delay &incr,
|
||||||
Delay total,
|
float variation,
|
||||||
|
const Delay &total,
|
||||||
bool total_with_minus,
|
bool total_with_minus,
|
||||||
const EarlyLate *early_late,
|
const EarlyLate *early_late,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
|
|
@ -3159,6 +3257,8 @@ ReportPath::reportLine(const char *what,
|
||||||
reportFieldDelay(slew, early_late, field, line);
|
reportFieldDelay(slew, early_late, field, line);
|
||||||
else if (field == field_incr_)
|
else if (field == field_incr_)
|
||||||
reportFieldDelay(incr, early_late, field, line);
|
reportFieldDelay(incr, early_late, field, line);
|
||||||
|
else if (field == field_variation_)
|
||||||
|
reportFieldDelay(variation, early_late, field, line);
|
||||||
else if (field == field_total_) {
|
else if (field == field_total_) {
|
||||||
if (total_with_minus)
|
if (total_with_minus)
|
||||||
reportFieldDelayMinus(total, early_late, field, line);
|
reportFieldDelayMinus(total, early_late, field, line);
|
||||||
|
|
@ -3171,6 +3271,8 @@ ReportPath::reportLine(const char *what,
|
||||||
else
|
else
|
||||||
reportFieldBlank(field, line);
|
reportFieldBlank(field, line);
|
||||||
}
|
}
|
||||||
|
else if (field == field_variation_)
|
||||||
|
reportFieldBlank(field, line);
|
||||||
else if (field == field_src_attr_) {
|
else if (field == field_src_attr_) {
|
||||||
if (src_attr != "")
|
if (src_attr != "")
|
||||||
reportField(src_attr.c_str(), field, line);
|
reportField(src_attr.c_str(), field, line);
|
||||||
|
|
@ -3195,7 +3297,7 @@ ReportPath::reportLine(const char *what,
|
||||||
// Only the total field.
|
// Only the total field.
|
||||||
void
|
void
|
||||||
ReportPath::reportLineTotal(const char *what,
|
ReportPath::reportLineTotal(const char *what,
|
||||||
Delay incr,
|
const Delay &incr,
|
||||||
const EarlyLate *early_late) const
|
const EarlyLate *early_late) const
|
||||||
{
|
{
|
||||||
reportLineTotal1(what, incr, false, early_late);
|
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.
|
// Only the total field and always with leading minus sign.
|
||||||
void
|
void
|
||||||
ReportPath::reportLineTotalMinus(const char *what,
|
ReportPath::reportLineTotalMinus(const char *what,
|
||||||
Delay decr,
|
const Delay &decr,
|
||||||
const EarlyLate *early_late) const
|
const EarlyLate *early_late) const
|
||||||
{
|
{
|
||||||
reportLineTotal1(what, decr, true, early_late);
|
reportLineTotal1(what, decr, true, early_late);
|
||||||
|
|
@ -3212,7 +3314,7 @@ ReportPath::reportLineTotalMinus(const char *what,
|
||||||
|
|
||||||
void
|
void
|
||||||
ReportPath::reportLineTotal1(const char *what,
|
ReportPath::reportLineTotal1(const char *what,
|
||||||
Delay incr,
|
const Delay &incr,
|
||||||
bool incr_with_minus,
|
bool incr_with_minus,
|
||||||
const EarlyLate *early_late) const
|
const EarlyLate *early_late) const
|
||||||
{
|
{
|
||||||
|
|
@ -3287,7 +3389,7 @@ ReportPath::reportSpaceFieldTime(float value,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ReportPath::reportSpaceFieldDelay(Delay value,
|
ReportPath::reportSpaceFieldDelay(const Delay &value,
|
||||||
const EarlyLate *early_late,
|
const EarlyLate *early_late,
|
||||||
std::string &line) const
|
std::string &line) const
|
||||||
{
|
{
|
||||||
|
|
@ -3296,11 +3398,11 @@ ReportPath::reportSpaceFieldDelay(Delay value,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ReportPath::reportTotalDelay(Delay value,
|
ReportPath::reportTotalDelay(const Delay &value,
|
||||||
const EarlyLate *early_late,
|
const EarlyLate *early_late,
|
||||||
std::string &line) const
|
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_))
|
if (stringEq(str, minus_zero_))
|
||||||
// Filter "-0.00" fields.
|
// Filter "-0.00" fields.
|
||||||
str = plus_zero_;
|
str = plus_zero_;
|
||||||
|
|
@ -3309,7 +3411,7 @@ ReportPath::reportTotalDelay(Delay value,
|
||||||
|
|
||||||
// Total time always with leading minus sign.
|
// Total time always with leading minus sign.
|
||||||
void
|
void
|
||||||
ReportPath::reportFieldDelayMinus(Delay value,
|
ReportPath::reportFieldDelayMinus(const Delay &value,
|
||||||
const EarlyLate *early_late,
|
const EarlyLate *early_late,
|
||||||
const ReportField *field,
|
const ReportField *field,
|
||||||
std::string &line) const
|
std::string &line) const
|
||||||
|
|
@ -3317,10 +3419,9 @@ ReportPath::reportFieldDelayMinus(Delay value,
|
||||||
if (delayAsFloat(value) == field_blank_)
|
if (delayAsFloat(value) == field_blank_)
|
||||||
reportFieldBlank(field, line);
|
reportFieldBlank(field, line);
|
||||||
else {
|
else {
|
||||||
const char *str = report_sigmas_
|
// Opposite min/max for negative value.
|
||||||
? delayAsString(-value, this, digits_)
|
const char *str = delayAsString(delayDiff(delay_zero, value, this),
|
||||||
// Opposite min/max for negative value.
|
early_late->opposite(), digits_, this);
|
||||||
: delayAsString(-value, early_late->opposite(), this, digits_);
|
|
||||||
if (stringEq(str, plus_zero_))
|
if (stringEq(str, plus_zero_))
|
||||||
// Force leading minus sign.
|
// Force leading minus sign.
|
||||||
str = minus_zero_;
|
str = minus_zero_;
|
||||||
|
|
@ -3329,17 +3430,15 @@ ReportPath::reportFieldDelayMinus(Delay value,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ReportPath::reportFieldDelay(Delay value,
|
ReportPath::reportFieldDelay(const Delay &value,
|
||||||
const EarlyLate *early_late,
|
const EarlyLate *early_late,
|
||||||
const ReportField *field,
|
const ReportField *field,
|
||||||
std::string &line) const
|
std::string &line) const
|
||||||
{
|
{
|
||||||
if (delayAsFloat(value) == field_blank_)
|
if (value.mean() == field_blank_)
|
||||||
reportFieldBlank(field, line);
|
reportFieldBlank(field, line);
|
||||||
else {
|
else {
|
||||||
const char *str = report_sigmas_
|
const char *str = delayAsString(value, early_late, digits_, this);
|
||||||
? delayAsString(value, this, digits_)
|
|
||||||
: delayAsString(value, early_late, this, digits_);
|
|
||||||
if (stringEq(str, minus_zero_))
|
if (stringEq(str, minus_zero_))
|
||||||
// Filter "-0.00" fields.
|
// Filter "-0.00" fields.
|
||||||
str = plus_zero_;
|
str = plus_zero_;
|
||||||
|
|
|
||||||
|
|
@ -56,12 +56,11 @@ public:
|
||||||
bool report_cap,
|
bool report_cap,
|
||||||
bool report_slew,
|
bool report_slew,
|
||||||
bool report_fanout,
|
bool report_fanout,
|
||||||
|
bool report_variation,
|
||||||
bool report_src_attr);
|
bool report_src_attr);
|
||||||
int digits() const { return digits_; }
|
int digits() const { return digits_; }
|
||||||
void setDigits(int digits);
|
void setDigits(int digits);
|
||||||
void setNoSplit(bool no_split);
|
void setNoSplit(bool no_split);
|
||||||
bool reportSigmas() const { return report_sigmas_; }
|
|
||||||
void setReportSigmas(bool report);
|
|
||||||
ReportField *findField(const char *name) const;
|
ReportField *findField(const char *name) const;
|
||||||
|
|
||||||
// Header above reportPathEnd results.
|
// Header above reportPathEnd results.
|
||||||
|
|
@ -267,8 +266,8 @@ protected:
|
||||||
float clk_time,
|
float clk_time,
|
||||||
const EarlyLate *early_late) const;
|
const EarlyLate *early_late) const;
|
||||||
void reportPathLine(const Path *path,
|
void reportPathLine(const Path *path,
|
||||||
Delay incr,
|
const Delay &incr,
|
||||||
Arrival time,
|
const Arrival &time,
|
||||||
const char *line_case) const;
|
const char *line_case) const;
|
||||||
void reportCommonClkPessimism(const PathEnd *end,
|
void reportCommonClkPessimism(const PathEnd *end,
|
||||||
Arrival &clk_arrival) const ;
|
Arrival &clk_arrival) const ;
|
||||||
|
|
@ -331,6 +330,7 @@ protected:
|
||||||
bool report_clk_path,
|
bool report_clk_path,
|
||||||
Arrival prev_time,
|
Arrival prev_time,
|
||||||
float time_offset) const;
|
float time_offset) const;
|
||||||
|
void reportVariation(const Path *path) const;
|
||||||
void reportHierPinsThru(const Path *path) const;
|
void reportHierPinsThru(const Path *path) const;
|
||||||
void reportInputExternalDelay(const Path *path,
|
void reportInputExternalDelay(const Path *path,
|
||||||
float time_offset) const;
|
float time_offset) const;
|
||||||
|
|
@ -345,38 +345,39 @@ protected:
|
||||||
const EarlyLate *early_late,
|
const EarlyLate *early_late,
|
||||||
const RiseFall *rf) const;
|
const RiseFall *rf) const;
|
||||||
void reportLine(const char *what,
|
void reportLine(const char *what,
|
||||||
Delay incr,
|
const Delay &incr,
|
||||||
Delay total,
|
const Delay &total,
|
||||||
const EarlyLate *early_late) const;
|
const EarlyLate *early_late) const;
|
||||||
void reportLine(const char *what,
|
void reportLine(const char *what,
|
||||||
Delay incr,
|
const Delay &incr,
|
||||||
Delay total,
|
const Delay &total,
|
||||||
const EarlyLate *early_late,
|
const EarlyLate *early_late,
|
||||||
const RiseFall *rf) const;
|
const RiseFall *rf) const;
|
||||||
void reportLine(const char *what,
|
void reportLine(const char *what,
|
||||||
Slew slew,
|
const Slew &slew,
|
||||||
Delay incr,
|
const Delay &incr,
|
||||||
Delay total,
|
const Delay &total,
|
||||||
const EarlyLate *early_late) const;
|
const EarlyLate *early_late) const;
|
||||||
void reportLine(const char *what,
|
void reportLine(const char *what,
|
||||||
float cap,
|
float cap,
|
||||||
Slew slew,
|
const Slew &slew,
|
||||||
float fanout,
|
float fanout,
|
||||||
Delay incr,
|
const Delay &incr,
|
||||||
Delay total,
|
float variation,
|
||||||
|
const Delay &total,
|
||||||
bool total_with_minus,
|
bool total_with_minus,
|
||||||
const EarlyLate *early_late,
|
const EarlyLate *early_late,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
std::string src_attr,
|
std::string src_attr,
|
||||||
const char *line_case) const;
|
const char *line_case) const;
|
||||||
void reportLineTotal(const char *what,
|
void reportLineTotal(const char *what,
|
||||||
Delay incr,
|
const Delay &incr,
|
||||||
const EarlyLate *early_late) const;
|
const EarlyLate *early_late) const;
|
||||||
void reportLineTotalMinus(const char *what,
|
void reportLineTotalMinus(const char *what,
|
||||||
Delay decr,
|
const Delay &decr,
|
||||||
const EarlyLate *early_late) const;
|
const EarlyLate *early_late) const;
|
||||||
void reportLineTotal1(const char *what,
|
void reportLineTotal1(const char *what,
|
||||||
Delay incr,
|
const Delay &incr,
|
||||||
bool incr_with_minus,
|
bool incr_with_minus,
|
||||||
const EarlyLate *early_late) const;
|
const EarlyLate *early_late) const;
|
||||||
void reportDashLineTotal() const;
|
void reportDashLineTotal() const;
|
||||||
|
|
@ -391,17 +392,17 @@ protected:
|
||||||
std::string &result) const;
|
std::string &result) const;
|
||||||
void reportSpaceFieldTime(float value,
|
void reportSpaceFieldTime(float value,
|
||||||
std::string &result) const;
|
std::string &result) const;
|
||||||
void reportSpaceFieldDelay(Delay value,
|
void reportSpaceFieldDelay(const Delay &value,
|
||||||
const EarlyLate *early_late,
|
const EarlyLate *early_late,
|
||||||
std::string &result) const;
|
std::string &result) const;
|
||||||
void reportFieldDelayMinus(Delay value,
|
void reportFieldDelayMinus(const Delay &value,
|
||||||
const EarlyLate *early_late,
|
const EarlyLate *early_late,
|
||||||
const ReportField *field,
|
const ReportField *field,
|
||||||
std::string &result) const;
|
std::string &result) const;
|
||||||
void reportTotalDelay(Delay value,
|
void reportTotalDelay(const Delay &value,
|
||||||
const EarlyLate *early_late,
|
const EarlyLate *early_late,
|
||||||
std::string &result) const;
|
std::string &result) const;
|
||||||
void reportFieldDelay(Delay value,
|
void reportFieldDelay(const Delay &value,
|
||||||
const EarlyLate *early_late,
|
const EarlyLate *early_late,
|
||||||
const ReportField *field,
|
const ReportField *field,
|
||||||
std::string &result) const;
|
std::string &result) const;
|
||||||
|
|
@ -465,8 +466,8 @@ protected:
|
||||||
Path &ref_path) const;
|
Path &ref_path) const;
|
||||||
const char *asRisingFalling(const RiseFall *rf) const;
|
const char *asRisingFalling(const RiseFall *rf) const;
|
||||||
const char *asRiseFall(const RiseFall *rf) const;
|
const char *asRiseFall(const RiseFall *rf) const;
|
||||||
Delay delayIncr(Delay time,
|
Delay delayIncr(const Delay &time,
|
||||||
Delay prev,
|
const Delay &prev,
|
||||||
const MinMax *min_max) const;
|
const MinMax *min_max) const;
|
||||||
|
|
||||||
// Path options.
|
// Path options.
|
||||||
|
|
@ -477,7 +478,6 @@ protected:
|
||||||
bool report_net_;
|
bool report_net_;
|
||||||
bool no_split_;
|
bool no_split_;
|
||||||
int digits_;
|
int digits_;
|
||||||
bool report_sigmas_;
|
|
||||||
|
|
||||||
int start_end_pt_width_;
|
int start_end_pt_width_;
|
||||||
|
|
||||||
|
|
@ -487,15 +487,15 @@ protected:
|
||||||
ReportField *field_capacitance_;
|
ReportField *field_capacitance_;
|
||||||
ReportField *field_slew_;
|
ReportField *field_slew_;
|
||||||
ReportField *field_fanout_;
|
ReportField *field_fanout_;
|
||||||
|
ReportField *field_variation_;
|
||||||
ReportField *field_src_attr_;
|
ReportField *field_src_attr_;
|
||||||
ReportField *field_edge_;
|
ReportField *field_edge_;
|
||||||
ReportField *field_case_;
|
ReportField *field_case_;
|
||||||
|
static constexpr float field_blank_ = -1;
|
||||||
|
int field_width_extra_;
|
||||||
|
|
||||||
const char *plus_zero_;
|
const char *plus_zero_;
|
||||||
const char *minus_zero_;
|
const char *minus_zero_;
|
||||||
|
|
||||||
static const float field_blank_;
|
|
||||||
static const float field_skip_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ReportField
|
class ReportField
|
||||||
|
|
|
||||||
|
|
@ -1334,7 +1334,7 @@ Search::arrivalsChanged(Vertex *vertex,
|
||||||
Path *path2 = tag_bldr->tagMatchPath(tag1);
|
Path *path2 = tag_bldr->tagMatchPath(tag1);
|
||||||
if (path2 == nullptr
|
if (path2 == nullptr
|
||||||
|| path1->tag(this) != path2->tag(this)
|
|| path1->tag(this) != path2->tag(this)
|
||||||
|| !delayEqual(path1->arrival(), path2->arrival())
|
|| !delayEqual(path1->arrival(), path2->arrival(), this)
|
||||||
|| path1->prevEdge(this) != path2->prevEdge(this)
|
|| path1->prevEdge(this) != path2->prevEdge(this)
|
||||||
|| path1->prevArc(this) != path2->prevArc(this)
|
|| path1->prevArc(this) != path2->prevArc(this)
|
||||||
|| path1->prevPath() != path2->prevPath())
|
|| path1->prevPath() != path2->prevPath())
|
||||||
|
|
@ -1420,8 +1420,8 @@ ArrivalVisitor::pruneCrprArrivals()
|
||||||
const ClkInfo *clk_info_no_crpr = path_no_crpr->clkInfo(this);
|
const ClkInfo *clk_info_no_crpr = path_no_crpr->clkInfo(this);
|
||||||
Arrival max_crpr = crpr->maxCrpr(clk_info_no_crpr);
|
Arrival max_crpr = crpr->maxCrpr(clk_info_no_crpr);
|
||||||
Arrival max_arrival_max_crpr = (min_max == MinMax::max())
|
Arrival max_arrival_max_crpr = (min_max == MinMax::max())
|
||||||
? max_arrival - max_crpr
|
? delayDiff(max_arrival, max_crpr, this)
|
||||||
: max_arrival + max_crpr;
|
: delaySum(max_arrival, max_crpr, this);
|
||||||
debugPrint(debug_, "search", 4, " cmp %s %s - %s = %s",
|
debugPrint(debug_, "search", 4, " cmp %s %s - %s = %s",
|
||||||
tag->to_string(this).c_str(),
|
tag->to_string(this).c_str(),
|
||||||
delayAsString(max_arrival, this),
|
delayAsString(max_arrival, this),
|
||||||
|
|
@ -1622,7 +1622,7 @@ Search::seedClkArrival(const Pin *pin,
|
||||||
sdc->exceptionFromClkStates(pin,rf,clk,rf,min_max,states);
|
sdc->exceptionFromClkStates(pin,rf,clk,rf,min_max,states);
|
||||||
Tag *tag = findTag(scene, rf, min_max, clk_info, true, nullptr, false,
|
Tag *tag = findTag(scene, rf, min_max, clk_info, true, nullptr, false,
|
||||||
states, true, nullptr);
|
states, true, nullptr);
|
||||||
Arrival arrival(clk_edge->time() + insertion);
|
Arrival arrival = delaySum(insertion, clk_edge->time(), this);
|
||||||
tag_bldr->setArrival(tag, arrival);
|
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);
|
Tag *tag = clkDataTag(pin, clk, rf, clk_edge, insertion, min_max, scene);
|
||||||
if (tag) {
|
if (tag) {
|
||||||
// Data arrivals include insertion delay.
|
// Data arrivals include insertion delay.
|
||||||
Arrival arrival(clk_edge->time() + insertion);
|
Arrival arrival = delaySum(insertion, clk_edge->time(), this);
|
||||||
tag_bldr->setArrival(tag, arrival);
|
tag_bldr->setArrival(tag, arrival);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1878,8 +1878,8 @@ Search::inputDelayRefPinArrival(Path *ref_path,
|
||||||
Clock *clk = clk_edge->clock();
|
Clock *clk = clk_edge->clock();
|
||||||
if (clk->isPropagated()) {
|
if (clk->isPropagated()) {
|
||||||
const ClkInfo *clk_info = ref_path->clkInfo(this);
|
const ClkInfo *clk_info = ref_path->clkInfo(this);
|
||||||
ref_arrival = delayAsFloat(ref_path->arrival());
|
ref_arrival = delayAsFloat(ref_path->arrival(), min_max, this);
|
||||||
ref_insertion = delayAsFloat(clk_info->insertion());
|
ref_insertion = delayAsFloat(clk_info->insertion(), min_max, this);
|
||||||
ref_latency = clk_info->latency();
|
ref_latency = clk_info->latency();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -2186,13 +2186,12 @@ PathVisitor::visitFromPath(const Pin *from_pin,
|
||||||
true, min_max,
|
true, min_max,
|
||||||
dcalc_ap,
|
dcalc_ap,
|
||||||
sdc);
|
sdc);
|
||||||
bool arc_delay_min_max_eq =
|
bool arc_delay_min_max_eq = delayEqual(arc_delay, arc_delay_opp, this);
|
||||||
fuzzyEqual(delayAsFloat(arc_delay), delayAsFloat(arc_delay_opp));
|
|
||||||
to_tag = search_->thruClkTag(from_path, from_vertex, from_tag, true,
|
to_tag = search_->thruClkTag(from_path, from_vertex, from_tag, true,
|
||||||
edge, to_rf, arc_delay_min_max_eq,
|
edge, to_rf, arc_delay_min_max_eq,
|
||||||
min_max, scene);
|
min_max, scene);
|
||||||
if (to_tag)
|
if (to_tag)
|
||||||
to_arrival = from_arrival + arc_delay;
|
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();
|
const LibertyCell *inst_cell = clk_port->libertyCell();
|
||||||
if (inst_cell->isMacro()) {
|
if (inst_cell->isMacro()) {
|
||||||
float slew = delayAsFloat(from_path->slew(this));
|
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_);
|
to_tag = search_->thruTag(to_tag, edge, to_rf, tag_cache_);
|
||||||
from_arrival = search_->clkPathArrival(from_path, from_clk_info,
|
from_arrival = search_->clkPathArrival(from_path, from_clk_info,
|
||||||
clk_edge, min_max);
|
clk_edge, min_max);
|
||||||
to_arrival = from_arrival + arc_delay;
|
to_arrival = delaySum(from_arrival, arc_delay, this);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
to_tag = nullptr;
|
to_tag = nullptr;
|
||||||
|
|
@ -2309,7 +2310,7 @@ PathVisitor::visitFromPath(const Pin *from_pin,
|
||||||
to_propagates_clk, edge, to_rf,
|
to_propagates_clk, edge, to_rf,
|
||||||
arc_delay_min_max_eq,
|
arc_delay_min_max_eq,
|
||||||
min_max, scene);
|
min_max, scene);
|
||||||
to_arrival = from_arrival + arc_delay;
|
to_arrival = delaySum(from_arrival, arc_delay, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -2317,8 +2318,8 @@ PathVisitor::visitFromPath(const Pin *from_pin,
|
||||||
|| sdc->isPathDelayInternalToBreak(from_pin))) {
|
|| sdc->isPathDelayInternalToBreak(from_pin))) {
|
||||||
arc_delay = search_->deratedDelay(from_vertex, arc, edge, false,
|
arc_delay = search_->deratedDelay(from_vertex, arc, edge, false,
|
||||||
min_max, dcalc_ap, sdc);
|
min_max, dcalc_ap, sdc);
|
||||||
if (!delayInf(arc_delay)) {
|
if (!delayInf(arc_delay, this)) {
|
||||||
to_arrival = from_arrival + arc_delay;
|
to_arrival = delaySum(from_arrival, arc_delay, this);
|
||||||
to_tag = search_->thruTag(from_tag, edge, to_rf, tag_cache_);
|
to_tag = search_->thruTag(from_tag, edge, to_rf, tag_cache_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2355,11 +2356,11 @@ Search::clkPathArrival(const Path *clk_path,
|
||||||
&& !clk_info->isPropagated()) {
|
&& !clk_info->isPropagated()) {
|
||||||
// Ideal clock, apply ideal insertion delay and latency.
|
// Ideal clock, apply ideal insertion delay and latency.
|
||||||
const EarlyLate *early_late = min_max;
|
const EarlyLate *early_late = min_max;
|
||||||
return clk_edge->time()
|
Arrival insertion = clockInsertion(clk_edge->clock(), clk_info->clkSrc(),
|
||||||
+ clockInsertion(clk_edge->clock(), clk_info->clkSrc(),
|
clk_edge->transition(), min_max,
|
||||||
clk_edge->transition(), min_max,
|
early_late, scene->mode());
|
||||||
early_late, scene->mode())
|
return delaySum(delaySum(insertion, clk_edge->time(), this),
|
||||||
+ clk_info->latency();
|
clk_info->latency(), this);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return clk_path->arrival();
|
return clk_path->arrival();
|
||||||
|
|
@ -3166,8 +3167,8 @@ Search::deratedDelay(const Vertex *from_vertex,
|
||||||
const Sdc *sdc)
|
const Sdc *sdc)
|
||||||
{
|
{
|
||||||
float derate = timingDerate(from_vertex, arc, edge, is_clk, sdc, min_max);
|
float derate = timingDerate(from_vertex, arc, edge, is_clk, sdc, min_max);
|
||||||
ArcDelay delay = graph_->arcDelay(edge, arc, dcalc_ap);
|
const ArcDelay &delay = graph_->arcDelay(edge, arc, dcalc_ap);
|
||||||
return delay * derate;
|
return delayProduct(delay, derate, this);;
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
|
|
@ -3568,9 +3569,9 @@ RequiredCmp::requiredsSave(Vertex *vertex,
|
||||||
while (path_iter.hasNext()) {
|
while (path_iter.hasNext()) {
|
||||||
Path *path = path_iter.next();
|
Path *path = path_iter.next();
|
||||||
size_t path_index = path->pathIndex(sta);
|
size_t path_index = path->pathIndex(sta);
|
||||||
Required req = requireds_[path_index];
|
const Required req = requireds_[path_index];
|
||||||
Required &prev_req = path->required();
|
const Required &prev_req = path->required();
|
||||||
bool changed = !delayEqual(prev_req, req);
|
bool changed = !delayEqual(prev_req, req, sta);
|
||||||
debugPrint(debug, "search", 3, "required %s save %s -> %s%s",
|
debugPrint(debug, "search", 3, "required %s save %s -> %s%s",
|
||||||
path->to_string(sta).c_str(),
|
path->to_string(sta).c_str(),
|
||||||
delayAsString(prev_req, sta),
|
delayAsString(prev_req, sta),
|
||||||
|
|
@ -3669,8 +3670,8 @@ RequiredVisitor::visitFromToPath(const Pin *,
|
||||||
if (to_tag_group && to_tag_group->hasTag(to_tag)) {
|
if (to_tag_group && to_tag_group->hasTag(to_tag)) {
|
||||||
size_t to_path_index = to_tag_group->pathIndex(to_tag);
|
size_t to_path_index = to_tag_group->pathIndex(to_tag);
|
||||||
Path &to_path = to_vertex->paths()[to_path_index];
|
Path &to_path = to_vertex->paths()[to_path_index];
|
||||||
Required &to_required = to_path.required();
|
const 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",
|
debugPrint(debug_, "search", 3, " to tag %2u: %s",
|
||||||
to_tag->index(),
|
to_tag->index(),
|
||||||
to_tag->to_string(this).c_str());
|
to_tag->to_string(this).c_str());
|
||||||
|
|
@ -3694,7 +3695,7 @@ RequiredVisitor::visitFromToPath(const Pin *,
|
||||||
Tag *to_path_tag = to_path->tag(this);
|
Tag *to_path_tag = to_path->tag(this);
|
||||||
if (Tag::matchNoCrpr(to_path_tag, to_tag)) {
|
if (Tag::matchNoCrpr(to_path_tag, to_tag)) {
|
||||||
Required to_required = to_path->required();
|
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",
|
debugPrint(debug_, "search", 3, " to tag %2u: %s",
|
||||||
to_path_tag->index(),
|
to_path_tag->index(),
|
||||||
to_path_tag->to_string(this).c_str());
|
to_path_tag->to_string(this).c_str());
|
||||||
|
|
@ -3873,14 +3874,14 @@ Slack
|
||||||
Search::totalNegativeSlack(const MinMax *min_max)
|
Search::totalNegativeSlack(const MinMax *min_max)
|
||||||
{
|
{
|
||||||
tnsPreamble();
|
tnsPreamble();
|
||||||
Slack tns = 0.0;
|
DelayDbl tns = 0.0;
|
||||||
for (Scene *scene : scenes_) {
|
for (Scene *scene : scenes_) {
|
||||||
size_t path_index = scene->pathIndex(min_max);
|
size_t path_index = scene->pathIndex(min_max);
|
||||||
Slack tns1 = tns_[path_index];
|
DelayDbl tns1 = tns_[path_index];
|
||||||
if (delayLess(tns1, tns, this))
|
if (delayLess(tns1, tns, this))
|
||||||
tns = tns1;
|
tns = tns1;
|
||||||
}
|
}
|
||||||
return tns;
|
return delayDblAsDelay(tns);
|
||||||
}
|
}
|
||||||
|
|
||||||
Slack
|
Slack
|
||||||
|
|
@ -3889,7 +3890,7 @@ Search::totalNegativeSlack(const Scene *scene,
|
||||||
{
|
{
|
||||||
tnsPreamble();
|
tnsPreamble();
|
||||||
PathAPIndex path_ap_index = scene->pathIndex(min_max);
|
PathAPIndex path_ap_index = scene->pathIndex(min_max);
|
||||||
return tns_[path_ap_index];
|
return delayDblAsDelay(tns_[path_ap_index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -3976,7 +3977,7 @@ Search::tnsIncr(Vertex *vertex,
|
||||||
debugPrint(debug_, "tns", 3, "tns+ %s %s",
|
debugPrint(debug_, "tns", 3, "tns+ %s %s",
|
||||||
delayAsString(slack, this),
|
delayAsString(slack, this),
|
||||||
vertex->to_string(this).c_str());
|
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))
|
if (tns_slacks_[path_ap_index].contains(vertex))
|
||||||
report_->critical(1513, "tns incr existing vertex");
|
report_->critical(1513, "tns incr existing vertex");
|
||||||
tns_slacks_[path_ap_index][vertex] = slack;
|
tns_slacks_[path_ap_index][vertex] = slack;
|
||||||
|
|
@ -3995,7 +3996,7 @@ Search::tnsDecr(Vertex *vertex,
|
||||||
debugPrint(debug_, "tns", 3, "tns- %s %s",
|
debugPrint(debug_, "tns", 3, "tns- %s %s",
|
||||||
delayAsString(slack, this),
|
delayAsString(slack, this),
|
||||||
vertex->to_string(this).c_str());
|
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);
|
tns_slacks_[path_ap_index].erase(vertex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
179
search/Search.i
179
search/Search.i
|
|
@ -39,6 +39,7 @@
|
||||||
#include "Bfs.hh"
|
#include "Bfs.hh"
|
||||||
#include "Scene.hh"
|
#include "Scene.hh"
|
||||||
#include "Sta.hh"
|
#include "Sta.hh"
|
||||||
|
#include "StaConfig.hh"
|
||||||
|
|
||||||
using namespace sta;
|
using namespace sta;
|
||||||
|
|
||||||
|
|
@ -155,26 +156,29 @@ find_requireds()
|
||||||
Sta::sta()->findRequireds();
|
Sta::sta()->findRequireds();
|
||||||
}
|
}
|
||||||
|
|
||||||
Slack
|
float
|
||||||
total_negative_slack_cmd(const MinMax *min_max)
|
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,
|
total_negative_slack_scene_cmd(const Scene *scene,
|
||||||
const MinMax *min_max)
|
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)
|
worst_slack_cmd(const MinMax *min_max)
|
||||||
{
|
{
|
||||||
|
Sta *sta = Sta::sta();
|
||||||
Slack worst_slack;
|
Slack worst_slack;
|
||||||
Vertex *worst_vertex;
|
Vertex *worst_vertex;
|
||||||
Sta::sta()->worstSlack(min_max, worst_slack, worst_vertex);
|
sta->worstSlack(min_max, worst_slack, worst_vertex);
|
||||||
return worst_slack;
|
return delayAsFloat(worst_slack, min_max, sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vertex *
|
Vertex *
|
||||||
|
|
@ -186,14 +190,15 @@ worst_slack_vertex(const MinMax *min_max)
|
||||||
return worst_vertex;;
|
return worst_vertex;;
|
||||||
}
|
}
|
||||||
|
|
||||||
Slack
|
float
|
||||||
worst_slack_scene(const Scene *scene,
|
worst_slack_scene(const Scene *scene,
|
||||||
const MinMax *min_max)
|
const MinMax *min_max)
|
||||||
{
|
{
|
||||||
|
Sta *sta = Sta::sta();
|
||||||
Slack worst_slack;
|
Slack worst_slack;
|
||||||
Vertex *worst_vertex;
|
Vertex *worst_vertex;
|
||||||
Sta::sta()->worstSlack(scene, min_max, worst_slack, worst_vertex);
|
sta->worstSlack(scene, min_max, worst_slack, worst_vertex);
|
||||||
return worst_slack;
|
return delayAsFloat(worst_slack, min_max, sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
Path *
|
Path *
|
||||||
|
|
@ -224,7 +229,7 @@ vertex_worst_slack_path(Vertex *vertex,
|
||||||
return sta->vertexWorstSlackPath(vertex, min_max);
|
return sta->vertexWorstSlackPath(vertex, min_max);
|
||||||
}
|
}
|
||||||
|
|
||||||
Slack
|
float
|
||||||
endpoint_slack(const Pin *pin,
|
endpoint_slack(const Pin *pin,
|
||||||
const char *path_group_name,
|
const char *path_group_name,
|
||||||
const MinMax *min_max)
|
const MinMax *min_max)
|
||||||
|
|
@ -233,7 +238,7 @@ endpoint_slack(const Pin *pin,
|
||||||
sta->ensureLibLinked();
|
sta->ensureLibLinked();
|
||||||
if (sta->isGroupPathName(path_group_name, sta->cmdSdc())) {
|
if (sta->isGroupPathName(path_group_name, sta->cmdSdc())) {
|
||||||
Slack slack = sta->endpointSlack(pin, std::string(path_group_name), min_max);
|
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 {
|
else {
|
||||||
sta->report()->error(1577, "%s is not a known path group name.",
|
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_cap,
|
||||||
bool report_slew,
|
bool report_slew,
|
||||||
bool report_fanout,
|
bool report_fanout,
|
||||||
|
bool report_variation,
|
||||||
bool report_src_attr)
|
bool report_src_attr)
|
||||||
{
|
{
|
||||||
Sta::sta()->setReportPathFields(report_input_pin,
|
Sta::sta()->setReportPathFields(report_input_pin,
|
||||||
|
|
@ -415,6 +421,7 @@ set_report_path_fields(bool report_input_pin,
|
||||||
report_cap,
|
report_cap,
|
||||||
report_slew,
|
report_slew,
|
||||||
report_fanout,
|
report_fanout,
|
||||||
|
report_variation,
|
||||||
report_src_attr);
|
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);
|
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
|
void
|
||||||
set_report_path_digits(int digits)
|
set_report_path_digits(int digits)
|
||||||
{
|
{
|
||||||
|
|
@ -456,12 +451,6 @@ set_report_path_no_split(bool no_split)
|
||||||
Sta::sta()->setReportPathNoSplit(no_split);
|
Sta::sta()->setReportPathNoSplit(no_split);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
set_report_path_sigmas(bool report_sigmas)
|
|
||||||
{
|
|
||||||
Sta::sta()->setReportPathSigmas(report_sigmas);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
report_path_cmd(Path *path)
|
report_path_cmd(Path *path)
|
||||||
{
|
{
|
||||||
|
|
@ -480,25 +469,28 @@ report_path_ends(PathEndSeq *ends)
|
||||||
void
|
void
|
||||||
report_arrival_wrt_clks(const Pin *pin,
|
report_arrival_wrt_clks(const Pin *pin,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
|
bool report_variance,
|
||||||
int digits)
|
int digits)
|
||||||
{
|
{
|
||||||
Sta::sta()->reportArrivalWrtClks(pin, scene, digits);
|
Sta::sta()->reportArrivalWrtClks(pin, scene, report_variance, digits);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
report_required_wrt_clks(const Pin *pin,
|
report_required_wrt_clks(const Pin *pin,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
|
bool report_variance,
|
||||||
int digits)
|
int digits)
|
||||||
{
|
{
|
||||||
Sta::sta()->reportRequiredWrtClks(pin, scene, digits);
|
Sta::sta()->reportRequiredWrtClks(pin, scene, report_variance, digits);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
report_slack_wrt_clks(const Pin *pin,
|
report_slack_wrt_clks(const Pin *pin,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
|
bool report_variance,
|
||||||
int digits)
|
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,
|
worst_clk_skew_cmd(const SetupHold *setup_hold,
|
||||||
bool include_internal_latency)
|
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,
|
find_clk_min_period(const Clock *clk,
|
||||||
bool ignore_port_paths)
|
bool ignore_port_paths)
|
||||||
{
|
{
|
||||||
|
|
@ -963,39 +957,37 @@ set_crpr_mode(const char *mode)
|
||||||
{
|
{
|
||||||
Sta *sta = Sta::sta();
|
Sta *sta = Sta::sta();
|
||||||
if (stringEq(mode, "same_pin"))
|
if (stringEq(mode, "same_pin"))
|
||||||
Sta::sta()->setCrprMode(CrprMode::same_pin);
|
sta->setCrprMode(CrprMode::same_pin);
|
||||||
else if (stringEq(mode, "same_transition"))
|
else if (stringEq(mode, "same_transition"))
|
||||||
Sta::sta()->setCrprMode(CrprMode::same_transition);
|
sta->setCrprMode(CrprMode::same_transition);
|
||||||
else
|
else
|
||||||
sta->report()->critical(1573, "unknown common clk pessimism mode.");
|
sta->report()->error(1573, "unknown common clk pessimism mode.");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
const char *
|
||||||
pocv_enabled()
|
pocv_mode()
|
||||||
{
|
{
|
||||||
return Sta::sta()->pocvEnabled();
|
return pocvModeName(Sta::sta()->pocvMode());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
set_pocv_enabled(bool enabled)
|
set_pocv_mode(const char *mode_name)
|
||||||
{
|
{
|
||||||
#if !SSTA
|
Sta *sta = Sta::sta();
|
||||||
if (enabled)
|
PocvMode mode = findPocvMode(mode_name);
|
||||||
Sta::sta()->report()->error(1574, "POCV support requires compilation with SSTA=1.");
|
sta->setPocvMode(mode);
|
||||||
#endif
|
|
||||||
return Sta::sta()->setPocvEnabled(enabled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
pocv_sigma_factor()
|
pocv_quantile()
|
||||||
{
|
{
|
||||||
return Sta::sta()->sigmaFactor();
|
return Sta::sta()->pocvQuantile();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
set_pocv_sigma_factor(float factor)
|
set_pocv_quantile(float quantile)
|
||||||
{
|
{
|
||||||
Sta::sta()->setSigmaFactor(factor);
|
Sta::sta()->setPocvQuantile(quantile);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
@ -1141,58 +1133,83 @@ Vertex *vertex() { return self->vertex(Sta::sta()); }
|
||||||
Path *path() { return self->path(); }
|
Path *path() { return self->path(); }
|
||||||
RiseFall *end_transition()
|
RiseFall *end_transition()
|
||||||
{ return const_cast<RiseFall*>(self->path()->transition(Sta::sta())); }
|
{ return const_cast<RiseFall*>(self->path()->transition(Sta::sta())); }
|
||||||
Slack slack() { return self->slack(Sta::sta()); }
|
|
||||||
ArcDelay margin() { return self->margin(Sta::sta()); }
|
float
|
||||||
Required data_required_time() { return self->requiredTimeOffset(Sta::sta()); }
|
slack()
|
||||||
Arrival data_arrival_time() { return self->dataArrivalTimeOffset(Sta::sta()); }
|
{
|
||||||
|
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()); }
|
const TimingRole *check_role() { return self->checkRole(Sta::sta()); }
|
||||||
MinMax *min_max() { return const_cast<MinMax*>(self->minMax(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 Clock *target_clk() { return self->targetClk(Sta::sta()); }
|
||||||
const ClockEdge *target_clk_edge() { return self->targetClkEdge(Sta::sta()); }
|
const ClockEdge *target_clk_edge() { return self->targetClkEdge(Sta::sta()); }
|
||||||
Path *target_clk_path() { return self->targetClkPath(); }
|
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 {
|
%extend Path {
|
||||||
float
|
float
|
||||||
arrival()
|
arrival()
|
||||||
{
|
{
|
||||||
return delayAsFloat(self->arrival());
|
Sta *sta = Sta::sta();
|
||||||
|
return delayAsFloat(self->arrival(), self->minMax(sta), sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
required()
|
required()
|
||||||
{
|
{
|
||||||
return delayAsFloat(self->required());
|
Sta *sta = Sta::sta();
|
||||||
|
return delayAsFloat(self->required(), self->minMax(sta), sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
slack()
|
slack()
|
||||||
{
|
{
|
||||||
Sta *sta = Sta::sta();
|
Sta *sta = Sta::sta();
|
||||||
return delayAsFloat(self->slack(sta));
|
return delayAsFloat(self->slack(sta), self->minMax(sta), sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Pin *
|
const Pin *
|
||||||
|
|
|
||||||
|
|
@ -683,7 +683,6 @@ proc_redirect report_path {
|
||||||
proc parse_report_path_options { cmd args_var default_format
|
proc parse_report_path_options { cmd args_var default_format
|
||||||
unknown_key_is_error } {
|
unknown_key_is_error } {
|
||||||
variable path_options
|
variable path_options
|
||||||
variable report_path_field_width_extra
|
|
||||||
global sta_report_default_digits
|
global sta_report_default_digits
|
||||||
|
|
||||||
upvar 1 $args_var args
|
upvar 1 $args_var args
|
||||||
|
|
@ -691,7 +690,7 @@ proc parse_report_path_options { cmd args_var default_format
|
||||||
unset path_options
|
unset path_options
|
||||||
}
|
}
|
||||||
parse_key_args $cmd args path_options {-format -digits -fields} \
|
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
|
set format $default_format
|
||||||
if [info exists path_options(-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
|
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 path_options(num_fmt) "%.${digits}f"
|
||||||
set_report_path_digits $digits
|
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_input_pin 0
|
||||||
set report_hier_pins 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_net 0
|
||||||
set report_slew 0
|
set report_slew 0
|
||||||
set report_fanout 0
|
set report_fanout 0
|
||||||
|
set report_variation 0
|
||||||
set report_src_attr 0
|
set report_src_attr 0
|
||||||
if { [info exists path_options(-fields)] } {
|
if { [info exists path_options(-fields)] } {
|
||||||
foreach field $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
|
set report_slew 1
|
||||||
} elseif { [string match "fanout" $field] } {
|
} elseif { [string match "fanout" $field] } {
|
||||||
set report_fanout 1
|
set report_fanout 1
|
||||||
|
} elseif { [string match "variation" $field] } {
|
||||||
|
set report_variation 1
|
||||||
} elseif { [string match "src*" $field] } {
|
} elseif { [string match "src*" $field] } {
|
||||||
set report_src_attr 1
|
set report_src_attr 1
|
||||||
} else {
|
} 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 \
|
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)]
|
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 } {
|
proc report_arrival { args } {
|
||||||
global sta_report_default_digits
|
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
|
check_argc_eq1 "report_arrival" $args
|
||||||
|
|
||||||
set pin [get_port_pin_error "pin" [lindex $args 0]]
|
set pin [get_port_pin_error "pin" [lindex $args 0]]
|
||||||
|
|
@ -783,17 +770,18 @@ proc report_arrival { args } {
|
||||||
} else {
|
} else {
|
||||||
set digits $sta_report_default_digits
|
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 } {
|
proc report_required { args } {
|
||||||
global sta_report_default_digits
|
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
|
check_argc_eq1 "report_required" $args
|
||||||
|
|
||||||
set pin [get_port_pin_error "pin" [lindex $args 0]]
|
set pin [get_port_pin_error "pin" [lindex $args 0]]
|
||||||
|
|
@ -804,17 +792,18 @@ proc report_required { args } {
|
||||||
} else {
|
} else {
|
||||||
set digits $sta_report_default_digits
|
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 } {
|
proc report_slack { args } {
|
||||||
global sta_report_default_digits
|
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
|
check_argc_eq1 "report_slack" $args
|
||||||
|
|
||||||
set pin [get_port_pin_error "pin" [lindex $args 0]]
|
set pin [get_port_pin_error "pin" [lindex $args 0]]
|
||||||
|
|
@ -825,7 +814,8 @@ proc report_slack { args } {
|
||||||
} else {
|
} else {
|
||||||
set digits $sta_report_default_digits
|
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 "MakeTimingModel.hh"
|
||||||
#include "parasitics/ConcreteParasitics.hh"
|
#include "parasitics/ConcreteParasitics.hh"
|
||||||
#include "spice/WritePathSpice.hh"
|
#include "spice/WritePathSpice.hh"
|
||||||
|
#include "DelayScalar.hh"
|
||||||
|
#include "DelayNormal.hh"
|
||||||
|
#include "DelaySkewNormal.hh"
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
||||||
|
|
@ -300,6 +303,7 @@ Sta::makeComponents()
|
||||||
makePower();
|
makePower();
|
||||||
makeClkSkews();
|
makeClkSkews();
|
||||||
makeCheckTiming();
|
makeCheckTiming();
|
||||||
|
delay_ops_ = new DelayOpsScalar();
|
||||||
|
|
||||||
setCmdNamespace1(CmdNamespace::sdc);
|
setCmdNamespace1(CmdNamespace::sdc);
|
||||||
setThreadCount1(defaultThreadCount());
|
setThreadCount1(defaultThreadCount());
|
||||||
|
|
@ -526,6 +530,7 @@ Sta::~Sta()
|
||||||
delete equiv_cells_;
|
delete equiv_cells_;
|
||||||
delete dispatch_queue_;
|
delete dispatch_queue_;
|
||||||
delete variables_;
|
delete variables_;
|
||||||
|
delete delay_ops_;
|
||||||
deleteContents(parasitics_name_map_);
|
deleteContents(parasitics_name_map_);
|
||||||
deleteContents(modes_);
|
deleteContents(modes_);
|
||||||
deleteContents(scenes_);
|
deleteContents(scenes_);
|
||||||
|
|
@ -2262,25 +2267,47 @@ Sta::setCrprMode(CrprMode mode)
|
||||||
variables_->setCrprMode(mode);
|
variables_->setCrprMode(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
PocvMode
|
||||||
Sta::pocvEnabled() const
|
Sta::pocvMode() const
|
||||||
{
|
{
|
||||||
return variables_->pocvEnabled();
|
return variables_->pocvMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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();
|
delaysInvalid();
|
||||||
variables_->setPocvEnabled(enabled);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
Sta::pocvQuantile()
|
||||||
|
{
|
||||||
|
return variables_->pocvQuantile();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Sta::setSigmaFactor(float factor)
|
Sta::setPocvQuantile(float quantile)
|
||||||
{
|
{
|
||||||
if (!fuzzyEqual(factor, sigma_factor_)) {
|
if (!fuzzyEqual(quantile, variables_->pocvQuantile())) {
|
||||||
sigma_factor_ = factor;
|
variables_->setPocvQuantile(quantile);
|
||||||
search_->arrivalsInvalid();
|
search_->arrivalsInvalid();
|
||||||
updateComponentsState();
|
updateComponentsState();
|
||||||
}
|
}
|
||||||
|
|
@ -2739,11 +2766,12 @@ Sta::setReportPathFields(bool report_input_pin,
|
||||||
bool report_cap,
|
bool report_cap,
|
||||||
bool report_slew,
|
bool report_slew,
|
||||||
bool report_fanout,
|
bool report_fanout,
|
||||||
|
bool report_variation,
|
||||||
bool report_src_attr)
|
bool report_src_attr)
|
||||||
{
|
{
|
||||||
report_path_->setReportFields(report_input_pin, report_hier_pins, report_net,
|
report_path_->setReportFields(report_input_pin, report_hier_pins, report_net,
|
||||||
report_cap, report_slew, report_fanout,
|
report_cap, report_slew, report_fanout,
|
||||||
report_src_attr);
|
report_variation, report_src_attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReportField *
|
ReportField *
|
||||||
|
|
@ -2764,12 +2792,6 @@ Sta::setReportPathNoSplit(bool no_split)
|
||||||
report_path_->setNoSplit(no_split);
|
report_path_->setNoSplit(no_split);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
Sta::setReportPathSigmas(bool report_sigmas)
|
|
||||||
{
|
|
||||||
report_path_->setReportSigmas(report_sigmas);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Sta::reportPathEnd(PathEnd *end)
|
Sta::reportPathEnd(PathEnd *end)
|
||||||
{
|
{
|
||||||
|
|
@ -2811,7 +2833,7 @@ Sta::reportClkSkew(ConstClockSeq &clks,
|
||||||
include_internal_latency, digits);
|
include_internal_latency, digits);
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
Delay
|
||||||
Sta::findWorstClkSkew(const SetupHold *setup_hold,
|
Sta::findWorstClkSkew(const SetupHold *setup_hold,
|
||||||
bool include_internal_latency)
|
bool include_internal_latency)
|
||||||
{
|
{
|
||||||
|
|
@ -3246,10 +3268,11 @@ Sta::endpointSlack(const Pin *pin,
|
||||||
void
|
void
|
||||||
Sta::reportArrivalWrtClks(const Pin *pin,
|
Sta::reportArrivalWrtClks(const Pin *pin,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
|
bool report_variance,
|
||||||
int digits)
|
int digits)
|
||||||
{
|
{
|
||||||
searchPreamble();
|
searchPreamble();
|
||||||
reportDelaysWrtClks(pin, scene, digits, false,
|
reportDelaysWrtClks(pin, scene, report_variance, digits, false,
|
||||||
[] (const Path *path) {
|
[] (const Path *path) {
|
||||||
return path->arrival();
|
return path->arrival();
|
||||||
});
|
});
|
||||||
|
|
@ -3258,9 +3281,10 @@ Sta::reportArrivalWrtClks(const Pin *pin,
|
||||||
void
|
void
|
||||||
Sta::reportRequiredWrtClks(const Pin *pin,
|
Sta::reportRequiredWrtClks(const Pin *pin,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
|
bool report_variance,
|
||||||
int digits)
|
int digits)
|
||||||
{
|
{
|
||||||
reportDelaysWrtClks(pin, scene, digits, true,
|
reportDelaysWrtClks(pin, scene, report_variance, digits, true,
|
||||||
[] (const Path *path) {
|
[] (const Path *path) {
|
||||||
return path->required();
|
return path->required();
|
||||||
});
|
});
|
||||||
|
|
@ -3269,9 +3293,10 @@ Sta::reportRequiredWrtClks(const Pin *pin,
|
||||||
void
|
void
|
||||||
Sta::reportSlackWrtClks(const Pin *pin,
|
Sta::reportSlackWrtClks(const Pin *pin,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
|
bool report_variance,
|
||||||
int digits)
|
int digits)
|
||||||
{
|
{
|
||||||
reportDelaysWrtClks(pin, scene, digits, true,
|
reportDelaysWrtClks(pin, scene, report_variance, digits, true,
|
||||||
[this] (const Path *path) {
|
[this] (const Path *path) {
|
||||||
return path->slack(this);
|
return path->slack(this);
|
||||||
});
|
});
|
||||||
|
|
@ -3280,6 +3305,7 @@ Sta::reportSlackWrtClks(const Pin *pin,
|
||||||
void
|
void
|
||||||
Sta::reportDelaysWrtClks(const Pin *pin,
|
Sta::reportDelaysWrtClks(const Pin *pin,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
|
bool report_variance,
|
||||||
int digits,
|
int digits,
|
||||||
bool find_required,
|
bool find_required,
|
||||||
PathDelayFunc get_path_delay)
|
PathDelayFunc get_path_delay)
|
||||||
|
|
@ -3288,14 +3314,17 @@ Sta::reportDelaysWrtClks(const Pin *pin,
|
||||||
Vertex *vertex, *bidir_vertex;
|
Vertex *vertex, *bidir_vertex;
|
||||||
graph_->pinVertices(pin, vertex, bidir_vertex);
|
graph_->pinVertices(pin, vertex, bidir_vertex);
|
||||||
if (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)
|
if (bidir_vertex)
|
||||||
reportDelaysWrtClks(vertex, scene, digits, find_required, get_path_delay);
|
reportDelaysWrtClks(vertex, scene, report_variance, digits,
|
||||||
|
find_required, get_path_delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Sta::reportDelaysWrtClks(Vertex *vertex,
|
Sta::reportDelaysWrtClks(Vertex *vertex,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
|
bool report_variance,
|
||||||
int digits,
|
int digits,
|
||||||
bool find_required,
|
bool find_required,
|
||||||
PathDelayFunc get_path_delay)
|
PathDelayFunc get_path_delay)
|
||||||
|
|
@ -3305,13 +3334,15 @@ Sta::reportDelaysWrtClks(Vertex *vertex,
|
||||||
else
|
else
|
||||||
search_->findArrivals(vertex->level());
|
search_->findArrivals(vertex->level());
|
||||||
const Sdc *sdc = scene->sdc();
|
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());
|
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 Clock *clk : sdc->sortedClocks()) {
|
||||||
for (const RiseFall *rf : RiseFall::range()) {
|
for (const RiseFall *rf : RiseFall::range()) {
|
||||||
const ClockEdge *clk_edge = clk->edge(rf);
|
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,
|
Sta::reportDelaysWrtClks(Vertex *vertex,
|
||||||
const ClockEdge *clk_edge,
|
const ClockEdge *clk_edge,
|
||||||
const Scene *scene,
|
const Scene *scene,
|
||||||
|
bool report_variance,
|
||||||
int digits,
|
int digits,
|
||||||
PathDelayFunc get_path_delay)
|
PathDelayFunc get_path_delay)
|
||||||
{
|
{
|
||||||
|
|
@ -3335,13 +3367,13 @@ Sta::reportDelaysWrtClks(Vertex *vertex,
|
||||||
report_->reportLine("%s r %s:%s f %s:%s",
|
report_->reportLine("%s r %s:%s f %s:%s",
|
||||||
clk_name.c_str(),
|
clk_name.c_str(),
|
||||||
formatDelay(RiseFall::rise(), MinMax::min(),
|
formatDelay(RiseFall::rise(), MinMax::min(),
|
||||||
delays, digits).c_str(),
|
delays, report_variance, digits).c_str(),
|
||||||
formatDelay(RiseFall::rise(), MinMax::max(),
|
formatDelay(RiseFall::rise(), MinMax::max(),
|
||||||
delays, digits).c_str(),
|
delays, report_variance, digits).c_str(),
|
||||||
formatDelay(RiseFall::fall(), MinMax::min(),
|
formatDelay(RiseFall::fall(), MinMax::min(),
|
||||||
delays, digits).c_str(),
|
delays, report_variance, digits).c_str(),
|
||||||
formatDelay(RiseFall::fall(), MinMax::max(),
|
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 MinMax *min_max = path->minMax(this);
|
||||||
const ClockEdge *path_clk_edge = path->clkEdge(this);
|
const ClockEdge *path_clk_edge = path->clkEdge(this);
|
||||||
if (path_clk_edge == clk_edge
|
if (path_clk_edge == clk_edge
|
||||||
&& !delayInf(delay))
|
&& !delayInf(delay, this))
|
||||||
delays.mergeValue(rf, min_max, delay, this);
|
delays.mergeValue(rf, min_max, delay, this);
|
||||||
}
|
}
|
||||||
return delays;
|
return delays;
|
||||||
|
|
@ -3370,13 +3402,14 @@ std::string
|
||||||
Sta::formatDelay(const RiseFall *rf,
|
Sta::formatDelay(const RiseFall *rf,
|
||||||
const MinMax *min_max,
|
const MinMax *min_max,
|
||||||
const RiseFallMinMaxDelay &delays,
|
const RiseFallMinMaxDelay &delays,
|
||||||
|
bool report_variance,
|
||||||
int digits)
|
int digits)
|
||||||
{
|
{
|
||||||
Delay delay;
|
Delay delay;
|
||||||
bool exists;
|
bool exists;
|
||||||
delays.value(rf, min_max, delay, exists);
|
delays.value(rf, min_max, delay, exists);
|
||||||
if (exists)
|
if (exists)
|
||||||
return delayAsString(delay, this, digits);
|
return delayAsString(delay, min_max, report_variance, digits, this);
|
||||||
else
|
else
|
||||||
return "---";
|
return "---";
|
||||||
}
|
}
|
||||||
|
|
@ -3439,7 +3472,7 @@ MinPeriodEndVisitor::visit(PathEnd *path_end)
|
||||||
|| !(network->isTopLevelPort(path->pin(sta_))
|
|| !(network->isTopLevelPort(path->pin(sta_))
|
||||||
|| pathIsFromInputPort(path_end)))) {
|
|| pathIsFromInputPort(path_end)))) {
|
||||||
Slack slack = path_end->slack(sta_);
|
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);
|
min_period_ = std::max(min_period_, period);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3589,7 +3622,7 @@ Sta::setIncrementalDelayTolerance(float tol)
|
||||||
graph_delay_calc_->setIncrementalDelayTolerance(tol);
|
graph_delay_calc_->setIncrementalDelayTolerance(tol);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArcDelay
|
const ArcDelay&
|
||||||
Sta::arcDelay(Edge *edge,
|
Sta::arcDelay(Edge *edge,
|
||||||
TimingArc *arc,
|
TimingArc *arc,
|
||||||
DcalcAPIndex ap_index)
|
DcalcAPIndex ap_index)
|
||||||
|
|
@ -3684,7 +3717,7 @@ Sta::ensureGraph()
|
||||||
void
|
void
|
||||||
Sta::makeGraph()
|
Sta::makeGraph()
|
||||||
{
|
{
|
||||||
graph_ = new Graph(this, 2, dcalcAnalysisPtCount());
|
graph_ = new Graph(this, dcalcAnalysisPtCount());
|
||||||
graph_->makeGraph();
|
graph_->makeGraph();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5535,12 +5568,12 @@ Sta::reportSlewChecks(const Net *net,
|
||||||
if (verbose)
|
if (verbose)
|
||||||
report_path_->reportLimitVerbose(report_path_->fieldSlew(),
|
report_path_->reportLimitVerbose(report_path_->fieldSlew(),
|
||||||
check.pin(), check.edge(),
|
check.pin(), check.edge(),
|
||||||
delayAsFloat(check.slew()),
|
delayAsFloat(check.slew(), min_max, this),
|
||||||
check.limit(), check.slack(),
|
check.limit(), check.slack(),
|
||||||
check.scene(), min_max);
|
check.scene(), min_max);
|
||||||
else
|
else
|
||||||
report_path_->reportLimitShort(report_path_->fieldSlew(), check.pin(),
|
report_path_->reportLimitShort(report_path_->fieldSlew(), check.pin(),
|
||||||
delayAsFloat(check.slew()),
|
delayAsFloat(check.slew(), min_max, this),
|
||||||
check.limit(), check.slack());
|
check.limit(), check.slack());
|
||||||
}
|
}
|
||||||
report_->reportLine("");
|
report_->reportLine("");
|
||||||
|
|
|
||||||
|
|
@ -49,11 +49,11 @@ StaState::StaState() :
|
||||||
arc_delay_calc_(nullptr),
|
arc_delay_calc_(nullptr),
|
||||||
graph_delay_calc_(nullptr),
|
graph_delay_calc_(nullptr),
|
||||||
search_(nullptr),
|
search_(nullptr),
|
||||||
|
delay_ops_(nullptr),
|
||||||
latches_(nullptr),
|
latches_(nullptr),
|
||||||
variables_(nullptr),
|
variables_(nullptr),
|
||||||
thread_count_(1),
|
thread_count_(1),
|
||||||
dispatch_queue_(nullptr),
|
dispatch_queue_(nullptr)
|
||||||
sigma_factor_(1.0)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -166,7 +166,7 @@ WorstSlack::initQueue(PathAPIndex path_ap_index)
|
||||||
slack_threshold_ = slack_init_;
|
slack_threshold_ = slack_init_;
|
||||||
for(Vertex *vertex : search_->endpoints()) {
|
for(Vertex *vertex : search_->endpoints()) {
|
||||||
Slack slack = search_->wnsSlack(vertex, path_ap_index);
|
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))
|
if (delayLess(slack, worst_slack_, this))
|
||||||
setWorstSlack(vertex, slack);
|
setWorstSlack(vertex, slack);
|
||||||
if (delayLessEqual(slack, slack_threshold_, this))
|
if (delayLessEqual(slack, slack_threshold_, this))
|
||||||
|
|
@ -177,8 +177,8 @@ WorstSlack::initQueue(PathAPIndex path_ap_index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debugPrint(debug_, "wns", 3, "threshold %s",
|
debugPrint(debug_, "wns", 3, "threshold %s",
|
||||||
delayAsString(slack_threshold_, this));
|
delayAsString(slack_threshold_, MinMax::max(), this));
|
||||||
// checkQueue();
|
//checkQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -199,7 +199,7 @@ WorstSlack::sortQueue(PathAPIndex path_ap_index)
|
||||||
Vertex *threshold_vertex = vertices[threshold_index];
|
Vertex *threshold_vertex = vertices[threshold_index];
|
||||||
slack_threshold_ = search_->wnsSlack(threshold_vertex, path_ap_index);
|
slack_threshold_ = search_->wnsSlack(threshold_vertex, path_ap_index);
|
||||||
debugPrint(debug_, "wns", 3, "threshold %s",
|
debugPrint(debug_, "wns", 3, "threshold %s",
|
||||||
delayAsString(slack_threshold_, this));
|
delayAsString(slack_threshold_, MinMax::max(), this));
|
||||||
|
|
||||||
// Reinsert vertices with slack < threshold.
|
// Reinsert vertices with slack < threshold.
|
||||||
queue_->clear();
|
queue_->clear();
|
||||||
|
|
@ -281,7 +281,7 @@ WorstSlack::updateWorstSlack(Vertex *vertex,
|
||||||
// Mark worst slack as unknown (updated by findWorstSlack().
|
// Mark worst slack as unknown (updated by findWorstSlack().
|
||||||
worst_vertex_ = nullptr;
|
worst_vertex_ = nullptr;
|
||||||
|
|
||||||
if (!delayEqual(slack, slack_init_)
|
if (!delayEqual(slack, slack_init_, this)
|
||||||
&& delayLessEqual(slack, slack_threshold_, this)) {
|
&& delayLessEqual(slack, slack_threshold_, this)) {
|
||||||
debugPrint(debug_, "wns", 3, "insert %s %s",
|
debugPrint(debug_, "wns", 3, "insert %s %s",
|
||||||
vertex->to_string(this).c_str(),
|
vertex->to_string(this).c_str(),
|
||||||
|
|
|
||||||
|
|
@ -484,7 +484,7 @@ WriteSpice::slewAxisMinValue(const TimingArc *arc)
|
||||||
{
|
{
|
||||||
GateTableModel *gate_model = arc->gateTableModel(scene_, min_max_);
|
GateTableModel *gate_model = arc->gateTableModel(scene_, min_max_);
|
||||||
if (gate_model) {
|
if (gate_model) {
|
||||||
const TableModel *model = gate_model->delayModel();
|
const TableModel *model = gate_model->delayModels()->model();
|
||||||
const TableAxis *axis1 = model->axis1();
|
const TableAxis *axis1 = model->axis1();
|
||||||
TableAxisVariable var1 = axis1->variable();
|
TableAxisVariable var1 = axis1->variable();
|
||||||
if (var1 == TableAxisVariable::input_transition_time
|
if (var1 == TableAxisVariable::input_transition_time
|
||||||
|
|
|
||||||
|
|
@ -1198,32 +1198,8 @@ using namespace sta;
|
||||||
Tcl_SetObjResult(interp, obj);
|
Tcl_SetObjResult(interp, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
%typemap(out) Delay {
|
%typemap(in) StringSet* {
|
||||||
Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1)));
|
$1 = tclListSetConstChar($input, interp);
|
||||||
}
|
|
||||||
|
|
||||||
%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(out) Mode* {
|
%typemap(out) Mode* {
|
||||||
|
|
|
||||||
|
|
@ -170,7 +170,7 @@ tclArcDcalcArg(ArcDcalcArg &gate,
|
||||||
obj = Tcl_NewStringObj(to_edge, strlen(to_edge));
|
obj = Tcl_NewStringObj(to_edge, strlen(to_edge));
|
||||||
Tcl_ListObjAppendElement(interp, list, obj);
|
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));
|
obj = Tcl_NewStringObj(input_delay, strlen(input_delay));
|
||||||
Tcl_ListObjAppendElement(interp, list, obj);
|
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
|
propagate_gated_clock_enable set_propagate_gated_clock_enable
|
||||||
}
|
}
|
||||||
|
|
||||||
trace variable ::sta_pocv_enabled "rw" \
|
trace variable ::sta_pocv_mode "rw" \
|
||||||
sta::trace_pocv_enabled
|
sta::trace_pocv_mode
|
||||||
|
|
||||||
proc trace_pocv_enabled { name1 name2 op } {
|
proc trace_pocv_mode { name1 name2 op } {
|
||||||
trace_boolean_var $op ::sta_pocv_enabled \
|
global sta_pocv_mode
|
||||||
pocv_enabled set_pocv_enabled
|
|
||||||
|
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.
|
trace variable ::sta_pocv_quantile "rw" \
|
||||||
set report_path_field_width_extra 5
|
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
|
#cmakedefine ZLIB_FOUND
|
||||||
|
|
||||||
#define SSTA ${SSTA}
|
|
||||||
|
|
||||||
#define TCL_READLINE ${TCL_READLINE}
|
#define TCL_READLINE ${TCL_READLINE}
|
||||||
|
|
|
||||||
|
|
@ -1032,7 +1032,7 @@ VerilogDclBus::VerilogDclBus(PortDirection *dir,
|
||||||
int
|
int
|
||||||
VerilogDclBus::size() const
|
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) :
|
VerilogDclArg::VerilogDclArg(const std::string &net_name) :
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue