Merge remote-tracking branch 'upstream/master' into update

Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
This commit is contained in:
Matt Liberty 2024-02-12 22:48:05 -08:00
commit d61313d8ad
386 changed files with 7288 additions and 8818 deletions

View File

@ -1,5 +1,5 @@
# OpenSTA, Static Timing Analyzer
# Copyright (c) 2023, Parallax Software, Inc.
# Copyright (c) 2024, 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
@ -24,14 +24,14 @@ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.14)
cmake_policy(SET CMP0086 NEW)
endif()
project(STA VERSION 2.4.0
project(STA VERSION 2.5.0
LANGUAGES CXX
)
option(USE_CUDD "Use CUDD BDD package")
option(CUDD_DIR "CUDD BDD package directory")
set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_VERBOSE_MAKEFILE OFF)
set(STA_HOME ${PROJECT_SOURCE_DIR})
message(STATUS "STA version: ${PROJECT_VERSION}")
@ -62,6 +62,7 @@ set(STA_SOURCE
app/StaMain.cc
dcalc/ArcDelayCalc.cc
dcalc/ArcDcalcWaveforms.cc
dcalc/ArnoldiDelayCalc.cc
dcalc/ArnoldiReduce.cc
dcalc/DcalcAnalysisPt.cc
@ -69,11 +70,11 @@ set(STA_SOURCE
dcalc/DelayCalcBase.cc
dcalc/DmpCeff.cc
dcalc/DmpDelayCalc.cc
dcalc/FindRoot.cc
dcalc/GraphDelayCalc.cc
dcalc/LumpedCapDelayCalc.cc
dcalc/NetCaps.cc
dcalc/ParallelDelayCalc.cc
dcalc/SlewDegradeDelayCalc.cc
dcalc/UnitDelayCalc.cc
graph/DelayFloat.cc
@ -114,7 +115,6 @@ set(STA_SOURCE
parasitics/ConcreteParasitics.cc
parasitics/EstimateParasitics.cc
parasitics/NullParasitics.cc
parasitics/Parasitics.cc
parasitics/ReduceParasitics.cc
parasitics/ReportParasiticAnnotation.cc
@ -325,16 +325,20 @@ set_property(SOURCE ${STA_SWIG_FILE}
-I${STA_HOME}/verilog
)
set_property(SOURCE ${STA_SWIG_FILE}
PROPERTY DEPENDS
set(SWIG_FILES
${STA_HOME}/dcalc/DelayCalc.i
${STA_HOME}/parasitics/Parasitics.i
${STA_HOME}/power/Power.i
${STA_HOME}/sdf/Sdf.i
${STA_HOME}/tcl/Exception.i
${STA_HOME}/tcl/StaTcl.i
${STA_HOME}/tcl/StaTclTypes.i
${STA_HOME}/tcl/NetworkEdit.i
${STA_HOME}/verilog/Verilog.i
)
set_property(SOURCE ${STA_SWIG_FILE}
PROPERTY DEPENDS ${SWIG_FILES}
)
swig_add_library(sta_swig
@ -343,16 +347,14 @@ swig_add_library(sta_swig
SOURCES ${STA_SWIG_FILE}
)
get_target_property(SWIG_FILES sta_swig SOURCES)
get_target_property(STA_SWIG_CXX_FILE sta_swig SOURCES)
foreach(SWIG_FILE ${SWIG_FILES})
set_source_files_properties(${SWIG_FILE}
PROPERTIES
# No simple way to modify the swig template that emits code full of warnings
# so suppress them.
COMPILE_OPTIONS "-Wno-cast-qual;-Wno-missing-braces;-Wno-deprecated-declarations"
set_source_files_properties(${STA_SWIG_CXX_FILE}
PROPERTIES
# No simple way to modify the swig template that emits code full of warnings
# so suppress them.
COMPILE_OPTIONS "-Wno-cast-qual;-Wno-missing-braces;-Wno-deprecated-declarations"
)
endforeach()
target_link_libraries(sta_swig
PUBLIC
@ -578,6 +580,7 @@ add_custom_target(sta_tags etags -o TAGS
${STA_SOURCE}
*/*.hh
include/sta/*.hh
${SWIG_FILES}
${STA_TCL_FILES}
${SWIG_TCL_FILES}
WORKING_DIRECTORY ${STA_HOME}

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,7 +1,7 @@
%module sta
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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
@ -17,6 +17,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
%include "Exception.i"
%include "StaTclTypes.i"
%include "StaTcl.i"
%include "Verilog.i"
%include "NetworkEdit.i"

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -63,7 +63,7 @@ get_filename_component(TCL_LIB_PARENT2 "${TCL_LIB_PARENT1}" PATH)
if (NOT TCL_HEADER)
find_file(TCL_HEADER tcl.h
PATHS ${TCL_LIB_PARENT1} ${TCL_LIB_PARENT2}
PATH_SUFFIXES include include/tcl
PATH_SUFFIXES include include/tcl include/tcl-tk
NO_DEFAULT_PATH
)
endif()

View File

@ -0,0 +1,43 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2024, 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/>.
#include "ArcDcalcWaveforms.hh"
namespace sta {
Table1
ArcDcalcWaveforms::inputWaveform(const Pin *,
const RiseFall *,
const Corner *,
const MinMax *)
{
return Table1();
}
Table1
ArcDcalcWaveforms::drvrRampWaveform(const Pin *,
const RiseFall *,
const Pin *,
const RiseFall *,
const Pin *,
const Corner *,
const MinMax *)
{
return Table1();
}
} // namespace

View File

@ -0,0 +1,59 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2024, 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/>.
#pragma once
#include "MinMax.hh"
#include "TableModel.hh"
#include "NetworkClass.hh"
namespace sta {
class Corner;
class DcalcAnalysisPt;
// Abstract class for the graph delay calculator traversal to interface
class ArcDcalcWaveforms
{
public:
virtual Table1 inputWaveform(const Pin *in_pin,
const RiseFall *in_rf,
const Corner *corner,
const MinMax *min_max);
virtual Table1 drvrWaveform(const Pin *in_pin,
const RiseFall *in_rf,
const Pin *drvr_pin,
const RiseFall *drvr_rf,
const Corner *corner,
const MinMax *min_max) = 0;
virtual Table1 loadWaveform(const Pin *in_pin,
const RiseFall *in_rf,
const Pin *drvr_pin,
const RiseFall *drvr_rf,
const Pin *load_pin,
const Corner *corner,
const MinMax *min_max) = 0;
virtual Table1 drvrRampWaveform(const Pin *in_pin,
const RiseFall *in_rf,
const Pin *drvr_pin,
const RiseFall *drvr_rf,
const Pin *load_pin,
const Corner *corner,
const MinMax *min_max);
};
} // namespace

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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
@ -16,10 +16,6 @@
#include "ArcDelayCalc.hh"
#include "TimingModel.hh"
#include "TimingArc.hh"
#include "GraphDelayCalc.hh"
namespace sta {
ArcDelayCalc::ArcDelayCalc(StaState *sta):
@ -27,27 +23,114 @@ ArcDelayCalc::ArcDelayCalc(StaState *sta):
{
}
TimingModel *
ArcDelayCalc::model(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const
void
ArcDelayCalc::gateDelay(const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *parasitic,
float,
const Pvt *,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew)
{
const OperatingConditions *op_cond = dcalc_ap->operatingConditions();
const TimingArc *corner_arc = arc->cornerArc(dcalc_ap->libertyIndex());
return corner_arc->model(op_cond);
LoadPinIndexMap load_pin_index_map(network_);
ArcDcalcResult dcalc_result = gateDelay(nullptr, arc, in_slew, load_cap, parasitic,
load_pin_index_map, dcalc_ap);
gate_delay = dcalc_result.gateDelay();
drvr_slew = dcalc_result.drvrSlew();
}
GateTimingModel *
ArcDelayCalc::gateModel(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const
////////////////////////////////////////////////////////////////
ArcDcalcArg::ArcDcalcArg() :
drvr_pin_(nullptr),
edge_(nullptr),
arc_(nullptr),
in_slew_(0.0),
parasitic_(nullptr)
{
return dynamic_cast<GateTimingModel*>(model(arc, dcalc_ap));
}
CheckTimingModel *
ArcDelayCalc::checkModel(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const
ArcDcalcArg::ArcDcalcArg(const Pin *drvr_pin,
Edge *edge,
const TimingArc *arc,
const Slew in_slew,
const Parasitic *parasitic) :
drvr_pin_(drvr_pin),
edge_(edge),
arc_(arc),
in_slew_(in_slew),
parasitic_(parasitic)
{
return dynamic_cast<CheckTimingModel*>(model(arc, dcalc_ap));
}
void
ArcDcalcArg::setParasitic(const Parasitic *parasitic)
{
parasitic_ = parasitic;
}
////////////////////////////////////////////////////////////////
ArcDcalcResult::ArcDcalcResult() :
gate_delay_(0.0),
drvr_slew_(0.0)
{
}
ArcDcalcResult::ArcDcalcResult(size_t load_count) :
gate_delay_(0.0),
drvr_slew_(0.0)
{
wire_delays_.resize(load_count);
load_slews_.resize(load_count);
}
void
ArcDcalcResult::setGateDelay(ArcDelay gate_delay)
{
gate_delay_ = gate_delay;
}
void
ArcDcalcResult::setDrvrSlew(Slew drvr_slew)
{
drvr_slew_ = drvr_slew;
}
ArcDelay
ArcDcalcResult::wireDelay(size_t load_idx) const
{
return wire_delays_[load_idx];
}
void
ArcDcalcResult::setWireDelay(size_t load_idx,
ArcDelay wire_delay)
{
wire_delays_[load_idx] = wire_delay;
}
void
ArcDcalcResult::setLoadCount(size_t load_count)
{
wire_delays_.resize(load_count);
load_slews_.resize(load_count);
}
Slew
ArcDcalcResult::loadSlew(size_t load_idx) const
{
return load_slews_[load_idx];
}
void
ArcDcalcResult::setLoadSlew(size_t load_idx,
Slew load_slew)
{
load_slews_[load_idx] = load_slew;
}
} // namespace

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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
@ -64,6 +64,8 @@ public:
rcmodel();
virtual ~rcmodel();
virtual float capacitance() const;
virtual PinSet unannotatedLoads(const Pin *drvr_pin,
const Parasitics *parasitics) const;
const Pin **pinV; // [n]
};
@ -74,7 +76,6 @@ struct timing_table
const LibertyCell *cell;
const Pvt *pvt;
float in_slew;
float relcap;
};
} // namespace

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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
@ -30,6 +30,7 @@
#include "TimingModel.hh"
#include "TimingArc.hh"
#include "TableModel.hh"
#include "PortDirection.hh"
#include "Network.hh"
#include "Graph.hh"
#include "Parasitics.hh"
@ -117,34 +118,33 @@ public:
Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
ReducedParasiticType reducedParasiticType() const override;
void inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap) override;
void gateDelay(const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew) override;
void loadDelay(const Pin *load_pin,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew) override;
string reportGateDelay(const TimingArc *arc,
Parasitic *reduceParasitic(const Parasitic *parasitic_network,
const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
ArcDcalcResult inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
ArcDcalcResult gateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
// Pass in load_cap or parasitic.
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
string reportGateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
int digits) override;
void finishDrvrPin() override;
void delay_work_set_thresholds(delay_work *D,
double lo,
double hi,
@ -152,14 +152,12 @@ public:
double derate);
private:
void gateDelaySlew(const LibertyCell *drvr_cell,
const GateTableModel *table_model,
const Slew &in_slew,
float related_out_cap,
const Pvt *pvt,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew);
ArcDcalcResult gateDelaySlew(const LibertyCell *drvr_cell,
const TimingArc *arc,
const GateTableModel *table_model,
const Slew &in_slew,
const LoadPinIndexMap &load_pin_index_map,
const Pvt *pvt);
void ar1_ceff_delay(delay_work *D,
timing_table *tab,
arnoldi1 *mod,
@ -224,9 +222,9 @@ private:
double *_delayV;
double *_slewV;
int pin_n_;
bool input_port_;
ArnoldiReduce *reduce_;
delay_work *delay_work_;
vector<rcmodel*> unsaved_parasitics_;
};
ArcDelayCalc *
@ -266,65 +264,70 @@ ArnoldiDelayCalc::findParasitic(const Pin *drvr_pin,
{
Parasitic *parasitic = nullptr;
const Corner *corner = dcalc_ap->corner();
// set_load net has precidence over parasitics.
if (!sdc_->drvrPinHasWireCap(drvr_pin, corner)) {
const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
Parasitic *parasitic_network =
parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap);
bool delete_parasitic_network = false;
const MinMax *cnst_min_max = dcalc_ap->constraintMinMax();
const OperatingConditions *op_cond = dcalc_ap->operatingConditions();
if (parasitic_network == nullptr) {
Wireload *wireload = sdc_->wireload(cnst_min_max);
if (wireload) {
float pin_cap, wire_cap, fanout;
bool has_wire_cap;
graph_delay_calc_->netCaps(drvr_pin, drvr_rf, dcalc_ap,
pin_cap, wire_cap, fanout, has_wire_cap);
parasitic_network = parasitics_->makeWireloadNetwork(drvr_pin, wireload,
fanout, op_cond,
parasitic_ap);
delete_parasitic_network = true;
}
// set_load net has precedence over parasitics.
if (sdc_->drvrPinHasWireCap(drvr_pin, corner)
|| network_->direction(drvr_pin)->isInternal())
return nullptr;
const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
Parasitic *parasitic_network =
parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap);
const MinMax *min_max = dcalc_ap->constraintMinMax();
if (parasitic_network == nullptr) {
Wireload *wireload = sdc_->wireload(min_max);
if (wireload) {
float pin_cap, wire_cap, fanout;
bool has_wire_cap;
graph_delay_calc_->netCaps(drvr_pin, drvr_rf, dcalc_ap,
pin_cap, wire_cap, fanout, has_wire_cap);
parasitic_network = parasitics_->makeWireloadNetwork(drvr_pin, wireload,
fanout, min_max,
parasitic_ap);
}
}
if (parasitic_network) {
parasitic = reduce_->reduceToArnoldi(parasitic_network,
drvr_pin,
parasitic_ap->couplingCapFactor(),
drvr_rf, op_cond, corner,
cnst_min_max, parasitic_ap);
if (delete_parasitic_network) {
Net *net = network_->net(drvr_pin);
parasitics_->deleteParasiticNetwork(net, parasitic_ap);
}
// Arnoldi parasitics are their own class that are not saved in the parasitic db.
unsaved_parasitics_.push_back(parasitic);
}
if (parasitic_network) {
rcmodel *rcmodel = reduce_->reduceToArnoldi(parasitic_network, drvr_pin,
parasitic_ap->couplingCapFactor(),
drvr_rf, corner, min_max, parasitic_ap);
// Arnoldi parasitics are their own class that are not saved in the parasitic db.
unsaved_parasitics_.push_back(rcmodel);
parasitic = rcmodel;
}
return parasitic;
}
ReducedParasiticType
ArnoldiDelayCalc::reducedParasiticType() const
Parasitic *
ArnoldiDelayCalc::reduceParasitic(const Parasitic *,
const Pin *,
const RiseFall *,
const DcalcAnalysisPt *)
{
return ReducedParasiticType::arnoldi;
// Decline because reduced arnoldi parasitics are not stored in the parasitics db.
return nullptr;
}
void
ArnoldiDelayCalc::inputPortDelay(const Pin *drvr_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap)
ArnoldiDelayCalc::finishDrvrPin()
{
for (auto parasitic : unsaved_parasitics_)
delete parasitic;
unsaved_parasitics_.clear();
}
ArcDcalcResult
ArnoldiDelayCalc::inputPortDelay(const Pin *,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
{
LumpedCapDelayCalc::inputPortDelay(drvr_pin, in_slew, rf, parasitic, dcalc_ap);
rcmodel_ = nullptr;
_delayV[0] = 0.0;
_slewV[0] = in_slew;
int j;
LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
ArcDcalcResult dcalc_result(load_pin_index_map.size());
if (parasitic) {
rcmodel_ = reinterpret_cast<rcmodel*>(const_cast<Parasitic*>(parasitic));
pin_n_ = rcmodel_->n;
@ -335,69 +338,67 @@ ArnoldiDelayCalc::inputPortDelay(const Pin *drvr_pin,
_delayV = (double*)realloc(_delayV,_pinNmax * sizeof(double));
_slewV = (double*)realloc(_slewV,_pinNmax * sizeof(double));
}
pin_n_ = 1;
pin_n_ = rcmodel_->n;
double slew_derate = drvr_library_->slewDerateFromLibrary();
double lo_thresh = drvr_library_->slewLowerThreshold(drvr_rf_);
double hi_thresh = drvr_library_->slewUpperThreshold(drvr_rf_);
bool rising = (drvr_rf_ == RiseFall::rise());
delay_work_set_thresholds(delay_work_, lo_thresh, hi_thresh, rising,
slew_derate);
double slew_derate = drvr_library->slewDerateFromLibrary();
double lo_thresh = drvr_library->slewLowerThreshold(rf);
double hi_thresh = drvr_library->slewUpperThreshold(rf);
bool rising = (rf == RiseFall::rise());
delay_work_set_thresholds(delay_work_, lo_thresh, hi_thresh, rising, slew_derate);
delay_c *c = delay_work_->c;
double c_log = c->vlg;
for (j=1;j<pin_n_;j++) {
for (int j=1;j<pin_n_;j++) {
double elmore = rcmodel_->elmore(j);
_delayV[j] = 0.6931472*elmore;
_slewV[j] = in_slew + c_log*elmore/slew_derate;
double wire_delay = 0.6931472*elmore;
double load_slew = in_slew + c_log*elmore/slew_derate;
_delayV[j] = wire_delay;
_slewV[j] = load_slew;
const Pin *load_pin = rcmodel_->pinV[j];
auto load_idx_itr = load_pin_index_map.find(load_pin);
if (load_idx_itr != load_pin_index_map.end()) {
size_t load_idx = load_idx_itr->second;
dcalc_result.setWireDelay(load_idx, wire_delay);
dcalc_result.setLoadSlew(load_idx, load_slew);
}
}
}
}
void
ArnoldiDelayCalc::gateDelay(const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew)
{
input_port_ = false;
drvr_rf_ = arc->toEdge()->asRiseFall();
const LibertyCell *drvr_cell = arc->from()->libertyCell();
drvr_library_ = drvr_cell->libertyLibrary();
drvr_parasitic_ = drvr_parasitic;
ConcreteParasitic *drvr_cparasitic =
reinterpret_cast<ConcreteParasitic*>(const_cast<Parasitic*>(drvr_parasitic));
rcmodel_ = dynamic_cast<rcmodel*>(drvr_cparasitic);
GateTimingModel *model = gateModel(arc, dcalc_ap);
GateTableModel *table_model = dynamic_cast<GateTableModel*>(model);
if (table_model && rcmodel_)
gateDelaySlew(drvr_cell, table_model, in_slew,
related_out_cap, pvt,
gate_delay, drvr_slew);
else
LumpedCapDelayCalc::gateDelay(arc, in_slew, load_cap, drvr_parasitic,
related_out_cap, pvt, dcalc_ap,
gate_delay, drvr_slew);
drvr_slew_ = drvr_slew;
multi_drvr_slew_factor_ = 1.0F;
dcalc_result = makeResult(drvr_library, rf, 0.0, in_slew, load_pin_index_map);
return dcalc_result;
}
void
ArcDcalcResult
ArnoldiDelayCalc::gateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
{
const LibertyCell *drvr_cell = arc->from()->libertyCell();
ConcreteParasitic *cparasitic =
reinterpret_cast<ConcreteParasitic*>(const_cast<Parasitic*>(parasitic));
rcmodel_ = dynamic_cast<rcmodel*>(cparasitic);
GateTableModel *table_model = gateTableModel(arc, dcalc_ap);
if (table_model && rcmodel_) {
const Pvt *pvt = pinPvt(drvr_pin, dcalc_ap);
return gateDelaySlew(drvr_cell, arc, table_model, in_slew, load_pin_index_map, pvt);
}
else
return LumpedCapDelayCalc::gateDelay(drvr_pin, arc, in_slew, load_cap,
parasitic, load_pin_index_map, dcalc_ap);
}
ArcDcalcResult
ArnoldiDelayCalc::gateDelaySlew(const LibertyCell *drvr_cell,
const TimingArc *arc,
const GateTableModel *table_model,
const Slew &in_slew,
float related_out_cap,
const Pvt *pvt,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew)
const LoadPinIndexMap &load_pin_index_map,
const Pvt *pvt)
{
pin_n_ = rcmodel_->n;
if (pin_n_ >= _pinNmax) {
@ -407,12 +408,15 @@ ArnoldiDelayCalc::gateDelaySlew(const LibertyCell *drvr_cell,
_slewV = (double*)realloc(_slewV,_pinNmax * sizeof(double));
}
ArcDcalcResult dcalc_result(load_pin_index_map.size());
pin_n_ = rcmodel_->n;
if (table_model) {
double slew_derate = drvr_library_->slewDerateFromLibrary();
double lo_thresh = drvr_library_->slewLowerThreshold(drvr_rf_);
double hi_thresh = drvr_library_->slewUpperThreshold(drvr_rf_);
bool rising = (drvr_rf_ == RiseFall::rise());
const RiseFall *rf = arc->toEdge()->asRiseFall();
if (table_model && rf) {
const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary();
double slew_derate = drvr_library->slewDerateFromLibrary();
double lo_thresh = drvr_library->slewLowerThreshold(rf);
double hi_thresh = drvr_library->slewUpperThreshold(rf);
bool rising = (rf == RiseFall::rise());
delay_work_set_thresholds(delay_work_, lo_thresh, hi_thresh, rising,
slew_derate);
if (rcmodel_->order > 0) {
@ -421,48 +425,43 @@ ArnoldiDelayCalc::gateDelaySlew(const LibertyCell *drvr_cell,
tab.cell = drvr_cell;
tab.pvt = pvt;
tab.in_slew = delayAsFloat(in_slew);
tab.relcap = related_out_cap;
ar1_ceff_delay(delay_work_, &tab, rcmodel_,
_delayV, _slewV);
}
gate_delay = _delayV[0];
drvr_slew = _slewV[0];
}
}
dcalc_result.setGateDelay(_delayV[0]);
dcalc_result.setDrvrSlew(_slewV[0]);
void
ArnoldiDelayCalc::loadDelay(const Pin *load_pin,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew)
{
// This does not appear to handle input port parasitics correctly.
wire_delay = 0.0;
load_slew = drvr_slew_ * multi_drvr_slew_factor_;
if (rcmodel_) {
// HACK
for (int i = 0; i < rcmodel_->n; i++) {
if (rcmodel_->pinV[i] == load_pin) {
wire_delay = _delayV[i] - _delayV[0];
load_slew = _slewV[i] * multi_drvr_slew_factor_;
break;
if (rcmodel_) {
for (int i = 0; i < rcmodel_->n; i++) {
const Pin *load_pin = rcmodel_->pinV[i];
auto load_idx_itr = load_pin_index_map.find(load_pin);
if (load_idx_itr != load_pin_index_map.end()) {
size_t load_idx = load_idx_itr->second;
ArcDelay wire_delay = _delayV[i] - _delayV[0];
Slew load_slew = _slewV[i];
thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew);
dcalc_result.setWireDelay(load_idx, wire_delay);
dcalc_result.setLoadSlew(load_idx, load_slew);
}
}
}
}
thresholdAdjust(load_pin, wire_delay, load_slew);
return dcalc_result;
}
string
ArnoldiDelayCalc::reportGateDelay(const TimingArc *,
const Slew &,
float,
const Parasitic *,
float,
const Pvt *,
const DcalcAnalysisPt *,
int)
ArnoldiDelayCalc::reportGateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
int digits)
{
return "";
return LumpedCapDelayCalc::reportGateDelay(drvr_pin, arc, in_slew, load_cap,
parasitic, load_pin_index_map,
dcalc_ap, digits);
}
////////////////////////////////////////////////////////////////
@ -1310,12 +1309,11 @@ ArnoldiDelayCalc::ra_get_r(delay_work *D,
c1 = ctot;
ArcDelay d1;
Slew s1;
tab->table->gateDelay(tab->pvt, tab->in_slew, c1, tab->relcap, pocv_enabled_, d1, s1);
tab->table->gateDelay(tab->pvt, tab->in_slew, c1, pocv_enabled_, d1, s1);
tlohi = slew_derate*delayAsFloat(s1);
r = tlohi/(c_log*c1);
if (rdelay>0.0 && r > rdelay)
r = rdelay;
// else printf("from rdelay %g to r %g\n",rdelay,r);
return r;
}
@ -1332,7 +1330,7 @@ ArnoldiDelayCalc::ra_get_s(delay_work *D,
double tlohi,smin,s;
ArcDelay d1;
Slew s1;
tab->table->gateDelay(tab->pvt, tab->in_slew, c, tab->relcap, pocv_enabled_, d1, s1);
tab->table->gateDelay(tab->pvt, tab->in_slew, c, pocv_enabled_, d1, s1);
tlohi = slew_derate*delayAsFloat(s1);
smin = r*c*c_smin; // c_smin = ra_hinv((1-vhi)/vhi-log(vhi)) + log(vhi);
if (c_log*r*c >= tlohi) {
@ -1365,8 +1363,8 @@ ArnoldiDelayCalc::ra_rdelay_1(timing_table *tab,
return 0.0;
ArcDelay d1, d2;
Slew s1, s2;
tab->table->gateDelay(tab->pvt, tab->in_slew, c1, tab->relcap, pocv_enabled_, d1, s1);
tab->table->gateDelay(tab->pvt, tab->in_slew, c2, tab->relcap, pocv_enabled_, d2, s2);
tab->table->gateDelay(tab->pvt, tab->in_slew, c1, pocv_enabled_, d1, s1);
tab->table->gateDelay(tab->pvt, tab->in_slew, c2, pocv_enabled_, d2, s2);
double dt50 = delayAsFloat(d1)-delayAsFloat(d2);
if (dt50 <= 0.0)
return 0.0;
@ -1418,8 +1416,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
units_->timeUnit()->asString(s));
thix = ra_solve_for_t(p,s,vhi);
tlox = ra_solve_for_t(p,s,vlo);
tab->table->gateDelay(tab->pvt,tab->in_slew, ctot, tab->relcap, pocv_enabled_,
df, sf);
tab->table->gateDelay(tab->pvt,tab->in_slew, ctot, pocv_enabled_, df, sf);
debugPrint(debug_, "arnoldi", 1, "table slew (in_slew %s ctot %s) = %s",
units_->timeUnit()->asString(tab->in_slew),
units_->capacitanceUnit()->asString(ctot),
@ -1430,7 +1427,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
units_->timeUnit()->asString(tlox-thix));
}
ceff = ctot;
tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, tab->relcap, pocv_enabled_,
tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, pocv_enabled_,
df, sf);
t50_sy = delayAsFloat(df);
t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5);
@ -1472,7 +1469,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
units_->timeUnit()->asString(ceff_time),
units_->capacitanceUnit()->asString(ceff));
tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, tab->relcap, pocv_enabled_, df, sf);
tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, pocv_enabled_, df, sf);
t50_sy = delayAsFloat(df);
t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5);
for (j=0;j<mod->n;j++) {

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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
@ -46,6 +46,14 @@ rcmodel::capacitance() const
return ctot;
}
PinSet
rcmodel::unannotatedLoads(const Pin *,
const Parasitics *) const
{
// This should never be called because the rcmodel is not saved in the Parasitics.
return PinSet();
}
struct ts_point
{
ParasiticNode *node_;
@ -62,7 +70,7 @@ struct ts_point
struct ts_edge
{
ConcreteParasiticResistor *resistor_;
ParasiticResistor *resistor_;
ts_point *from;
ts_point *to;
};
@ -131,23 +139,21 @@ ArnoldiReduce::~ArnoldiReduce()
free(ts_pointV);
}
Parasitic *
rcmodel *
ArnoldiReduce::reduceToArnoldi(Parasitic *parasitic,
const Pin *drvr_pin,
float coupling_cap_factor,
const RiseFall *rf,
const OperatingConditions *op_cond,
const Corner *corner,
const MinMax *cnst_min_max,
const MinMax *min_max,
const ParasiticAnalysisPt *ap)
{
parasitic_network_ = reinterpret_cast<ConcreteParasiticNetwork*>(parasitic);
drvr_pin_ = drvr_pin;
coupling_cap_factor_ = coupling_cap_factor;
rf_ = rf;
op_cond_ = op_cond;
corner_ = corner;
cnst_min_max_ = cnst_min_max;
min_max_ = min_max;
ap_ = ap;
loadWork();
return makeRcmodelDrv();
@ -158,18 +164,21 @@ ArnoldiReduce::loadWork()
{
pt_map_.clear();
int resistor_count = 0;
ConcreteParasiticDeviceSet devices;
parasitic_network_->devices(&devices);
ConcreteParasiticDeviceSet::Iterator device_iter(devices);
while (device_iter.hasNext()) {
ParasiticDevice *device = device_iter.next();
if (parasitics_->isResistor(device))
resistor_count++;
}
const ParasiticResistorSeq &resistors = parasitics_->resistors(parasitic_network_);
int resistor_count = resistors.size();
termN = parasitic_network_->pinNodes()->size();
int subnode_count = parasitic_network_->subNodes()->size();
termN = 0;
int subnode_count = 0;
ParasiticNodeSeq nodes = parasitics_->nodes(parasitic_network_);
for (ParasiticNode *node : nodes) {
if (!parasitics_->isExternal(node)) {
const Pin *pin = parasitics_->pin(node);
if (pin)
termN++;
else
subnode_count++;
}
}
ts_pointN = subnode_count + 1 + termN;
ts_edgeN = resistor_count;
allocPoints();
@ -191,50 +200,42 @@ ArnoldiReduce::loadWork()
pend = pterm0;
e = e0;
int index = 0;
ConcreteParasiticSubNodeMap::Iterator
sub_node_iter(parasitic_network_->subNodes());
while (sub_node_iter.hasNext()) {
ConcreteParasiticSubNode *node = sub_node_iter.next();
pt_map_[node] = index;
p = p0 + index;
p->node_ = node;
p->eN = 0;
p->is_term = false;
index++;
for (ParasiticNode *node : nodes) {
if (!parasitics_->isExternal(node)) {
const Pin *pin = parasitics_->pin(node);
if (pin) {
p = pend++;
pt_map_[node] = p - p0;
p->node_ = node;
p->eN = 0;
p->is_term = true;
tindex = p - pterm0;
p->tindex = tindex;
pinV[tindex] = pin;
}
else {
pt_map_[node] = index;
p = p0 + index;
p->node_ = node;
p->eN = 0;
p->is_term = false;
index++;
}
}
}
ConcreteParasiticPinNodeMap::Iterator
pin_node_iter(parasitic_network_->pinNodes());
while (pin_node_iter.hasNext()) {
ConcreteParasiticPinNode *node = pin_node_iter.next();
p = pend++;
pt_map_[node] = p - p0;
p->node_ = node;
p->eN = 0;
p->is_term = true;
tindex = p - pterm0;
p->tindex = tindex;
const Pin *pin = parasitics_->connectionPin(node);
pinV[tindex] = pin;
}
ts_edge **eV = ts_eV;
ConcreteParasiticDeviceSet::Iterator device_iter2(devices);
while (device_iter2.hasNext()) {
ParasiticDevice *device = device_iter2.next();
if (parasitics_->isResistor(device)) {
ConcreteParasiticResistor *resistor =
reinterpret_cast<ConcreteParasiticResistor*>(device);
ts_point *pt1 = findPt(resistor->node1());
ts_point *pt2 = findPt(resistor->node2());
e->from = pt1;
e->to = pt2;
e->resistor_ = resistor;
pt1->eN++;
if (e->from != e->to)
pt2->eN++;
e++;
}
for (ParasiticResistor *resistor : resistors) {
ts_point *pt1 = findPt(parasitics_->node1(resistor));
ts_point *pt2 = findPt(parasitics_->node2(resistor));
e->from = pt1;
e->to = pt2;
e->resistor_ = resistor;
pt1->eN++;
if (e->from != e->to)
pt2->eN++;
e++;
}
for (p=p0;p!=pend;p++) {
@ -313,8 +314,7 @@ ArnoldiReduce::findPt(ParasiticNode *node)
rcmodel *
ArnoldiReduce::makeRcmodelDrv()
{
ParasiticNode *drv_node = parasitics_->findNode(parasitic_network_,
drvr_pin_);
ParasiticNode *drv_node = parasitics_->findNode(parasitic_network_, drvr_pin_);
ts_point *pdrv = findPt(drv_node);
makeRcmodelDfs(pdrv);
getRC();
@ -322,8 +322,7 @@ ArnoldiReduce::makeRcmodelDrv()
return nullptr;
setTerms(pdrv);
makeRcmodelFromTs();
rcmodel *mod = makeRcmodelFromW();
return mod;
return makeRcmodelFromW();
}
#define ts_orient( pp, ee) \
@ -415,7 +414,7 @@ ArnoldiReduce::getRC()
p->r = 0.0;
if (p->node_) {
ParasiticNode *node = p->node_;
double cap = parasitics_->nodeGndCap(node, ap_)
double cap = parasitics_->nodeGndCap(node)
+ pinCapacitance(node);
if (cap > 0.0) {
p->c = cap;
@ -424,7 +423,7 @@ ArnoldiReduce::getRC()
else
p->c = 0.0;
if (p->in_edge && p->in_edge->resistor_)
p->r = parasitics_->value(p->in_edge->resistor_, ap_);
p->r = parasitics_->value(p->in_edge->resistor_);
if (!(p->r>=0.0 && p->r<100e+3)) { // 0 < r < 100kohm
debugPrint(debug_, "arnoldi", 1,
"R value %g out of range, drvr pin %s",
@ -433,20 +432,33 @@ ArnoldiReduce::getRC()
}
}
}
for (ParasiticCapacitor *capacitor : parasitics_->capacitors(parasitic_network_)) {
float cap = parasitics_->value(capacitor) * ap_->couplingCapFactor();
ParasiticNode *node1 = parasitics_->node1(capacitor);
if (!parasitics_->isExternal(node1)) {
ts_point *pt = findPt(node1);
pt->c += cap;
}
ParasiticNode *node2 = parasitics_->node2(capacitor);
if (!parasitics_->isExternal(node2)) {
ts_point *pt = findPt(node2);
pt->c += cap;
}
}
}
float
ArnoldiReduce::pinCapacitance(ParasiticNode *node)
{
const Pin *pin = parasitics_->connectionPin(node);
const Pin *pin = parasitics_->pin(node);
float pin_cap = 0.0;
if (pin) {
Port *port = network_->port(pin);
LibertyPort *lib_port = network_->libertyPort(port);
if (lib_port)
pin_cap = sdc_->pinCapacitance(pin,rf_, op_cond_, corner_, cnst_min_max_);
pin_cap = sdc_->pinCapacitance(pin,rf_, corner_, min_max_);
else if (network_->isTopLevelPort(pin))
pin_cap = sdc_->portExtCap(port, rf_, corner_, cnst_min_max_);
pin_cap = sdc_->portExtCap(port, rf_, corner_, min_max_);
}
return pin_cap;
}

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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
@ -37,21 +37,20 @@ class rcmodel;
struct ts_edge;
struct ts_point;
typedef Map<ConcreteParasiticNode*, int> ArnolidPtMap;
typedef Map<ParasiticNode*, int> ArnolidPtMap;
class ArnoldiReduce : public StaState
{
public:
ArnoldiReduce(StaState *sta);
~ArnoldiReduce();
Parasitic *reduceToArnoldi(Parasitic *parasitic,
const Pin *drvr_pin,
float coupling_cap_factor,
const RiseFall *rf,
const OperatingConditions *op_cond,
const Corner *corner,
const MinMax *cnst_min_max,
const ParasiticAnalysisPt *ap);
rcmodel *reduceToArnoldi(Parasitic *parasitic,
const Pin *drvr_pin,
float coupling_cap_factor,
const RiseFall *rf,
const Corner *corner,
const MinMax *cnst_min_max,
const ParasiticAnalysisPt *ap);
protected:
void loadWork();
@ -70,9 +69,8 @@ protected:
const Pin *drvr_pin_;
float coupling_cap_factor_;
const RiseFall *rf_;
const OperatingConditions *op_cond_;
const Corner *corner_;
const MinMax *cnst_min_max_;
const MinMax *min_max_;
const ParasiticAnalysisPt *ap_;
// ParasiticNode -> ts_point index.
ArnolidPtMap pt_map_;

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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
@ -20,7 +20,6 @@
#include "StringUtil.hh"
#include "UnitDelayCalc.hh"
#include "LumpedCapDelayCalc.hh"
#include "SlewDegradeDelayCalc.hh"
#include "DmpDelayCalc.hh"
#include "ArnoldiDelayCalc.hh"
@ -35,7 +34,6 @@ registerDelayCalcs()
{
registerDelayCalc("unit", makeUnitDelayCalc);
registerDelayCalc("lumped_cap", makeLumpedCapDelayCalc);
registerDelayCalc("slew_degrade", makeSlewDegradeDelayCalc);
registerDelayCalc("dmp_ceff_elmore", makeDmpCeffElmoreDelayCalc);
registerDelayCalc("dmp_ceff_two_pole", makeDmpCeffTwoPoleDelayCalc);
registerDelayCalc("arnoldi", makeArnoldiDelayCalc);

View File

@ -3,7 +3,7 @@
%{
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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
@ -19,6 +19,8 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Sta.hh"
#include "ArcDelayCalc.hh"
#include "dcalc/ArcDcalcWaveforms.hh"
%}
@ -59,4 +61,76 @@ report_delay_calc_cmd(Edge *edge,
return Sta::sta()->reportDelayCalc(edge, arc, corner, min_max, digits);
}
////////////////////////////////////////////////////////////////
Table1
ccs_input_waveform(const Pin *in_pin,
const RiseFall *in_rf,
const Corner *corner,
const MinMax *min_max)
{
cmdLinkedNetwork();
Sta *sta = Sta::sta();
ArcDcalcWaveforms *arc_dcalc = dynamic_cast<ArcDcalcWaveforms*>(sta->arcDelayCalc());
if (arc_dcalc)
return arc_dcalc->inputWaveform(in_pin, in_rf, corner, min_max);
else
return Table1();
}
Table1
ccs_driver_waveform(const Pin *in_pin,
const RiseFall *in_rf,
const Pin *drvr_pin,
const RiseFall *drvr_rf,
const Corner *corner,
const MinMax *min_max)
{
cmdLinkedNetwork();
Sta *sta = Sta::sta();
ArcDcalcWaveforms *arc_dcalc = dynamic_cast<ArcDcalcWaveforms*>(sta->arcDelayCalc());
if (arc_dcalc)
return arc_dcalc->drvrWaveform(in_pin, in_rf, drvr_pin, drvr_rf, corner, min_max);
else
return Table1();
}
Table1
ccs_driver_ramp_waveform(const Pin *in_pin,
const RiseFall *in_rf,
const Pin *drvr_pin,
const RiseFall *drvr_rf,
const Pin *load_pin,
const Corner *corner,
const MinMax *min_max)
{
cmdLinkedNetwork();
Sta *sta = Sta::sta();
ArcDcalcWaveforms *arc_dcalc = dynamic_cast<ArcDcalcWaveforms*>(sta->arcDelayCalc());
if (arc_dcalc)
return arc_dcalc->drvrRampWaveform(in_pin, in_rf, drvr_pin, drvr_rf,
load_pin, corner, min_max);
else
return Table1();
}
Table1
ccs_load_waveform(const Pin *in_pin,
const RiseFall *in_rf,
const Pin *drvr_pin,
const RiseFall *drvr_rf,
const Pin *load_pin,
const Corner *corner,
const MinMax *min_max)
{
cmdLinkedNetwork();
Sta *sta = Sta::sta();
ArcDcalcWaveforms *arc_dcalc = dynamic_cast<ArcDcalcWaveforms*>(sta->arcDelayCalc());
if (arc_dcalc)
return arc_dcalc->loadWaveform(in_pin, in_rf, drvr_pin, drvr_rf,
load_pin, corner, min_max);
else
return Table1();
}
%} // inline

View File

@ -1,5 +1,5 @@
# OpenSTA, Static Timing Analyzer
# Copyright (c) 2023, Parallax Software, Inc.
# Copyright (c) 2024, 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
@ -116,7 +116,7 @@ proc set_delay_calculator { alg } {
if { [is_delay_calc_name $alg] } {
set_delay_calculator_cmd $alg
} else {
sta_error 435 "delay calculator $alg not found."
sta_error 180 "delay calculator $alg not found."
}
}
@ -145,38 +145,38 @@ proc set_assigned_delay_cmd { cmd cmd_args } {
if [info exists keys(-from)] {
set from_pins [get_port_pins_error "from_pins" $keys(-from)]
} else {
sta_error 442 "$cmd missing -from argument."
sta_error 181 "$cmd missing -from argument."
}
if [info exists keys(-to)] {
set to_pins [get_port_pins_error "to_pins" $keys(-to)]
} else {
sta_error 443 "$cmd missing -to argument."
sta_error 182 "$cmd missing -to argument."
}
set delay [lindex $cmd_args 0]
if {![string is double $delay]} {
sta_error 444 "$cmd delay is not a float."
sta_error 183 "$cmd delay is not a float."
}
set delay [time_ui_sta $delay]
if {[info exists flags(-cell)] && [info exists flags(-net)]} {
sta_error 445 "set_annotated_delay -cell and -net options are mutually excluive."
sta_error 184 "set_annotated_delay -cell and -net options are mutually excluive."
} elseif {[info exists flags(-cell)]} {
if { $from_pins != {} } {
set inst [[lindex $from_pins 0] instance]
foreach pin $from_pins {
if {[$pin instance] != $inst} {
sta_error 446 "$cmd pin [get_full_name $pin] is not attached to instance [get_full_name $inst]."
sta_error 185 "$cmd pin [get_full_name $pin] is not attached to instance [get_full_name $inst]."
}
}
foreach pin $to_pins {
if {[$pin instance] != $inst} {
sta_error 447 "$cmd pin [get_full_name $pin] is not attached to instance [get_full_name $inst]"
sta_error 186 "$cmd pin [get_full_name $pin] is not attached to instance [get_full_name $inst]"
}
}
}
} elseif {![info exists flags(-net)]} {
sta_error 448 "$cmd -cell or -net required."
sta_error 187 "$cmd -cell or -net required."
}
foreach from_pin $from_pins {
set from_vertices [$from_pin vertices]
@ -240,7 +240,7 @@ proc set_assigned_check_cmd { cmd cmd_args } {
if { [info exists keys(-from)] } {
set from_pins [get_port_pins_error "from_pins" $keys(-from)]
} else {
sta_error 449 "$cmd missing -from argument."
sta_error 188 "$cmd missing -from argument."
}
set from_rf "rise_fall"
if { [info exists keys(-clock)] } {
@ -249,14 +249,14 @@ proc set_assigned_check_cmd { cmd cmd_args } {
|| $clk_arg eq "fall" } {
set from_rf $clk_arg
} else {
sta_error 450 "$cmd -clock must be rise or fall."
sta_error 189 "$cmd -clock must be rise or fall."
}
}
if { [info exists keys(-to)] } {
set to_pins [get_port_pins_error "to_pins" $keys(-to)]
} else {
sta_error 451 "$cmd missing -to argument."
sta_error 190 "$cmd missing -to argument."
}
set to_rf [parse_rise_fall_flags flags]
set corner [parse_corner keys]
@ -271,7 +271,7 @@ proc set_assigned_check_cmd { cmd cmd_args } {
} elseif { [info exists flags(-removal)] } {
set role "removal"
} else {
sta_error 452 "$cmd missing -setup|-hold|-recovery|-removal check type.."
sta_error 191 "$cmd missing -setup|-hold|-recovery|-removal check type.."
}
set cond ""
if { [info exists key(-cond)] } {
@ -279,7 +279,7 @@ proc set_assigned_check_cmd { cmd cmd_args } {
}
set check_value [lindex $cmd_args 0]
if { ![string is double $check_value] } {
sta_error 453 "$cmd check_value is not a float."
sta_error 192 "$cmd check_value is not a float."
}
set check_value [time_ui_sta $check_value]
@ -347,7 +347,7 @@ proc set_assigned_transition { args } {
set slew [lindex $args 0]
if {![string is double $slew]} {
sta_error 428 "set_assigned_transition transition is not a float."
sta_error 210 "set_assigned_transition transition is not a float."
}
set slew [time_ui_sta $slew]
set pins [get_port_pins_error "pins" [lindex $args 1]]

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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
@ -18,53 +18,85 @@
#include "Liberty.hh"
#include "TimingArc.hh"
#include "TimingModel.hh"
#include "TableModel.hh"
#include "Network.hh"
#include "Parasitics.hh"
#include "Sdc.hh"
#include "Corner.hh"
#include "DcalcAnalysisPt.hh"
namespace sta {
using std::log;
DelayCalcBase::DelayCalcBase(StaState *sta) :
ArcDelayCalc(sta)
{
}
void
DelayCalcBase::reduceParasitic(const Parasitic *parasitic_network,
const Net *net,
const Corner *corner,
const MinMaxAll *min_max)
{
NetConnectedPinIterator *pin_iter = network_->connectedPinIterator(net);
while (pin_iter->hasNext()) {
const Pin *pin = pin_iter->next();
if (network_->isDriver(pin)) {
for (RiseFall *rf : RiseFall::range()) {
for (const MinMax *min_max : min_max->range()) {
if (corner == nullptr) {
for (const Corner *corner1 : *corners_) {
DcalcAnalysisPt *dcalc_ap = corner1->findDcalcAnalysisPt(min_max);
reduceParasitic(parasitic_network, pin, rf, dcalc_ap);
}
}
else {
DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max);
reduceParasitic(parasitic_network, pin, rf, dcalc_ap);
}
}
}
}
}
delete pin_iter;
}
TimingModel *
DelayCalcBase::model(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const
{
const OperatingConditions *op_cond = dcalc_ap->operatingConditions();
const TimingArc *corner_arc = arc->cornerArc(dcalc_ap->libertyIndex());
return corner_arc->model(op_cond);
}
GateTimingModel *
DelayCalcBase::gateModel(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const
{
return dynamic_cast<GateTimingModel*>(model(arc, dcalc_ap));
}
GateTableModel *
DelayCalcBase::gateTableModel(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const
{
return dynamic_cast<GateTableModel*>(model(arc, dcalc_ap));
}
CheckTimingModel *
DelayCalcBase::checkModel(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const
{
return dynamic_cast<CheckTimingModel*>(model(arc, dcalc_ap));
}
void
DelayCalcBase::finishDrvrPin()
{
for (auto parasitic : unsaved_parasitics_)
parasitics_->deleteUnsavedParasitic(parasitic);
unsaved_parasitics_.clear();
for (auto drvr_pin : reduced_parasitic_drvrs_)
parasitics_->deleteDrvrReducedParasitics(drvr_pin);
reduced_parasitic_drvrs_.clear();
}
void
DelayCalcBase::inputPortDelay(const Pin *,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const DcalcAnalysisPt *)
{
drvr_cell_ = nullptr;
drvr_library_ = network_->defaultLibertyLibrary();
drvr_slew_ = in_slew;
drvr_rf_ = rf;
drvr_parasitic_ = parasitic;
input_port_ = true;
}
void
DelayCalcBase::gateDelayInit(const TimingArc *arc,
const Slew &in_slew,
const Parasitic *drvr_parasitic)
{
drvr_cell_ = arc->from()->libertyCell();
drvr_library_ = drvr_cell_->libertyLibrary();
drvr_rf_ = arc->toEdge()->asRiseFall();
drvr_slew_ = in_slew;
drvr_parasitic_ = drvr_parasitic;
input_port_ = false;
}
// For DSPF on an input port the elmore delay is used as the time
@ -73,40 +105,47 @@ DelayCalcBase::gateDelayInit(const TimingArc *arc,
// Note that this uses the driver thresholds and relies on
// thresholdAdjust to convert the delay and slew to the load's thresholds.
void
DelayCalcBase::dspfWireDelaySlew(const Pin *,
DelayCalcBase::dspfWireDelaySlew(const Pin *load_pin,
const RiseFall *rf,
Slew drvr_slew,
float elmore,
ArcDelay &wire_delay,
Slew &load_slew)
{
float vth = drvr_library_->inputThreshold(drvr_rf_);
float vl = drvr_library_->slewLowerThreshold(drvr_rf_);
float vh = drvr_library_->slewUpperThreshold(drvr_rf_);
float slew_derate = drvr_library_->slewDerateFromLibrary();
LibertyLibrary *load_library = thresholdLibrary(load_pin);
float vth = load_library->inputThreshold(rf);
float vl = load_library->slewLowerThreshold(rf);
float vh = load_library->slewUpperThreshold(rf);
float slew_derate = load_library->slewDerateFromLibrary();
wire_delay = -elmore * log(1.0 - vth);
load_slew = drvr_slew_ + elmore * log((1.0 - vl) / (1.0 - vh)) / slew_derate;
load_slew = drvr_slew + elmore * log((1.0 - vl) / (1.0 - vh)) / slew_derate;
load_slew = drvr_slew + elmore * log((1.0 - vl) / (1.0 - vh)) / slew_derate;
}
void
DelayCalcBase::thresholdAdjust(const Pin *load_pin,
const LibertyLibrary *drvr_library,
const RiseFall *rf,
ArcDelay &load_delay,
Slew &load_slew)
{
LibertyLibrary *load_library = thresholdLibrary(load_pin);
if (load_library
&& drvr_library_
&& load_library != drvr_library_) {
float drvr_vth = drvr_library_->outputThreshold(drvr_rf_);
float load_vth = load_library->inputThreshold(drvr_rf_);
float drvr_slew_delta = drvr_library_->slewUpperThreshold(drvr_rf_)
- drvr_library_->slewLowerThreshold(drvr_rf_);
&& drvr_library
&& load_library != drvr_library) {
float drvr_vth = drvr_library->outputThreshold(rf);
float load_vth = load_library->inputThreshold(rf);
float drvr_slew_delta = drvr_library->slewUpperThreshold(rf)
- drvr_library->slewLowerThreshold(rf);
float load_delay_delta =
delayAsFloat(load_slew) * ((load_vth - drvr_vth) / drvr_slew_delta);
load_delay += (drvr_rf_ == RiseFall::rise())
load_delay += (rf == RiseFall::rise())
? load_delay_delta
: -load_delay_delta;
float load_slew_delta = load_library->slewUpperThreshold(drvr_rf_)
- load_library->slewLowerThreshold(drvr_rf_);
float drvr_slew_derate = drvr_library_->slewDerateFromLibrary();
float load_slew_delta = load_library->slewUpperThreshold(rf)
- load_library->slewLowerThreshold(rf);
float drvr_slew_derate = drvr_library->slewDerateFromLibrary();
float load_slew_derate = load_library->slewDerateFromLibrary();
load_slew = load_slew * ((load_slew_delta / load_slew_derate)
/ (drvr_slew_delta / drvr_slew_derate));
@ -129,4 +168,55 @@ DelayCalcBase::thresholdLibrary(const Pin *load_pin)
}
}
ArcDelay
DelayCalcBase::checkDelay(const Pin *check_pin,
const TimingArc *arc,
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
const DcalcAnalysisPt *dcalc_ap)
{
CheckTimingModel *model = checkModel(arc, dcalc_ap);
if (model) {
float from_slew1 = delayAsFloat(from_slew);
float to_slew1 = delayAsFloat(to_slew);
return model->checkDelay(pinPvt(check_pin, dcalc_ap), from_slew1, to_slew1,
related_out_cap, pocv_enabled_);
}
else
return delay_zero;
}
string
DelayCalcBase::reportCheckDelay(const Pin *check_pin,
const TimingArc *arc,
const Slew &from_slew,
const char *from_slew_annotation,
const Slew &to_slew,
float related_out_cap,
const DcalcAnalysisPt *dcalc_ap,
int digits)
{
CheckTimingModel *model = checkModel(arc, dcalc_ap);
if (model) {
float from_slew1 = delayAsFloat(from_slew);
float to_slew1 = delayAsFloat(to_slew);
return model->reportCheckDelay(pinPvt(check_pin, dcalc_ap), from_slew1,
from_slew_annotation, to_slew1,
related_out_cap, false, digits);
}
return "";
}
const Pvt *
DelayCalcBase::pinPvt(const Pin *pin,
const DcalcAnalysisPt *dcalc_ap)
{
const Instance *drvr_inst = network_->instance(pin);
const Pvt *pvt = sdc_->pvt(drvr_inst, dcalc_ap->constraintMinMax());
if (pvt == nullptr)
pvt = dcalc_ap->operatingConditions();
return pvt;
}
} // namespace

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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
@ -20,44 +20,64 @@
namespace sta {
class GateTableModel;
class DelayCalcBase : public ArcDelayCalc
{
public:
explicit DelayCalcBase(StaState *sta);
void inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
void finishDrvrPin() override;
void reduceParasitic(const Parasitic *parasitic_network,
const Net *net,
const Corner *corner,
const MinMaxAll *min_max) override;
ArcDelay checkDelay(const Pin *check_pin,
const TimingArc *arc,
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
const DcalcAnalysisPt *dcalc_ap) override;
void finishDrvrPin() override;
string reportCheckDelay(const Pin *check_pin,
const TimingArc *arc,
const Slew &from_slew,
const char *from_slew_annotation,
const Slew &to_slew,
float related_out_cap,
const DcalcAnalysisPt *dcalc_ap,
int digits) override;
protected:
void gateDelayInit(const TimingArc *arc,
const Slew &in_slew,
const Parasitic *drvr_parasitic);
GateTimingModel *gateModel(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const;
GateTableModel *gateTableModel(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const;
CheckTimingModel *checkModel(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const;
TimingModel *model(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const;
// Find the liberty library to use for logic/slew thresholds.
LibertyLibrary *thresholdLibrary(const Pin *load_pin);
// Adjust load_delay and load_slew from driver thresholds to load thresholds.
void thresholdAdjust(const Pin *load_pin,
const LibertyLibrary *drvr_library,
const RiseFall *rf,
ArcDelay &load_delay,
Slew &load_slew);
// Helper function for input ports driving dspf parasitic.
void dspfWireDelaySlew(const Pin *load_pin,
float elmore,
const RiseFall *rf,
Slew drvr_slew,
float elmore,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew);
const Pvt *pinPvt(const Pin *pin,
const DcalcAnalysisPt *dcalc_ap);
Slew drvr_slew_;
const LibertyCell *drvr_cell_;
const LibertyLibrary *drvr_library_;
const Parasitic *drvr_parasitic_;
bool input_port_;
const RiseFall *drvr_rf_;
// Parasitics returned by findParasitic that are reduced or estimated
// that can be deleted after delay calculation for the driver pin
// is finished.
Vector<Parasitic*> unsaved_parasitics_;
Vector<const Pin *> reduced_parasitic_drvrs_;
using ArcDelayCalc::reduceParasitic;
};
} // namespace

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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
@ -34,45 +34,39 @@ class DmpCeffDelayCalc : public LumpedCapDelayCalc
public:
DmpCeffDelayCalc(StaState *sta);
virtual ~DmpCeffDelayCalc();
virtual void inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap);
virtual void gateDelay(const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// return values
ArcDelay &gate_delay,
Slew &drvr_slew);
virtual float ceff(const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap);
virtual string reportGateDelay(const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
int digits);
virtual void copyState(const StaState *sta);
ArcDcalcResult gateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
string reportGateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
int digits) override;
void copyState(const StaState *sta) override;
protected:
void gateDelaySlew(double &delay,
virtual void loadDelaySlew(const Pin *load_pin,
double drvr_slew,
const RiseFall *rf,
const LibertyLibrary *drvr_library,
const Parasitic *parasitic,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew) = 0;
void gateDelaySlew(// Return values.
double &delay,
double &slew);
void loadDelaySlew(const Pin *load_pin,
double elmore,
ArcDelay &delay,
Slew &slew);
void loadDelaySlewElmore(const Pin *load_pin,
double elmore,
ArcDelay &delay,
Slew &slew);
// Select the appropriate special case Dartu/Menezes/Pileggi algorithm.
void setCeffAlgorithm(const LibertyLibrary *library,
const LibertyCell *cell,
@ -80,7 +74,6 @@ protected:
const GateTableModel *gate_model,
const RiseFall *rf,
double in_slew,
float related_out_cap,
double c2,
double rpi,
double c1);

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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
@ -19,12 +19,13 @@
#include "TableModel.hh"
#include "TimingArc.hh"
#include "Liberty.hh"
#include "PortDirection.hh"
#include "Network.hh"
#include "Sdc.hh"
#include "Parasitics.hh"
#include "DcalcAnalysisPt.hh"
#include "GraphDelayCalc.hh"
#include "DmpCeff.hh"
#include "Network.hh"
namespace sta {
@ -35,9 +36,22 @@ class DmpCeffElmoreDelayCalc : public DmpCeffDelayCalc
public:
DmpCeffElmoreDelayCalc(StaState *sta);
ArcDelayCalc *copy() override;
void loadDelay(const Pin *load_pin,
ArcDelay &wire_delay,
Slew &load_slew) override;
ArcDcalcResult inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
protected:
void loadDelaySlew(const Pin *load_pin,
double drvr_slew,
const RiseFall *rf,
const LibertyLibrary *drvr_library,
const Parasitic *parasitic,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew) override;
};
ArcDelayCalc *
@ -57,26 +71,54 @@ DmpCeffElmoreDelayCalc::copy()
return new DmpCeffElmoreDelayCalc(this);
}
void
DmpCeffElmoreDelayCalc::loadDelay(const Pin *load_pin,
ArcDelay &wire_delay,
Slew &load_slew)
ArcDcalcResult
DmpCeffElmoreDelayCalc::inputPortDelay(const Pin *,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
{
ArcDelay wire_delay1 = 0.0;
Slew load_slew1 = drvr_slew_;
ArcDcalcResult dcalc_result(load_pin_index_map.size());
LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
for (auto load_pin_index : load_pin_index_map) {
const Pin *load_pin = load_pin_index.first;
size_t load_idx = load_pin_index.second;
ArcDelay wire_delay = 0.0;
Slew load_slew = in_slew;
bool elmore_exists = false;
float elmore = 0.0;
if (parasitic)
parasitics_->findElmore(parasitic, load_pin, elmore, elmore_exists);
if (elmore_exists)
// Input port with no external driver.
dspfWireDelaySlew(load_pin, rf, in_slew, elmore, wire_delay, load_slew);
thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew);
dcalc_result.setWireDelay(load_idx, wire_delay);
dcalc_result.setLoadSlew(load_idx, load_slew);
}
return dcalc_result;
}
void
DmpCeffElmoreDelayCalc::loadDelaySlew(const Pin *load_pin,
double drvr_slew,
const RiseFall *rf,
const LibertyLibrary *drvr_library,
const Parasitic *parasitic,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew)
{
wire_delay = 0.0;
load_slew = drvr_slew;
bool elmore_exists = false;
float elmore = 0.0;
if (drvr_parasitic_)
parasitics_->findElmore(drvr_parasitic_, load_pin, elmore, elmore_exists);
if (elmore_exists) {
if (input_port_)
dspfWireDelaySlew(load_pin, elmore, wire_delay1, load_slew1);
else
loadDelaySlew(load_pin, elmore, wire_delay1, load_slew1);
}
thresholdAdjust(load_pin, wire_delay1, load_slew1);
wire_delay = wire_delay1;
load_slew = load_slew1 * multi_drvr_slew_factor_;
if (parasitic)
parasitics_->findElmore(parasitic, load_pin, elmore, elmore_exists);
if (elmore_exists)
loadDelaySlewElmore(load_pin, elmore, wire_delay, load_slew);
thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew);
}
////////////////////////////////////////////////////////////////
@ -91,28 +133,31 @@ public:
Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
ReducedParasiticType reducedParasiticType() const override;
void inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap) override;
void gateDelay(const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew) override;
void loadDelay(const Pin *load_pin,
ArcDelay &wire_delay,
Slew &load_slew) override;
ArcDcalcResult inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
ArcDcalcResult gateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
private:
void loadDelay(Parasitic *pole_residue,
void loadDelaySlew(const Pin *load_pin,
double drvr_slew,
const RiseFall *rf,
const LibertyLibrary *drvr_library,
const Parasitic *parasitic,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew) override;
void loadDelay(double drvr_slew,
Parasitic *pole_residue,
double p1,
double k1,
ArcDelay &wire_delay,
@ -164,104 +209,117 @@ DmpCeffTwoPoleDelayCalc::findParasitic(const Pin *drvr_pin,
{
Parasitic *parasitic = nullptr;
const Corner *corner = dcalc_ap->corner();
// set_load net has precidence over parasitics.
if (!sdc_->drvrPinHasWireCap(drvr_pin, corner)) {
const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
if (parasitics_->haveParasitics()) {
// Prefer PiPoleResidue.
parasitic = parasitics_->findPiPoleResidue(drvr_pin, rf, parasitic_ap);
if (parasitic == nullptr) {
parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap);
if (parasitic == nullptr) {
Parasitic *parasitic_network =
parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap);
if (parasitic_network) {
parasitics_->reduceToPiPoleResidue2(parasitic_network, drvr_pin,
dcalc_ap->operatingConditions(),
corner,
dcalc_ap->constraintMinMax(),
parasitic_ap);
parasitic = parasitics_->findPiPoleResidue(drvr_pin, rf, parasitic_ap);
reduced_parasitic_drvrs_.push_back(drvr_pin);
}
}
}
}
else {
const MinMax *cnst_min_max = dcalc_ap->constraintMinMax();
Wireload *wireload = sdc_->wireload(cnst_min_max);
if (wireload) {
float pin_cap, wire_cap, fanout;
bool has_wire_cap;
graph_delay_calc_->netCaps(drvr_pin, rf, dcalc_ap,
pin_cap, wire_cap, fanout, has_wire_cap);
parasitic = parasitics_->estimatePiElmore(drvr_pin, rf, wireload,
fanout, pin_cap,
dcalc_ap->operatingConditions(),
corner,
cnst_min_max,
parasitic_ap);
// Estimated parasitics are not recorded in the "database", so
// save it for deletion after the drvr pin delay calc is finished.
if (parasitic)
unsaved_parasitics_.push_back(parasitic);
}
}
// set_load net has precedence over parasitics.
if (sdc_->drvrPinHasWireCap(drvr_pin, corner)
|| network_->direction(drvr_pin)->isInternal())
return nullptr;
const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
// Prefer PiPoleResidue.
parasitic = parasitics_->findPiPoleResidue(drvr_pin, rf, parasitic_ap);
if (parasitic)
return parasitic;
parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap);
if (parasitic)
return parasitic;
Parasitic *parasitic_network =
parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap);
if (parasitic_network) {
parasitic = parasitics_->reduceToPiPoleResidue2(parasitic_network, drvr_pin, rf,
corner,
dcalc_ap->constraintMinMax(),
parasitic_ap);
if (parasitic)
return parasitic;
}
const MinMax *cnst_min_max = dcalc_ap->constraintMinMax();
Wireload *wireload = sdc_->wireload(cnst_min_max);
if (wireload) {
float pin_cap, wire_cap, fanout;
bool has_wire_cap;
graph_delay_calc_->netCaps(drvr_pin, rf, dcalc_ap, pin_cap, wire_cap,
fanout, has_wire_cap);
parasitic = parasitics_->estimatePiElmore(drvr_pin, rf, wireload,
fanout, pin_cap, corner,
cnst_min_max);
}
return parasitic;
}
ReducedParasiticType
DmpCeffTwoPoleDelayCalc::reducedParasiticType() const
ArcDcalcResult
DmpCeffTwoPoleDelayCalc::inputPortDelay(const Pin *,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
{
return ReducedParasiticType::pi_pole_residue2;
ArcDcalcResult dcalc_result(load_pin_index_map.size());
ArcDelay wire_delay = 0.0;
Slew load_slew = in_slew;
LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
for (auto load_pin_index : load_pin_index_map) {
const Pin *load_pin = load_pin_index.first;
size_t load_idx = load_pin_index.second;
if (parasitics_->isPiPoleResidue(parasitic)) {
const Parasitic *pole_residue = parasitics_->findPoleResidue(parasitic, load_pin);
if (pole_residue) {
size_t pole_count = parasitics_->poleResidueCount(pole_residue);
if (pole_count >= 1) {
ComplexFloat pole1, residue1;
// Find the 1st (elmore) pole.
parasitics_->poleResidue(pole_residue, 0, pole1, residue1);
if (pole1.imag() == 0.0
&& residue1.imag() == 0.0) {
float p1 = pole1.real();
float elmore = 1.0F / p1;
dspfWireDelaySlew(load_pin, rf, in_slew, elmore, wire_delay, load_slew);
thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew);
}
}
}
}
dcalc_result.setWireDelay(load_idx, wire_delay);
dcalc_result.setLoadSlew(load_idx, load_slew);
}
return dcalc_result;
}
ArcDcalcResult
DmpCeffTwoPoleDelayCalc::gateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
{
const LibertyLibrary *drvr_library = arc->to()->libertyLibrary();
const RiseFall *rf = arc->toEdge()->asRiseFall();
vth_ = drvr_library->outputThreshold(rf);
vl_ = drvr_library->slewLowerThreshold(rf);
vh_ = drvr_library->slewUpperThreshold(rf);
slew_derate_ = drvr_library->slewDerateFromLibrary();
return DmpCeffDelayCalc::gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic,
load_pin_index_map, dcalc_ap) ;
}
void
DmpCeffTwoPoleDelayCalc::inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap)
DmpCeffTwoPoleDelayCalc::loadDelaySlew(const Pin *load_pin,
double drvr_slew,
const RiseFall *rf,
const LibertyLibrary *drvr_library,
const Parasitic *parasitic,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew)
{
parasitic_is_pole_residue_ = parasitics_->isPiPoleResidue(parasitic);
DmpCeffDelayCalc::inputPortDelay(port_pin, in_slew, rf, parasitic, dcalc_ap);
}
void
DmpCeffTwoPoleDelayCalc::gateDelay(const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew)
{
gateDelayInit(arc, in_slew, drvr_parasitic);
parasitic_is_pole_residue_ = parasitics_->isPiPoleResidue(drvr_parasitic);
vth_ = drvr_library_->outputThreshold(drvr_rf_);
vl_ = drvr_library_->slewLowerThreshold(drvr_rf_);
vh_ = drvr_library_->slewUpperThreshold(drvr_rf_);
slew_derate_ = drvr_library_->slewDerateFromLibrary();
DmpCeffDelayCalc::gateDelay(arc, in_slew, load_cap, drvr_parasitic,
related_out_cap, pvt, dcalc_ap,
gate_delay, drvr_slew);
}
void
DmpCeffTwoPoleDelayCalc::loadDelay(const Pin *load_pin,
ArcDelay &wire_delay,
Slew &load_slew)
{
// Should handle PiElmore parasitic.
ArcDelay wire_delay1 = 0.0;
Slew load_slew1 = drvr_slew_;
wire_delay = 0.0;
load_slew = drvr_slew;
Parasitic *pole_residue = 0;
if (parasitic_is_pole_residue_)
pole_residue = parasitics_->findPoleResidue(drvr_parasitic_, load_pin);
pole_residue = parasitics_->findPoleResidue(parasitic, load_pin);
if (pole_residue) {
size_t pole_count = parasitics_->poleResidueCount(pole_residue);
if (pole_count >= 1) {
@ -272,37 +330,31 @@ DmpCeffTwoPoleDelayCalc::loadDelay(const Pin *load_pin,
&& residue1.imag() == 0.0) {
float p1 = pole1.real();
float k1 = residue1.real();
if (input_port_) {
float elmore = 1.0F / p1;
// Input port with no external driver.
dspfWireDelaySlew(load_pin, elmore, wire_delay1, load_slew1);
}
else {
if (pole_count >= 2)
loadDelay(pole_residue, p1, k1, wire_delay1, load_slew1);
else {
float elmore = 1.0F / p1;
wire_delay1 = elmore;
load_slew1 = drvr_slew_;
}
}
if (pole_count >= 2)
loadDelay(drvr_slew, pole_residue, p1, k1, wire_delay, load_slew);
else {
float elmore = 1.0F / p1;
wire_delay = elmore;
load_slew = drvr_slew;
}
}
}
}
thresholdAdjust(load_pin, wire_delay1, load_slew1);
wire_delay = wire_delay1;
load_slew = load_slew1 * multi_drvr_slew_factor_;
thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew);
}
void
DmpCeffTwoPoleDelayCalc::loadDelay(Parasitic *pole_residue,
double p1, double k1,
ArcDelay &wire_delay,
DmpCeffTwoPoleDelayCalc::loadDelay(double drvr_slew,
Parasitic *pole_residue,
double p1,
double k1,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew)
{
ComplexFloat pole2, residue2;
parasitics_->poleResidue(pole_residue, 1, pole2, residue2);
if (!delayZero(drvr_slew_)
if (!delayZero(drvr_slew)
&& pole2.imag() == 0.0
&& residue2.imag() == 0.0) {
double p2 = pole2.real();
@ -311,7 +363,7 @@ DmpCeffTwoPoleDelayCalc::loadDelay(Parasitic *pole_residue,
double k2_p2_2 = k2 / (p2 * p2);
double B = k1_p1_2 + k2_p2_2;
// Convert tt to 0:1 range.
float tt = delayAsFloat(drvr_slew_) * slew_derate_ / (vh_ - vl_);
float tt = delayAsFloat(drvr_slew) * slew_derate_ / (vh_ - vl_);
double y_tt = (tt - B + k1_p1_2 * exp(-p1 * tt)
+ k2_p2_2 * exp(-p2 * tt)) / tt;
wire_delay = loadDelay(vth_, p1, p2, k1, k2, B, k1_p1_2, k2_p2_2, tt, y_tt)

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

106
dcalc/FindRoot.cc Normal file
View File

@ -0,0 +1,106 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, 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/>.
#include "FindRoot.hh"
#include <algorithm> // abs
namespace sta {
using std::abs;
double
findRoot(FindRootFunc func,
double x1,
double x2,
double x_tol,
int max_iter,
// Return value.
bool &fail)
{
double y1, y2, dy1;
func(x1, y1, dy1);
func(x2, y2, dy1);
return findRoot(func, x1, y1, x2, y2, x_tol, max_iter, fail);
}
double
findRoot(FindRootFunc func,
double x1,
double y1,
double x2,
double y2,
double x_tol,
int max_iter,
// Return value.
bool &fail)
{
if ((y1 > 0.0 && y2 > 0.0) || (y1 < 0.0 && y2 < 0.0)) {
// Initial bounds do not surround a root.
fail = true;
return 0.0;
}
if (y1 == 0.0) {
fail = false;
return x1;
}
if (y2 == 0.0) {
fail = false;
return x2;
}
if (y1 > 0.0)
// Swap x1/x2 so func(x1) < 0.
std::swap(x1, x2);
double root = (x1 + x2) * 0.5;
double dx_prev = abs(x2 - x1);
double dx = dx_prev;
double y, dy;
func(root, y, dy);
for (int iter = 0; iter < max_iter; iter++) {
// Newton/raphson out of range.
if ((((root - x2) * dy - y) * ((root - x1) * dy - y) > 0.0)
// Not decreasing fast enough.
|| (abs(2.0 * y) > abs(dx_prev * dy))) {
// Bisect x1/x2 interval.
dx_prev = dx;
dx = (x2 - x1) * 0.5;
root = x1 + dx;
}
else {
dx_prev = dx;
dx = y / dy;
root -= dx;
}
if (abs(dx) <= x_tol * abs(root)) {
// Converged.
fail = false;
return root;
}
func(root, y, dy);
if (y < 0.0)
x1 = root;
else
x2 = root;
}
fail = true;
return root;
}
} // namespace

View File

@ -16,12 +16,33 @@
#pragma once
#include <functional>
namespace sta {
class ArcDelayCalc;
class StaState;
typedef const std::function<void (double x,
// Return values.
double &y,
double &dy)> FindRootFunc;
ArcDelayCalc *
makeSlewDegradeDelayCalc(StaState *sta);
double
findRoot(FindRootFunc func,
double x1,
double x2,
double x_tol,
int max_iter,
// Return value.
bool &fail);
double
findRoot(FindRootFunc func,
double x1,
double y1,
double x2,
double y2,
double x_tol,
int max_iter,
// Return value.
bool &fail);
} // namespace

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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
@ -23,6 +23,7 @@
#include "TimingArc.hh"
#include "TimingModel.hh"
#include "Liberty.hh"
#include "PortDirection.hh"
#include "Network.hh"
#include "Sdc.hh"
#include "Parasitics.hh"
@ -57,176 +58,131 @@ LumpedCapDelayCalc::findParasitic(const Pin *drvr_pin,
{
Parasitic *parasitic = nullptr;
const Corner *corner = dcalc_ap->corner();
// set_load net has precidence over parasitics.
if (!sdc_->drvrPinHasWireCap(drvr_pin, corner)) {
const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
if (parasitics_->haveParasitics()) {
// Prefer PiElmore.
parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap);
if (parasitic == nullptr) {
Parasitic *parasitic_network =
parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap);
if (parasitic_network) {
parasitics_->reduceToPiElmore(parasitic_network, drvr_pin,
dcalc_ap->operatingConditions(),
corner,
dcalc_ap->constraintMinMax(),
parasitic_ap);
parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap);
reduced_parasitic_drvrs_.push_back(drvr_pin);
}
}
}
else {
const MinMax *cnst_min_max = dcalc_ap->constraintMinMax();
Wireload *wireload = sdc_->wireload(cnst_min_max);
if (wireload) {
float pin_cap, wire_cap, fanout;
bool has_net_load;
graph_delay_calc_->netCaps(drvr_pin, rf, dcalc_ap,
pin_cap, wire_cap, fanout, has_net_load);
parasitic = parasitics_->estimatePiElmore(drvr_pin, rf, wireload,
fanout, pin_cap,
dcalc_ap->operatingConditions(),
corner,
cnst_min_max,
parasitic_ap);
// Estimated parasitics are not recorded in the "database", so save
// it for deletion after the drvr pin delay calc is finished.
if (parasitic)
unsaved_parasitics_.push_back(parasitic);
}
}
// set_load net has precedence over parasitics.
if (sdc_->drvrPinHasWireCap(drvr_pin, corner)
|| network_->direction(drvr_pin)->isInternal())
return nullptr;
const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
// Prefer PiElmore.
parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap);
if (parasitic)
return parasitic;
Parasitic *parasitic_network = parasitics_->findParasiticNetwork(drvr_pin,
parasitic_ap);
if (parasitic_network) {
parasitic = reduceParasitic(parasitic_network, drvr_pin, rf, dcalc_ap);
if (parasitic)
return parasitic;
}
const MinMax *min_max = dcalc_ap->constraintMinMax();
Wireload *wireload = sdc_->wireload(min_max);
if (wireload) {
float pin_cap, wire_cap, fanout;
bool has_net_load;
graph_delay_calc_->netCaps(drvr_pin, rf, dcalc_ap,
pin_cap, wire_cap, fanout, has_net_load);
parasitic = parasitics_->estimatePiElmore(drvr_pin, rf, wireload, fanout,
pin_cap, corner, min_max);
}
return parasitic;
}
ReducedParasiticType
LumpedCapDelayCalc::reducedParasiticType() const
Parasitic *
LumpedCapDelayCalc::reduceParasitic(const Parasitic *parasitic_network,
const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap)
{
return ReducedParasiticType::pi_elmore;
const Corner *corner = dcalc_ap->corner();
const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
return parasitics_->reduceToPiElmore(parasitic_network, drvr_pin, rf,
corner, dcalc_ap->constraintMinMax(),
parasitic_ap);
}
float
LumpedCapDelayCalc::ceff(const TimingArc *,
const Slew &,
float load_cap,
const Parasitic *,
float,
const Pvt *,
const DcalcAnalysisPt *)
ArcDcalcResult
LumpedCapDelayCalc::inputPortDelay(const Pin *,
float in_slew,
const RiseFall *rf,
const Parasitic *,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
{
return load_cap;
const LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
return makeResult(drvr_library,rf, 0.0, in_slew, load_pin_index_map);
}
void
LumpedCapDelayCalc::gateDelay(const TimingArc *arc,
ArcDcalcResult
LumpedCapDelayCalc::gateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew)
const Parasitic *,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
{
gateDelayInit(arc, in_slew, drvr_parasitic);
GateTimingModel *model = gateModel(arc, dcalc_ap);
debugPrint(debug_, "delay_calc", 3,
" in_slew = %s load_cap = %s related_load_cap = %s lumped",
" in_slew = %s load_cap = %s lumped",
delayAsString(in_slew, this),
units()->capacitanceUnit()->asString(load_cap),
units()->capacitanceUnit()->asString(related_out_cap));
units()->capacitanceUnit()->asString(load_cap));
const RiseFall *rf = arc->toEdge()->asRiseFall();
const LibertyLibrary *drvr_library = arc->to()->libertyLibrary();
if (model) {
ArcDelay gate_delay1;
Slew drvr_slew1;
ArcDelay gate_delay;
Slew drvr_slew;
float in_slew1 = delayAsFloat(in_slew);
// NaNs cause seg faults during table lookup.
if (isnan(load_cap) || isnan(related_out_cap) || isnan(delayAsFloat(in_slew)))
report_->error(710, "gate delay input variable is NaN");
model->gateDelay(pvt, in_slew1, load_cap, related_out_cap,
pocv_enabled_, gate_delay1, drvr_slew1);
gate_delay = gate_delay1;
drvr_slew = drvr_slew1;
drvr_slew_ = drvr_slew1;
}
else {
gate_delay = delay_zero;
drvr_slew = delay_zero;
drvr_slew_ = 0.0;
if (isnan(load_cap) || isnan(delayAsFloat(in_slew)))
report_->error(1350, "gate delay input variable is NaN");
model->gateDelay(pinPvt(drvr_pin, dcalc_ap), in_slew1, load_cap, pocv_enabled_,
gate_delay, drvr_slew);
return makeResult(drvr_library, rf, gate_delay, drvr_slew, load_pin_index_map);
}
else
return makeResult(drvr_library, rf, delay_zero, delay_zero, load_pin_index_map);
}
void
LumpedCapDelayCalc::loadDelay(const Pin *load_pin,
ArcDelay &wire_delay,
Slew &load_slew)
ArcDcalcResult
LumpedCapDelayCalc::makeResult(const LibertyLibrary *drvr_library,
const RiseFall *rf,
ArcDelay gate_delay,
Slew drvr_slew,
const LoadPinIndexMap &load_pin_index_map)
{
Delay wire_delay1 = 0.0;
Slew load_slew1 = drvr_slew_ * multi_drvr_slew_factor_;
thresholdAdjust(load_pin, wire_delay1, load_slew1);
wire_delay = wire_delay1;
load_slew = load_slew1;
ArcDcalcResult dcalc_result(load_pin_index_map.size());
dcalc_result.setGateDelay(gate_delay);
dcalc_result.setDrvrSlew(drvr_slew);
for (auto load_pin_index : load_pin_index_map) {
const Pin *load_pin = load_pin_index.first;
size_t load_idx = load_pin_index.second;
ArcDelay wire_delay = 0.0;
thresholdAdjust(load_pin, drvr_library, rf, wire_delay, drvr_slew);
dcalc_result.setWireDelay(load_idx, wire_delay);
dcalc_result.setLoadSlew(load_idx, drvr_slew);
}
return dcalc_result;
}
string
LumpedCapDelayCalc::reportGateDelay(const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
int digits)
LumpedCapDelayCalc::reportGateDelay(const Pin *check_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *,
const LoadPinIndexMap &,
const DcalcAnalysisPt *dcalc_ap,
int digits)
{
GateTimingModel *model = gateModel(arc, dcalc_ap);
if (model) {
float in_slew1 = delayAsFloat(in_slew);
return model->reportGateDelay(pvt, in_slew1, load_cap, related_out_cap,
return model->reportGateDelay(pinPvt(check_pin, dcalc_ap), in_slew1, load_cap,
false, digits);
}
return "";
}
void
LumpedCapDelayCalc::checkDelay(const TimingArc *arc,
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &margin)
{
CheckTimingModel *model = checkModel(arc, dcalc_ap);
if (model) {
float from_slew1 = delayAsFloat(from_slew);
float to_slew1 = delayAsFloat(to_slew);
model->checkDelay(pvt, from_slew1, to_slew1, related_out_cap, pocv_enabled_, margin);
}
else
margin = delay_zero;
}
string
LumpedCapDelayCalc::reportCheckDelay(const TimingArc *arc,
const Slew &from_slew,
const char *from_slew_annotation,
const Slew &to_slew,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
int digits)
{
CheckTimingModel *model = checkModel(arc, dcalc_ap);
if (model) {
float from_slew1 = delayAsFloat(from_slew);
float to_slew1 = delayAsFloat(to_slew);
return model->reportCheckDelay(pvt, from_slew1, from_slew_annotation,
to_slew1, related_out_cap, false, digits);
}
return "";
}
} // namespace

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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
@ -30,54 +30,40 @@ public:
Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
ReducedParasiticType reducedParasiticType() const override;
void gateDelay(const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew) override;
float ceff(const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap) override;
void loadDelay(const Pin *load_pin,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew) override;
void checkDelay(const TimingArc *arc,
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &margin) override;
string reportGateDelay(const TimingArc *arc,
Parasitic *reduceParasitic(const Parasitic *parasitic_network,
const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
ArcDcalcResult inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
ArcDcalcResult gateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
string reportGateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
int digits) override;
string reportCheckDelay(const TimingArc *arc,
const Slew &from_slew,
const char *from_slew_annotation,
const Slew &to_slew,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
int digits) override;
protected:
ArcDcalcResult makeResult(const LibertyLibrary *drvr_library,
const RiseFall *rf,
ArcDelay gate_delay,
Slew drvr_slew,
const LoadPinIndexMap &load_pin_index_map);
using ArcDelayCalc::reduceParasitic;
};
ArcDelayCalc *

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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
@ -31,141 +31,81 @@ ParallelDelayCalc::ParallelDelayCalc(StaState *sta):
{
}
void
ParallelDelayCalc::inputPortDelay(const Pin *drvr_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap)
ArcDcalcResultSeq
ParallelDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args,
float load_cap,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
{
DelayCalcBase::inputPortDelay(drvr_pin, in_slew, rf, parasitic, dcalc_ap);
multi_drvr_slew_factor_ = 1.0;
}
void
ParallelDelayCalc::gateDelayInit(const TimingArc *arc,
const Slew &in_slew,
const Parasitic *drvr_parasitic)
{
DelayCalcBase::gateDelayInit(arc, in_slew, drvr_parasitic);
multi_drvr_slew_factor_ = 1.0F;
}
void
ParallelDelayCalc::findParallelGateDelays(const MultiDrvrNet *multi_drvr,
GraphDelayCalc *dcalc)
{
int count = RiseFall::index_count * corners_->dcalcAnalysisPtCount();
parallel_delays_.resize(count);
parallel_slews_.resize(count);
for (auto dcalc_ap : corners_->dcalcAnalysisPts()) {
for (auto drvr_rf : RiseFall::range()) {
DcalcAPIndex ap_index = dcalc_ap->index();
int drvr_rf_index = drvr_rf->index();
int index = ap_index * RiseFall::index_count + drvr_rf_index;
findMultiDrvrGateDelay(multi_drvr, drvr_rf, dcalc_ap, dcalc,
parallel_delays_[index],
parallel_slews_[index]);
}
if (dcalc_args.size() == 1) {
ArcDcalcArg &dcalc_arg = dcalc_args[0];
ArcDcalcResult dcalc_result = gateDelay(dcalc_arg.drvrPin(), dcalc_arg.arc(),
dcalc_arg.inSlew(),
load_cap, dcalc_arg.parasitic(),
load_pin_index_map, dcalc_ap);
ArcDcalcResultSeq dcalc_results;
dcalc_results.push_back(dcalc_result);
return dcalc_results;
}
return gateDelaysParallel(dcalc_args, load_cap, load_pin_index_map, dcalc_ap);
}
void
ParallelDelayCalc::findMultiDrvrGateDelay(const MultiDrvrNet *multi_drvr,
const RiseFall *drvr_rf,
const DcalcAnalysisPt *dcalc_ap,
GraphDelayCalc *dcalc,
// Return values.
ArcDelay &parallel_delay,
Slew &parallel_slew)
ArcDcalcResultSeq
ParallelDelayCalc::gateDelaysParallel(ArcDcalcArgSeq &dcalc_args,
float load_cap,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
{
ArcDelay delay_sum = 0.0;
size_t drvr_count = dcalc_args.size();
ArcDcalcResultSeq dcalc_results(drvr_count);
Slew slew_sum = 0.0;
for (Vertex *drvr_vertex : *multi_drvr->drvrs()) {
Pin *drvr_pin = drvr_vertex->pin();
Instance *drvr_inst = network_->instance(drvr_pin);
const Pvt *pvt = sdc_->pvt(drvr_inst, dcalc_ap->constraintMinMax());
if (pvt == nullptr)
pvt = dcalc_ap->operatingConditions();
VertexInEdgeIterator edge_iter(drvr_vertex, graph_);
while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next();
TimingArcSet *arc_set = edge->timingArcSet();
const LibertyPort *related_out_port = arc_set->relatedOut();
for (TimingArc *arc : arc_set->arcs()) {
RiseFall *arc_rf = arc->toEdge()->asRiseFall();
if (arc_rf == drvr_rf) {
Vertex *from_vertex = edge->from(graph_);
RiseFall *from_rf = arc->fromEdge()->asRiseFall();
Slew from_slew = dcalc->edgeFromSlew(from_vertex, from_rf,
edge, dcalc_ap);
ArcDelay intrinsic_delay;
Slew intrinsic_slew;
gateDelay(arc, from_slew, 0.0, 0, 0.0, pvt, dcalc_ap,
intrinsic_delay, intrinsic_slew);
Parasitic *parasitic = findParasitic(drvr_pin, drvr_rf, dcalc_ap);
const Pin *related_out_pin = 0;
float related_out_cap = 0.0;
if (related_out_port) {
Instance *inst = network_->instance(drvr_pin);
related_out_pin = network_->findPin(inst, related_out_port);
if (related_out_pin) {
Parasitic *related_out_parasitic = findParasitic(related_out_pin,
drvr_rf,
dcalc_ap);
related_out_cap = dcalc->loadCap(related_out_pin,
related_out_parasitic,
drvr_rf, dcalc_ap);
}
}
float load_cap = dcalc->loadCap(drvr_pin, parasitic,
drvr_rf, dcalc_ap);
ArcDelay gate_delay;
Slew gate_slew;
gateDelay(arc, from_slew, load_cap, parasitic,
related_out_cap, pvt, dcalc_ap,
gate_delay, gate_slew);
delay_sum += 1.0F / (gate_delay - intrinsic_delay);
slew_sum += 1.0F / gate_slew;
}
}
ArcDelay load_delay_sum = 0.0;
vector<ArcDelay> intrinsic_delays(dcalc_args.size());
vector<ArcDelay> load_delays(dcalc_args.size());
for (size_t drvr_idx = 0; drvr_idx < drvr_count; drvr_idx++) {
ArcDcalcArg &dcalc_arg = dcalc_args[drvr_idx];
ArcDcalcResult &dcalc_result = dcalc_results[drvr_idx];
const Pin *drvr_pin = dcalc_arg.drvrPin();
const TimingArc *arc = dcalc_arg.arc();
Slew in_slew = dcalc_arg.inSlew();
ArcDcalcResult intrinsic_result = gateDelay(drvr_pin, arc, in_slew, 0.0, nullptr,
load_pin_index_map, dcalc_ap);
ArcDelay intrinsic_delay = intrinsic_result.gateDelay();
intrinsic_delays[drvr_idx] = intrinsic_result.gateDelay();
ArcDcalcResult gate_result = gateDelay(drvr_pin, arc, in_slew, load_cap,
dcalc_arg.parasitic(),
load_pin_index_map, dcalc_ap);
ArcDelay gate_delay = gate_result.gateDelay();
Slew drvr_slew = gate_result.drvrSlew();
ArcDelay load_delay = gate_delay - intrinsic_delay;
load_delays[drvr_idx] = load_delay;
if (!delayZero(load_delay))
load_delay_sum += 1.0 / load_delay;
if (!delayZero(drvr_slew))
slew_sum += 1.0 / drvr_slew;
dcalc_result.setLoadCount(load_pin_index_map.size());
for (auto load_pin_index : load_pin_index_map) {
size_t load_idx = load_pin_index.second;
dcalc_result.setWireDelay(load_idx, gate_result.wireDelay(load_idx));
dcalc_result.setLoadSlew(load_idx, gate_result.loadSlew(load_idx));
}
}
parallel_delay = 1.0F / delay_sum;
parallel_slew = 1.0F / slew_sum;
}
void
ParallelDelayCalc::parallelGateDelay(const Pin *,
const TimingArc *arc,
const Slew &from_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &gate_delay,
Slew &gate_slew)
{
ArcDelay intrinsic_delay;
Slew intrinsic_slew;
gateDelay(arc, from_slew, 0.0, 0, 0.0, pvt, dcalc_ap,
intrinsic_delay, intrinsic_slew);
const RiseFall *drvr_rf = arc->toEdge()->asRiseFall();
int index = dcalc_ap->index() * RiseFall::index_count + drvr_rf->index();
ArcDelay parallel_delay = parallel_delays_[index];
Slew parallel_slew = parallel_slews_[index];
gate_delay = parallel_delay + intrinsic_delay;
gate_slew = parallel_slew;
ArcDelay gate_load_delay = delayZero(load_delay_sum)
? delay_zero
: 1.0 / load_delay_sum;
ArcDelay drvr_slew = delayZero(slew_sum) ? delay_zero : 1.0 / slew_sum;
Delay gate_delay1;
Slew gate_slew1;
gateDelay(arc, from_slew, load_cap, drvr_parasitic,
related_out_cap, pvt, dcalc_ap,
gate_delay1, gate_slew1);
float factor = delayRatio(gate_slew, gate_slew1);
multi_drvr_slew_factor_ = factor;
for (size_t drvr_idx = 0; drvr_idx < drvr_count; drvr_idx++) {
ArcDcalcResult &dcalc_result = dcalc_results[drvr_idx];
dcalc_result.setGateDelay(intrinsic_delays[drvr_idx] + gate_load_delay);
dcalc_result.setDrvrSlew(drvr_slew);
}
return dcalc_results;
}
} // namespace

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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
@ -17,52 +17,26 @@
#pragma once
#include <vector>
#include <map>
#include "DelayCalcBase.hh"
namespace sta {
// Delay calculation for parallel gates based on using parallel drive resistance.
// Delay calculation for parallel gates using parallel drive resistance.
class ParallelDelayCalc : public DelayCalcBase
{
public:
explicit ParallelDelayCalc(StaState *sta);
void inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap) override;
void gateDelayInit(const TimingArc *arc,
const Slew &in_slew,
const Parasitic *drvr_parasitic);
void findParallelGateDelays(const MultiDrvrNet *multi_drvr,
GraphDelayCalc *dcalc) override;
void parallelGateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &from_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &gate_delay,
Slew &gate_slew) override;
ParallelDelayCalc(StaState *sta);
ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &dcalc_args,
float load_cap,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
protected:
void findMultiDrvrGateDelay(const MultiDrvrNet *multi_drvr,
const RiseFall *drvr_rf,
const DcalcAnalysisPt *dcalc_ap,
GraphDelayCalc *dcalc,
// Return values.
ArcDelay &parallel_delay,
Slew &parallel_slew);
// [drvr_rf->index][dcalc_ap->index]
vector<ArcDelay> parallel_delays_;
// [drvr_rf->index][dcalc_ap->index]
vector<Slew> parallel_slews_;
float multi_drvr_slew_factor_;
ArcDcalcResultSeq gateDelaysParallel(ArcDcalcArgSeq &dcalc_args,
float load_cap,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap);
};
} // namespace

View File

@ -1,141 +0,0 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, 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/>.
#include "SlewDegradeDelayCalc.hh"
#include "TimingArc.hh"
#include "Liberty.hh"
#include "Network.hh"
#include "Sdc.hh"
#include "Parasitics.hh"
#include "DcalcAnalysisPt.hh"
#include "LumpedCapDelayCalc.hh"
namespace sta {
// Liberty table model lumped capacitance arc delay calculator.
// Effective capacitance is the pi model total capacitance (C1+C2).
// Wire delays are elmore delays.
// Driver slews are degraded to loads by rise/fall transition_degradation
// tables.
class SlewDegradeDelayCalc : public LumpedCapDelayCalc
{
public:
SlewDegradeDelayCalc(StaState *sta);
ArcDelayCalc *copy() override;
void inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap) override;
void gateDelay(const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew) override;
void loadDelay(const Pin *load_pin,
ArcDelay &wire_delay,
Slew &load_slew) override;
using LumpedCapDelayCalc::gateDelay;
using LumpedCapDelayCalc::reportGateDelay;
private:
const Pvt *pvt_;
};
ArcDelayCalc *
makeSlewDegradeDelayCalc(StaState *sta)
{
return new SlewDegradeDelayCalc(sta);
}
SlewDegradeDelayCalc::SlewDegradeDelayCalc(StaState *sta) :
LumpedCapDelayCalc(sta)
{
}
ArcDelayCalc *
SlewDegradeDelayCalc::copy()
{
return new SlewDegradeDelayCalc(this);
}
void
SlewDegradeDelayCalc::inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap)
{
pvt_ = dcalc_ap->operatingConditions();
LumpedCapDelayCalc::inputPortDelay(port_pin, in_slew, rf, parasitic, dcalc_ap);
}
void
SlewDegradeDelayCalc::gateDelay(const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew)
{
input_port_ = false;
drvr_parasitic_ = drvr_parasitic;
drvr_rf_ = arc->toEdge()->asRiseFall();
drvr_cell_ = arc->from()->libertyCell();
drvr_library_ = drvr_cell_->libertyLibrary();
pvt_ = pvt;
LumpedCapDelayCalc::gateDelay(arc, in_slew, load_cap, drvr_parasitic,
related_out_cap, pvt, dcalc_ap,
gate_delay, drvr_slew);
}
void
SlewDegradeDelayCalc::loadDelay(const Pin *load_pin,
ArcDelay &wire_delay,
Slew &load_slew)
{
ArcDelay wire_delay1 = 0.0;
Slew load_slew1 = drvr_slew_;
bool elmore_exists = false;
float elmore = 0.0;
if (drvr_parasitic_)
parasitics_->findElmore(drvr_parasitic_, load_pin, elmore, elmore_exists);
if (elmore_exists) {
if (drvr_library_ && drvr_library_->wireSlewDegradationTable(drvr_rf_)) {
wire_delay1 = elmore;
load_slew1 = drvr_library_->degradeWireSlew(drvr_rf_,
delayAsFloat(drvr_slew_),
delayAsFloat(wire_delay1));
}
dspfWireDelaySlew(load_pin, elmore, wire_delay1, load_slew1);
}
thresholdAdjust(load_pin, wire_delay1, load_slew1);
wire_delay = wire_delay1;
load_slew = load_slew1 * multi_drvr_slew_factor_;
}
} // namespace

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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
@ -45,86 +45,82 @@ UnitDelayCalc::findParasitic(const Pin *,
return nullptr;
}
ReducedParasiticType
UnitDelayCalc::reducedParasiticType() const
Parasitic *
UnitDelayCalc::reduceParasitic(const Parasitic *,
const Pin *,
const RiseFall *,
const DcalcAnalysisPt *)
{
return ReducedParasiticType::none;
return nullptr;
}
void
UnitDelayCalc::reduceParasitic(const Parasitic *,
const Net *,
const Corner *,
const MinMaxAll *)
{
}
ArcDcalcResult
UnitDelayCalc::inputPortDelay(const Pin *,
float,
const RiseFall *,
const Parasitic *,
const DcalcAnalysisPt *)
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
{
return unitDelayResult(load_pin_index_map);
}
void
UnitDelayCalc::gateDelay(const TimingArc *,
ArcDcalcResult
UnitDelayCalc::gateDelay(const Pin *,
const TimingArc *,
const Slew &,
float,
const Parasitic *,
float,
const Pvt *, const DcalcAnalysisPt *,
// Return values.
ArcDelay &gate_delay, Slew &drvr_slew)
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
{
gate_delay = units_->timeUnit()->scale();
drvr_slew = 0.0;
return unitDelayResult(load_pin_index_map);
}
void
UnitDelayCalc::findParallelGateDelays(const MultiDrvrNet *,
GraphDelayCalc *)
ArcDcalcResultSeq
UnitDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args,
float,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
{
size_t drvr_count = dcalc_args.size();
ArcDcalcResultSeq dcalc_results(drvr_count);
for (size_t drvr_idx = 0; drvr_idx < drvr_count; drvr_idx++) {
ArcDcalcResult &dcalc_result = dcalc_results[drvr_idx];
dcalc_result = unitDelayResult(load_pin_index_map);
}
return dcalc_results;
}
void
UnitDelayCalc::parallelGateDelay(const Pin *,
const TimingArc *,
const Slew &,
float,
const Parasitic *,
float,
const Pvt *,
const DcalcAnalysisPt *,
// Return values.
ArcDelay &gate_delay,
Slew &gate_slew)
ArcDcalcResult
UnitDelayCalc::unitDelayResult(const LoadPinIndexMap &load_pin_index_map)
{
gate_delay = units_->timeUnit()->scale();
gate_slew = 0.0;
}
void
UnitDelayCalc::loadDelay(const Pin *,
ArcDelay &wire_delay,
Slew &load_slew)
{
wire_delay = 0.0;
load_slew = 0.0;
}
float
UnitDelayCalc::ceff(const TimingArc *,
const Slew &,
float,
const Parasitic *,
float,
const Pvt *,
const DcalcAnalysisPt *)
{
return 0.0;
size_t load_count = load_pin_index_map.size();
ArcDcalcResult dcalc_result(load_count);
dcalc_result.setGateDelay(units_->timeUnit()->scale());
dcalc_result.setDrvrSlew(0.0);
for (size_t load_idx = 0; load_idx < load_count; load_idx++) {
dcalc_result.setWireDelay(load_idx, 0.0);
dcalc_result.setLoadSlew(load_idx, 0.0);
}
return dcalc_result;
}
string
UnitDelayCalc::reportGateDelay(const TimingArc *,
UnitDelayCalc::reportGateDelay(const Pin *,
const TimingArc *,
const Slew &,
float,
const Parasitic *,
float,
const Pvt *,
const LoadPinIndexMap &,
const DcalcAnalysisPt *,
int)
{
@ -133,26 +129,24 @@ UnitDelayCalc::reportGateDelay(const TimingArc *,
return result;
}
void
UnitDelayCalc::checkDelay(const TimingArc *,
ArcDelay
UnitDelayCalc::checkDelay(const Pin *,
const TimingArc *,
const Slew &,
const Slew &,
float,
const Pvt *,
const DcalcAnalysisPt *,
// Return values.
ArcDelay &margin)
const DcalcAnalysisPt *)
{
margin = units_->timeUnit()->scale();
return units_->timeUnit()->scale();
}
string
UnitDelayCalc::reportCheckDelay(const TimingArc *,
UnitDelayCalc::reportCheckDelay(const Pin *,
const TimingArc *,
const Slew &,
const char *,
const Slew &,
float,
const Pvt *,
const DcalcAnalysisPt *,
int)
{

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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
@ -29,72 +29,58 @@ public:
Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
ReducedParasiticType reducedParasiticType() const override;
void inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
Parasitic *reduceParasitic(const Parasitic *parasitic_network,
const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
void reduceParasitic(const Parasitic *parasitic_network,
const Net *net,
const Corner *corner,
const MinMaxAll *min_max) override;
ArcDcalcResult inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
ArcDcalcResult gateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
// Pass in load_cap or parasitic.
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &args,
float load_cap,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
ArcDelay checkDelay(const Pin *check_pin,
const TimingArc *arc,
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
const DcalcAnalysisPt *dcalc_ap) override;
void gateDelay(const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew) override;
void findParallelGateDelays(const MultiDrvrNet *multi_drvr,
GraphDelayCalc *dcalc) override;
// Retrieve the delay and slew for one parallel gate.
void parallelGateDelay(const Pin *drvr_pin,
string reportGateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &from_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &gate_delay,
Slew &gate_slew) override;
void loadDelay(const Pin *load_pin,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew) override;
float ceff(const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap) override;
void checkDelay(const TimingArc *arc,
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &margin) override;
string reportGateDelay(const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
int digits) override;
string reportCheckDelay(const TimingArc *arc,
string reportCheckDelay(const Pin *check_pin,
const TimingArc *arc,
const Slew &from_slew,
const char *from_slew_annotation,
const Slew &to_slew,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
int digits) override;
void finishDrvrPin() override;
void finishDrvrPin() override;
protected:
ArcDcalcResult unitDelayResult(const LoadPinIndexMap &load_pin_index_map);
};
ArcDelayCalc *

View File

@ -1,5 +1,5 @@
# OpenSTA, Static Timing Analyzer
# Copyright (c) 2023, Parallax Software, Inc.
# Copyright (c) 2024, 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

52
doc/CLA.txt Normal file
View File

@ -0,0 +1,52 @@
Parallax Software maintains a responsible open source policy and
promotes good practices in intellectual property management. Please
read this Agreement carefully. By submitting your Contributions (see
definition below) and clicking ["Sign in with GitHub to agree"], you
agree to all of the terms and conditions defined herein.
Parallax Software, Inc. appreciates your willingness to grant
permission to use your software code checked directly into a source
control system that is available by GitHub Inc ("Contributions") in
conjunction with OpenSTA. By clicking ["Sign in with GitHub to
agree"], you hereby grant to Parallax Software and to recipients of
software distributed with OpenSTA a perpetual, worldwide,
non-exclusive, no-charge, royalty-free, irrevocable license to use,
make, have made, offer to sell, sell, import, reproduce, prepare
derivative works of, publicly display, publicly perform, sublicense,
and distribute your present and future Contributions and such
derivative works as part of OpenSTA.
Nothing in this license shall constitute a copyright transfer or in
any other way infringe your rights to use your own Contributions for
any other purpose. This license is for your protection as a
Contributor as well as the protection of OpenSTA and its users.
1. You represent and warrant that you are the sole owner of the
Contributions and/or have sufficient rights in your Contribution to
grant all rights you grant hereunder.
2. You represent that the Contributions are your original works of
authorship, that you created the Contributions and did not copy them
from another source, and no other person claims, or has the right to
claim, any right in any invention or patent related to the
Contributions.
3. You represent that you are legally entitled to grant the above
license. If your employer has rights to intellectual property that you
create, you represent that you have received permission to make the
Contributions on behalf of that employer, or that your employer has
waived such rights for the Contributions.
4. Finally, it means that you have not entered into any agreements
that would prevent you from granting the rights provided in this
Agreement.
5. You understand that the decision to include the Contribution in any
product or source repository is entirely that of Parallax Software and
this Agreement does not guarantee that the Contributions will be
included in any product, technology or services.
If you become aware of any facts or circumstances related to the
representation above that would make these representations inaccurate
or untrue, you agree to notify Parallax Software promptly with any
details.

View File

@ -3,6 +3,19 @@ OpenSTA Timing Analyzer Release Notes
This file summarizes user visible changes for each release.
Release 2.5.0 2024/01/17
-------------------------
The report_net -connections, -verbose and -hier_pins flags are deprecated.
The report_instance -connections and -verbose flags are deprecated.
The options are now enabled in all cases.
The read_spef parasitic reduction arguments have changed. The
-reduce_to and -delete_after_reduce arguments are deprecated and
replaced with the -reduce flag. With the -reduce flag, the current
delay calculator reduces the parastic network to the appropriate type
and deletes the parasitic network.
Release 2.4.0 2023/01/19
-------------------------

Binary file not shown.

Binary file not shown.

View File

@ -1,5 +1,5 @@
# OpenSTA, Static Timing Analyzer
# Copyright (c) 2023, Parallax Software, Inc.
# Copyright (c) 2024, 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

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
exec tclsh $0 ${1+"$@"}
# OpenSTA, Static Timing Analyzer
# Copyright (c) 2023, Parallax Software, Inc.
# Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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
@ -200,7 +200,7 @@ delayAsFloat(const Delay &delay,
else if (early_late == EarlyLate::late())
return delay.mean() + delay.sigma() * sta->sigmaFactor();
else
sta->report()->critical(594, "unknown early/late value.");
sta->report()->critical(1020, "unknown early/late value.");
}
return delay.mean();
}

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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
@ -375,7 +375,7 @@ delayAsFloat(const Delay &delay,
else if (early_late == EarlyLate::late())
return delay.mean() + delay.sigma(early_late) * sta->sigmaFactor();
else
sta->report()->critical(595, "unknown early/late value.");
sta->report()->critical(1030, "unknown early/late value.");
}
return delay.mean();
}

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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
@ -106,7 +106,7 @@ public:
int &bidirect_count,
int &load_count,
const Network *network);
virtual void operator()(Pin *pin);
virtual void operator()(const Pin *pin);
protected:
Pin *drvr_pin_;
@ -133,7 +133,7 @@ FindNetDrvrLoadCounts::FindNetDrvrLoadCounts(Pin *drvr_pin,
}
void
FindNetDrvrLoadCounts::operator()(Pin *pin)
FindNetDrvrLoadCounts::operator()(const Pin *pin)
{
if (network_->isDriver(pin)) {
if (pin != drvr_pin_)
@ -790,7 +790,7 @@ Graph::arcDelayAnnotated(const Edge *edge,
if (arc_delay_annotated_.size()) {
size_t index = (edge->arcDelays() + arc->index()) * ap_count_ + ap_index;
if (index >= arc_delay_annotated_.size())
report_->critical(208, "arc_delay_annotated array bounds exceeded");
report_->critical(1080, "arc_delay_annotated array bounds exceeded");
return arc_delay_annotated_[index];
}
else
@ -805,7 +805,7 @@ Graph::setArcDelayAnnotated(Edge *edge,
{
size_t index = (edge->arcDelays() + arc->index()) * ap_count_ + ap_index;
if (index >= arc_delay_annotated_.size())
report_->critical(209, "arc_delay_annotated array bounds exceeded");
report_->critical(1081, "arc_delay_annotated array bounds exceeded");
arc_delay_annotated_[index] = annotated;
}
@ -817,7 +817,7 @@ Graph::wireDelayAnnotated(Edge *edge,
size_t index = (edge->arcDelays() + TimingArcSet::wireArcIndex(rf)) * ap_count_
+ ap_index;
if (index >= arc_delay_annotated_.size())
report_->critical(210, "arc_delay_annotated array bounds exceeded");
report_->critical(1082, "arc_delay_annotated array bounds exceeded");
return arc_delay_annotated_[index];
}
@ -830,7 +830,7 @@ Graph::setWireDelayAnnotated(Edge *edge,
size_t index = (edge->arcDelays() + TimingArcSet::wireArcIndex(rf)) * ap_count_
+ ap_index;
if (index >= arc_delay_annotated_.size())
report_->critical(228, "arc_delay_annotated array bounds exceeded");
report_->critical(1083, "arc_delay_annotated array bounds exceeded");
arc_delay_annotated_[index] = annotated;
}

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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
@ -18,10 +18,14 @@
#include <string>
#include <vector>
#include <map>
#include "MinMax.hh"
#include "LibertyClass.hh"
#include "TimingArc.hh"
#include "TableModel.hh"
#include "NetworkClass.hh"
#include "GraphClass.hh"
#include "Delay.hh"
#include "ParasiticsClass.hh"
#include "StaState.hh"
@ -30,18 +34,77 @@ namespace sta {
using std::string;
using std::vector;
using std::map;
class Corner;
class Parasitic;
class DcalcAnalysisPt;
class MultiDrvrNet;
// Driver load pin -> index in driver loads.
typedef map<const Pin *, size_t, PinIdLess> LoadPinIndexMap;
// Arguments for gate delay calculation delay/slew at one driver pin
// through one timing arc at one delay calc analysis point.
class ArcDcalcArg
{
public:
ArcDcalcArg();
ArcDcalcArg(const Pin *drvr_pin,
Edge *edge,
const TimingArc *arc,
const Slew in_slew,
const Parasitic *parasitic);
const Pin *drvrPin() const { return drvr_pin_; }
Edge *edge() const { return edge_; }
const TimingArc *arc() const { return arc_; }
Slew inSlew() const { return in_slew_; }
const Parasitic *parasitic() { return parasitic_; }
void setParasitic(const Parasitic *parasitic);
protected:
const Pin *drvr_pin_;
Edge *edge_;
const TimingArc *arc_;
Slew in_slew_;
const Parasitic *parasitic_;
};
// Arc delay calc result.
class ArcDcalcResult
{
public:
ArcDcalcResult();
ArcDcalcResult(size_t load_count);
void setLoadCount(size_t load_count);
ArcDelay &gateDelay() { return gate_delay_; }
void setGateDelay(ArcDelay gate_delay);
Slew &drvrSlew() { return drvr_slew_; }
void setDrvrSlew(Slew drvr_slew);
ArcDelay wireDelay(size_t load_idx) const;
void setWireDelay(size_t load_idx,
ArcDelay wire_delay);
Slew loadSlew(size_t load_idx) const;
void setLoadSlew(size_t load_idx,
Slew load_slew);
protected:
ArcDelay gate_delay_;
Slew drvr_slew_;
// Load wire delay and slews indexed by load pin index.
vector<ArcDelay> wire_delays_;
vector<Slew> load_slews_;
};
typedef vector<ArcDcalcArg> ArcDcalcArgSeq;
typedef vector<ArcDcalcResult> ArcDcalcResultSeq;
// Delay calculator class hierarchy.
// ArcDelayCalc
// UnitDelayCalc
// DelayCalcBase
// ParallelDelayCalc
// LumpedCapDelayCalc
// SlewDegradeDelayCalc
// DmpCeffDelayCalc
// DmpCeffElmoreDelayCalc
// DmpCeffTwoPoleDelayCalc
@ -61,95 +124,80 @@ public:
virtual Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) = 0;
virtual ReducedParasiticType reducedParasiticType() const = 0;
// Reduce parasitic_network to a representation acceptable to the delay calculator.
virtual Parasitic *reduceParasitic(const Parasitic *parasitic_network,
const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) = 0;
// Reduce parasitic_network to a representation acceptable to the delay calculator
// for one or more corners and min/max rise/fall.
// Null corner means reduce all corners.
virtual void reduceParasitic(const Parasitic *parasitic_network,
const Net *net,
const Corner *corner,
const MinMaxAll *min_max) = 0;
// Find the wire delays and slews for an input port without a driving cell.
// This call primarily initializes the load delay/slew iterator.
virtual void inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap) = 0;
virtual ArcDcalcResult inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) = 0;
// Find the delay and slew for arc driving drvr_pin.
virtual ArcDcalcResult gateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
// Pass in load_cap or parasitic.
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) = 0;
virtual void gateDelay(const TimingArc *arc,
const Slew &in_slew,
// Pass in load_cap or drvr_parasitic.
float load_cap,
const Parasitic *drvr_parasitic,
const Parasitic *parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew) = 0;
Slew &drvr_slew) __attribute__ ((deprecated));
// Find gate delays and slews for parallel gates.
virtual void findParallelGateDelays(const MultiDrvrNet *multi_drvr,
GraphDelayCalc *dcalc) = 0;
// Retrieve the delay and slew for one parallel gate.
virtual void parallelGateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &from_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &gate_delay,
Slew &gate_slew) = 0;
// Find the wire delay and load slew of a load pin.
// Called after inputPortDelay or gateDelay.
virtual void loadDelay(const Pin *load_pin,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew) = 0;
// Ceff for parasitics with pi models.
virtual float ceff(const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap) = 0;
virtual ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &args,
float load_cap,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) = 0;
// Find the delay for a timing check arc given the arc's
// from/clock, to/data slews and related output pin parasitic.
virtual void checkDelay(const TimingArc *arc,
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &margin) = 0;
virtual ArcDelay checkDelay(const Pin *check_pin,
const TimingArc *arc,
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
const DcalcAnalysisPt *dcalc_ap) = 0;
// Report delay and slew calculation.
virtual string reportGateDelay(const TimingArc *arc,
virtual string reportGateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
// Pass in load_cap or drvr_parasitic.
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
int digits) = 0;
// Report timing check delay calculation.
virtual string reportCheckDelay(const TimingArc *arc,
virtual string reportCheckDelay(const Pin *check_pin,
const TimingArc *arc,
const Slew &from_slew,
const char *from_slew_annotation,
const Slew &to_slew,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
int digits) = 0;
virtual void finishDrvrPin() = 0;
protected:
GateTimingModel *gateModel(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const;
CheckTimingModel *checkModel(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const;
TimingModel *model(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const;
};
} // namespace

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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
@ -55,8 +55,7 @@ public:
void operatingConditionsChanged();
// Make one parasitic analysis points.
void makeParasiticAnalysisPts(bool per_corner,
bool per_min_max);
void makeParasiticAnalysisPts(bool per_corner);
int parasiticAnalysisPtCount() const;
ParasiticAnalysisPtSeq &parasiticAnalysisPts();
@ -114,7 +113,7 @@ public:
protected:
void setParasiticAnalysisPtcount(int ap_count);
void setParasiticAP(ParasiticAnalysisPt *path_ap,
int ap_index);
int mm_index);
void setDcalcAnalysisPtcount(DcalcAPIndex ap_count);
void addDcalcAP(DcalcAnalysisPt *dcalc_ap);
void addPathAP(PathAnalysisPt *path_ap);

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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
@ -17,6 +17,7 @@
#pragma once
#include <vector>
#include <mutex>
#include "Map.hh"
#include "NetworkClass.hh"
@ -25,10 +26,12 @@
#include "DcalcAnalysisPt.hh"
#include "StaState.hh"
#include "Delay.hh"
#include "ArcDelayCalc.hh"
namespace sta {
using std::vector;
using std::map;
class DelayCalcObserver;
class MultiDrvrNet;
@ -69,43 +72,32 @@ public:
// delays to be recomputed during incremental delay calculation.
virtual float incrementalDelayTolerance();
virtual void setIncrementalDelayTolerance(float tol);
// Load pin_cap + wire_cap.
virtual float loadCap(const Pin *drvr_pin,
const RiseFall *drvr_rf,
const DcalcAnalysisPt *dcalc_ap) const;
// Load pin_cap + wire_cap including parasitic min/max for rise/fall.
virtual float loadCap(const Pin *drvr_pin,
const DcalcAnalysisPt *dcalc_ap) const;
// pin_cap = net pin capacitances + port external pin capacitance,
// wire_cap = annotated net capacitance + port external wire capacitance.
virtual void loadCap(const Pin *drvr_pin,
const Parasitic *drvr_parasitic,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
float &pin_cap,
float &wire_cap) const;
// Load pin_cap + wire_cap including parasitic.
virtual float loadCap(const Pin *drvr_pin,
const Parasitic *drvr_parasitic,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) const;
float loadCap(const Pin *drvr_pin,
const Parasitic *drvr_parasitic,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
const MultiDrvrNet *multi_drvr) const;
virtual void netCaps(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
float &pin_cap,
float &wire_cap,
float &fanout,
bool &has_set_load) const;
float ceff(Edge *edge,
TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap);
const DcalcAnalysisPt *dcalc_ap) const;
float loadCap(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) const;
void loadCap(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
float &pin_cap,
float &wire_cap) const;
void netCaps(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
float &pin_cap,
float &wire_cap,
float &fanout,
bool &has_set_load) const;
LoadPinIndexMap makeLoadPinIndexMap(Vertex *drvr_vertex);
void findDriverArcDelays(Vertex *drvr_vertex,
Edge *edge,
const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap,
ArcDelayCalc *arc_delay_calc);
// Precedence:
// SDF annotation
// Liberty library
@ -170,18 +162,38 @@ protected:
const DcalcAnalysisPt *dcalc_ap);
bool findDriverDelays(Vertex *drvr_vertex,
ArcDelayCalc *arc_delay_calc);
MultiDrvrNet *multiDrvrNet(const Vertex *drvr_vertex) const;
MultiDrvrNet *findMultiDrvrNet(Vertex *drvr_pin);
MultiDrvrNet *makeMultiDrvrNet(PinSet &drvr_pins);
MultiDrvrNet *makeMultiDrvrNet(Vertex *drvr_vertex);
bool hasMultiDrvrs(Vertex *drvr_vertex);
Vertex *firstLoad(Vertex *drvr_vertex);
bool findDriverDelays1(Vertex *drvr_vertex,
MultiDrvrNet *multi_drvr,
ArcDelayCalc *arc_delay_calc);
void initLoadSlews(Vertex *drvr_vertex);
bool findDriverEdgeDelays(const Instance *drvr_inst,
const Pin *drvr_pin,
Vertex *drvr_vertex,
bool findDriverEdgeDelays(Vertex *drvr_vertex,
const MultiDrvrNet *multi_drvr,
Edge *edge,
ArcDelayCalc *arc_delay_calc);
bool findDriverArcDelays(Vertex *drvr_vertex,
const MultiDrvrNet *multi_drvr,
Edge *edge,
const TimingArc *arc,
LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
ArcDelayCalc *arc_delay_calc);
ArcDcalcArgSeq makeArcDcalcArgs(Vertex *drvr_vertex,
const MultiDrvrNet *multi_drvr,
Edge *edge,
const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap,
ArcDelayCalc *arc_delay_calc);
void findParallelEdge(Vertex *vertex,
Edge *drvr_edge,
const TimingArc *drvr_arc,
// Return values.
Edge *&edge,
const TimingArc *&arc);
void initWireDelays(Vertex *drvr_vertex);
void initRootSlews(Vertex *vertex);
void zeroSlewAndWireDelays(Vertex *drvr_vertex);
@ -189,23 +201,24 @@ protected:
ArcDelayCalc *arc_delay_calc,
bool propagate);
void enqueueTimingChecksEdges(Vertex *vertex);
bool findArcDelay(const Pin *drvr_pin,
Vertex *drvr_vertex,
const TimingArc *arc,
const Parasitic *drvr_parasitic,
float related_out_cap,
Vertex *from_vertex,
Edge *edge,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
const MultiDrvrNet *multi_drvr,
ArcDelayCalc *arc_delay_calc);
bool annotateDelaysSlews(Edge *edge,
const TimingArc *arc,
ArcDcalcResult &dcalc_result,
LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap);
bool annotateDelaySlew(Edge *edge,
const TimingArc *arc,
ArcDelay &gate_delay,
Slew &gate_slew,
const DcalcAnalysisPt *dcalc_ap);
void annotateLoadDelays(Vertex *drvr_vertex,
const RiseFall *drvr_rf,
const ArcDelay &extra_delay,
bool merge,
const DcalcAnalysisPt *dcalc_ap,
ArcDelayCalc *arc_delay_calc);
const RiseFall *drvr_rf,
ArcDcalcResult &dcalc_result,
LoadPinIndexMap &load_pin_index_map,
const ArcDelay &extra_delay,
bool merge,
const DcalcAnalysisPt *dcalc_ap);
void findLatchEdgeDelays(Edge *edge);
void findCheckEdgeDelays(Edge *edge,
ArcDelayCalc *arc_delay_calc);
@ -214,12 +227,36 @@ protected:
const RiseFall *from_rf,
const DcalcAnalysisPt *dcalc_ap);
bool bidirectDrvrSlewFromLoad(const Vertex *vertex) const;
MultiDrvrNet *multiDrvrNet(const Vertex *drvr_vertex) const;
void loadCap(const Parasitic *drvr_parasitic,
bool has_set_load,
// Return values.
float &pin_cap,
float &wire_cap) const;
float loadCap(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
ArcDelayCalc *arc_delay_calc) const;
void parasiticLoad(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
const MultiDrvrNet *multi_drvr,
ArcDelayCalc *arc_delay_calc,
// Return values.
float &cap,
const Parasitic *&parasitic) const;
void parasiticLoad(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
const MultiDrvrNet *multi_drvr,
ArcDelayCalc *arc_delay_calc,
// Return values.
float &pin_cap,
float &wire_cap,
const Parasitic *&parasitic) const;
void netCaps(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
const MultiDrvrNet *multi_drvr,
// Return values.
float &pin_cap,
float &wire_cap,
float &fanout,
bool &has_net_load) const;
// Observer for edge delay changes.
DelayCalcObserver *observer_;
@ -239,7 +276,7 @@ protected:
SearchPred *clk_pred_;
BfsFwdIterator *iter_;
MultiDrvrNetMap multi_drvr_net_map_;
bool multi_drvr_nets_found_;
std::mutex multi_drvr_lock_;
// Percentage (0.0:1.0) change in delay that causes downstream
// delays to be recomputed during incremental delay calculation.
float incremental_delay_tolerance_;
@ -264,10 +301,9 @@ public:
class MultiDrvrNet
{
public:
MultiDrvrNet(VertexSet *drvrs);
~MultiDrvrNet();
const VertexSet *drvrs() const { return drvrs_; }
VertexSet *drvrs() { return drvrs_; }
MultiDrvrNet();
VertexSeq &drvrs() { return drvrs_; }
const VertexSeq &drvrs() const { return drvrs_; }
bool parallelGates(const Network *network) const;
Vertex *dcalcDrvr() const { return dcalc_drvr_; }
void setDcalcDrvr(Vertex *drvr);
@ -283,7 +319,7 @@ public:
private:
// Driver that triggers delay calculation for all the drivers on the net.
Vertex *dcalc_drvr_;
VertexSet *drvrs_;
VertexSeq drvrs_;
// [drvr_rf->index][dcalc_ap->index]
vector<NetCaps> net_caps_;
};

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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
@ -319,6 +319,7 @@ public:
DriverWaveform *findDriverWaveform(const char *name);
DriverWaveform *driverWaveformDefault() { return driver_waveform_default_; }
void addDriverWaveform(DriverWaveform *driver_waveform);
void ensureVoltageWaveforms();
protected:
float degradeWireSlew(const TableModel *model,
@ -370,6 +371,7 @@ protected:
DriverWaveformMap driver_waveform_map_;
// Unnamed driver waveform.
DriverWaveform *driver_waveform_default_;
bool have_voltage_waveforms_;
static constexpr float input_threshold_default_ = .5;
static constexpr float output_threshold_default_ = .5;

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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
@ -29,7 +29,6 @@ public:
void gateDelay(const Pvt *pvt,
float in_slew,
float load_cap,
float related_out_cap,
bool pocv_enabled,
// Return values.
ArcDelay &gate_delay,
@ -37,7 +36,6 @@ public:
string reportGateDelay(const Pvt *pvt,
float in_slew,
float load_cap,
float related_out_cap,
bool pocv_enabled,
int digits) const override;
float driveResistance(const Pvt *pvt) const override;
@ -54,13 +52,11 @@ class CheckLinearModel : public CheckTimingModel
public:
explicit CheckLinearModel(LibertyCell *cell,
float intrinsic);
void checkDelay(const Pvt *pvt,
float from_slew,
float to_slew,
float related_out_cap,
bool pocv_enabled,
// Return values.
ArcDelay &margin) const override;
ArcDelay checkDelay(const Pvt *pvt,
float from_slew,
float to_slew,
float related_out_cap,
bool pocv_enabled) const override;
string reportCheckDelay(const Pvt *pvt,
float from_slew,
const char *from_slew_annotation,

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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

View File

@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
// Copyright (c) 2024, 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
@ -238,6 +238,7 @@ public:
// the other primitives.
LeafInstanceIterator *leafInstanceIterator() const;
LeafInstanceIterator *leafInstanceIterator(const Instance *hier_inst) const;
InstanceSeq leafInstances();
// Iterate over the children of an instance.
virtual InstanceChildIterator *
childIterator(const Instance *instance) const = 0;

Some files were not shown because too many files have changed in this diff Show More