Merge remote-tracking branch 'upstream/master' into update
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
This commit is contained in:
commit
d61313d8ad
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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++) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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]]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
776
dcalc/DmpCeff.cc
776
dcalc/DmpCeff.cc
File diff suppressed because it is too large
Load Diff
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 *
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ¶llel_delay,
|
||||
Slew ¶llel_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
|
||||
|
|
|
|||
|
|
@ -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 ¶llel_delay,
|
||||
Slew ¶llel_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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 *
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
-------------------------
|
||||
|
||||
|
|
|
|||
BIN
doc/OpenSTA.odt
BIN
doc/OpenSTA.odt
Binary file not shown.
BIN
doc/OpenSTA.pdf
BIN
doc/OpenSTA.pdf
Binary file not shown.
|
|
@ -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
|
||||
|
|
|
|||
1040
doc/messages.txt
1040
doc/messages.txt
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ¶siticAnalysisPts();
|
||||
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 *¶sitic) 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 *¶sitic) 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_;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in New Issue