Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2026-01-03 16:59:35 -08:00
parent 7f65853afa
commit d42b821c00
384 changed files with 33435 additions and 32562 deletions

View File

@ -32,7 +32,7 @@ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.14)
cmake_policy(SET CMP0086 NEW)
endif()
project(STA VERSION 2.7.0
project(STA VERSION 3.0.0
LANGUAGES CXX
)
@ -77,7 +77,6 @@ set(STA_SOURCE
dcalc/ArnoldiDelayCalc.cc
dcalc/ArnoldiReduce.cc
dcalc/CcsCeffDelayCalc.cc
dcalc/DcalcAnalysisPt.cc
dcalc/DelayCalc.cc
dcalc/DelayCalcBase.cc
dcalc/DmpCeff.cc
@ -135,6 +134,7 @@ set(STA_SOURCE
parasitics/SpefReaderPvt.hh
power/Power.cc
power/ReportPower.cc
power/VcdReader.cc
power/SaifReader.cc
power/VcdParse.cc
@ -154,7 +154,6 @@ set(STA_SOURCE
sdc/PortDelay.cc
sdc/PortExtCap.cc
sdc/Sdc.cc
sdc/SdcGraph.cc
sdc/SdcCmdComment.cc
sdc/Variables.cc
sdc/WriteSdc.cc
@ -168,15 +167,14 @@ set(STA_SOURCE
search/CheckMaxSkews.cc
search/CheckMinPeriods.cc
search/CheckMinPulseWidths.cc
search/CheckCapacitanceLimits.cc
search/CheckFanoutLimits.cc
search/CheckSlewLimits.cc
search/CheckCapacitances.cc
search/CheckFanouts.cc
search/CheckSlews.cc
search/CheckTiming.cc
search/ClkInfo.cc
search/ClkLatency.cc
search/ClkNetwork.cc
search/ClkSkew.cc
search/Corner.cc
search/Crpr.cc
search/FindRegister.cc
search/GatedClk.cc
@ -184,8 +182,8 @@ set(STA_SOURCE
search/Latches.cc
search/Levelize.cc
search/MakeTimingModel.cc
search/Mode.cc
search/Path.cc
search/PathAnalysisPt.cc
search/Path.cc
search/PathEnd.cc
search/PathEnum.cc
@ -195,6 +193,7 @@ set(STA_SOURCE
search/ReportPath.cc
search/Search.cc
search/SearchPred.cc
search/Scene.cc
search/Sim.cc
search/Sta.cc
search/StaState.cc
@ -222,6 +221,7 @@ set(STA_SOURCE
util/ReportStd.cc
util/ReportTcl.cc
util/RiseFallMinMax.cc
util/RiseFallMinMaxDelay.cc
util/RiseFallValues.cc
util/Stats.cc
util/StringSeq.cc
@ -549,14 +549,14 @@ endif()
target_compile_options(OpenSTA
PRIVATE
$<$<CXX_COMPILER_ID:GNU>:${CXX_FLAGS}>
$<$<CXX_COMPILER_ID:GNU>:${CXX_FLAGS} -Wno-format-zero-length>
$<$<CXX_COMPILER_ID:Clang>:${CXX_FLAGS} -Wno-gnu-zero-variadic-macro-arguments>
$<$<CXX_COMPILER_ID:AppleClang>:${CXX_FLAGS} -Wno-gnu-zero-variadic-macro-arguments>
)
# Disable compiler specific extensions like gnu++11.
set_target_properties(OpenSTA PROPERTIES CXX_EXTENSIONS OFF)
target_compile_features(OpenSTA PUBLIC cxx_std_17)
target_compile_features(OpenSTA PUBLIC cxx_std_20)
message(STATUS "STA library: ${CMAKE_BINARY_DIR}/libOpenSTA.a")

View File

@ -27,6 +27,7 @@
#include <stdio.h>
#include <cstdlib> // exit
#include <filesystem>
#include <tcl.h>
#if TCL_READLINE
#include <tclreadline.h>
@ -47,7 +48,6 @@ using sta::evalTclInit;
using sta::sourceTclFile;
using sta::parseThreadsArg;
using sta::tcl_inits;
using sta::is_regular_file;
// Swig uses C linkage for init functions.
extern "C" {
@ -87,20 +87,11 @@ main(int argc,
}
else {
// Set argc to 1 so Tcl_Main doesn't source any files.
// Tcl_Main never returns.
#if 0
// It should be possible to pass argc/argv to staTclAppInit with
// a closure but I couldn't get the signature to match Tcl_AppInitProc.
Tcl_Main(1, argv, [=](Tcl_Interp *interp)
{ sta::staTclAppInit(argc, argv, interp);
return 1;
});
#else
// Workaround.
// Store argc and argv in static variables for tclAppInit.
cmd_argc = argc;
cmd_argv = argv;
// Tcl_Main never returns.
Tcl_Main(1, argv, tclAppInit);
#endif
return 0;
}
}
@ -141,7 +132,7 @@ staTclAppInit(int argc,
string init_path = home;
init_path += "/";
init_path += init_filename;
if (is_regular_file(init_path.c_str()))
if (std::filesystem::is_regular_file(init_path.c_str()))
sourceTclFile(init_path.c_str(), true, true, interp);
}
}

View File

@ -30,7 +30,6 @@
#include "Machine.hh"
#include "StringUtil.hh"
#include "Vector.hh"
#include "Sta.hh"
namespace sta {
@ -148,12 +147,4 @@ unencode(const char *inits[])
return unencoded;
}
// Hack until c++17 filesystem is better supported.
bool
is_regular_file(const char *filename)
{
struct stat sb;
return stat(filename, &sb) == 0 && S_ISREG(sb.st_mode);
}
} // namespace

View File

@ -31,7 +31,6 @@
#include "Network.hh"
#include "Graph.hh"
#include "ArcDelayCalc.hh"
#include "DcalcAnalysisPt.hh"
#include "GraphDelayCalc.hh"
namespace sta {
@ -40,7 +39,8 @@ using std::make_shared;
Waveform
ArcDcalcWaveforms::inputWaveform(ArcDcalcArg &dcalc_arg,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
const StaState *sta)
{
const Network *network = sta->network();
@ -55,7 +55,8 @@ ArcDcalcWaveforms::inputWaveform(ArcDcalcArg &dcalc_arg,
const Vertex *in_vertex = graph->pinLoadVertex(in_pin);
GraphDelayCalc *graph_dcalc = sta->graphDelayCalc();
Slew in_slew = graph_dcalc->edgeFromSlew(in_vertex, in_rf,
dcalc_arg.arc()->role(), dcalc_ap);
dcalc_arg.arc()->role(),
scene, min_max);
LibertyLibrary *library = port->libertyLibrary();
float vdd;
bool vdd_exists;
@ -67,7 +68,8 @@ ArcDcalcWaveforms::inputWaveform(ArcDcalcArg &dcalc_arg,
FloatSeq *time_values = new FloatSeq;
for (float time : *in_waveform.axis1()->values())
time_values->push_back(time + dcalc_arg.inputDelay());
TableAxisPtr time_axis = make_shared<TableAxis>(TableAxisVariable::time, time_values);
TableAxisPtr time_axis = make_shared<TableAxis>(TableAxisVariable::time,
time_values);
// Scale the waveform from 0:vdd.
FloatSeq *scaled_values = new FloatSeq;
for (float value : *in_waveform.values()) {

View File

@ -31,8 +31,7 @@
namespace sta {
class StaState;
class Corner;
class DcalcAnalysisPt;
class Scene;
class ArcDcalcArg;
// Abstract class for delay calculation waveforms for ploting.
@ -47,7 +46,8 @@ public:
protected:
Waveform inputWaveform(ArcDcalcArg &dcalc_arg,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
const StaState *sta);
};

View File

@ -46,14 +46,15 @@ ArcDelayCalc::gateDelay(const TimingArc *arc,
const Parasitic *parasitic,
float,
const Pvt *,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew)
{
LoadPinIndexMap load_pin_index_map(network_);
ArcDcalcResult dcalc_result = gateDelay(nullptr, arc, in_slew, load_cap, parasitic,
load_pin_index_map, dcalc_ap);
load_pin_index_map, scene, min_max);
gate_delay = dcalc_result.gateDelay();
drvr_slew = dcalc_result.drvrSlew();
}

View File

@ -43,7 +43,6 @@
#include "Graph.hh"
#include "Parasitics.hh"
#include "Sdc.hh"
#include "DcalcAnalysisPt.hh"
#include "DelayCalc.hh"
#include "ArcDelayCalc.hh"
#include "LumpedCapDelayCalc.hh"
@ -129,17 +128,20 @@ public:
const char *name() const override { return "arnoldi"; }
Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
Parasitic *reduceParasitic(const Parasitic *parasitic_network,
const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
ArcDcalcResult inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
ArcDcalcResult gateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
@ -147,14 +149,16 @@ public:
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) 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,
const Scene *scene,
const MinMax *min_max,
int digits) override;
void finishDrvrPin() override;
void delay_work_set_thresholds(delay_work *D,
@ -273,35 +277,34 @@ ArnoldiDelayCalc::~ArnoldiDelayCalc()
Parasitic *
ArnoldiDelayCalc::findParasitic(const Pin *drvr_pin,
const RiseFall *drvr_rf,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
Parasitic *parasitic = nullptr;
const Corner *corner = dcalc_ap->corner();
const Sdc *sdc = scene->sdc();
Parasitics *parasitics = scene->parasitics(min_max);
if (parasitics == nullptr
// 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();
parasitics->findParasiticNetwork(drvr_pin);
if (parasitic_network == nullptr) {
Wireload *wireload = sdc_->wireload(min_max);
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,
graph_delay_calc_->netCaps(drvr_pin, drvr_rf, scene, min_max,
pin_cap, wire_cap, fanout, has_wire_cap);
parasitic_network = parasitics_->makeWireloadNetwork(drvr_pin, wireload,
fanout, min_max,
parasitic_ap);
parasitic_network = parasitics->makeWireloadNetwork(drvr_pin, wireload,
fanout, scene, min_max);
}
}
if (parasitic_network) {
rcmodel *rcmodel = reduce_->reduceToArnoldi(parasitic_network, drvr_pin,
parasitic_ap->couplingCapFactor(),
drvr_rf, corner, min_max, parasitic_ap);
parasitics->couplingCapFactor(),
drvr_rf, scene, min_max);
// Arnoldi parasitics are their own class that are not saved in the parasitic db.
unsaved_parasitics_.push_back(rcmodel);
parasitic = rcmodel;
@ -313,7 +316,8 @@ Parasitic *
ArnoldiDelayCalc::reduceParasitic(const Parasitic *,
const Pin *,
const RiseFall *,
const DcalcAnalysisPt *)
const Scene *,
const MinMax *)
{
// Decline because reduced arnoldi parasitics are not stored in the parasitics db.
return nullptr;
@ -333,7 +337,8 @@ ArnoldiDelayCalc::inputPortDelay(const Pin *,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
const Scene *,
const MinMax *)
{
rcmodel_ = nullptr;
_delayV[0] = 0.0;
@ -389,21 +394,22 @@ ArnoldiDelayCalc::gateDelay(const Pin *drvr_pin,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
const LibertyCell *drvr_cell = arc->from()->libertyCell();
ConcreteParasitic *cparasitic =
reinterpret_cast<ConcreteParasitic*>(const_cast<Parasitic*>(parasitic));
rcmodel_ = dynamic_cast<rcmodel*>(cparasitic);
pocv_enabled_ = variables_->pocvEnabled();
GateTableModel *table_model = arc->gateTableModel(dcalc_ap);
GateTableModel *table_model = arc->gateTableModel(scene, min_max);
if (table_model && rcmodel_) {
const Pvt *pvt = pinPvt(drvr_pin, dcalc_ap);
const Pvt *pvt = pinPvt(drvr_pin, scene, min_max);
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);
parasitic, load_pin_index_map, scene, min_max);
}
ArcDcalcResult
@ -470,12 +476,13 @@ ArnoldiDelayCalc::reportGateDelay(const Pin *drvr_pin,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
int digits)
{
return LumpedCapDelayCalc::reportGateDelay(drvr_pin, arc, in_slew, load_cap,
parasitic, load_pin_index_map,
dcalc_ap, digits);
scene, min_max, digits);
}
////////////////////////////////////////////////////////////////

View File

@ -154,17 +154,17 @@ ArnoldiReduce::reduceToArnoldi(Parasitic *parasitic,
const Pin *drvr_pin,
float coupling_cap_factor,
const RiseFall *rf,
const Corner *corner,
const MinMax *min_max,
const ParasiticAnalysisPt *ap)
const Scene *scene,
const MinMax *min_max)
{
parasitic_network_ = reinterpret_cast<ConcreteParasiticNetwork*>(parasitic);
drvr_pin_ = drvr_pin;
coupling_cap_factor_ = coupling_cap_factor;
rf_ = rf;
corner_ = corner;
scene_ = scene;
min_max_ = min_max;
ap_ = ap;
parasitics_ = scene->parasitics(min_max);
parasitic_network_ = reinterpret_cast<ConcreteParasiticNetwork*>(parasitic);
loadWork();
return makeRcmodelDrv();
}
@ -444,7 +444,7 @@ ArnoldiReduce::getRC()
}
}
for (ParasiticCapacitor *capacitor : parasitics_->capacitors(parasitic_network_)) {
float cap = parasitics_->value(capacitor) * ap_->couplingCapFactor();
float cap = parasitics_->value(capacitor) * parasitics_->couplingCapFactor();
ParasiticNode *node1 = parasitics_->node1(capacitor);
if (!parasitics_->isExternal(node1)) {
ts_point *pt = findPt(node1);
@ -466,10 +466,11 @@ ArnoldiReduce::pinCapacitance(ParasiticNode *node)
if (pin) {
Port *port = network_->port(pin);
LibertyPort *lib_port = network_->libertyPort(port);
const Sdc *sdc = scene_->sdc();
if (lib_port)
pin_cap = sdc_->pinCapacitance(pin,rf_, corner_, min_max_);
pin_cap = sdc->pinCapacitance(pin,rf_, scene_, min_max_);
else if (network_->isTopLevelPort(pin))
pin_cap = sdc_->portExtCap(port, rf_, corner_, min_max_);
pin_cap = sdc->portExtCap(port, rf_, min_max_);
}
return pin_cap;
}

View File

@ -28,7 +28,8 @@
#pragma once
#include "Map.hh"
#include <map>
#include "Transition.hh"
#include "NetworkClass.hh"
#include "ParasiticsClass.hh"
@ -39,13 +40,13 @@ namespace sta {
class ConcreteParasiticNetwork;
class ConcreteParasiticNode;
class Corner;
class Scene;
class rcmodel;
struct ts_edge;
struct ts_point;
typedef Map<ParasiticNode*, int> ArnolidPtMap;
using ArnolidPtMap = std::map<ParasiticNode*, int>;
class ArnoldiReduce : public StaState
{
@ -56,9 +57,8 @@ public:
const Pin *drvr_pin,
float coupling_cap_factor,
const RiseFall *rf,
const Corner *corner,
const MinMax *cnst_min_max,
const ParasiticAnalysisPt *ap);
const Scene *scene,
const MinMax *min_max);
protected:
void loadWork();
@ -73,13 +73,13 @@ protected:
void makeRcmodelFromTs();
rcmodel *makeRcmodelFromW();
Parasitics *parasitics_;
ConcreteParasiticNetwork *parasitic_network_;
const Pin *drvr_pin_;
float coupling_cap_factor_;
const RiseFall *rf_;
const Corner *corner_;
const Scene *scene_;
const MinMax *min_max_;
const ParasiticAnalysisPt *ap_;
// ParasiticNode -> ts_point index.
ArnolidPtMap pt_map_;

View File

@ -30,8 +30,7 @@
#include "TimingArc.hh"
#include "Network.hh"
#include "Graph.hh"
#include "Corner.hh"
#include "DcalcAnalysisPt.hh"
#include "Scene.hh"
#include "Parasitics.hh"
#include "GraphDelayCalc.hh"
#include "DmpDelayCalc.hh"
@ -86,17 +85,20 @@ CcsCeffDelayCalc::gateDelay(const Pin *drvr_pin,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
in_slew_ = delayAsFloat(in_slew);
load_cap_ = load_cap;
parasitics_ = scene->parasitics(min_max);
parasitic_ = parasitic;
output_waveforms_ = nullptr;
GateTableModel *table_model = arc->gateTableModel(dcalc_ap);
GateTableModel *table_model = arc->gateTableModel(scene, min_max);
if (table_model && parasitic) {
OutputWaveforms *output_waveforms = table_model->outputWaveforms();
parasitics_->piModel(parasitic, c2_, rpi_, c1_);
Parasitics *parasitics = scene->parasitics(min_max);
parasitics->piModel(parasitic, c2_, rpi_, c1_);
if (output_waveforms
&& rpi_ > 0.0 && c1_ > 0.0
// Bounds check because extrapolating waveforms does not work for shit.
@ -114,8 +116,7 @@ CcsCeffDelayCalc::gateDelay(const Pin *drvr_pin,
vl_ = drvr_library->slewLowerThreshold(drvr_rf_) * vdd_;
vh_ = drvr_library->slewUpperThreshold(drvr_rf_) * vdd_;
const DcalcAnalysisPtSeq &dcalc_aps = corners_->dcalcAnalysisPts();
drvr_cell->ensureVoltageWaveforms(dcalc_aps);
drvr_cell->ensureVoltageWaveforms(scenes_);
in_slew_ = delayAsFloat(in_slew);
output_waveforms_ = output_waveforms;
ref_time_ = output_waveforms_->referenceTime(in_slew_);
@ -129,7 +130,7 @@ CcsCeffDelayCalc::gateDelay(const Pin *drvr_pin,
}
}
return table_dcalc_->gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic,
load_pin_index_map, dcalc_ap);
load_pin_index_map, scene, min_max);
}
void
@ -574,7 +575,7 @@ CcsCeffDelayCalc::drvrRampWaveform(const Pin *in_pin,
const Pin *drvr_pin,
const RiseFall *drvr_rf,
const Pin *load_pin,
const Corner *corner,
const Scene *scene,
const MinMax *min_max)
{
bool elmore_exists = false;
@ -582,7 +583,7 @@ CcsCeffDelayCalc::drvrRampWaveform(const Pin *in_pin,
if (parasitic_) {
parasitics_->findElmore(parasitic_, load_pin, elmore, elmore_exists);
bool dcalc_success = makeWaveformPreamble(in_pin, in_rf, drvr_pin,
drvr_rf, corner, min_max);
drvr_rf, scene, min_max);
if (dcalc_success
&& elmore_exists) {
FloatSeq *load_times = new FloatSeq;
@ -617,7 +618,7 @@ CcsCeffDelayCalc::makeWaveformPreamble(const Pin *in_pin,
const RiseFall *in_rf,
const Pin *drvr_pin,
const RiseFall *drvr_rf,
const Corner *corner,
const Scene *scene,
const MinMax *min_max)
{
Vertex *in_vertex = graph_->pinLoadVertex(in_pin);
@ -641,15 +642,15 @@ CcsCeffDelayCalc::makeWaveformPreamble(const Pin *in_pin,
}
}
if (arc) {
DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max);
const Slew &in_slew = graph_->slew(in_vertex, in_rf, dcalc_ap->index());
parasitic_ = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf, dcalc_ap);
DcalcAPIndex slew_index = scene->dcalcAnalysisPtIndex(min_max);
const Slew &in_slew = graph_->slew(in_vertex, in_rf, slew_index);
parasitic_ = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf, scene, min_max);
if (parasitic_) {
parasitics_->piModel(parasitic_, c2_, rpi_, c1_);
LoadPinIndexMap load_pin_index_map =
graph_delay_calc_->makeLoadPinIndexMap(drvr_vertex);
gateDelay(drvr_pin, arc, in_slew, load_cap_, parasitic_,
load_pin_index_map, dcalc_ap);
load_pin_index_map, scene, min_max);
return true;
}
}
@ -666,20 +667,19 @@ CcsCeffDelayCalc::reportGateDelay(const Pin *drvr_pin,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
int digits)
{
Parasitic *pi_elmore = nullptr;
const RiseFall *rf = arc->toEdge()->asRiseFall();
if (parasitic && !parasitics_->isPiElmore(parasitic)) {
const ParasiticAnalysisPt *ap = dcalc_ap->parasiticAnalysisPt();
pi_elmore = parasitics_->reduceToPiElmore(parasitic, drvr_pin_, rf,
dcalc_ap->corner(),
dcalc_ap->constraintMinMax(), ap);
scene, min_max);
}
string report = table_dcalc_->reportGateDelay(drvr_pin, arc, in_slew, load_cap,
pi_elmore, load_pin_index_map,
dcalc_ap, digits);
scene, min_max, digits);
parasitics_->deleteDrvrReducedParasitics(drvr_pin);
return report;
}

View File

@ -29,7 +29,7 @@
namespace sta {
typedef std::map<const Pin*, FloatSeq, PinIdLess> WatchPinValuesMap;
using WatchPinValuesMap = std::map<const Pin*, FloatSeq, PinIdLess>;
ArcDelayCalc *
makeCcsCeffDelayCalc(StaState *sta);
@ -49,14 +49,16 @@ public:
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
std::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,
const Scene *scene,
const MinMax *min_max,
int digits) override;
// Record waveform for drvr/load pin.
@ -100,7 +102,7 @@ protected:
const RiseFall *in_rf,
const Pin *drvr_pin,
const RiseFall *drvr_rf,
const Corner *corner,
const Scene *scene,
const MinMax *min_max);
Waveform drvrWaveform();
Waveform loadWaveform(const Pin *load_pin);
@ -109,7 +111,7 @@ protected:
const Pin *drvr_pin,
const RiseFall *drvr_rf,
const Pin *load_pin,
const Corner *corner,
const Scene *scene,
const MinMax *min_max);
void vl(double t,
double elmore,
@ -124,6 +126,7 @@ protected:
const RiseFall *drvr_rf_;
double in_slew_;
double load_cap_;
Parasitics *parasitics_;
const Parasitic *parasitic_;
OutputWaveforms *output_waveforms_;

View File

@ -1,68 +0,0 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software.
//
// Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// This notice may not be removed or altered from any source distribution.
#include "StringUtil.hh"
#include "DcalcAnalysisPt.hh"
#include "Corner.hh"
namespace sta {
DcalcAnalysisPt::DcalcAnalysisPt(Corner *corner,
DcalcAPIndex index,
const OperatingConditions *op_cond,
const MinMax *min_max,
const MinMax *check_clk_slew_min_max) :
corner_(corner),
index_(index),
op_cond_(op_cond),
min_max_(min_max),
check_clk_slew_min_max_(check_clk_slew_min_max)
{
}
void
DcalcAnalysisPt::setOperatingConditions(const OperatingConditions *op_cond)
{
op_cond_ = op_cond;
}
ParasiticAnalysisPt *
DcalcAnalysisPt::parasiticAnalysisPt() const
{
return corner_->findParasiticAnalysisPt(min_max_);
}
void
DcalcAnalysisPt::setCheckClkSlewIndex(DcalcAPIndex index)
{
check_clk_slew_index_ = index;
}
int
DcalcAnalysisPt::libertyIndex() const
{
return corner_->libertyIndex(min_max_);
}
} // namespace

View File

@ -24,7 +24,9 @@
#include "DelayCalc.hh"
#include "Map.hh"
#include <map>
#include "ContainerHelpers.hh"
#include "StringUtil.hh"
#include "UnitDelayCalc.hh"
#include "LumpedCapDelayCalc.hh"
@ -35,7 +37,7 @@
namespace sta {
typedef Map<const char*, MakeArcDelayCalc, CharPtrLess> DelayCalcMap;
typedef std::map<const char*, MakeArcDelayCalc, CharPtrLess> DelayCalcMap;
static DelayCalcMap *delay_calcs = nullptr;
@ -71,7 +73,7 @@ ArcDelayCalc *
makeDelayCalc(const char *name,
StaState *sta)
{
MakeArcDelayCalc maker = delay_calcs->findKey(name);
MakeArcDelayCalc maker = findKey(delay_calcs, name);
if (maker)
return maker(sta);
else
@ -81,7 +83,7 @@ makeDelayCalc(const char *name,
bool
isDelayCalcName(const char *name)
{
return delay_calcs->hasKey(name);
return delay_calcs->contains(name);
}
StringSeq

View File

@ -32,8 +32,6 @@
#include "dcalc/PrimaDelayCalc.hh"
#include "Sta.hh"
using std::string;
%}
%inline %{
@ -62,15 +60,15 @@ set_delay_calc_incremental_tolerance(float tol)
Sta::sta()->setIncrementalDelayTolerance(tol);
}
string
std::string
report_delay_calc_cmd(Edge *edge,
TimingArc *arc,
const Corner *corner,
const Scene *scene,
const MinMax *min_max,
int digits)
{
Sta *sta = Sta::sta();
return sta->reportDelayCalc(edge, arc, corner, min_max, digits);
return sta->reportDelayCalc(edge, arc, scene, min_max, digits);
}
void

View File

@ -25,7 +25,7 @@
namespace eval sta {
define_cmd_args "report_dcalc" \
{[-from from_pin] [-to to_pin] [-corner corner] [-min] [-max] [-digits digits]}
{[-from from_pin] [-to to_pin] [-scene scene] [-min] [-max] [-digits digits]}
proc_redirect report_dcalc {
report_dcalc_cmd "report_dcalc" $args "-digits"
@ -36,9 +36,9 @@ proc report_dcalc_cmd { cmd cmd_args digits_key } {
global sta_report_default_digits
parse_key_args $cmd cmd_args \
keys "$digits_key -from -to -corner" \
keys "$digits_key -from -to -scene -corner" \
flags {-min -max}
set corner [parse_corner keys]
set scene [parse_scene keys]
set min_max [parse_min_max_flags flags]
check_argc_eq0 $cmd $cmd_args
@ -56,7 +56,7 @@ proc report_dcalc_cmd { cmd cmd_args digits_key } {
while {[$iter has_next]} {
set edge [$iter next]
if { [$edge to] == $to_vertex } {
report_edge_dcalc $edge $corner $min_max $digits
report_edge_dcalc $edge $scene $min_max $digits
}
}
$iter finish
@ -68,7 +68,7 @@ proc report_dcalc_cmd { cmd cmd_args digits_key } {
set iter [$from_vertex out_edge_iterator]
while {[$iter has_next]} {
set edge [$iter next]
report_edge_dcalc $edge $corner $min_max $digits
report_edge_dcalc $edge $scene $min_max $digits
}
$iter finish
}
@ -78,14 +78,14 @@ proc report_dcalc_cmd { cmd cmd_args digits_key } {
set iter [$to_vertex in_edge_iterator]
while {[$iter has_next]} {
set edge [$iter next]
report_edge_dcalc $edge $corner $min_max $digits
report_edge_dcalc $edge $scene $min_max $digits
}
$iter finish
}
}
}
proc report_edge_dcalc { edge corner min_max digits } {
proc report_edge_dcalc { edge scene min_max digits } {
set role [$edge role]
if { $role != "wire" } {
set from_vertex [$edge from]
@ -111,9 +111,9 @@ proc report_edge_dcalc { edge corner min_max digits } {
set to [get_name [$to_pin port]]
set to_rf [$arc to_edge]
report_line "$from $from_rf -> $to $to_rf"
report_line [report_delay_calc_cmd $edge $arc $corner $min_max $digits]
if { [$edge delay_annotated $arc $corner $min_max] } {
set delay [$edge arc_delay $arc $corner $min_max]
report_line [report_delay_calc_cmd $edge $arc $scene $min_max $digits]
if { [$edge delay_annotated $arc $scene $min_max] } {
set delay [$edge arc_delay $arc $scene $min_max]
report_line "Annotated value = [format_time $delay $digits]"
}
report_line "............................................."
@ -140,16 +140,16 @@ define_cmd_args "set_pocv_sigma_factor" { factor }
################################################################
define_cmd_args "set_assigned_delay" \
{-cell|-net [-rise] [-fall] [-corner corner] [-min] [-max]\
{-cell|-net [-rise] [-fall] [-scene scene] [-min] [-max]\
[-from from_pins] [-to to_pins] delay}
# Change the delay for timing arcs between from_pins and to_pins matching
# on cell (instance) or net.
proc set_assigned_delay { args } {
parse_key_args "set_assigned_delay" args keys {-corner -from -to} \
parse_key_args "set_assigned_delay" args keys {-scene -corner -from -to} \
flags {-cell -net -rise -fall -max -min}
check_argc_eq1 "set_assigned_delay" $args
set corner [parse_corner keys]
set scene [parse_scene keys]
set min_max [parse_min_max_all_check_flags flags]
set to_rf [parse_rise_fall_flags flags]
@ -192,28 +192,28 @@ proc set_assigned_delay { args } {
foreach from_pin $from_pins {
set from_vertices [$from_pin vertices]
set_assigned_delay1 [lindex $from_vertices 0] \
$to_pins $to_rf $corner $min_max $delay
$to_pins $to_rf $scene $min_max $delay
if { [llength $from_vertices] == 2 } {
set_assigned_delay1 [lindex $from_vertices 1] \
$to_pins $to_rf $corner $min_max $delay
$to_pins $to_rf $scene $min_max $delay
}
}
}
proc set_assigned_delay1 { from_vertex to_pins to_rf corner min_max delay } {
proc set_assigned_delay1 { from_vertex to_pins to_rf scene min_max delay } {
foreach to_pin $to_pins {
set to_vertices [$to_pin vertices]
set_assigned_delay2 $from_vertex [lindex $to_vertices 0] \
$to_rf $corner $min_max $delay
$to_rf $scene $min_max $delay
if { [llength $to_vertices] == 2 } {
# Bidirect driver.
set_assigned_delay2 $from_vertex [lindex $to_vertices 1] \
$to_rf $corner $min_max $delay
$to_rf $scene $min_max $delay
}
}
}
proc set_assigned_delay2 {from_vertex to_vertex to_rf corner min_max delay} {
proc set_assigned_delay2 {from_vertex to_vertex to_rf scene min_max delay} {
set matched 0
set edge_iter [$from_vertex out_edge_iterator]
while {[$edge_iter has_next]} {
@ -223,7 +223,7 @@ proc set_assigned_delay2 {from_vertex to_vertex to_rf corner min_max delay} {
foreach arc [$edge timing_arcs] {
if { $to_rf == "rise_fall" \
|| $to_rf eq [$arc to_edge_name] } {
set_arc_delay $edge $arc $corner $min_max $delay
set_arc_delay $edge $arc $scene $min_max $delay
set matched 1
}
}
@ -239,13 +239,13 @@ proc set_assigned_delay2 {from_vertex to_vertex to_rf corner min_max delay} {
define_cmd_args "set_assigned_check" \
{-setup|-hold|-recovery|-removal [-rise] [-fall]\
[-corner corner] [-min] [-max]\
[-scene scene] [-min] [-max]\
[-from from_pins] [-to to_pins] [-clock rise|fall]\
[-cond sdf_cond] check_value}
proc set_assigned_check { args } {
parse_key_args "set_assigned_check" args \
keys {-from -to -corner -clock -cond} \
keys {-from -to -scene -corner -clock -cond} \
flags {-setup -hold -recovery -removal -rise -fall -max -min}
check_argc_eq1 "set_assigned_check" $args
@ -271,7 +271,7 @@ proc set_assigned_check { args } {
sta_error 190 "set_assigned_check missing -to argument."
}
set to_rf [parse_rise_fall_flags flags]
set corner [parse_corner keys]
set scene [parse_scene keys]
set min_max [parse_min_max_all_check_flags flags]
if { [info exists flags(-setup)] } {
@ -298,31 +298,31 @@ proc set_assigned_check { args } {
foreach from_pin $from_pins {
set from_vertices [$from_pin vertices]
set_assigned_check1 [lindex $from_vertices 0] $from_rf \
$to_pins $to_rf $role $corner $min_max $cond $check_value
$to_pins $to_rf $role $scene $min_max $cond $check_value
if { [llength $from_vertices] == 2 } {
set_assigned_check1 [lindex $from_vertices 1] $from_rf \
$to_pins $to_rf $role $corner $min_max $cond $check_value
$to_pins $to_rf $role $scene $min_max $cond $check_value
}
}
}
proc set_assigned_check1 { from_vertex from_rf to_pins to_rf \
role corner min_max cond check_value } {
role scene min_max cond check_value } {
foreach to_pin $to_pins {
set to_vertices [$to_pin vertices]
set_assigned_check2 $from_vertex $from_rf [lindex $to_vertices 0] \
$to_rf $role $corner $min_max $cond $check_value
$to_rf $role $scene $min_max $cond $check_value
if { [llength $to_vertices] == 2 } {
# Bidirect driver.
set_assigned_check2 $from_vertex $from_rf \
[lindex $to_vertices 1] $to_rf $role $corner $min_max \
[lindex $to_vertices 1] $to_rf $role $scene $min_max \
$cond $check_value
}
}
}
proc set_assigned_check2 { from_vertex from_rf to_vertex to_rf \
role corner min_max cond check_value } {
role scene min_max cond check_value } {
set edge_iter [$from_vertex out_edge_iterator]
set matched 0
while {[$edge_iter has_next]} {
@ -335,7 +335,7 @@ proc set_assigned_check2 { from_vertex from_rf to_vertex to_rf \
|| $to_rf eq [$arc to_edge_name]) \
&& [$arc role] eq $role \
&& ($cond eq "" || [$arc sdf_cond] eq $cond) } {
set_arc_delay $edge $arc $corner $min_max $check_value
set_arc_delay $edge $arc $scene $min_max $check_value
set matched 1
}
}
@ -350,14 +350,14 @@ proc set_assigned_check2 { from_vertex from_rf to_vertex to_rf \
################################################################a
define_cmd_args "set_assigned_transition" \
{[-rise] [-fall] [-corner corner] [-min] [-max] slew pins}
{[-rise] [-fall] [-scene scene] [-min] [-max] slew pins}
# Change the slew on a list of ports.
proc set_assigned_transition { args } {
parse_key_args "set_assigned_transition" args keys {-corner} \
parse_key_args "set_assigned_transition" args keys {-scene -corner} \
flags {-rise -fall -max -min}
set corner [parse_corner keys]
set scene [parse_scene keys]
set min_max [parse_min_max_all_check_flags flags]
set tr [parse_rise_fall_flags flags]
check_argc_eq2 "set_assigned_transition" $args
@ -371,7 +371,7 @@ proc set_assigned_transition { args } {
foreach pin $pins {
set vertices [$pin vertices]
set vertex [lindex $vertices 0]
set_annotated_slew $vertex $corner $min_max $tr $slew
set_annotated_slew $vertex $scene $min_max $tr $slew
if { [llength $vertices] == 2 } {
# Bidirect driver.
set vertex [lindex $vertices 1]
@ -380,5 +380,27 @@ proc set_assigned_transition { args } {
}
}
################################################################
define_cmd_args "report_slews" {[-scenes scenes] pin}
proc report_slews { args } {
global sta_report_default_digits
parse_key_args "report_slews" args keys {-corner -scenes} flags {}
check_argc_eq1 "report_slews" $args
set scenes [parse_scenes_or_all keys]
set pin [get_port_pin_error "pin" [lindex $args 0]]
set digits $sta_report_default_digits
foreach vertex [$pin vertices] {
set rise_min [format_time [$vertex slew_scenes rise $scenes min] $digits]
set rise_max [format_time [$vertex slew_scenes rise $scenes max] $digits]
set fall_min [format_time [$vertex slew_scenes fall $scenes min] $digits]
set fall_max [format_time [$vertex slew_scenes fall $scenes max] $digits]
report_line "[vertex_path_name $vertex] [rise_short_name] $rise_min:$rise_max [fall_short_name] $fall_min:$fall_max"
}
}
# sta namespace end
}

View File

@ -32,8 +32,7 @@
#include "Parasitics.hh"
#include "Graph.hh"
#include "Sdc.hh"
#include "Corner.hh"
#include "DcalcAnalysisPt.hh"
#include "Scene.hh"
#include "GraphDelayCalc.hh"
#include "Variables.hh"
@ -50,7 +49,7 @@ DelayCalcBase::DelayCalcBase(StaState *sta) :
void
DelayCalcBase::reduceParasitic(const Parasitic *parasitic_network,
const Net *net,
const Corner *corner,
const Scene *scene,
const MinMaxAll *min_max)
{
NetConnectedPinIterator *pin_iter = network_->connectedPinIterator(net);
@ -59,16 +58,12 @@ DelayCalcBase::reduceParasitic(const Parasitic *parasitic_network,
if (network_->isDriver(pin)) {
for (const 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);
if (scene == nullptr) {
for (const Scene *scene1 : scenes_)
reduceParasitic(parasitic_network, pin, rf, scene1, min_max);
}
else
reduceParasitic(parasitic_network, pin, rf, scene, min_max);
}
}
}
@ -162,13 +157,15 @@ DelayCalcBase::checkDelay(const Pin *check_pin,
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
CheckTimingModel *model = arc->checkModel(dcalc_ap);
CheckTimingModel *model = arc->checkModel(scene, min_max);
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,
return model->checkDelay(pinPvt(check_pin, scene, min_max),
from_slew1, to_slew1,
related_out_cap,
variables_->pocvEnabled());
}
@ -183,40 +180,46 @@ DelayCalcBase::reportCheckDelay(const Pin *check_pin,
const char *from_slew_annotation,
const Slew &to_slew,
float related_out_cap,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
int digits)
{
CheckTimingModel *model = arc->checkModel(dcalc_ap);
CheckTimingModel *model = arc->checkModel(scene, min_max);
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 model->reportCheckDelay(pinPvt(check_pin, scene, min_max),
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 Scene *scene,
const MinMax *min_max)
{
const Instance *drvr_inst = network_->instance(pin);
const Pvt *pvt = sdc_->pvt(drvr_inst, dcalc_ap->constraintMinMax());
const Sdc *sdc = scene->sdc();
const Pvt *pvt = sdc->pvt(drvr_inst, min_max);
if (pvt == nullptr)
pvt = dcalc_ap->operatingConditions();
pvt = sdc->operatingConditions(min_max);
return pvt;
}
void
DelayCalcBase::setDcalcArgParasiticSlew(ArcDcalcArg &gate,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
const Pin *drvr_pin = gate.drvrPin();
if (drvr_pin) {
const Parasitic *parasitic;
float load_cap;
graph_delay_calc_->parasiticLoad(drvr_pin, gate.drvrEdge(), dcalc_ap,
graph_delay_calc_->parasiticLoad(drvr_pin, gate.drvrEdge(),
scene, min_max,
nullptr, this, load_cap,
parasitic);
gate.setLoadCap(load_cap);
@ -224,17 +227,19 @@ DelayCalcBase::setDcalcArgParasiticSlew(ArcDcalcArg &gate,
const Pin *in_pin = gate.inPin();
const Vertex *in_vertex = graph_->pinLoadVertex(in_pin);
const Slew &in_slew = graph_delay_calc_->edgeFromSlew(in_vertex, gate.inEdge(),
gate.edge(), dcalc_ap);
gate.edge(),
scene, min_max);
gate.setInSlew(in_slew);
}
}
void
DelayCalcBase::setDcalcArgParasiticSlew(ArcDcalcArgSeq &gates,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
for (ArcDcalcArg &gate : gates)
setDcalcArgParasiticSlew(gate, dcalc_ap);
setDcalcArgParasiticSlew(gate, scene, min_max);
}
} // namespace

View File

@ -34,23 +34,26 @@ class GateTableModel;
class DelayCalcBase : public ArcDelayCalc
{
public:
explicit DelayCalcBase(StaState *sta);
DelayCalcBase(StaState *sta);
void finishDrvrPin() override;
void reduceParasitic(const Parasitic *parasitic_network,
const Net *net,
const Corner *corner,
const Scene *scene,
const MinMaxAll *min_max) override;
void setDcalcArgParasiticSlew(ArcDcalcArg &gate,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
void setDcalcArgParasiticSlew(ArcDcalcArgSeq &gates,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *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;
const Scene *scene,
const MinMax *min_max) override;
std::string reportCheckDelay(const Pin *check_pin,
const TimingArc *arc,
@ -58,7 +61,8 @@ public:
const char *from_slew_annotation,
const Slew &to_slew,
float related_out_cap,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
int digits) override;
protected:
@ -79,7 +83,8 @@ protected:
ArcDelay &wire_delay,
Slew &load_slew);
const Pvt *pinPvt(const Pin *pin,
const DcalcAnalysisPt *dcalc_ap);
const Scene *scene,
const MinMax *min_max);
using ArcDelayCalc::reduceParasitic;
};

View File

@ -44,7 +44,6 @@
#include "Network.hh"
#include "Sdc.hh"
#include "Parasitics.hh"
#include "DcalcAnalysisPt.hh"
#include "ArcDelayCalc.hh"
#include "FindRoot.hh"
#include "Variables.hh"
@ -1495,20 +1494,22 @@ DmpCeffDelayCalc::gateDelay(const Pin *drvr_pin,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
parasitics_ = scene->parasitics(min_max);
const RiseFall *rf = arc->toEdge()->asRiseFall();
const LibertyCell *drvr_cell = arc->from()->libertyCell();
const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary();
GateTableModel *table_model = arc->gateTableModel(dcalc_ap);
GateTableModel *table_model = arc->gateTableModel(scene, min_max);
if (table_model && parasitic) {
float in_slew1 = delayAsFloat(in_slew);
float c2, rpi, c1;
parasitics_->piModel(parasitic, c2, rpi, c1);
if (isnan(c2) || isnan(c1) || isnan(rpi))
report_->error(1040, "parasitic Pi model has NaNs.");
setCeffAlgorithm(drvr_library, drvr_cell, pinPvt(drvr_pin, dcalc_ap),
setCeffAlgorithm(drvr_library, drvr_cell, pinPvt(drvr_pin, scene, min_max),
table_model, rf, in_slew1, c2, rpi, c1);
double gate_delay, drvr_slew;
gateDelaySlew(gate_delay, drvr_slew);
@ -1529,7 +1530,7 @@ DmpCeffDelayCalc::gateDelay(const Pin *drvr_pin,
else {
ArcDcalcResult dcalc_result =
LumpedCapDelayCalc::gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic,
load_pin_index_map, dcalc_ap);
load_pin_index_map, scene, min_max);
if (parasitic
&& !unsuppored_model_warned_) {
unsuppored_model_warned_ = true;
@ -1589,12 +1590,13 @@ DmpCeffDelayCalc::reportGateDelay(const Pin *drvr_pin,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
int digits)
{
ArcDcalcResult dcalc_result = gateDelay(drvr_pin, arc, in_slew, load_cap,
parasitic, load_pin_index_map, dcalc_ap);
GateTableModel *model = arc->gateTableModel(dcalc_ap);
parasitic, load_pin_index_map, scene, min_max);
GateTableModel *model = arc->gateTableModel(scene, min_max);
float c_eff = 0.0;
string result;
const LibertyCell *drvr_cell = arc->to()->libertyCell();
@ -1603,9 +1605,11 @@ DmpCeffDelayCalc::reportGateDelay(const Pin *drvr_pin,
const Unit *cap_unit = units->capacitanceUnit();
const Unit *res_unit = units->resistanceUnit();
if (parasitic && dmp_alg_) {
Parasitics *parasitics = scene->parasitics(min_max);
c_eff = dmp_alg_->ceff();
float c2, rpi, c1;
parasitics_->piModel(parasitic, c2, rpi, c1);
parasitics->piModel(parasitic, c2, rpi, c1);
result += "Pi model C2=";
result += cap_unit->asString(c2, digits);
result += " Rpi=";
@ -1621,7 +1625,8 @@ DmpCeffDelayCalc::reportGateDelay(const Pin *drvr_pin,
if (model) {
const Unit *time_unit = units->timeUnit();
float in_slew1 = delayAsFloat(in_slew);
result += model->reportGateDelay(pinPvt(drvr_pin, dcalc_ap), in_slew1, c_eff,
result += model->reportGateDelay(pinPvt(drvr_pin, scene, min_max),
in_slew1, c_eff,
variables_->pocvEnabled(), digits);
result += "Driver waveform slew = ";
float drvr_slew = delayAsFloat(dcalc_result.drvrSlew());

View File

@ -49,14 +49,16 @@ public:
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
std::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,
const Scene *scene,
const MinMax *min_max,
int digits) override;
void copyState(const StaState *sta) override;
@ -87,6 +89,7 @@ protected:
double rpi,
double c1);
const Parasitics *parasitics_;
static bool unsuppored_model_warned_;
private:

View File

@ -31,7 +31,6 @@
#include "Network.hh"
#include "Sdc.hh"
#include "Parasitics.hh"
#include "DcalcAnalysisPt.hh"
#include "GraphDelayCalc.hh"
#include "DmpCeff.hh"
@ -50,7 +49,8 @@ public:
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
protected:
void loadDelaySlew(const Pin *load_pin,
@ -86,8 +86,10 @@ DmpCeffElmoreDelayCalc::inputPortDelay(const Pin *,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
const Scene *scene,
const MinMax *min_max)
{
Parasitics *parasitics = scene->parasitics(min_max);
ArcDcalcResult dcalc_result(load_pin_index_map.size());
LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
for (auto [load_pin, load_idx] : load_pin_index_map) {
@ -96,7 +98,7 @@ DmpCeffElmoreDelayCalc::inputPortDelay(const Pin *,
bool elmore_exists = false;
float elmore = 0.0;
if (parasitic)
parasitics_->findElmore(parasitic, load_pin, elmore, elmore_exists);
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);
@ -140,20 +142,23 @@ public:
const char *name() const override { return "dmp_ceff_two_pole"; }
Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
ArcDcalcResult inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) 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;
const Scene *scene,
const MinMax *min_max) override;
private:
void loadDelaySlew(const Pin *load_pin,
@ -213,42 +218,40 @@ DmpCeffTwoPoleDelayCalc::copy()
Parasitic *
DmpCeffTwoPoleDelayCalc::findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
Parasitic *parasitic = nullptr;
const Corner *corner = dcalc_ap->corner();
const Sdc *sdc = scene->sdc();
Parasitics *parasitics = scene->parasitics(min_max);
if (parasitics == nullptr
// 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);
parasitic = parasitics->findPiPoleResidue(drvr_pin, rf, min_max);
if (parasitic)
return parasitic;
parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap);
parasitic = parasitics->findPiElmore(drvr_pin, rf, min_max);
if (parasitic)
return parasitic;
Parasitic *parasitic_network =
parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap);
parasitics->findParasiticNetwork(drvr_pin);
if (parasitic_network) {
parasitic = parasitics_->reduceToPiPoleResidue2(parasitic_network, drvr_pin, rf,
corner,
dcalc_ap->constraintMinMax(),
parasitic_ap);
parasitic = parasitics->reduceToPiPoleResidue2(parasitic_network, drvr_pin, rf,
scene, min_max);
if (parasitic)
return parasitic;
}
const MinMax *cnst_min_max = dcalc_ap->constraintMinMax();
Wireload *wireload = sdc_->wireload(cnst_min_max);
Wireload *wireload = sdc->wireload(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,
graph_delay_calc_->netCaps(drvr_pin, rf, scene, min_max, pin_cap, wire_cap,
fanout, has_wire_cap);
parasitic = parasitics_->estimatePiElmore(drvr_pin, rf, wireload,
fanout, pin_cap, corner,
cnst_min_max);
parasitic = parasitics->estimatePiElmore(drvr_pin, rf, wireload,
fanout, pin_cap,
scene, min_max);
}
return parasitic;
}
@ -259,21 +262,23 @@ DmpCeffTwoPoleDelayCalc::inputPortDelay(const Pin *,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
const Scene *scene,
const MinMax *min_max)
{
const Parasitics *parasitics = scene->parasitics(min_max);
ArcDcalcResult dcalc_result(load_pin_index_map.size());
ArcDelay wire_delay = 0.0;
Slew load_slew = in_slew;
LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
for (const auto [load_pin, load_idx] : load_pin_index_map) {
if (parasitics_->isPiPoleResidue(parasitic)) {
const Parasitic *pole_residue = parasitics_->findPoleResidue(parasitic, load_pin);
if (parasitics->isPiPoleResidue(parasitic)) {
const Parasitic *pole_residue = parasitics->findPoleResidue(parasitic, load_pin);
if (pole_residue) {
size_t pole_count = parasitics_->poleResidueCount(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);
parasitics->poleResidue(pole_residue, 0, pole1, residue1);
if (pole1.imag() == 0.0
&& residue1.imag() == 0.0) {
float p1 = pole1.real();
@ -297,8 +302,10 @@ DmpCeffTwoPoleDelayCalc::gateDelay(const Pin *drvr_pin,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
parasitics_ = scene->parasitics(min_max);
const LibertyLibrary *drvr_library = arc->to()->libertyLibrary();
const RiseFall *rf = arc->toEdge()->asRiseFall();
vth_ = drvr_library->outputThreshold(rf);
@ -306,7 +313,7 @@ DmpCeffTwoPoleDelayCalc::gateDelay(const Pin *drvr_pin,
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) ;
load_pin_index_map, scene, min_max) ;
}
void

View File

@ -28,10 +28,10 @@
namespace sta {
typedef const std::function<void (double x,
using FindRootFunc = const std::function<void (double x,
// Return values.
double &y,
double &dy)> FindRootFunc;
double &dy)>;
double
findRoot(FindRootFunc func,

File diff suppressed because it is too large Load Diff

View File

@ -35,7 +35,6 @@
#include "Network.hh"
#include "Sdc.hh"
#include "Parasitics.hh"
#include "DcalcAnalysisPt.hh"
#include "GraphDelayCalc.hh"
#include "Variables.hh"
@ -64,35 +63,37 @@ LumpedCapDelayCalc::copy()
Parasitic *
LumpedCapDelayCalc::findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
Parasitic *parasitic = nullptr;
const Corner *corner = dcalc_ap->corner();
Parasitics *parasitics = scene->parasitics(min_max);
const Sdc *sdc = scene->sdc();
if (parasitics == nullptr
// set_load net has precedence over parasitics.
if (sdc_->drvrPinHasWireCap(drvr_pin, corner)
|| sdc->drvrPinHasWireCap(drvr_pin)
|| network_->direction(drvr_pin)->isInternal())
return nullptr;
const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
// Prefer PiElmore.
parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap);
parasitic = parasitics->findPiElmore(drvr_pin, rf, min_max);
if (parasitic)
return parasitic;
Parasitic *parasitic_network = parasitics_->findParasiticNetwork(drvr_pin,
parasitic_ap);
Parasitic *parasitic_network = parasitics->findParasiticNetwork(drvr_pin);
if (parasitic_network) {
parasitic = reduceParasitic(parasitic_network, drvr_pin, rf, dcalc_ap);
parasitic = reduceParasitic(parasitic_network, drvr_pin, rf, scene, min_max);
if (parasitic)
return parasitic;
}
const MinMax *min_max = dcalc_ap->constraintMinMax();
Wireload *wireload = sdc_->wireload(min_max);
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,
graph_delay_calc_->netCaps(drvr_pin, rf, scene, min_max,
pin_cap, wire_cap, fanout, has_net_load);
parasitic = parasitics_->estimatePiElmore(drvr_pin, rf, wireload, fanout,
pin_cap, corner, min_max);
parasitic = parasitics->estimatePiElmore(drvr_pin, rf, wireload, fanout,
pin_cap, scene, min_max);
}
return parasitic;
}
@ -101,14 +102,13 @@ Parasitic *
LumpedCapDelayCalc::reduceParasitic(const Parasitic *parasitic_network,
const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
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);
Parasitics *parasitics = scene->parasitics(min_max);
return parasitics->reduceToPiElmore(parasitic_network, drvr_pin, rf,
scene, min_max);
}
ArcDcalcResult
@ -117,7 +117,8 @@ LumpedCapDelayCalc::inputPortDelay(const Pin *,
const RiseFall *rf,
const Parasitic *,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
const Scene *,
const MinMax *)
{
const LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
return makeResult(drvr_library,rf, 0.0, in_slew, load_pin_index_map);
@ -130,9 +131,10 @@ LumpedCapDelayCalc::gateDelay(const Pin *drvr_pin,
float load_cap,
const Parasitic *,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
GateTimingModel *model = arc->gateModel(dcalc_ap);
GateTimingModel *model = arc->gateModel(scene, min_max);
debugPrint(debug_, "delay_calc", 3,
" in_slew = %s load_cap = %s lumped",
delayAsString(in_slew, this),
@ -146,7 +148,7 @@ LumpedCapDelayCalc::gateDelay(const Pin *drvr_pin,
// NaNs cause seg faults during table lookup.
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,
model->gateDelay(pinPvt(drvr_pin, scene, min_max), in_slew1, load_cap,
variables_->pocvEnabled(),
gate_delay, drvr_slew);
return makeResult(drvr_library, rf, gate_delay, drvr_slew, load_pin_index_map);
@ -182,14 +184,15 @@ LumpedCapDelayCalc::reportGateDelay(const Pin *check_pin,
float load_cap,
const Parasitic *,
const LoadPinIndexMap &,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
int digits)
{
GateTimingModel *model = arc->gateModel(dcalc_ap);
GateTimingModel *model = arc->gateModel(scene, min_max);
if (model) {
float in_slew1 = delayAsFloat(in_slew);
return model->reportGateDelay(pinPvt(check_pin, dcalc_ap), in_slew1, load_cap,
false, digits);
return model->reportGateDelay(pinPvt(check_pin, scene, min_max),
in_slew1, load_cap, false, digits);
}
return "";
}

View File

@ -38,32 +38,37 @@ public:
const char *name() const override { return "lumped_cap"; }
Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
bool reduceSupported() const override { return true; }
Parasitic *reduceParasitic(const Parasitic *parasitic_network,
const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
ArcDcalcResult inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) 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;
const Scene *scene,
const MinMax *min_max) override;
std::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,
const Scene *scene,
const MinMax *min_max,
int digits) override;
protected:

View File

@ -25,7 +25,7 @@
#include "ParallelDelayCalc.hh"
#include "TimingArc.hh"
#include "Corner.hh"
#include "Scene.hh"
#include "Network.hh"
#include "Graph.hh"
#include "Sdc.hh"
@ -44,25 +44,28 @@ ParallelDelayCalc::ParallelDelayCalc(StaState *sta):
ArcDcalcResultSeq
ParallelDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
if (dcalc_args.size() == 1) {
ArcDcalcArg &dcalc_arg = dcalc_args[0];
ArcDcalcResult dcalc_result = gateDelay(dcalc_arg.drvrPin(), dcalc_arg.arc(),
dcalc_arg.inSlew(), dcalc_arg.loadCap(),
dcalc_arg.parasitic(),
load_pin_index_map, dcalc_ap);
load_pin_index_map,
scene, min_max);
ArcDcalcResultSeq dcalc_results;
dcalc_results.push_back(dcalc_result);
return dcalc_results;
}
return gateDelaysParallel(dcalc_args, load_pin_index_map, dcalc_ap);
return gateDelaysParallel(dcalc_args, load_pin_index_map, scene, min_max);
}
ArcDcalcResultSeq
ParallelDelayCalc::gateDelaysParallel(ArcDcalcArgSeq &dcalc_args,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
size_t drvr_count = dcalc_args.size();
ArcDcalcResultSeq dcalc_results(drvr_count);
@ -75,16 +78,16 @@ ParallelDelayCalc::gateDelaysParallel(ArcDcalcArgSeq &dcalc_args,
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();
const Slew &in_slew = dcalc_arg.inSlew();
ArcDcalcResult intrinsic_result = gateDelay(drvr_pin, arc, in_slew, 0.0, nullptr,
load_pin_index_map, dcalc_ap);
load_pin_index_map, scene, min_max);
ArcDelay intrinsic_delay = intrinsic_result.gateDelay();
intrinsic_delays[drvr_idx] = intrinsic_result.gateDelay();
ArcDcalcResult gate_result = gateDelay(drvr_pin, arc, in_slew, dcalc_arg.loadCap(),
dcalc_arg.parasitic(),
load_pin_index_map, dcalc_ap);
load_pin_index_map, scene, min_max);
ArcDelay gate_delay = gate_result.gateDelay();
Slew drvr_slew = gate_result.drvrSlew();
ArcDelay load_delay = gate_delay - intrinsic_delay;

View File

@ -38,11 +38,13 @@ public:
ParallelDelayCalc(StaState *sta);
ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &dcalc_args,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
protected:
ArcDcalcResultSeq gateDelaysParallel(ArcDcalcArgSeq &dcalc_args,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap);
const Scene *scene,
const MinMax *min_max);
};
} // namespace

View File

@ -33,8 +33,7 @@
#include "PortDirection.hh"
#include "Network.hh"
#include "Sdc.hh"
#include "DcalcAnalysisPt.hh"
#include "Corner.hh"
#include "Scene.hh"
#include "Graph.hh"
#include "Parasitics.hh"
#include "GraphDelayCalc.hh"
@ -64,9 +63,12 @@ makePrimaDelayCalc(StaState *sta)
PrimaDelayCalc::PrimaDelayCalc(StaState *sta) :
DelayCalcBase(sta),
dcalc_args_(nullptr),
scene_(nullptr),
min_max_(nullptr),
parasitics_(nullptr),
parasitic_network_(nullptr),
load_pin_index_map_(nullptr),
pin_node_map_(network_),
node_index_map_(ParasiticNodeLess(parasitics_, network_)),
prima_order_(3),
make_waveforms_(false),
waveform_drvr_pin_(nullptr),
@ -81,7 +83,7 @@ PrimaDelayCalc::PrimaDelayCalc(const PrimaDelayCalc &dcalc) :
dcalc_args_(nullptr),
load_pin_index_map_(nullptr),
pin_node_map_(network_),
node_index_map_(ParasiticNodeLess(parasitics_, network_)),
node_index_map_(dcalc.node_index_map_),
prima_order_(dcalc.prima_order_),
make_waveforms_(false),
waveform_drvr_pin_(nullptr),
@ -113,27 +115,26 @@ PrimaDelayCalc::copyState(const StaState *sta)
Parasitic *
PrimaDelayCalc::findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
const Corner *corner = dcalc_ap->corner();
const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
// set_load net has precidence over parasitics.
if (sdc_->drvrPinHasWireCap(drvr_pin, corner)
const Sdc *sdc = scene->sdc();
Parasitics *parasitics = scene->parasitics(min_max);
if (parasitics == nullptr
// set_load net has precedence over parasitics.
|| network_->direction(drvr_pin)->isInternal())
return nullptr;
Parasitic *parasitic = parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap);
Parasitic *parasitic = parasitics->findParasiticNetwork(drvr_pin);
if (parasitic)
return parasitic;
const MinMax *cnst_min_max = dcalc_ap->constraintMinMax();
Wireload *wireload = sdc_->wireload(cnst_min_max);
Wireload *wireload = sdc->wireload(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,
graph_delay_calc_->netCaps(drvr_pin, rf, scene, min_max, pin_cap, wire_cap,
fanout, has_wire_cap);
parasitic = parasitics_->makeWireloadNetwork(drvr_pin, wireload,
fanout, cnst_min_max,
parasitic_ap);
parasitic = parasitics->makeWireloadNetwork(drvr_pin, wireload,
fanout, scene, min_max);
}
return parasitic;
}
@ -142,7 +143,8 @@ Parasitic *
PrimaDelayCalc::reduceParasitic(const Parasitic *,
const Pin *,
const RiseFall *,
const DcalcAnalysisPt *)
const Scene *,
const MinMax *)
{
return nullptr;
}
@ -153,18 +155,16 @@ PrimaDelayCalc::inputPortDelay(const Pin *drvr_pin,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
Parasitics *parasitics = scene->parasitics(min_max);
ArcDcalcResult dcalc_result(load_pin_index_map.size());
LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
const Parasitic *pi_elmore = nullptr;
if (parasitic && parasitics_->isParasiticNetwork(parasitic)) {
const ParasiticAnalysisPt *ap = dcalc_ap->parasiticAnalysisPt();
pi_elmore = parasitics_->reduceToPiElmore(parasitic, drvr_pin, rf,
dcalc_ap->corner(),
dcalc_ap->constraintMinMax(), ap);
}
if (parasitic && parasitics->isParasiticNetwork(parasitic))
pi_elmore = parasitics->reduceToPiElmore(parasitic, drvr_pin, rf,
scene, min_max);
for (auto load_pin_index : load_pin_index_map) {
const Pin *load_pin = load_pin_index.first;
@ -174,7 +174,7 @@ PrimaDelayCalc::inputPortDelay(const Pin *drvr_pin,
bool elmore_exists = false;
float elmore = 0.0;
if (pi_elmore)
parasitics_->findElmore(pi_elmore, load_pin, elmore, elmore_exists);
parasitics->findElmore(pi_elmore, 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);
@ -192,33 +192,37 @@ PrimaDelayCalc::gateDelay(const Pin *drvr_pin,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
ArcDcalcArgSeq dcalc_args;
dcalc_args.emplace_back(nullptr, drvr_pin, nullptr, arc, in_slew, load_cap, parasitic);
ArcDcalcResultSeq dcalc_results = gateDelays(dcalc_args, load_pin_index_map, dcalc_ap);
ArcDcalcResultSeq dcalc_results = gateDelays(dcalc_args, load_pin_index_map, scene, min_max);
return dcalc_results[0];
}
ArcDcalcResultSeq
PrimaDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
dcalc_args_ = &dcalc_args;
load_pin_index_map_ = &load_pin_index_map;
drvr_count_ = dcalc_args.size();
dcalc_ap_ = dcalc_ap;
scene_ = scene;
min_max_ = min_max;
drvr_rf_ = dcalc_args[0].arc()->toEdge()->asRiseFall();
parasitic_network_ = dcalc_args[0].parasitic();
load_cap_ = dcalc_args[0].loadCap();
parasitics_ = scene->parasitics(min_max);
node_index_map_ = NodeIndexMap(ParasiticNodeLess(parasitics_, network_));
bool failed = false;
output_waveforms_.resize(drvr_count_);
const DcalcAnalysisPtSeq &dcalc_aps = corners_->dcalcAnalysisPts();
for (size_t drvr_idx = 0; drvr_idx < drvr_count_; drvr_idx++) {
ArcDcalcArg &dcalc_arg = dcalc_args[drvr_idx];
GateTableModel *table_model = dcalc_arg.arc()->gateTableModel(dcalc_ap);
GateTableModel *table_model = dcalc_arg.arc()->gateTableModel(scene, min_max);
if (table_model && dcalc_arg.parasitic()) {
OutputWaveforms *output_waveforms = table_model->outputWaveforms();
float in_slew = dcalc_arg.inSlewFlt();
@ -236,7 +240,7 @@ PrimaDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args,
drvr_library->supplyVoltage("VDD", vdd_, vdd_exists);
if (!vdd_exists)
report_->error(1720, "VDD not defined in library %s", drvr_library->name());
drvr_cell->ensureVoltageWaveforms(dcalc_aps);
drvr_cell->ensureVoltageWaveforms(scenes_);
if (drvr_idx == 0) {
vth_ = drvr_library->outputThreshold(drvr_rf_) * vdd_;
vl_ = drvr_library->slewLowerThreshold(drvr_rf_) * vdd_;
@ -266,11 +270,13 @@ PrimaDelayCalc::tableDcalcResults()
const Pin *drvr_pin = dcalc_arg.drvrPin();
if (drvr_pin) {
const RiseFall *rf = dcalc_arg.drvrEdge();
const Parasitic *parasitic = table_dcalc_->findParasitic(drvr_pin, rf, dcalc_ap_);
const Parasitic *parasitic = table_dcalc_->findParasitic(drvr_pin, rf,
scene_, min_max_);
dcalc_arg.setParasitic(parasitic);
}
}
return table_dcalc_->gateDelays(*dcalc_args_, *load_pin_index_map_, dcalc_ap_);
return table_dcalc_->gateDelays(*dcalc_args_, *load_pin_index_map_,
scene_, min_max_);
}
void
@ -388,8 +394,7 @@ PrimaDelayCalc::driverResistance()
{
const Pin *drvr_pin = (*dcalc_args_)[0].drvrPin();
LibertyPort *drvr_port = network_->libertyPort(drvr_pin);
const MinMax *min_max = dcalc_ap_->delayMinMax();
return drvr_port->driveResistance(drvr_rf_, min_max);
return drvr_port->driveResistance(drvr_rf_, min_max_);
}
void
@ -458,17 +463,16 @@ PrimaDelayCalc::pinCapacitance(ParasiticNode *node)
{
const Pin *pin = parasitics_->pin(node);
float pin_cap = 0.0;
const Sdc *sdc = scene_->sdc();
if (pin) {
Port *port = network_->port(pin);
LibertyPort *lib_port = network_->libertyPort(port);
const Corner *corner = dcalc_ap_->corner();
const MinMax *cnst_min_max = dcalc_ap_->constraintMinMax();
if (lib_port) {
if (!includes_pin_caps_)
pin_cap = sdc_->pinCapacitance(pin, drvr_rf_, corner, cnst_min_max);
pin_cap = sdc->pinCapacitance(pin, drvr_rf_, scene_, min_max_);
}
else if (network_->isTopLevelPort(pin))
pin_cap = sdc_->portExtCap(port, drvr_rf_, corner, cnst_min_max);
pin_cap = sdc->portExtCap(port, drvr_rf_, min_max_);
}
return pin_cap;
}
@ -910,14 +914,15 @@ PrimaDelayCalc::reportGateDelay(const Pin *drvr_pin,
float load_cap,
const Parasitic *,
const LoadPinIndexMap &,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
int digits)
{
GateTimingModel *model = arc->gateModel(dcalc_ap);
GateTimingModel *model = arc->gateModel(scene, min_max);
if (model) {
float in_slew1 = delayAsFloat(in_slew);
return model->reportGateDelay(pinPvt(drvr_pin, dcalc_ap), in_slew1, load_cap,
false, digits);
return model->reportGateDelay(pinPvt(drvr_pin, scene, min_max),
in_slew1, load_cap, false, digits);
}
return "";
}

View File

@ -29,7 +29,6 @@
#include <Eigen/SparseCore>
#include <Eigen/SparseLU>
#include "Map.hh"
#include "LumpedCapDelayCalc.hh"
#include "ArcDcalcWaveforms.hh"
#include "Parasitics.hh"
@ -38,16 +37,16 @@ namespace sta {
class ArcDelayCalc;
class StaState;
class Corner;
class Scene;
typedef Map<const Pin*, size_t, PinIdLess> PinNodeMap;
typedef std::map<const ParasiticNode*, size_t, ParasiticNodeLess> NodeIndexMap;
typedef Map<const Pin*, size_t> PortIndexMap;
typedef Eigen::SparseMatrix<double> MatrixSd;
typedef Map<const Pin*, Eigen::VectorXd, PinIdLess> PinLMap;
typedef std::map<const Pin*, FloatSeq, PinIdLess> WatchPinValuesMap;
using PinNodeMap = std::map<const Pin*, size_t, PinIdLess>;
using NodeIndexMap = std::map<const ParasiticNode*, size_t, ParasiticNodeLess>;
using PortIndexMap = std::map<const Pin*, size_t>;
using MatrixSd = Eigen::SparseMatrix<double>;
using PinLMap = std::map<const Pin*, Eigen::VectorXd, PinIdLess>;
using WatchPinValuesMap = std::map<const Pin*, FloatSeq, PinIdLess>;
typedef Table1 Waveform;
using Waveform = Table1;
ArcDelayCalc *
makePrimaDelayCalc(StaState *sta);
@ -65,35 +64,41 @@ public:
void setPrimaReduceOrder(size_t order);
Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
bool reduceSupported() const override { return false; }
Parasitic *reduceParasitic(const Parasitic *parasitic_network,
const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
ArcDcalcResult inputPortDelay(const Pin *drvr_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) 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;
const Scene *scene,
const MinMax *min_max) override;
ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &dcalc_args,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
std::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,
const Scene *scene,
const MinMax *min_max,
int digits) override;
// Record waveform for drvr/load pin.
@ -147,7 +152,7 @@ protected:
const Pin *drvr_pin,
const RiseFall *drvr_rf,
const Pin *load_pin,
const Corner *corner,
const Scene *scene,
const MinMax *min_max);
void primaReduce();
void primaReduce2();
@ -168,7 +173,9 @@ protected:
ArcDcalcArgSeq *dcalc_args_;
size_t drvr_count_;
float load_cap_;
const DcalcAnalysisPt *dcalc_ap_;
const Scene *scene_;
const MinMax *min_max_;
Parasitics *parasitics_;
const Parasitic *parasitic_network_;
const RiseFall *drvr_rf_;
const LoadPinIndexMap *load_pin_index_map_;

View File

@ -50,7 +50,8 @@ UnitDelayCalc::copy()
Parasitic *
UnitDelayCalc::findParasitic(const Pin *,
const RiseFall *,
const DcalcAnalysisPt *)
const Scene *,
const MinMax *)
{
return nullptr;
}
@ -59,7 +60,8 @@ Parasitic *
UnitDelayCalc::reduceParasitic(const Parasitic *,
const Pin *,
const RiseFall *,
const DcalcAnalysisPt *)
const Scene *,
const MinMax *)
{
return nullptr;
}
@ -67,20 +69,22 @@ UnitDelayCalc::reduceParasitic(const Parasitic *,
void
UnitDelayCalc::reduceParasitic(const Parasitic *,
const Net *,
const Corner *,
const Scene *,
const MinMaxAll *)
{
}
void
UnitDelayCalc::setDcalcArgParasiticSlew(ArcDcalcArg &,
const DcalcAnalysisPt *)
const Scene *,
const MinMax *)
{
}
void
UnitDelayCalc::setDcalcArgParasiticSlew(ArcDcalcArgSeq &,
const DcalcAnalysisPt *)
const Scene *,
const MinMax *)
{
}
@ -90,7 +94,8 @@ UnitDelayCalc::inputPortDelay(const Pin *,
const RiseFall *,
const Parasitic *,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
const Scene *,
const MinMax *)
{
return unitDelayResult(load_pin_index_map);
}
@ -102,7 +107,8 @@ UnitDelayCalc::gateDelay(const Pin *,
float,
const Parasitic *,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
const Scene *,
const MinMax *)
{
return unitDelayResult(load_pin_index_map);
}
@ -110,7 +116,8 @@ UnitDelayCalc::gateDelay(const Pin *,
ArcDcalcResultSeq
UnitDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
const Scene *,
const MinMax *)
{
size_t drvr_count = dcalc_args.size();
ArcDcalcResultSeq dcalc_results(drvr_count);
@ -142,7 +149,8 @@ UnitDelayCalc::reportGateDelay(const Pin *,
float,
const Parasitic *,
const LoadPinIndexMap &,
const DcalcAnalysisPt *,
const Scene *,
const MinMax *,
int)
{
string result("Delay = 1.0\n");
@ -156,7 +164,8 @@ UnitDelayCalc::checkDelay(const Pin *,
const Slew &,
const Slew &,
float,
const DcalcAnalysisPt *)
const Scene *,
const MinMax *)
{
return units_->timeUnit()->scale();
}
@ -168,7 +177,8 @@ UnitDelayCalc::reportCheckDelay(const Pin *,
const char *,
const Slew &,
float,
const DcalcAnalysisPt *,
const Scene *,
const MinMax *,
int)
{
return "Check = 1.0\n";

View File

@ -37,26 +37,31 @@ public:
const char *name() const override { return "unit"; }
Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
bool reduceSupported() const override { return false; }
Parasitic *reduceParasitic(const Parasitic *parasitic_network,
const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
void reduceParasitic(const Parasitic *parasitic_network,
const Net *net,
const Corner *corner,
const Scene *scene,
const MinMaxAll *min_max) override;
void setDcalcArgParasiticSlew(ArcDcalcArg &gate,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
void setDcalcArgParasiticSlew(ArcDcalcArgSeq &gates,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
ArcDcalcResult inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
ArcDcalcResult gateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
@ -64,23 +69,27 @@ public:
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &args,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *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;
const Scene *scene,
const MinMax *min_max) override;
std::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,
const Scene *scene,
const MinMax *min_max,
int digits) override;
std::string reportCheckDelay(const Pin *check_pin,
const TimingArc *arc,
@ -88,7 +97,8 @@ public:
const char *from_slew_annotation,
const Slew &to_slew,
float related_out_cap,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
int digits) override;
void finishDrvrPin() override;

View File

@ -24,6 +24,45 @@
This file summarizes STA API changes for each release.
Release 3.0.0 2025/11/26
------------------------
OpenSTA now requires c++ 20.
Corner replaced by Scene
mode()
parasitics(min_max)
DcalcAnalysisPt replaced by scene/min_min
DcalcAnalysisPt replaced by scene/min_min
PathAnalysisPt replaced by scene/min_min
StaState::sdc_ moved to Mode
StaState::sim_ moved to Mode
StaState::clk_network__ moved to Mode
StaState::parasitics_ moved to Scene
Sta::findPathEnds group_paths arg has been changed from PathGroupNameSet*
to StdStringSeq&.
Sta::isClock has been removed. Use mode->clkNetwork()->isClock instead.
Sta::vertexSlew renamed to slew
Sta::vertexSlack renamed to slack
Sta::vertexSlacks renamed to slacks
Sta::vertexArrival renamed to arrival
Sta::vertexRequired renamed to required
Sta::pinSlack renamed to slack
Sta::pinArrival renamed to arrival
FuncExpr::Operator::op_* renamed to FuncExpr::Op::*
FuncExprPortIterator has been removed. Use FuncExpr::ports().
Sdc::clocks() now returns ClockSeq&.
Sdc::clks() has been removed.
The Vector/Map/Set/UnorderedSet classes have been removed and replaced by
the std containers. The member functions are now templated functions found
in ContainerHelpers.hh.
Release 2.6.2 2025/03/30
------------------------

View File

@ -3,6 +3,180 @@ OpenSTA Timing Analyzer Release Notes
This file summarizes user visible changes for each release.
Release 3.0.0 2025/11/26
------------------------
This release adds multi-corner multi-mode (mcmm) support. The SDC
constraints in each mode describe a different operating mode, such as
mission mode or scan mode.
A "scene" is the combination of a mode and corner. Each scene can have
separate min/max liberty and spef files.
THe basic structure of a multi-corner/multi-mode command file is
read_liberty
read_verilog
link_design
read_sdc -mode... or set_mode followed by sdc commands
read_spef -name...
define_scene...
report_checks [-scenes]
This is an example script with 2 corners, 2 modes and 3 scenes.
read_liberty bc.lib
read_liberty wc.lib
read_verilog design.v
link_design top
read_sdc -mode run design.sdc
read_sdc -mode scan design_scan.sdc
read_spef -name bc bc.spef
read_spef -name wc wc.spef
define_scene bc \
-mode run \
-liberty bc \
-spef bc
define_scene wc \
-mode run \
-liberty wc \
-spef wc
define_scene scan \
-mode scan \
-liberty wc \
-spef wc
report_checks
report_checks -scenes bc
report_checks -scenes wc
report_checks -scenes scan
................
Alternatively, the set_mode command can be used to define commands
for each mode at the command level instead of using SDC files.
set_mode run
create_clock -period 10 clock
set_input_delay 0 -clock clock [all_inputs -no_clocks]
set_output_delay 0 -clock clock [all_outputs]
set_mode scan
create_clock -period 100 scan_clock
set_input_delay 0 -clock scan_clock scan_in
set_output_delay 0 -clock scan_clock scan_out
................
The define_corners command is supported for compatiblity but should
not be used with mcmm flows. Similarly, the -min/-max arguemnts to
read_liberty and read_spaf are supported for compabibility but should
not be used with mcmm flows.
................
An initial mode and scene named "default" are defined for single mode,
single corner analysis. SDC commands defined interactively and read
with read_sdc without a -mode argument are defined in the "default"
mode.
Use the set_mode command to define a mode or set the command
interpreter to add following commands to mode mode_name.
set_mode mode_name
If mode_name does not exist it is created. When modes are created the
default mode is deleted.
The read_sdc command has a -mode argument to assign the commands in the file
to a mode.
read_sdc [-mode mode_name]
If the mode does not exist it is created. Multiple SDC files can
append commands to a mode by using the -mode_name argument for each
one. If no -mode arguement is is used the commands are added to the
current mode.
................
The define_scene command defines a scene for a mode (SDC), liberty files
and spef parasitics.
define_scene -mode mode_name
-liberty liberty_files | -liberty_min liberty_min_files -liberty_max liberty_max_files
[-spef spef_file | -spef_min spef_min_file -spef_max spef_max_file]
Use get_scenes to find defined scenes.
get_scenes [-modes mode_names] scene_name
................
Use the read_spef -name argument to append multiple parasitics files
to annotate hierarchical blocks. Scene definitions use the spef_name
to specify which parasitices to use for each scene.
read_spef -name spef_name
report_parasitic_annotation [-name spef_name]
If -name is omitted the base name of the file name is used.
The read_spef -corner/-min/-max arguments are supported for comppatibility
but will be removed in a future release.
The read_spef -reduce options don't work because sdc, liberty ap isn't known
................
The report_checks and report_check_typescommands support a -scenes
argument to report timing checks/paths from multiple scenes.
report_checks -scenes
report_check_types -scenes
report_slews -scenes
report_clock_latency -scenes
................
To annotate delays with SDF when there are multiple scenes, use
the -scene argument.
read_sdf -scene
report_annotated_delay -scene
report_annotated_check -scene
SDF annotation for mcmm analysis must follow the scene definitions.
................
VCD annotation with read_vcd now supports a -mode arguement.
read_vcd [-mode mode_name]
................
The -corner args has been removed from the following commands because they are no
longer necessary.
set_load -corner
set_port_fanout_number -corner
................
The report_pulse_width_checks command is no longer supported. Use
report_check_types -min_pulse_width.
................
Delay calculation slew values now propagate through set_case_analysis
and set_logic_zero, set_logic_one, set_logic_dc constraints.
Power analysis now ignores set_case_analysis and set_logic_zero,
set_logic_one, set_logic_dc.
Release 2.7.0 2025/05/19
-------------------------
@ -19,6 +193,9 @@ to remove paths through identical pins and rise/fall edges.
Instances now have pins for verilog netlist power/ground connections,
Sta::findPathEnds group_paths arg has been changed from PathGroupNameSet*
to StdStringSeq&.
Release 2.6.1 2025/03/30
-------------------------
@ -93,6 +270,8 @@ timing groups.
report_clock_skew -include_internal_latency
report_clock_latency -include_internal_latency
The report_clock_skew requires a -scene argument if multiple scenes are defined.
The all_inputs command now supports the -no_clocks argument to exclude
clocks from the list.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

2
examples/mcmm2_mode1.sdc Normal file
View File

@ -0,0 +1,2 @@
create_clock -name m1_clk -period 1000 {clk1 clk2 clk3}
set_input_delay -clock m1_clk 100 {in1 in2}

2
examples/mcmm2_mode2.sdc Normal file
View File

@ -0,0 +1,2 @@
create_clock -name m2_clk -period 500 {clk1 clk3}
set_output_delay -clock m2_clk 100 out

18
examples/mcmm3.tcl Normal file
View File

@ -0,0 +1,18 @@
# mmcm reg1 parasitics
read_liberty asap7_small_ff.lib.gz
read_liberty asap7_small_ss.lib.gz
read_verilog reg1_asap7.v
link_design top
read_sdc -mode mode1 mcmm2_mode1.sdc
read_sdc -mode mode2 mcmm2_mode2.sdc
read_spef -name reg1_ff reg1_asap7.spef
read_spef -name reg1_ss reg1_asap7_ss.spef
define_scene scene1 -mode mode1 -liberty asap7_small_ff -spef reg1_ff
define_scene scene2 -mode mode2 -liberty asap7_small_ss -spef reg1_ss
report_checks -scenes scene1
report_checks -scenes scene2
report_checks -group_path_count 4

View File

@ -1,15 +1,20 @@
# 3 corners with +/- 10% derating example
define_corners ss tt ff
read_liberty -corner ss nangate45_slow.lib.gz
read_liberty -corner tt nangate45_typ.lib.gz
read_liberty -corner ff nangate45_fast.lib.gz
# 3 liberty corners with +/- 10% derating example
read_liberty nangate45_slow.lib.gz
read_liberty nangate45_typ.lib.gz
read_liberty nangate45_fast.lib.gz
read_verilog example1.v
link_design top
set_timing_derate -early 0.9
set_timing_derate -late 1.1
create_clock -name clk -period 10 {clk1 clk2 clk3}
set_input_delay -clock clk 0 {in1 in2}
# report all corners
define_scene ss -liberty nangate45_slow
define_scene tt -liberty nangate45_typ
define_scene ff -liberty nangate45_fast
# report all scenes
report_checks -path_delay min_max
# report typical corner
report_checks -corner tt
# report typical scene
report_checks -scene tt

135
examples/reg1_asap7.spef Normal file
View File

@ -0,0 +1,135 @@
*SPEF "IEEE 1481-1998"
*DESIGN "reg1"
*DATE "Fri Nov 20 13:23:00 2002"
*VENDOR "Parallax Software, Inc"
*PROGRAM "Handjob"
*VERSION "1.0.1c"
*DESIGN_FLOW "MISSING_NETS"
*DIVIDER /
*DELIMITER :
*BUS_DELIMITER [ ]
*T_UNIT 1.0 PS
*C_UNIT 1.0 FF
*R_UNIT 1.0 KOHM
*L_UNIT 1.0 UH
*POWER_NETS VDD
*GROUND_NETS VSS
*PORTS
in1 I
in2 I
clk1 I
clk2 I
clk3 I
out O
*D_NET in1 13.4
*CONN
*P in1 I
*I r1:D I *L .0036
*CAP
1 in1 6.7
2 r1:D 6.7
*RES
3 in1 r1:D 2.42
*END
*D_NET in2 13.4
*CONN
*P in2 I
*I r2:D I *L .0036
*CAP
1 in2 6.7
2 r2:D 6.7
*RES
3 in2 r2:D 2.42
*END
*D_NET clk1 13.4
*CONN
*P clk1 I
*I r1:CLK I *L .0036
*CAP
1 clk1 6.7
2 r1:CLK 6.7
*RES
3 clk1 r1:CLK 2.42
*END
*D_NET clk2 13.4
*CONN
*P clk2 I
*I r2:CLK I *L .0036
*CAP
1 clk2 6.7
2 r2:CLK 6.7
*RES
3 clk2 r2:CLK 2.42
*END
*D_NET clk3 13.4
*CONN
*P clk3 I
*I r3:CLK I *L .0036
*CAP
1 clk3 6.7
2 r3:CLK 6.7
*RES
3 clk3 r3:CLK 2.42
*END
*D_NET r1q 13.4
*CONN
*I r1:Q O
*I u2:A I *L .0086
*CAP
1 r1:Q 6.7
2 u2:A 6.7
*RES
3 r1:Q u2:A 2.42
*END
*D_NET r2q 13.4
*CONN
*I r2:Q O
*I u1:A I *L .0086
*CAP
1 r2:Q 6.7
2 u1:A 6.7
*RES
3 r2:Q u1:A 2.42
*END
*D_NET u1z 13.4
*CONN
*I u1:Y O
*I u2:B I *L .0086
*CAP
1 u1:Y 6.7
2 u2:B 6.7
*RES
3 u1:Y u2:B 2.42
*END
*D_NET u2z 13.4
*CONN
*I u2:Y O
*I r3:D I *L .0086
*CAP
1 u2:Y 6.7
2 r3:D 6.7
*RES
3 u2:Y r3:D 2.42
*END
*D_NET out 13.4
*CONN
*I r3:Q O
*P out O
*CAP
1 r3:Q 6.7
2 out 6.7
*RES
3 r3:Q out 2.42
*END

11
examples/reg1_asap7.v Normal file
View File

@ -0,0 +1,11 @@
module top (in1, in2, clk1, clk2, clk3, out);
input in1, in2, clk1, clk2, clk3;
output out;
wire r1q, r2q, u1z, u2z;
DFFHQx4_ASAP7_75t_R r1 (.D(in1), .CLK(clk1), .Q(r1q));
DFFHQx4_ASAP7_75t_R r2 (.D(in2), .CLK(clk2), .Q(r2q));
BUFx2_ASAP7_75t_R u1 (.A(r2q), .Y(u1z));
AND2x2_ASAP7_75t_R u2 (.A(r1q), .B(u1z), .Y(u2z));
DFFHQx4_ASAP7_75t_R r3 (.D(u2z), .CLK(clk3), .Q(out));
endmodule // top

135
examples/reg1_asap7_ss.spef Normal file
View File

@ -0,0 +1,135 @@
*SPEF "IEEE 1481-1998"
*DESIGN "reg1"
*DATE "Fri Nov 20 13:23:00 2002"
*VENDOR "Parallax Software, Inc"
*PROGRAM "Handjob"
*VERSION "1.0.1c"
*DESIGN_FLOW "MISSING_NETS"
*DIVIDER /
*DELIMITER :
*BUS_DELIMITER [ ]
*T_UNIT 1.0 PS
*C_UNIT 1.0 FF
*R_UNIT 1.0 KOHM
*L_UNIT 1.0 UH
*POWER_NETS VDD
*GROUND_NETS VSS
*PORTS
in1 I
in2 I
clk1 I
clk2 I
clk3 I
out O
*D_NET in1 13.4
*CONN
*P in1 I
*I r1:D I *L .0036
*CAP
1 in1 8.1
2 r1:D 8.1
*RES
3 in1 r1:D 2.7
*END
*D_NET in2 13.4
*CONN
*P in2 I
*I r2:D I *L .0036
*CAP
1 in2 8.1
2 r2:D 8.1
*RES
3 in2 r2:D 2.7
*END
*D_NET clk1 13.4
*CONN
*P clk1 I
*I r1:CLK I *L .0036
*CAP
1 clk1 8.1
2 r1:CLK 8.1
*RES
3 clk1 r1:CLK 2.7
*END
*D_NET clk2 13.4
*CONN
*P clk2 I
*I r2:CLK I *L .0036
*CAP
1 clk2 8.1
2 r2:CLK 8.1
*RES
3 clk2 r2:CLK 2.7
*END
*D_NET clk3 13.4
*CONN
*P clk3 I
*I r3:CLK I *L .0036
*CAP
1 clk3 8.1
2 r3:CLK 8.1
*RES
3 clk3 r3:CLK 2.7
*END
*D_NET r1q 13.4
*CONN
*I r1:Q O
*I u2:A I *L .0086
*CAP
1 r1:Q 8.1
2 u2:A 8.1
*RES
3 r1:Q u2:A 2.7
*END
*D_NET r2q 13.4
*CONN
*I r2:Q O
*I u1:A I *L .0086
*CAP
1 r2:Q 8.1
2 u1:A 8.1
*RES
3 r2:Q u1:A 2.7
*END
*D_NET u1z 13.4
*CONN
*I u1:Y O
*I u2:B I *L .0086
*CAP
1 u1:Y 8.1
2 u2:B 8.1
*RES
3 u1:Y u2:B 2.7
*END
*D_NET u2z 13.4
*CONN
*I u2:Y O
*I r3:D I *L .0086
*CAP
1 u2:Y 8.1
2 r3:D 8.1
*RES
3 u2:Y r3:D 2.7
*END
*D_NET out 13.4
*CONN
*I r3:Q O
*P out O
*CAP
1 r3:Q 8.1
2 out 8.1
*RES
3 r3:Q out 2.7
*END

View File

@ -24,6 +24,7 @@
#include "Graph.hh"
#include "ContainerHelpers.hh"
#include "Debug.hh"
#include "Stats.hh"
#include "MinMax.hh"
@ -34,7 +35,6 @@
#include "Liberty.hh"
#include "PortDirection.hh"
#include "Network.hh"
#include "DcalcAnalysisPt.hh"
#include "FuncExpr.hh"
namespace sta {
@ -56,7 +56,7 @@ Graph::Graph(StaState *sta,
slew_rf_count_(slew_rf_count),
ap_count_(ap_count),
period_check_annotations_(nullptr),
reg_clk_vertices_(new VertexSet(graph_))
reg_clk_vertices_(makeVertexSet(this))
{
// For the benifit of reg_clk_vertices_ that references graph_.
graph_ = this;
@ -68,7 +68,6 @@ Graph::~Graph()
delete edges_;
vertices_->clear();
delete vertices_;
delete reg_clk_vertices_;
removePeriodCheckAnnotations();
}
@ -254,7 +253,7 @@ Graph::makeInstDrvrWireEdges(const Instance *inst,
while (pin_iter->hasNext()) {
Pin *pin = pin_iter->next();
if (network_->isDriver(pin)
&& !visited_drvrs.hasKey(pin))
&& !visited_drvrs.contains(pin))
makeWireEdgesFromPin(pin, visited_drvrs);
}
delete pin_iter;
@ -391,6 +390,13 @@ Graph::makeWireEdge(const Pin *from_pin,
}
}
void
Graph::makeSceneAfter()
{
ap_count_ = dcalcAnalysisPtCount();
initSlews();
}
////////////////////////////////////////////////////////////////
Vertex *
@ -440,7 +446,7 @@ Graph::makeVertex(Pin *pin,
vertex->init(pin, is_bidirect_drvr, is_reg_clk);
initSlews(vertex);
if (is_reg_clk)
reg_clk_vertices_->insert(vertex);
reg_clk_vertices_.insert(vertex);
return vertex;
}
@ -452,7 +458,7 @@ Graph::pinVertices(const Pin *pin,
{
vertex = Graph::vertex(network_->vertexId(pin));
if (network_->direction(pin)->isBidirect())
bidirect_drvr_vertex = pin_bidirect_drvr_vertex_map_.findKey(pin);
bidirect_drvr_vertex = findKey(pin_bidirect_drvr_vertex_map_, pin);
else
bidirect_drvr_vertex = nullptr;
}
@ -461,7 +467,7 @@ Vertex *
Graph::pinDrvrVertex(const Pin *pin) const
{
if (network_->direction(pin)->isBidirect())
return pin_bidirect_drvr_vertex_map_.findKey(pin);
return findKey(pin_bidirect_drvr_vertex_map_, pin);
else
return Graph::vertex(network_->vertexId(pin));
}
@ -476,7 +482,7 @@ void
Graph::deleteVertex(Vertex *vertex)
{
if (vertex->isRegClk())
reg_clk_vertices_->erase(vertex);
reg_clk_vertices_.erase(vertex);
Pin *pin = vertex->pin_;
if (vertex->isBidirectDriver())
pin_bidirect_drvr_vertex_map_.erase(pin_bidirect_drvr_vertex_map_
@ -574,30 +580,6 @@ Graph::gateEdgeArc(const Pin *in_pin,
////////////////////////////////////////////////////////////////
Path *
Graph::makePaths(Vertex *vertex,
uint32_t count)
{
Path *paths = new Path[count];
vertex->setPaths(paths);
return paths;
}
Path *
Graph::paths(const Vertex *vertex) const
{
return vertex->paths();
}
void
Graph::deletePaths(Vertex *vertex)
{
vertex->setPaths(nullptr);
vertex->tag_group_index_ = tag_group_index_max;
}
////////////////////////////////////////////////////////////////
const Slew &
Graph::slew(const Vertex *vertex,
const RiseFall *rf,
@ -831,19 +813,6 @@ Graph::initArcDelays(Edge *edge)
arc_delays[i] = 0.0;
}
bool
Graph::delayAnnotated(Edge *edge)
{
TimingArcSet *arc_set = edge->timingArcSet();
for (TimingArc *arc : arc_set->arcs()) {
for (DcalcAPIndex ap_index = 0; ap_index < ap_count_; ap_index++) {
if (!arcDelayAnnotated(edge, arc, ap_index))
return false;
}
}
return true;
}
////////////////////////////////////////////////////////////////
void
@ -906,7 +875,7 @@ Graph::periodCheckAnnotation(const Pin *pin,
{
exists = false;
if (period_check_annotations_) {
float *periods = period_check_annotations_->findKey(pin);
float *periods = findKey(period_check_annotations_, pin);
if (periods) {
period = periods[ap_index];
if (period >= 0.0)
@ -922,7 +891,7 @@ Graph::setPeriodCheckAnnotation(const Pin *pin,
{
if (period_check_annotations_ == nullptr)
period_check_annotations_ = new PeriodCheckAnnotations(network_);
float *periods = period_check_annotations_->findKey(pin);
float *periods = findKey(period_check_annotations_, pin);
if (periods == nullptr) {
periods = new float[ap_count_];
// Use negative (illegal) period values to indicate unannotated checks.
@ -986,16 +955,13 @@ Vertex::init(Pin *pin,
paths_ = nullptr;
tag_group_index_ = tag_group_index_max;
slew_annotated_ = false;
sim_value_ = unsigned(LogicValue::unknown);
is_disabled_constraint_ = false;
is_gated_clk_enable_ = false;
has_checks_ = false;
is_check_clk_ = false;
is_constrained_ = false;
has_downstream_clk_pin_ = false;
level_ = 0;
visited1_ = false;
visited2_ = false;
has_sim_value_ = false;
bfs_in_queue_ = 0;
}
@ -1082,11 +1048,17 @@ Vertex::setSlews(Slew *slews)
slews_ = slews;
}
void
Vertex::setHasSimValue(bool has_sim)
{
has_sim_value_ = has_sim;
}
bool
Vertex::slewAnnotated(const RiseFall *rf,
const MinMax *min_max) const
{
int index = min_max->index() * transitionCount() + rf->index();
int index = min_max->index() * RiseFall::index_count+ rf->index();
return ((1 << index) & slew_annotated_) != 0;
}
@ -1105,7 +1077,7 @@ Vertex::setSlewAnnotated(bool annotated,
// only rise/fall.
if (ap_index > 1)
ap_index = 0;
int index = ap_index * transitionCount() + rf->index();
int index = ap_index * RiseFall::index_count + rf->index();
if (annotated)
slew_annotated_ |= (1 << index);
else
@ -1130,6 +1102,15 @@ Vertex::setTagGroupIndex(TagGroupIndex tag_index)
tag_group_index_ = tag_index;
}
Path *
Vertex::makePaths(uint32_t count)
{
delete [] paths_;
Path *paths = new Path[count];
paths_ = paths;
return paths;
}
void
Vertex::setPaths(Path *paths)
{
@ -1137,30 +1118,12 @@ Vertex::setPaths(Path *paths)
paths_ = paths;
}
LogicValue
Vertex::simValue() const
{
return static_cast<LogicValue>(sim_value_);
}
void
Vertex::setSimValue(LogicValue value)
Vertex::deletePaths()
{
sim_value_ = unsigned(value);
}
bool
Vertex::isConstant() const
{
LogicValue value = static_cast<LogicValue>(sim_value_);
return value == LogicValue::zero
|| value == LogicValue::one;
}
void
Vertex::setIsDisabledConstraint(bool disabled)
{
is_disabled_constraint_ = disabled;
delete [] paths_;
paths_ = nullptr;
tag_group_index_ = tag_group_index_max;
}
bool
@ -1187,18 +1150,6 @@ Vertex::setIsCheckClk(bool is_check_clk)
is_check_clk_ = is_check_clk;
}
void
Vertex::setIsGatedClkEnable(bool enable)
{
is_gated_clk_enable_ = enable;
}
void
Vertex::setIsConstrained(bool constrained)
{
is_constrained_ = constrained;
}
void
Vertex::setHasDownstreamClkPin(bool has_clk_pin)
{
@ -1251,10 +1202,9 @@ Edge::init(VertexId from,
arc_delay_annotated_is_bits_ = true;
arc_delay_annotated_.bits_ = 0;
delay_annotation_is_incremental_ = false;
sim_timing_sense_ = unsigned(TimingSense::unknown);
is_disabled_constraint_ = false;
is_disabled_cond_ = false;
is_disabled_loop_ = false;
has_sim_sense_ = false;
has_disabled_cond_ = false;
}
Edge::~Edge()
@ -1384,48 +1334,6 @@ Edge::sense() const
return arc_set_->sense();
}
TimingSense
Edge::simTimingSense() const
{
return static_cast<TimingSense>(sim_timing_sense_);
}
void
Edge::setSimTimingSense(TimingSense sense)
{
sim_timing_sense_ = unsigned(sense);
}
bool
Edge::isDisabledConstraint() const
{
const TimingRole *role = arc_set_->role();
bool is_wire = role->isWire();
return is_disabled_constraint_
|| arc_set_->isDisabledConstraint()
// set_disable_timing cell does not disable timing checks.
|| (!(role->isTimingCheck() || is_wire)
&& arc_set_->libertyCell()->isDisabledConstraint())
|| (!is_wire
&& arc_set_->from()->isDisabledConstraint())
|| (!is_wire
&& arc_set_->to()->isDisabledConstraint());
}
void
Edge::setIsDisabledConstraint(bool disabled)
{
is_disabled_constraint_ = disabled;
}
void
Edge::setIsDisabledCond(bool disabled)
{
is_disabled_cond_ = disabled;
}
void
Edge::setIsDisabledLoop(bool disabled)
{
@ -1444,6 +1352,18 @@ Edge::setIsBidirectNetPath(bool is_bidir)
is_bidirect_net_path_ = is_bidir;
}
void
Edge::setHasSimSense(bool has_sense)
{
has_sim_sense_ = has_sense;
}
void
Edge::setHasDisabledCond(bool has_disabled)
{
has_disabled_cond_ = has_disabled;
}
////////////////////////////////////////////////////////////////
VertexIterator::VertexIterator(Graph *graph) :
@ -1483,7 +1403,7 @@ VertexIterator::findNextPin()
Pin *pin = pin_iter_->next();
vertex_ = graph_->vertex(network_->vertexId(pin));
bidir_vertex_ = network_->direction(pin)->isBidirect()
? graph_->pin_bidirect_drvr_vertex_map_.findKey(pin)
? findKey(graph_->pin_bidirect_drvr_vertex_map_, pin)
: nullptr;
if (vertex_ || bidir_vertex_)
return true;
@ -1600,7 +1520,19 @@ EdgesThruHierPinIterator::EdgesThruHierPinIterator(const Pin *hpin,
{
FindEdgesThruHierPinVisitor visitor(edges_, graph);
visitDrvrLoadsThruHierPin(hpin, network, &visitor);
edge_iter_.init(edges_);
edge_iter_ = edges_.begin();
}
bool
EdgesThruHierPinIterator::hasNext()
{
return edge_iter_ != edges_.end();
}
Edge *
EdgesThruHierPinIterator::next()
{
return *edge_iter_++;
}
////////////////////////////////////////////////////////////////
@ -1617,9 +1549,5 @@ VertexIdLess::operator()(const Vertex *vertex1,
return graph_->id(vertex1) < graph_->id(vertex2);
}
VertexSet::VertexSet(Graph *&graph) :
Set<Vertex*, VertexIdLess>(VertexIdLess(graph))
{
}
} // namespace

View File

@ -31,8 +31,9 @@
#include "Liberty.hh"
#include "Network.hh"
#include "Clock.hh"
#include "Corner.hh"
#include "Scene.hh"
#include "Search.hh"
#include "Sdc.hh"
#include "Sta.hh"
using namespace sta;
@ -93,21 +94,21 @@ vertex_iterator()
void
set_arc_delay(Edge *edge,
TimingArc *arc,
const Corner *corner,
const Scene *scene,
const MinMaxAll *min_max,
float delay)
{
Sta::sta()->setArcDelay(edge, arc, corner, min_max, delay);
Sta::sta()->setArcDelay(edge, arc, scene, min_max, delay);
}
void
set_annotated_slew(Vertex *vertex,
const Corner *corner,
const Scene *scene,
const MinMaxAll *min_max,
const RiseFallBoth *rf,
float slew)
{
Sta::sta()->setAnnotatedSlew(vertex, corner, min_max, rf, slew);
Sta::sta()->setAnnotatedSlew(vertex, scene, min_max, rf, slew);
}
// Remove all delay and slew annotations.
@ -132,20 +133,20 @@ int level() { return Sta::sta()->vertexLevel(self); }
int tag_group_index() { return self->tagGroupIndex(); }
Slew
slew(const RiseFall *rf,
slew(const RiseFallBoth *rf,
const MinMax *min_max)
{
Sta *sta = Sta::sta();
return sta->vertexSlew(self, rf, min_max);
return sta->slew(self, rf, sta->scenes(), min_max);
}
Slew
slew_corner(const RiseFall *rf,
const Corner *corner,
slew_scenes(const RiseFallBoth *rf,
const SceneSeq scenes,
const MinMax *min_max)
{
Sta *sta = Sta::sta();
return sta->vertexSlew(self, rf, corner, min_max);
return sta->slew(self, rf, scenes, min_max);
}
VertexOutEdgeIterator *
@ -160,162 +161,13 @@ in_edge_iterator()
return new VertexInEdgeIterator(self, Sta::sta()->graph());
}
FloatSeq
arrivals_clk(const RiseFall *rf,
Clock *clk,
const RiseFall *clk_rf)
{
Sta *sta = Sta::sta();
FloatSeq arrivals;
const ClockEdge *clk_edge = nullptr;
if (clk)
clk_edge = clk->edge(clk_rf);
for (auto path_ap : sta->corners()->pathAnalysisPts()) {
arrivals.push_back(delayAsFloat(sta->vertexArrival(self, rf, clk_edge,
path_ap, nullptr)));
}
return arrivals;
}
float
arrival(const MinMax *min_max)
{
Sta *sta = Sta::sta();
return delayAsFloat(sta->vertexArrival(self, min_max));
}
StringSeq
arrivals_clk_delays(const RiseFall *rf,
Clock *clk,
const RiseFall *clk_rf,
int digits)
{
Sta *sta = Sta::sta();
StringSeq arrivals;
const ClockEdge *clk_edge = nullptr;
if (clk)
clk_edge = clk->edge(clk_rf);
for (auto path_ap : sta->corners()->pathAnalysisPts()) {
arrivals.push_back(delayAsString(sta->vertexArrival(self, rf, clk_edge,
path_ap, nullptr),
sta, digits));
}
return arrivals;
}
FloatSeq
requireds_clk(const RiseFall *rf,
Clock *clk,
const RiseFall *clk_rf)
{
Sta *sta = Sta::sta();
FloatSeq reqs;
const ClockEdge *clk_edge = nullptr;
if (clk)
clk_edge = clk->edge(clk_rf);
for (auto path_ap : sta->corners()->pathAnalysisPts()) {
reqs.push_back(delayAsFloat(sta->vertexRequired(self, rf, clk_edge,
path_ap)));
}
return reqs;
}
StringSeq
requireds_clk_delays(const RiseFall *rf,
Clock *clk,
const RiseFall *clk_rf,
int digits)
{
Sta *sta = Sta::sta();
StringSeq reqs;
const ClockEdge *clk_edge = nullptr;
if (clk)
clk_edge = clk->edge(clk_rf);
for (auto path_ap : sta->corners()->pathAnalysisPts()) {
reqs.push_back(delayAsString(sta->vertexRequired(self, rf, clk_edge, path_ap),
sta, digits));
}
return reqs;
}
Slack
slack(MinMax *min_max)
{
Sta *sta = Sta::sta();
return sta->vertexSlack(self, min_max);
}
FloatSeq
slacks(RiseFall *rf)
{
Sta *sta = Sta::sta();
FloatSeq slacks;
for (auto path_ap : sta->corners()->pathAnalysisPts()) {
slacks.push_back(delayAsFloat(sta->vertexSlack(self, rf, path_ap)));
}
return slacks;
}
// Slack with respect to a clock rise/fall edge.
FloatSeq
slacks_clk(const RiseFall *rf,
Clock *clk,
const RiseFall *clk_rf)
{
Sta *sta = Sta::sta();
FloatSeq slacks;
const ClockEdge *clk_edge = nullptr;
if (clk)
clk_edge = clk->edge(clk_rf);
for (auto path_ap : sta->corners()->pathAnalysisPts()) {
slacks.push_back(delayAsFloat(sta->vertexSlack(self, rf, clk_edge,
path_ap)));
}
return slacks;
}
StringSeq
slacks_clk_delays(const RiseFall *rf,
Clock *clk,
const RiseFall *clk_rf,
int digits)
{
Sta *sta = Sta::sta();
StringSeq slacks;
const ClockEdge *clk_edge = nullptr;
if (clk)
clk_edge = clk->edge(clk_rf);
for (auto path_ap : sta->corners()->pathAnalysisPts()) {
slacks.push_back(delayAsString(sta->vertexSlack(self, rf, clk_edge,
path_ap),
sta, digits));
}
return slacks;
}
VertexPathIterator *
path_iterator(const RiseFall *rf,
const MinMax *min_max)
{
return Sta::sta()->vertexPathIterator(self, rf, min_max);
return new VertexPathIterator(self, rf, min_max, Sta::sta());
}
bool
has_downstream_clk_pin()
{
return self->hasDownstreamClkPin();
}
bool
is_clock()
{
Sta *sta = Sta::sta();
Search *search = sta->search();
return search->isClock(self);
}
bool is_disabled_constraint() { return self->isDisabledConstraint(); }
} // Vertex methods
%extend Edge {
@ -328,28 +180,51 @@ const char *sense() { return to_string(self->sense()); }
TimingArcSeq &
timing_arcs() { return self->timingArcSet()->arcs(); }
bool is_disabled_loop() { return Sta::sta()->isDisabledLoop(self); }
bool is_disabled_constraint() { return Sta::sta()->isDisabledConstraint(self);}
bool is_disabled_constant() { return Sta::sta()->isDisabledConstant(self); }
bool is_disabled_constraint()
{
Sta *sta = Sta::sta();
const Sdc *sdc = sta->cmdSdc();
return sta->isDisabledConstraint(self, sdc);
}
bool is_disabled_constant()
{
Sta *sta = Sta::sta();
const Mode *mode = sta->cmdMode();
return sta->isDisabledConstant(self, mode);
}
bool is_disabled_cond_default()
{ return Sta::sta()->isDisabledCondDefault(self); }
PinSet
disabled_constant_pins() { return Sta::sta()->disabledConstantPins(self); }
disabled_constant_pins()
{
Sta *sta = Sta::sta();
const Mode *mode = sta->cmdMode();
return sta->disabledConstantPins(self, mode);
}
bool is_disabled_bidirect_inst_path()
{ return Sta::sta()->isDisabledBidirectInstPath(self); }
bool is_disabled_bidirect_net_path()
{ return Sta::sta()->isDisabledBidirectNetPath(self); }
bool is_disabled_preset_clear()
{ return Sta::sta()->isDisabledPresetClr(self); }
const char *
sim_timing_sense(){return to_string(Sta::sta()->simTimingSense(self));}
sim_timing_sense(){
Sta *sta = Sta::sta();
const Mode *mode = sta->cmdMode();
return to_string(sta->simTimingSense(self, mode));
}
FloatSeq
arc_delays(TimingArc *arc)
{
Sta *sta = Sta::sta();
FloatSeq delays;
for (auto dcalc_ap : sta->corners()->dcalcAnalysisPts())
delays.push_back(delayAsFloat(sta->arcDelay(self, arc, dcalc_ap)));
DcalcAPIndex ap_count = sta->dcalcAnalysisPtCount();
for (DcalcAPIndex ap_index = 0; ap_index < ap_count; ap_index++)
delays.push_back(delayAsFloat(sta->arcDelay(self, arc, ap_index)));
return delays;
}
@ -359,31 +234,31 @@ arc_delay_strings(TimingArc *arc,
{
Sta *sta = Sta::sta();
StringSeq delays;
for (auto dcalc_ap : sta->corners()->dcalcAnalysisPts())
delays.push_back(delayAsString(sta->arcDelay(self, arc, dcalc_ap),
DcalcAPIndex ap_count = sta->dcalcAnalysisPtCount();
for (DcalcAPIndex ap_index = 0; ap_index < ap_count; ap_index++)
delays.push_back(delayAsString(sta->arcDelay(self, arc, ap_index),
sta, digits));
return delays;
}
bool
delay_annotated(TimingArc *arc,
const Corner *corner,
const Scene *scene,
const MinMax *min_max)
{
DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max);
return Sta::sta()->arcDelayAnnotated(self, arc, dcalc_ap);
return Sta::sta()->arcDelayAnnotated(self, arc, scene, min_max);
}
float
arc_delay(TimingArc *arc,
const Corner *corner,
const Scene *scene,
const MinMax *min_max)
{
DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max);
return delayAsFloat(Sta::sta()->arcDelay(self, arc, dcalc_ap));
DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max);
return delayAsFloat(Sta::sta()->arcDelay(self, arc, ap_index));
}
string
std::string
cond()
{
FuncExpr *cond = self->timingArcSet()->cond();

View File

@ -180,10 +180,6 @@ proc edge_disable_reason { edge } {
if { $disables != "" } { append disables ", " }
append disables "bidirect instance path"
}
if [$edge is_disabled_bidirect_net_path] {
if { $disables != "" } { append disables ", " }
append disables "bidirect net path"
}
if { [$edge is_disabled_preset_clear] } {
if { $disables != "" } { append disables ", " }
append disables "sta_preset_clear_arcs_enabled"
@ -295,28 +291,6 @@ proc edge_disable_reason_verbose { edge } {
return $disables
}
################################################################
define_cmd_args "report_slews" {[-corner corner] pin}
proc report_slews { args } {
global sta_report_default_digits
parse_key_args "report_slews" args keys {-corner} flags {}
check_argc_eq1 "report_slews" $args
set corner [parse_corner_or_all keys]
set pin [get_port_pin_error "pin" [lindex $args 0]]
set digits $sta_report_default_digits
foreach vertex [$pin vertices] {
if { $corner == "NULL" } {
report_line "[vertex_path_name $vertex] [rise_short_name] [format_time [$vertex slew rise min] $digits]:[format_time [$vertex slew rise max] $digits] [fall_short_name] [format_time [$vertex slew fall min] $digits]:[format_time [$vertex slew fall max] $digits]"
} else {
report_line "[vertex_path_name $vertex] [rise_short_name] [format_time [$vertex slew_corner rise $corner min] $digits]:[format_time [$vertex slew_corner rise $corner max] $digits] [fall_short_name] [format_time [$vertex slew_corner fall $corner min] $digits]:[format_time [$vertex slew_corner fall $corner max] $digits]"
}
}
}
proc vertex_path_name { vertex } {
set pin [$vertex pin]
set pin_name [get_full_name $pin]

View File

@ -22,6 +22,7 @@
//
// This notice may not be removed or altered from any source distribution.
#include "ContainerHelpers.hh"
#include "StringUtil.hh"
#include "Network.hh"
#include "NetworkCmp.hh"

View File

@ -40,17 +40,16 @@
namespace sta {
class Corner;
class Scene;
class Parasitic;
class DcalcAnalysisPt;
class MultiDrvrNet;
class ArcDcalcArg;
typedef std::vector<ArcDcalcArg*> ArcDcalcArgPtrSeq;
typedef std::vector<ArcDcalcArg> ArcDcalcArgSeq;
using ArcDcalcArgPtrSeq = std::vector<ArcDcalcArg*>;
using ArcDcalcArgSeq = std::vector<ArcDcalcArg>;
// Driver load pin -> index in driver loads.
typedef std::map<const Pin *, size_t, PinIdLess> LoadPinIndexMap;
using LoadPinIndexMap = std::map<const Pin *, size_t, PinIdLess>;
// Arguments for gate delay calculation delay/slew at one driver pin
// through one timing arc at one delay calc analysis point.
@ -81,7 +80,7 @@ public:
const Net *drvrNet(const Network *network) const;
Edge *edge() const { return edge_; }
const TimingArc *arc() const { return arc_; }
Slew inSlew() const { return in_slew_; }
const Slew &inSlew() const { return in_slew_; }
float inSlewFlt() const;
void setInSlew(Slew in_slew);
const Parasitic *parasitic() const { return parasitic_; }
@ -138,8 +137,7 @@ protected:
std::vector<Slew> load_slews_;
};
typedef std::vector<ArcDcalcArg> ArcDcalcArgSeq;
typedef std::vector<ArcDcalcResult> ArcDcalcResultSeq;
using ArcDcalcResultSeq = std::vector<ArcDcalcResult>;
// Delay calculator class hierarchy.
// ArcDelayCalc
@ -160,7 +158,7 @@ typedef std::vector<ArcDcalcResult> ArcDcalcResultSeq;
class ArcDelayCalc : public StaState
{
public:
explicit ArcDelayCalc(StaState *sta);
ArcDelayCalc(StaState *sta);
virtual ~ArcDelayCalc() {}
virtual ArcDelayCalc *copy() = 0;
virtual const char *name() const = 0;
@ -169,25 +167,29 @@ public:
// calculator by probing parasitics_.
virtual Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) = 0;
const Scene *scene,
const MinMax *min_max) = 0;
virtual bool reduceSupported() 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;
const Scene *scene,
const MinMax *min_max) = 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.
// for one or more scenes and min/max rise/fall.
// Null scene means reduce all scenes.
virtual void reduceParasitic(const Parasitic *parasitic_network,
const Net *net,
const Corner *corner,
const Scene *scene,
const MinMaxAll *min_max) = 0;
// Set the in_slew, load_cap, parasitic for gates.
virtual void setDcalcArgParasiticSlew(ArcDcalcArg &gate,
const DcalcAnalysisPt *dcalc_ap) = 0;
const Scene *scene,
const MinMax *min_max) = 0;
virtual void setDcalcArgParasiticSlew(ArcDcalcArgSeq &gates,
const DcalcAnalysisPt *dcalc_ap) = 0;
const Scene *scene,
const MinMax *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 ArcDcalcResult inputPortDelay(const Pin *port_pin,
@ -195,7 +197,8 @@ public:
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) = 0;
const Scene *scene,
const MinMax *min_max) = 0;
// Find the delay and slew for arc driving drvr_pin.
virtual ArcDcalcResult gateDelay(const Pin *drvr_pin,
@ -205,7 +208,8 @@ public:
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) = 0;
const Scene *scene,
const MinMax *min_max) = 0;
// deprecated 2024-02-27
virtual void gateDelay(const TimingArc *arc,
const Slew &in_slew,
@ -213,7 +217,8 @@ public:
const Parasitic *parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew) __attribute__ ((deprecated));
@ -221,7 +226,8 @@ public:
// Find gate delays and slews for parallel gates.
virtual ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &args,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) = 0;
const Scene *scene,
const MinMax *min_max) = 0;
// Find the delay for a timing check arc given the arc's
// from/clock, to/data slews and related output pin parasitic.
@ -230,7 +236,8 @@ public:
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
const DcalcAnalysisPt *dcalc_ap) = 0;
const Scene *scene,
const MinMax *min_max) = 0;
// Report delay and slew calculation.
virtual std::string reportGateDelay(const Pin *drvr_pin,
const TimingArc *arc,
@ -238,7 +245,8 @@ public:
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
int digits) = 0;
// Report timing check delay calculation.
virtual std::string reportCheckDelay(const Pin *check_pin,
@ -247,7 +255,8 @@ public:
const char *from_slew_annotation,
const Slew &to_slew,
float related_out_cap,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
int digits) = 0;
virtual void finishDrvrPin() = 0;
};

View File

@ -34,8 +34,8 @@ struct DdManager;
namespace sta {
typedef std::map<const LibertyPort*, DdNode*, LibertyPortLess> BddPortVarMap;
typedef std::map<unsigned, const LibertyPort*> BddVarIdxPortMap;
using BddPortVarMap = std::map<const LibertyPort*, DdNode*, LibertyPortLess>;
using BddVarIdxPortMap = std::map<unsigned, const LibertyPort*>;
class Bdd : public StaState
{

View File

@ -25,9 +25,9 @@
#pragma once
#include <mutex>
#include <vector>
#include "Iterator.hh"
#include "Set.hh"
#include "GraphClass.hh"
#include "VertexVisitor.hh"
#include "StaState.hh"
@ -39,7 +39,7 @@ class BfsFwdIterator;
class BfsBkwdIterator;
// LevelQueue is a vector of vertex vectors indexed by logic level.
typedef Vector<VertexSeq> LevelQueue;
using LevelQueue = std::vector<VertexSeq>;
// Abstract base class for forward and backward breadth first search iterators.
// Visit all of the vertices at a level before moving to the next.
@ -58,19 +58,19 @@ public:
void ensureSize();
// Reset to virgin state.
void clear();
bool empty() const;
[[nodiscard]] bool empty() const;
// Enqueue a vertex to search from.
void enqueue(Vertex *vertex);
// Enqueue vertices adjacent to a vertex.
void enqueueAdjacentVertices(Vertex *vertex);
void enqueueAdjacentVertices(Vertex *vertex,
SearchPred *search_pred);
void enqueueAdjacentVertices(Vertex *vertex,
Level to_level);
virtual void enqueueAdjacentVertices(Vertex *vertex,
const Mode *mode);
virtual void enqueueAdjacentVertices(Vertex *vertex,
SearchPred *search_pred,
Level to_level) = 0;
bool inQueue(Vertex *vertex);
const Mode *mode) = 0;
virtual void enqueueAdjacentVertices(Vertex *vertex,
SearchPred *search_pred) = 0;
[[nodiscard]] bool inQueue(Vertex *vertex);
void checkInQueue(Vertex *vertex);
// Notify iterator that vertex will be deleted.
void deleteVertexBefore(Vertex *vertex);
@ -131,9 +131,11 @@ public:
SearchPred *search_pred,
StaState *sta);
virtual ~BfsFwdIterator();
virtual void enqueueAdjacentVertices(Vertex *vertex,
SearchPred *search_pred);
virtual void enqueueAdjacentVertices(Vertex *vertex,
SearchPred *search_pred,
Level to_level);
const Mode *mode);
using BfsIterator::enqueueAdjacentVertices;
protected:
@ -151,9 +153,11 @@ public:
SearchPred *search_pred,
StaState *sta);
virtual ~BfsBkwdIterator();
virtual void enqueueAdjacentVertices(Vertex *vertex,
SearchPred *search_pred);
virtual void enqueueAdjacentVertices(Vertex *vertex,
SearchPred *search_pred,
Level to_level);
const Mode *mode);
using BfsIterator::enqueueAdjacentVertices;
protected:

256
include/sta/BoundedHeap.hh Normal file
View File

@ -0,0 +1,256 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software.
//
// Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// This notice may not be removed or altered from any source distribution.
#pragma once
#include <vector>
#include <algorithm>
#include <functional>
namespace sta {
// BoundedHeap: A container that maintains the top N elements using a min-heap.
// This provides O(log n) insertion when the heap is full, O(1) when not full,
// and O(n log n) extraction of all elements. Useful for maintaining top K
// elements without storing all elements.
//
// The heap maintains the "worst" (minimum according to Compare) element at
// the root, so new elements that are better than the worst can replace it.
// For example, with Compare = std::greater<int>, this maintains the N largest
// values (greater values are "better").
//
// Template parameters:
// T: The element type
// Compare: Comparison function object type (default: std::less<T>)
// For top N largest, use std::greater<T>
// For top N smallest, use std::less<T>
template <typename T, typename Compare = std::less<T>>
class BoundedHeap {
public:
using value_type = T;
using size_type = size_t;
using const_reference = const T&;
using compare_type = Compare;
// Constructors
explicit BoundedHeap(size_type max_size,
const Compare& comp = Compare()) :
max_size_(max_size),
comp_(comp),
min_heap_comp_(comp)
{
heap_.reserve(max_size);
}
// Copy constructor
BoundedHeap(const BoundedHeap& other) :
heap_(other.heap_),
max_size_(other.max_size_),
comp_(other.comp_),
min_heap_comp_(other.comp_)
{}
// Assignment operator
BoundedHeap& operator=(const BoundedHeap& other)
{
if (this != &other) {
heap_ = other.heap_;
max_size_ = other.max_size_;
comp_ = other.comp_;
min_heap_comp_ = MinHeapCompare(other.comp_);
}
return *this;
}
// Move constructor
BoundedHeap(BoundedHeap&& other) noexcept :
heap_(std::move(other.heap_)),
max_size_(other.max_size_),
comp_(std::move(other.comp_)),
min_heap_comp_(comp_)
{}
// Move assignment operator
BoundedHeap& operator=(BoundedHeap&& other) noexcept
{
if (this != &other) {
heap_ = std::move(other.heap_);
max_size_ = other.max_size_;
comp_ = std::move(other.comp_);
min_heap_comp_ = MinHeapCompare(comp_);
}
return *this;
}
void
setMaxSize(size_t max_size)
{
max_size_ = max_size;
heap_.reserve(max_size);
}
// Insert an element into the heap.
// If the heap is not full, the element is added.
// If the heap is full and the new element is better than the worst element,
// the worst element is replaced. Otherwise, the element is ignored.
// Returns true if the element was inserted, false if it was ignored.
bool
insert(const T& value) {
if (heap_.size() < max_size_) {
heap_.push_back(value);
std::push_heap(heap_.begin(), heap_.end(), min_heap_comp_);
return true;
}
else if (!heap_.empty()) {
// When keeping N worst (smallest) values: if new value is smaller than worst,
// we should keep it and remove the largest element to make room.
// If new value is larger than worst, we reject it (already have worse values).
// comp_(value, worst) is true when value < worst (value is smaller/worse)
if (comp_(value, heap_.front())) {
// New value is smaller than worst - find and replace the largest element
auto max_it = std::max_element(heap_.begin(), heap_.end(), comp_);
*max_it = value;
// Rebuild heap since we modified an internal element
std::make_heap(heap_.begin(), heap_.end(), min_heap_comp_);
return true;
}
// Otherwise, new value is >= worst, so we already have worse values - reject it
}
return false;
}
// Insert an element using move semantics
bool insert(T&& value)
{
if (heap_.size() < max_size_) {
heap_.push_back(std::move(value));
std::push_heap(heap_.begin(), heap_.end(), min_heap_comp_);
return true;
}
else if (!heap_.empty()) {
// When keeping N worst (smallest) values: if new value is smaller than worst,
// we should keep it and remove the largest element to make room.
// If new value is larger than worst, we reject it (already have worse values).
// comp_(value, worst) is true when value < worst (value is smaller/worse)
if (comp_(value, heap_.front())) {
// New value is smaller than worst - find and replace the largest element
auto max_it = std::max_element(heap_.begin(), heap_.end(), comp_);
*max_it = std::move(value);
// Rebuild heap since we modified an internal element
std::make_heap(heap_.begin(), heap_.end(), min_heap_comp_);
return true;
}
// Otherwise, new value is >= worst, so we already have worse values - reject it
}
return false;
}
// Extract all elements sorted from best to worst.
// This destroys the heap structure but preserves the elements.
std::vector<T> extract()
{
// Convert heap to sorted vector (best to worst)
std::sort_heap(heap_.begin(), heap_.end(), min_heap_comp_);
// Reverse to get best first (according to user's comparison)
std::reverse(heap_.begin(), heap_.end());
std::vector<T> result = std::move(heap_);
heap_.clear();
return result;
}
// Extract all elements sorted from best to worst (const version).
// Creates a copy since we can't modify the heap.
std::vector<T> extract() const
{
std::vector<T> temp_heap = heap_;
std::sort_heap(temp_heap.begin(), temp_heap.end(), min_heap_comp_);
std::reverse(temp_heap.begin(), temp_heap.end());
return temp_heap;
}
// Get the worst element (the one that would be replaced next).
// Requires !empty()
const_reference worst() const
{
return heap_.front();
}
// Check if the heap is empty
bool empty() const
{
return heap_.empty();
}
// Get the current number of elements in the heap
size_type size() const
{
return heap_.size();
}
// Get the maximum size of the heap
size_type max_size() const
{
return max_size_;
}
// Check if the heap is full
bool full() const
{
return heap_.size() >= max_size_;
}
// Clear all elements from the heap
void clear()
{
heap_.clear();
}
// Get the comparison function
Compare compare() const
{
return comp_;
}
private:
std::vector<T> heap_;
size_type max_size_;
Compare comp_;
// Helper comparator for min-heap: we want the worst element at root
// so we can easily remove it when adding better elements.
// This is the inverse of the user's comparison.
struct MinHeapCompare
{
Compare comp_;
explicit MinHeapCompare(const Compare& c) : comp_(c) {}
bool operator()(const T& a, const T& b) const {
return comp_(b, a); // Inverted: worst is at root
}
};
MinHeapCompare min_heap_comp_;
};
} // namespace sta

View File

@ -24,8 +24,8 @@
#pragma once
#include "Map.hh"
#include "Set.hh"
#include <map>
#include "StaState.hh"
#include "NetworkClass.hh"
#include "GraphClass.hh"
@ -33,31 +33,34 @@
namespace sta {
typedef Map<const Pin*, ClockSet> PinClksMap;
typedef Map<const Clock *, PinSet*> ClkPinsMap;
using PinClksMap = std::map<const Pin*, ClockSet>;
using ClkPinsMap = std::map<const Clock *, PinSet*>;
class Sta;
// Find clock network pins.
// This is not as reliable as Search::isClock but is much cheaper.
class ClkNetwork : public StaState
{
public:
ClkNetwork(StaState *sta);
ClkNetwork(Mode *mode,
StaState *sta);
~ClkNetwork();
void ensureClkNetwork();
void clear();
bool isClock(const Pin *pin) const;
bool isClock(const Vertex *vertex) const;
bool isClock(const Net *net) const;
bool isIdealClock(const Pin *pin) const;
bool isIdealClock(const Vertex *vertex) const;
bool isPropagatedClock(const Pin *pin) const;
const ClockSet *clocks(const Pin *pin);
const ClockSet *idealClocks(const Pin *pin);
const ClockSet *clocks(const Pin *pin) const;
const ClockSet *clocks(const Vertex *vertex) const;
const ClockSet *idealClocks(const Pin *pin) const;
const PinSet *pins(const Clock *clk);
void clkPinsInvalid();
float idealClkSlew(const Pin *pin,
const RiseFall *rf,
const MinMax *min_max);
const MinMax *min_max) const;
protected:
void deletePinBefore(const Pin *pin);
@ -66,6 +69,8 @@ protected:
friend class Sta;
private:
Mode *mode_;
void findClkPins();
void findClkPins(bool ideal_only,
PinClksMap &clk_pin_map);

View File

@ -24,6 +24,8 @@
#pragma once
#include <map>
#include "MinMax.hh"
#include "RiseFallMinMax.hh"
#include "SdcClass.hh"
@ -32,7 +34,7 @@
namespace sta {
typedef Map<Pin*, PinSet*> ClkHpinEdgeMap;
using ClkHpinEdgeMap = std::map<Pin*, PinSet*>;
class Clock : public SdcCmdComment
{
@ -264,7 +266,7 @@ public:
const RiseFallBoth *tgt_rf,
const SetupHoldAll *setup_hold);
const RiseFallMinMax *uncertainties(const RiseFall *src_rf) const;
bool empty() const;
[[nodiscard]] bool empty() const;
private:
const Clock *src_;

View File

@ -25,9 +25,9 @@
#pragma once
#include <functional>
#include <vector>
#include <map>
#include "Vector.hh"
#include "Map.hh"
#include "StringUtil.hh"
#include "NetworkClass.hh"
@ -45,17 +45,17 @@ class PatternMatch;
class LibertyCell;
class LibertyPort;
typedef Map<std::string, ConcreteCell*> ConcreteCellMap;
typedef Vector<ConcretePort*> ConcretePortSeq;
typedef Map<std::string, ConcretePort*> ConcretePortMap;
typedef ConcreteCellMap::ConstIterator ConcreteLibraryCellIterator;
typedef ConcretePortSeq::ConstIterator ConcreteCellPortIterator;
typedef ConcretePortSeq::ConstIterator ConcretePortMemberIterator;
using ConcreteCellMap = std::map<std::string, ConcreteCell*>;
using ConcretePortSeq = std::vector<ConcretePort*>;
using ConcretePortMap = std::map<std::string, ConcretePort*>;
using ConcreteLibraryCellIterator = MapIterator<ConcreteCellMap, ConcreteCell*>;
using ConcreteCellPortIterator = VectorIterator<ConcretePortSeq, ConcretePort*>;
using ConcretePortMemberIterator = VectorIterator<ConcretePortSeq, ConcretePort*>;
class ConcreteLibrary
{
public:
explicit ConcreteLibrary(const char *name,
ConcreteLibrary(const char *name,
const char *filename,
bool is_liberty);
virtual ~ConcreteLibrary();
@ -263,14 +263,15 @@ private:
class ConcreteCellPortBitIterator : public Iterator<ConcretePort*>
{
public:
explicit ConcreteCellPortBitIterator(const ConcreteCell *cell);
ConcreteCellPortBitIterator(const ConcreteCell *cell);
virtual bool hasNext();
virtual ConcretePort *next();
private:
void findNext();
ConcretePortSeq::ConstIterator port_iter_;
const ConcretePortSeq &ports_;
ConcretePortSeq::const_iterator port_iter_;
ConcretePortMemberIterator *member_iter_;
ConcretePort *next_;
};

View File

@ -25,9 +25,10 @@
#pragma once
#include <functional>
#include <vector>
#include <map>
#include <set>
#include "Map.hh"
#include "Set.hh"
#include "StringUtil.hh"
#include "Network.hh"
#include "LibertyClass.hh"
@ -45,16 +46,14 @@ class ConcretePort;
class ConcreteBindingTbl;
class ConcreteLibertyLibraryIterator;
typedef Vector<ConcreteLibrary*> ConcreteLibrarySeq;
typedef Map<const char*, ConcreteLibrary*, CharPtrLess> ConcreteLibraryMap;
typedef ConcreteLibrarySeq::ConstIterator ConcreteLibraryIterator;
typedef Map<const char *, ConcreteInstance*,
CharPtrLess> ConcreteInstanceChildMap;
typedef Map<const char *, ConcreteNet*, CharPtrLess> ConcreteInstanceNetMap;
typedef Vector<ConcreteNet*> ConcreteNetSeq;
typedef Vector<ConcretePin*> ConcretePinSeq;
typedef Map<Cell*, Instance*> CellNetworkViewMap;
typedef Set<const ConcreteNet*> ConcreteNetSet;
using ConcreteLibrarySeq = std::vector<ConcreteLibrary*>;
using ConcreteLibraryMap = std::map<const char*, ConcreteLibrary*, CharPtrLess>;
using ConcreteInstanceChildMap = std::map<const char *, ConcreteInstance*, CharPtrLess>;
using ConcreteInstanceNetMap = std::map<const char *, ConcreteNet*, CharPtrLess>;
using ConcreteNetSeq = std::vector<ConcreteNet*>;
using ConcretePinSeq = std::vector<ConcretePin*>;
using CellNetworkViewMap = std::map<Cell*, Instance*>;
using ConcreteNetSet = std::set<const ConcreteNet*>;
// This adapter implements the network api for the concrete network.
// A superset of the Network api methods are implemented in the interface.

View File

@ -0,0 +1,381 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software.
//
// Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// This notice may not be removed or altered from any source distribution.
#pragma once
#include <type_traits>
#include <utility> // for std::declval
#include <map>
#include <set>
#include <vector>
#include <algorithm>
#include <ranges>
#include <functional>
namespace sta {
// C++ kung foo courtesy of chat gtp.
// ------------------------------------------------------------
// 1. Sequence containers (vector<T*>, list<T*>, deque<T*>, …)
// ------------------------------------------------------------
template <typename Container>
std::enable_if_t<std::is_pointer_v<typename Container::value_type>>
deleteContents(Container& c)
{
for (auto ptr : c)
delete ptr;
c.clear();
}
template <typename Container>
std::enable_if_t<std::is_pointer_v<typename Container::value_type>>
deleteContents(Container *c)
{
for (auto ptr : *c)
delete ptr;
c->clear();
}
// ------------------------------------------------------------
// 2. Maps (map<K, T*>, unordered_map<K, T*>)
// ------------------------------------------------------------
template <typename Map>
std::enable_if_t<std::is_pointer_v<typename Map::mapped_type>
>
deleteContents(Map& m)
{
for (auto& kv : m)
delete kv.second;
m.clear();
}
template <typename Map>
std::enable_if_t<std::is_pointer_v<typename Map::mapped_type>
>
deleteContents(Map *m)
{
for (auto& kv : *m)
delete kv.second;
m->clear();
}
// ------------------------------------------------------------
// 3. Sets (set<T*>, unordered_set<T*>)
// ------------------------------------------------------------
template <typename Set>
std::enable_if_t<
std::is_pointer_v<typename Set::value_type> &&
!std::is_same_v<typename Set::value_type, typename Set::mapped_type>
>
deleteContents(Set& s)
{
for (auto ptr : s)
delete ptr;
s.clear();
}
////////////////////////////////////////////////////////////////
// detect whether container has mapped_type
template<typename, typename = void>
struct has_mapped_type : std::false_type {};
template<typename T>
struct has_mapped_type<T, std::void_t<typename T::mapped_type>>
: std::true_type {};
// handle pointer types
template<typename T>
struct has_mapped_type<T*, void> : has_mapped_type<T> {};
// return-type chooser: use struct, NOT alias template
template<typename C, bool = has_mapped_type<C>::value>
struct find_return;
// pointer to map
template<typename C>
struct find_return<C*, true>
{
using type = typename C::mapped_type;
};
// pointer to set
template<typename C>
struct find_return<C*, false>
{
using type = typename C::key_type;
};
// map ref
template<typename C>
struct find_return<C, true>
{
using type = typename C::mapped_type;
};
// set ref
template<typename C>
struct find_return<C, false>
{
using type = typename C::key_type;
};
// Find an value in a contaiiner of pointers.
// return nullptr if not found.
template<typename AssocContainer>
auto
findKey(const AssocContainer& c,
typename AssocContainer::key_type key)
-> typename find_return<AssocContainer>::type
{
using ReturnType = typename find_return<AssocContainer>::type;
static_assert(std::is_pointer_v<ReturnType>,
"findKey requires pointer types");
auto it = c.find(key);
if (it == c.end())
return nullptr;
if constexpr (has_mapped_type<AssocContainer>::value)
return it->second; // map
else
return *it; // set
}
// Find an value in a contaiiner of pointers.
// return nullptr if not found.
template<typename AssocContainer>
auto
findKey(const AssocContainer* c,
typename AssocContainer::key_type key)
-> typename find_return<AssocContainer>::type
{
using ReturnType = typename find_return<AssocContainer>::type;
static_assert(std::is_pointer_v<ReturnType>,
"findKey requires pointer types");
auto it = c->find(key);
if (it == c->end())
return nullptr;
if constexpr (has_mapped_type<AssocContainer>::value)
// map
return it->second;
else
// set
return *it;
}
template<typename AssocContainer>
void
findKeyValue(const AssocContainer& c,
typename AssocContainer::key_type key,
typename find_return<AssocContainer>::type &value,
bool &exists)
{
auto it = c.find(key);
if (it == c.end()) {
exists = false;
return;
}
if constexpr (has_mapped_type<AssocContainer>::value) {
// map
value = it->second;
exists = true;
}
else {
// set
value = *it;
exists = true;
}
}
template<typename AssocContainer>
void
findKeyValue(const AssocContainer *c,
typename AssocContainer::key_type key,
typename find_return<AssocContainer>::type &value,
bool &exists)
{
auto it = c->find(key);
if (it == c->end()) {
exists = false;
return;
}
if constexpr (has_mapped_type<AssocContainer>::value) {
// map
value = it->second;
exists = true;
}
else {
// set
value = *it;
exists = true;
}
}
template<typename AssocContainer>
auto
findKeyValuePtr(AssocContainer& c,
typename AssocContainer::key_type key)
-> typename find_return<AssocContainer>::type*
{
auto it = c.find(key);
if (it == c.end())
return nullptr;
if constexpr (has_mapped_type<AssocContainer>::value)
// map
return &it->second;
else
// set
return *it;
}
////////////////////////////////////////////////////////////////
// Determine if two std::set's intersect.
// Returns true if there is at least one common element.
template <typename Set>
bool
intersects(const Set &set1,
const Set &set2,
typename Set::key_compare key_less)
{
auto iter1 = set1.begin();
auto end1 = set1.end();
auto iter2 = set2.begin();
auto end2 = set2.end();
while (iter1 != end1 && iter2 != end2) {
if (key_less(*iter1, *iter2))
iter1++;
else if (key_less(*iter2, *iter1))
iter2++;
else
return true;
}
return false;
}
// Determine if two std::set's intersect (pointer version).
// Returns true if there is at least one common element.
template <typename Set>
bool
intersects(const Set *set1,
const Set *set2,
typename Set::key_compare key_less)
{
if (set1 && set2) {
auto iter1 = set1->begin();
auto end1 = set1->end();
auto iter2 = set2->begin();
auto end2 = set2->end();
while (iter1 != end1 && iter2 != end2) {
if (key_less(*iter1, *iter2))
iter1++;
else if (key_less(*iter2, *iter1))
iter2++;
else
return true;
}
}
return false;
}
////////////////////////////////////////////////////////////////
// Compare set contents.
template <typename Set>
int
compare(const Set *set1,
const Set *set2,
typename Set::key_compare key_less)
{
size_t size1 = set1 ? set1->size() : 0;
size_t size2 = set2 ? set2->size() : 0;
if (size1 == size2) {
if (set1 == nullptr || set2 == nullptr) {
// Both are null or empty, so they're equal
return 0;
}
auto iter1 = set1->begin();
auto iter2 = set2->begin();
auto end1 = set1->end();
auto end2 = set2->end();
while (iter1 != end1 && iter2 != end2) {
if (key_less(*iter1, *iter2))
return -1;
else if (key_less(*iter2, *iter1))
return 1;
++iter1;
++iter2;
}
// Sets are equal.
return 0;
}
else
return (size1 > size2) ? 1 : -1;
}
////////////////////////////////////////////////////////////////
// Sort functions that do not require begin()/end() range.
// reference arg
template<std::ranges::random_access_range Range,
typename Comp = std::less<>>
requires std::predicate<Comp&,
std::ranges::range_reference_t<Range>,
std::ranges::range_reference_t<Range>>
void
sort(Range& r,
Comp comp = Comp{})
{
std::sort(std::ranges::begin(r), std::ranges::end(r), comp);
}
// pointer arg
template<typename Range,
typename Comp = std::less<>>
requires std::ranges::random_access_range<Range> &&
std::predicate<Comp&,
std::ranges::range_reference_t<Range>,
std::ranges::range_reference_t<Range>>
void
sort(Range* r,
Comp comp = Comp{})
{
std::sort(std::ranges::begin(*r), std::ranges::end(*r), comp);
}
} // namespace

View File

@ -1,139 +0,0 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software.
//
// Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// This notice may not be removed or altered from any source distribution.
#pragma once
#include "MinMax.hh"
#include "Vector.hh"
#include "StringSet.hh"
#include "GraphClass.hh"
#include "SearchClass.hh"
#include "StaState.hh"
namespace sta {
class ParasiticAnalysisPt;
class DcalcAnalysisPt;
class PathAnalysisPt;
class Corner;
class Corners;
class LibertyLibrary;
typedef Vector<Corner*> CornerSeq;
typedef Map<const char *, Corner*, CharPtrLess> CornerMap;
typedef Vector<ParasiticAnalysisPt*> ParasiticAnalysisPtSeq;
typedef Vector<DcalcAnalysisPt*> DcalcAnalysisPtSeq;
typedef Vector<PathAnalysisPt*> PathAnalysisPtSeq;
typedef Vector<LibertyLibrary*> LibertySeq;
class Corners : public StaState
{
public:
explicit Corners(StaState *sta);
~Corners();
void clear();
int count() const;
void copy(Corners *corners);
bool multiCorner() const;
Corner *findCorner(const char *corner);
Corner *findCorner(int corner_index);
void makeCorners(StringSet *corner_names);
void analysisTypeChanged();
void operatingConditionsChanged();
// Make one parasitic analysis points.
void makeParasiticAnalysisPts(bool per_corner);
int parasiticAnalysisPtCount() const;
ParasiticAnalysisPtSeq &parasiticAnalysisPts();
DcalcAPIndex dcalcAnalysisPtCount() const;
DcalcAnalysisPtSeq &dcalcAnalysisPts();
const DcalcAnalysisPtSeq &dcalcAnalysisPts() const;
PathAPIndex pathAnalysisPtCount() const;
PathAnalysisPt *findPathAnalysisPt(PathAPIndex path_index) const;
PathAnalysisPtSeq &pathAnalysisPts();
const PathAnalysisPtSeq &pathAnalysisPts() const;
CornerSeq &corners() { return corners_; }
// Iterators for range iteration.
// for (auto corner : *sta->corners()) {}
CornerSeq::iterator begin() { return corners_.begin(); }
CornerSeq::iterator end() { return corners_.end(); }
protected:
void makeAnalysisPts();
void makeDcalcAnalysisPts(Corner *corner);
DcalcAnalysisPt *makeDcalcAnalysisPt(Corner *corner,
const MinMax *min_max,
const MinMax *check_clk_slew_min_max);
void makePathAnalysisPts(Corner *corner);
void makePathAnalysisPts(Corner *corner,
bool swap_clk_min_max,
DcalcAnalysisPt *dcalc_ap_min,
DcalcAnalysisPt *dcalc_ap_max);
private:
CornerMap corner_map_;
CornerSeq corners_;
ParasiticAnalysisPtSeq parasitic_analysis_pts_;
DcalcAnalysisPtSeq dcalc_analysis_pts_;
PathAnalysisPtSeq path_analysis_pts_;
};
class Corner
{
public:
Corner(const char *name,
int index);
const char *name() const { return name_.c_str(); }
int index() const { return index_; }
ParasiticAnalysisPt *findParasiticAnalysisPt(const MinMax *min_max) const;
int parasiticAnalysisPtcount();
DcalcAnalysisPt *findDcalcAnalysisPt(const MinMax *min_max) const;
PathAnalysisPt *findPathAnalysisPt(const MinMax *min_max) const;
void addLiberty(LibertyLibrary *lib,
const MinMax *min_max);
const LibertySeq &libertyLibraries(const MinMax *min_max) const;
int libertyIndex(const MinMax *min_max) const;
protected:
void setParasiticAnalysisPtcount(int ap_count);
void setParasiticAP(ParasiticAnalysisPt *path_ap,
int mm_index);
void setDcalcAnalysisPtcount(DcalcAPIndex ap_count);
void addDcalcAP(DcalcAnalysisPt *dcalc_ap);
void addPathAP(PathAnalysisPt *path_ap);
private:
std::string name_;
int index_;
ParasiticAnalysisPtSeq parasitic_analysis_pts_;
DcalcAnalysisPtSeq dcalc_analysis_pts_;
PathAnalysisPtSeq path_analysis_pts_;
LibertySeq liberty_[MinMax::index_count];
friend class Corners;
};
} // namespace

View File

@ -24,7 +24,8 @@
#pragma once
#include "UnorderedSet.hh"
#include <unordered_set>
#include "MinMax.hh"
#include "TimingRole.hh"
#include "StaState.hh"
@ -52,7 +53,9 @@ public:
const CycleAccting *acct2) const;
};
typedef UnorderedSet<CycleAccting*, CycleAcctingHash, CycleAcctingEqual> CycleAcctingSet;
using CycleAcctingSet = std::unordered_set<CycleAccting*,
CycleAcctingHash,
CycleAcctingEqual>;
class CycleAcctings
{

View File

@ -55,7 +55,7 @@ public:
void removeMargin(const RiseFallBoth *from_rf,
const RiseFallBoth *to_rf,
const SetupHoldAll *setup_hold);
bool empty() const;
[[nodiscard]] bool empty() const;
void marginIsOneValue(const SetupHold *setup_hold,
// Return values.
float &value,

View File

@ -1,81 +0,0 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software.
//
// Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// This notice may not be removed or altered from any source distribution.
#pragma once
#include "Iterator.hh"
#include "MinMax.hh"
#include "LibertyClass.hh"
#include "SdcClass.hh"
#include "ParasiticsClass.hh"
#include "GraphClass.hh"
#include "StaState.hh"
namespace sta {
class Corner;
// Delay calculation analysis point.
// This collects all of the parameters used to find one set of
// delay calculation results.
class DcalcAnalysisPt
{
public:
DcalcAnalysisPt(Corner *corner,
DcalcAPIndex index,
const OperatingConditions *op_cond,
const MinMax *min_max,
const MinMax *check_clk_slew_min_max);
Corner *corner() const { return corner_; }
// Which of the delay_count results this analysis point corresponds to.
DcalcAPIndex index() const { return index_; }
// Slew index of timing check data.
DcalcAPIndex checkDataSlewIndex() const { return index_; }
// Slew index of timing check clock.
DcalcAPIndex checkClkSlewIndex() const { return check_clk_slew_index_; }
// Slew min/max of timing check clock.
const MinMax *checkClkSlewMinMax() const { return check_clk_slew_min_max_; }
// Constraint min/max values to use.
const MinMax *constraintMinMax() const { return min_max_; }
// Constraints::operatingCondition(cnst_min_max_)
const OperatingConditions *operatingConditions() const { return op_cond_; }
void setOperatingConditions(const OperatingConditions *op_cond);
// Delay merging min/max operator (for wires).
const MinMax *delayMinMax() const { return min_max_; }
// Merge min/max slews across timing arcs.
const MinMax *slewMinMax() const { return min_max_; }
ParasiticAnalysisPt *parasiticAnalysisPt() const;
void setCheckClkSlewIndex(DcalcAPIndex index);
int libertyIndex() const;
private:
Corner *corner_;
DcalcAPIndex index_;
DcalcAPIndex check_clk_slew_index_;
const OperatingConditions *op_cond_;
const MinMax *min_max_;
const MinMax *check_clk_slew_min_max_;
};
} // namespace

View File

@ -24,10 +24,11 @@
#pragma once
#include <string>
#include <cstdarg>
#include <map>
#include <mutex>
#include "Map.hh"
#include "StringUtil.hh"
namespace sta {
@ -35,13 +36,12 @@ namespace sta {
class Report;
class Pin;
typedef Map<const char *, int, CharPtrLess> DebugMap;
using DebugMap = std::map<std::string, int>;
class Debug
{
public:
explicit Debug(Report *report);
~Debug();
Debug(Report *report);
int level(const char *what);
void setLevel(const char *what,
int level);
@ -57,18 +57,15 @@ protected:
Report *report_;
std::mutex buffer_lock_;
bool debug_on_;
DebugMap *debug_map_;
DebugMap debug_map_;
int stats_level_;
};
// Inlining a varargs function would eval the args, which can
// be expensive, so use a macro.
// Note that "##__VA_ARGS__" is a gcc extension to support zero arguments (no comma).
// clang -Wno-gnu-zero-variadic-macro-arguments suppresses the warning.
// c++20 has "__VA_OPT__" to deal with the zero arg case so this is temporary.
#define debugPrint(debug, what, level, ...) \
if (debug->check(what, level)) { \
debug->reportLine(what, ##__VA_ARGS__); \
debug->reportLine(what __VA_OPT__(,) __VA_ARGS__); \
}
} // namespace

View File

@ -41,10 +41,10 @@
namespace sta {
typedef Delay ArcDelay;
typedef Delay Slew;
typedef Delay Arrival;
typedef Delay Required;
typedef Delay Slack;
using ArcDelay = Delay;
using Slew = Delay;
using Arrival = Delay;
using Required = Delay;
using Slack = Delay;
} // namespace

View File

@ -31,7 +31,7 @@ namespace sta {
class ArcDelayCalc;
class StaState;
typedef ArcDelayCalc *(*MakeArcDelayCalc)(StaState *sta);
using MakeArcDelayCalc = ArcDelayCalc *(*)(StaState *sta);
// Register builtin delay calculators.
void

View File

@ -32,9 +32,9 @@ namespace sta {
class StaState;
typedef float Delay;
using Delay = float;
// Delay double for accumulating Delays.
typedef double DelayDbl;
using DelayDbl = double;
const Delay delay_zero = 0.0;

View File

@ -24,7 +24,9 @@
#pragma once
#include "Map.hh"
#include <set>
#include <vector>
#include "NetworkClass.hh"
#include "LibertyClass.hh"
#include "SdcClass.hh"
@ -35,10 +37,10 @@ class TimingRole;
class DisabledCellPorts;
class DisabledInstancePorts;
typedef Vector<DisabledInstancePorts*> DisabledInstancePortsSeq;
typedef Vector<DisabledCellPorts*> DisabledCellPortsSeq;
typedef Vector<LibertyPortPair> LibertyPortPairSeq;
typedef Set<TimingArcSet*> TimingArcSetSet;
using DisabledInstancePortsSeq = std::vector<DisabledInstancePorts*>;
using DisabledCellPortsSeq = std::vector<DisabledCellPorts*>;
using LibertyPortPairSeq = std::vector<LibertyPortPair>;
using TimingArcSetSet = std::set<TimingArcSet*, TimingArcSetLess>;
// Base class for disabled cell and instance ports.
class DisabledPorts
@ -56,13 +58,13 @@ public:
LibertyPort *to);
void removeDisabledFromTo(LibertyPort *from,
LibertyPort *to);
bool isDisabled(LibertyPort *from,
[[nodiscard]] bool isDisabled(LibertyPort *from,
LibertyPort *to,
const TimingRole *role);
LibertyPortPairSet *fromTo() const { return from_to_; }
LibertyPortSet *from() const { return from_; }
LibertyPortSet *to() const { return to_; }
bool all() const { return all_; }
[[nodiscard]] bool all() const { return all_; }
private:
bool all_;
@ -80,7 +82,7 @@ public:
LibertyCell *cell() const { return cell_; }
void setDisabled(TimingArcSet *arc_set);
void removeDisabled(TimingArcSet *arc_set);
bool isDisabled(TimingArcSet *arc_set) const;
[[nodiscard]] bool isDisabled(TimingArcSet *arc_set) const;
TimingArcSetSet *timingArcSets() const { return arc_sets_; }
using DisabledPorts::isDisabled;
@ -102,7 +104,7 @@ private:
};
DisabledCellPortsSeq
sortByName(DisabledCellPortsMap *cell_map);
sortByName(const DisabledCellPortsMap *cell_map);
DisabledInstancePortsSeq
sortByPathName(const DisabledInstancePortsMap *inst_map,
const Network *network);

View File

@ -24,15 +24,15 @@
#pragma once
#include "Vector.hh"
#include "Map.hh"
#include "UnorderedMap.hh"
#include <map>
#include <unordered_map>
#include "LibertyClass.hh"
namespace sta {
typedef Map<LibertyCell*, LibertyCellSeq*> EquivCellMap;
typedef UnorderedMap<unsigned, LibertyCellSeq*> LibertyCellHashMap;
using EquivCellMap = std::map<LibertyCell*, LibertyCellSeq*>;
using LibertyCellHashMap = std::unordered_map<unsigned, LibertyCellSeq*>;
class EquivCells
{

View File

@ -67,7 +67,7 @@ protected:
class FileNotReadable : public Exception
{
public:
explicit FileNotReadable(const char *filename);
FileNotReadable(const char *filename);
virtual const char *what() const noexcept;
protected:
@ -78,7 +78,7 @@ protected:
class FileNotWritable : public Exception
{
public:
explicit FileNotWritable(const char *filename);
FileNotWritable(const char *filename);
virtual const char *what() const noexcept;
protected:

View File

@ -24,8 +24,9 @@
#pragma once
#include <vector>
#include "Error.hh"
#include "Set.hh"
#include "SdcCmdComment.hh"
#include "SdcClass.hh"
@ -44,7 +45,7 @@ class ExceptionThru;
class ExceptionTo;
class ExceptionState;
typedef Vector<ExceptionPath*> ExceptionPathSeq;
using ExceptionPathSeq = std::vector<ExceptionPath*>;
class ExceptionPath : public SdcCmdComment
{
@ -593,14 +594,14 @@ exceptionThrusClone(ExceptionThruSeq *thrus,
class ExceptionPtIterator
{
public:
explicit ExceptionPtIterator(const ExceptionPath *exception);
ExceptionPtIterator(const ExceptionPath *exception);
bool hasNext();
ExceptionPt *next();
private:
const ExceptionPath *exception_;
bool from_done_;
ExceptionThruSeq::Iterator thru_iter_;
ExceptionThruSeq::iterator thru_iter_;
bool to_done_;
};
@ -667,8 +668,8 @@ private:
int index_;
};
bool
exceptionStateLess(const ExceptionState *state1,
int
exceptionStateCmp(const ExceptionState *state1,
const ExceptionState *state2);
// Exception thrown by check.

View File

@ -26,7 +26,6 @@
#include <string>
#include "Set.hh"
#include "NetworkClass.hh"
#include "LibertyClass.hh"
@ -35,16 +34,16 @@ namespace sta {
class FuncExpr
{
public:
enum Operator {op_port,
op_not,
op_or,
op_and,
op_xor,
op_one,
op_zero};
enum class Op {port,
not_,
or_,
and_,
xor_,
one,
zero};
// Constructors.
FuncExpr(Operator op,
FuncExpr(Op op,
FuncExpr *left,
FuncExpr *right,
LibertyPort *port);
@ -67,14 +66,15 @@ public:
FuncExpr *copy();
// Delete expression and all of its subexpressions.
void deleteSubexprs();
// op == op_port
// op == port
LibertyPort *port() const;
Operator op() const { return op_; }
Op op() const { return op_; }
// When operator is NOT left is the only operand.
FuncExpr *left() const { return left_; }
// nullptr when op == op_not
// nullptr when op == not_
FuncExpr *right() const { return right_; }
TimingSense portTimingSense(const LibertyPort *port) const;
LibertyPortSet ports() const;
// Return true if expression has port as an input.
bool hasPort(const LibertyPort *port) const;
std::string to_string() const;
@ -86,11 +86,14 @@ public:
bool checkSize(LibertyPort *port);
private:
void findPorts(const FuncExpr *expr,
LibertyPortSet &ports) const;
std::string to_string(bool with_parens) const;
std::string to_string(bool with_parens,
char op) const;
Operator op_;
Op op_;
FuncExpr *left_;
FuncExpr *right_;
LibertyPort *port_;
@ -100,18 +103,4 @@ private:
FuncExpr *
funcExprNot(FuncExpr *expr);
class FuncExprPortIterator : public Iterator<LibertyPort*>
{
public:
explicit FuncExprPortIterator(const FuncExpr *expr);
virtual bool hasNext() { return iter_.hasNext(); }
virtual LibertyPort *next() { return iter_.next(); }
private:
void findPorts(const FuncExpr *expr);
LibertyPortSet ports_;
LibertyPortSet::ConstIterator iter_;
};
} // namespace

View File

@ -26,10 +26,9 @@
#include <mutex>
#include <atomic>
#include <map>
#include "Iterator.hh"
#include "Map.hh"
#include "Vector.hh"
#include "ObjectTable.hh"
#include "LibertyClass.hh"
#include "NetworkClass.hh"
@ -44,12 +43,12 @@ namespace sta {
class MinMax;
class Sdc;
typedef ObjectTable<Vertex> VertexTable;
typedef ObjectTable<Edge> EdgeTable;
typedef Map<const Pin*, Vertex*> PinVertexMap;
typedef Iterator<Edge*> VertexEdgeIterator;
typedef Map<const Pin*, float*, PinIdLess> PeriodCheckAnnotations;
typedef ObjectId EdgeId;
using VertexTable = ObjectTable<Vertex>;
using EdgeTable = ObjectTable<Edge>;
using PinVertexMap = std::map<const Pin*, Vertex*>;
using VertexEdgeIterator = Iterator<Edge*>;
using PeriodCheckAnnotations = std::map<const Pin*, float*, PinIdLess>;
using EdgeId = ObjectId;
static constexpr EdgeId edge_id_null = object_id_null;
static constexpr ObjectIdx edge_idx_null = object_id_null;
@ -94,10 +93,6 @@ public:
void deleteVertex(Vertex *vertex);
bool hasFaninOne(Vertex *vertex) const;
VertexId vertexCount() { return vertices_->size(); }
Path *makePaths(Vertex *vertex,
uint32_t count);
Path *paths(const Vertex *vertex) const;
void deletePaths(Vertex *vertex);
// Reported slew are the same as those in the liberty tables.
// reported_slews = measured_slews / slew_derate_from_library
@ -163,8 +158,6 @@ public:
const RiseFall *rf,
DcalcAPIndex ap_index,
bool annotated);
// True if any edge arc is annotated.
bool delayAnnotated(Edge *edge);
void minPulseWidthArc(Vertex *vertex,
const RiseFall *hi_low,
@ -188,7 +181,8 @@ public:
// Remove all delay and slew annotations.
void removeDelaySlewAnnotations();
VertexSet *regClkVertices() { return reg_clk_vertices_; }
VertexSet &regClkVertices() { return reg_clk_vertices_; }
void makeSceneAfter();
static constexpr int vertex_level_bits = 24;
static constexpr int vertex_level_max = (1<<vertex_level_bits)-1;
@ -233,7 +227,7 @@ protected:
// Sdf period check annotations.
PeriodCheckAnnotations *period_check_annotations_;
// Register/latch clock vertices to search from.
VertexSet *reg_clk_vertices_;
VertexSet reg_clk_vertices_;
friend class Vertex;
friend class VertexIterator;
@ -253,21 +247,23 @@ public:
std::string to_string(const StaState *sta) const;
// compatibility
const char *name(const Network *network) const;
bool isBidirectDriver() const { return is_bidirect_drvr_; }
bool isDriver(const Network *network) const;
[[nodiscard]] bool isBidirectDriver() const { return is_bidirect_drvr_; }
[[nodiscard]] bool isDriver(const Network *network) const;
Level level() const { return level_; }
void setLevel(Level level);
bool visited() const { return visited1_; }
[[nodiscard]] bool visited() const { return visited1_; }
void setVisited(bool visited);
bool visited2() const { return visited2_; }
[[nodiscard]] bool visited2() const { return visited2_; }
void setVisited2(bool visited);
bool isRoot() const{ return level_ == 0; }
bool hasFanin() const;
bool hasFanout() const;
[[nodiscard]] bool isRoot() const{ return level_ == 0; }
[[nodiscard]] bool hasFanin() const;
[[nodiscard]] bool hasFanout() const;
Slew *slews() { return slews_; }
const Slew *slews() const { return slews_; }
Path *paths() const { return paths_; }
Path *makePaths(uint32_t count);
void setPaths(Path *paths);
void deletePaths();
TagGroupIndex tagGroupIndex() const;
void setTagGroupIndex(TagGroupIndex tag_index);
// Slew is annotated by sdc set_annotated_transition cmd.
@ -279,38 +275,24 @@ public:
const RiseFall *rf,
DcalcAPIndex ap_index);
void removeSlewAnnotated();
// Constant zero/one from simulation.
bool isConstant() const;
LogicValue simValue() const;
void setSimValue(LogicValue value);
bool isDisabledConstraint() const { return is_disabled_constraint_; }
void setIsDisabledConstraint(bool disabled);
// True when vertex has timing check edges that constrain it.
bool hasChecks() const { return has_checks_; }
[[nodiscard]] bool hasChecks() const { return has_checks_; }
void setHasChecks(bool has_checks);
bool isCheckClk() const { return is_check_clk_; }
[[nodiscard]] bool isCheckClk() const { return is_check_clk_; }
void setIsCheckClk(bool is_check_clk);
bool isGatedClkEnable() const { return is_gated_clk_enable_; }
void setIsGatedClkEnable(bool enable);
bool hasDownstreamClkPin() const { return has_downstream_clk_pin_; }
[[nodiscard]] bool hasDownstreamClkPin() const { return has_downstream_clk_pin_; }
void setHasDownstreamClkPin(bool has_clk_pin);
// Vertices are constrained if they have one or more of the
// following timing constraints:
// output delay constraints
// data check constraints
// path delay constraints
bool isConstrained() const { return is_constrained_; }
void setIsConstrained(bool constrained);
bool bfsInQueue(BfsIndex index) const;
[[nodiscard]] bool bfsInQueue(BfsIndex index) const;
void setBfsInQueue(BfsIndex index, bool value);
bool isRegClk() const { return is_reg_clk_; }
[[nodiscard]] bool isRegClk() const { return is_reg_clk_; }
// Has sim value in some mode.
[[nodiscard]] bool hasSimValue() const { return has_sim_value_; }
void setHasSimValue(bool has_sim);
// ObjectTable interface.
ObjectIdx objectIdx() const { return object_idx_; }
[[nodiscard]] ObjectIdx objectIdx() const { return object_idx_; }
void setObjectIdx(ObjectIdx idx);
static int transitionCount() { return 2; } // rise/fall
protected:
void init(Pin *pin,
bool is_bidirect_drvr,
@ -336,23 +318,19 @@ protected:
int level_:Graph::vertex_level_bits; // 24
unsigned int slew_annotated_:slew_annotated_bits; // 4
// LogicValue gcc barfs if this is dcl'd.
unsigned sim_value_:3;
// Bidirect pins have two vertices.
// This flag distinguishes the driver and load vertices.
bool is_bidirect_drvr_:1;
bool is_reg_clk_:1;
bool is_disabled_constraint_:1;
bool is_gated_clk_enable_:1;
// Constrained by timing check edge.
bool has_checks_:1;
// Is the clock for a timing check.
bool is_check_clk_:1;
bool is_constrained_:1;
bool has_downstream_clk_pin_:1;
bool visited1_:1;
bool visited2_:1;
bool has_sim_value_;
private:
friend class Graph;
@ -382,18 +360,8 @@ public:
void setArcDelays(ArcDelay *arc_delays);
bool delay_Annotation_Is_Incremental() const {return delay_annotation_is_incremental_;};
void setDelayAnnotationIsIncremental(bool is_incr);
// Edge is disabled by set_disable_timing constraint.
bool isDisabledConstraint() const;
void setIsDisabledConstraint(bool disabled);
// Timing sense for the to_pin function after simplifying the
// function based constants on the instance pins.
TimingSense simTimingSense() const;
void setSimTimingSense(TimingSense sense);
// Edge is disabled by constants in condition (when) function.
bool isDisabledCond() const { return is_disabled_cond_; }
void setIsDisabledCond(bool disabled);
// Edge is disabled to break combinational loops.
bool isDisabledLoop() const { return is_disabled_loop_; }
[[nodiscard]] bool isDisabledLoop() const { return is_disabled_loop_; }
void setIsDisabledLoop(bool disabled);
// Edge is disabled to prevent converging clocks from merging (Xilinx).
bool isBidirectInstPath() const { return is_bidirect_inst_path_; }
@ -401,6 +369,10 @@ public:
bool isBidirectNetPath() const { return is_bidirect_net_path_; }
void setIsBidirectNetPath(bool is_bidir);
void removeDelayAnnotated();
[[nodiscard]] bool hasSimSense() const { return has_sim_sense_; }
void setHasSimSense(bool has_sense);
[[nodiscard]] bool hasDisabledCond() const { return has_disabled_cond_; }
void setHasDisabledCond(bool has_disabled);
// ObjectTable interface.
ObjectIdx objectIdx() const { return object_idx_; }
@ -435,11 +407,9 @@ protected:
bool delay_annotation_is_incremental_:1;
bool is_bidirect_inst_path_:1;
bool is_bidirect_net_path_:1;
// Timing sense from function and constants on edge instance.
unsigned sim_timing_sense_:timing_sense_bit_count;
bool is_disabled_constraint_:1;
bool is_disabled_cond_:1;
bool is_disabled_loop_:1;
bool has_sim_sense_:1;
bool has_disabled_cond_:1;
unsigned object_idx_:VertexTable::idx_bits;
private:
@ -456,7 +426,7 @@ private:
class VertexIterator : public Iterator<Vertex*>
{
public:
explicit VertexIterator(Graph *graph);
VertexIterator(Graph *graph);
virtual bool hasNext() { return vertex_ || bidir_vertex_; }
virtual Vertex *next();
@ -508,29 +478,19 @@ public:
EdgesThruHierPinIterator(const Pin *hpin,
Network *network,
Graph *graph);
virtual bool hasNext() { return edge_iter_.hasNext(); }
virtual Edge *next() { return edge_iter_.next(); }
virtual bool hasNext();
virtual Edge *next();
private:
EdgeSet edges_;
EdgeSet::Iterator edge_iter_;
EdgeSet::iterator edge_iter_;
};
class VertexIdLess
// Helper function to create a VertexSet with the comparator initialized
inline VertexSet
makeVertexSet(StaState *sta)
{
public:
VertexIdLess(Graph *&graph);
bool operator()(const Vertex *vertex1,
const Vertex *vertex2) const;
private:
Graph *&graph_;
};
class VertexSet : public Set<Vertex*, VertexIdLess>
{
public:
VertexSet(Graph *&graph);
};
return VertexSet(VertexIdLess(sta->graphRef()));
}
} // namespace

View File

@ -25,10 +25,10 @@
#pragma once
#include <limits>
#include <vector>
#include <set>
#include "ObjectId.hh"
#include "Set.hh"
#include "Vector.hh"
#include "MinMax.hh"
#include "Transition.hh"
#include "Delay.hh"
@ -42,19 +42,29 @@ class Edge;
class VertexIterator;
class VertexInEdgeIterator;
class VertexOutEdgeIterator;
class GraphLoop;
class VertexSet;
typedef ObjectId VertexId;
typedef ObjectId EdgeId;
typedef Vector<Vertex*> VertexSeq;
typedef Vector<Edge*> EdgeSeq;
typedef Set<Edge*> EdgeSet;
typedef int Level;
typedef int DcalcAPIndex;
typedef int TagGroupIndex;
typedef Vector<GraphLoop*> GraphLoopSeq;
typedef std::vector<Slew> SlewSeq;
class VertexIdLess
{
public:
VertexIdLess() = delete;
VertexIdLess(Graph *&graph);
bool operator()(const Vertex *vertex1,
const Vertex *vertex2) const;
private:
Graph *&graph_;
};
using VertexId = ObjectId;
using EdgeId = ObjectId;
using VertexSeq = std::vector<Vertex*>;
using VertexSet = std::set<Vertex*, VertexIdLess>;
using EdgeSeq = std::vector<Edge*>;
using EdgeSet = std::set<Edge*>;
using Level = int;
using DcalcAPIndex = int;
using TagGroupIndex = int;
using SlewSeq = std::vector<Slew>;
static constexpr int level_max = std::numeric_limits<Level>::max();

View File

@ -33,7 +33,7 @@ namespace sta {
class VertexNameLess
{
public:
explicit VertexNameLess(Network *network);
VertexNameLess(Network *network);
bool operator()(const Vertex *vertex1,
const Vertex *vertex2);

View File

@ -24,15 +24,15 @@
#pragma once
#include <vector>
#include <mutex>
#include <array>
#include <vector>
#include <map>
#include <mutex>
#include "Map.hh"
#include "NetworkClass.hh"
#include "GraphClass.hh"
#include "SearchClass.hh"
#include "DcalcAnalysisPt.hh"
#include "SdcClass.hh"
#include "StaState.hh"
#include "ArcDelayCalc.hh"
@ -42,9 +42,10 @@ class DelayCalcObserver;
class MultiDrvrNet;
class FindVertexDelays;
class NetCaps;
class SearchPred;
typedef Map<const Vertex*, MultiDrvrNet*> MultiDrvrNetMap;
typedef std::vector<SlewSeq> DrvrLoadSlews;
using MultiDrvrNetMap = std::map<const Vertex*, MultiDrvrNet*>;
using DrvrLoadSlews = std::vector<SlewSeq>;
// This class traverses the graph calling the arc delay calculator and
// annotating delays on graph edges.
@ -73,7 +74,7 @@ public:
// Returned string is owned by the caller.
virtual std::string reportDelayCalc(const Edge *edge,
const TimingArc *arc,
const Corner *corner,
const Scene *scene,
const MinMax *min_max,
int digits);
// Percentage (0.0:1.0) change in delay that causes downstream
@ -82,19 +83,23 @@ public:
virtual void setIncrementalDelayTolerance(float tol);
float loadCap(const Pin *drvr_pin,
const DcalcAnalysisPt *dcalc_ap) const;
const Scene *scene,
const MinMax *min_max) const;
float loadCap(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) const;
const Scene *scene,
const MinMax *min_max) const;
void loadCap(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
// Return values.
float &pin_cap,
float &wire_cap) const;
void netCaps(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
// Return values.
float &pin_cap,
float &wire_cap,
@ -102,7 +107,8 @@ public:
bool &has_set_load) const;
void parasiticLoad(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
const MultiDrvrNet *multi_drvr,
ArcDelayCalc *arc_delay_calc,
// Return values.
@ -112,14 +118,15 @@ public:
void findDriverArcDelays(Vertex *drvr_vertex,
Edge *edge,
const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
ArcDelayCalc *arc_delay_calc);
// Precedence:
// SDF annotation
// Liberty port timing group timing_type minimum_period.
// Liberty port min_period attribute.
void minPeriod(const Pin *pin,
const Corner *corner,
const Scene *scene,
// Return values.
float &min_period,
bool &exists);
@ -127,11 +134,13 @@ public:
Slew edgeFromSlew(const Vertex *from_vertex,
const RiseFall *from_rf,
const Edge *edge,
const DcalcAnalysisPt *dcalc_ap);
const Scene *scene,
const MinMax *min_max);
Slew edgeFromSlew(const Vertex *from_vertex,
const RiseFall *from_rf,
const TimingRole *role,
const DcalcAnalysisPt *dcalc_ap);
const Scene *scene,
const MinMax *min_max);
bool bidirectDrvrSlewFromLoad(const Pin *pin) const;
protected:
@ -145,13 +154,15 @@ protected:
void seedNoDrvrSlew(Vertex *drvr_vertex,
const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
ArcDelayCalc *arc_delay_calc);
void seedNoDrvrCellSlew(Vertex *drvr_vertex,
const Pin *drvr_pin,
const RiseFall *rf,
const InputDrive *drive,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
ArcDelayCalc *arc_delay_calc);
void seedLoadSlew(Vertex *vertex);
void setInputPortWireDelays(Vertex *vertex);
@ -162,7 +173,8 @@ protected:
const LibertyPort *from_port,
float *from_slews,
const LibertyPort *to_port,
const DcalcAnalysisPt *dcalc_ap);
const Scene *scene,
const MinMax *min_max);
LibertyPort *driveCellDefaultFromPort(const LibertyCell *cell,
const LibertyPort *to_port);
int findPortIndex(const LibertyCell *cell,
@ -171,7 +183,8 @@ protected:
Vertex *drvr_vertex,
const TimingArc *arc,
float from_slew,
const DcalcAnalysisPt *dcalc_ap);
const Scene *scene,
const MinMax *min_max);
void findDriverDelays(Vertex *drvr_vertex,
ArcDelayCalc *arc_delay_calc,
LoadPinIndexMap &load_pin_index_map);
@ -196,14 +209,16 @@ protected:
const MultiDrvrNet *multi_drvr,
Edge *edge,
const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
ArcDelayCalc *arc_delay_calc,
LoadPinIndexMap &load_pin_index_map);
ArcDcalcArgSeq makeArcDcalcArgs(Vertex *drvr_vertex,
const MultiDrvrNet *multi_drvr,
Edge *edge,
const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
ArcDelayCalc *arc_delay_calc);
void findParallelEdge(Vertex *vertex,
const TimingArc *drvr_arc,
@ -225,34 +240,40 @@ protected:
const TimingArc *arc,
ArcDcalcResult &dcalc_result,
LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap);
const Scene *scene,
const MinMax *min_max);
bool annotateDelaySlew(Edge *edge,
const TimingArc *arc,
ArcDelay &gate_delay,
Slew &gate_slew,
const DcalcAnalysisPt *dcalc_ap);
const Scene *scene,
const MinMax *min_max);
bool annotateLoadDelays(Vertex *drvr_vertex,
const RiseFall *drvr_rf,
ArcDcalcResult &dcalc_result,
LoadPinIndexMap &load_pin_index_map,
const ArcDelay &extra_delay,
bool merge,
const DcalcAnalysisPt *dcalc_ap);
const Scene *scene,
const MinMax *min_max);
void findLatchEdgeDelays(Edge *edge);
void findCheckEdgeDelays(Edge *edge,
ArcDelayCalc *arc_delay_calc);
void deleteMultiDrvrNets();
Slew checkEdgeClkSlew(const Vertex *from_vertex,
const RiseFall *from_rf,
const DcalcAnalysisPt *dcalc_ap);
const Scene *scene,
const MinMax *min_max);
float loadCap(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
ArcDelayCalc *arc_delay_calc) const;
void parasiticLoad(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
const MultiDrvrNet *multi_drvr,
ArcDelayCalc *arc_delay_calc,
// Return values.
@ -261,7 +282,8 @@ protected:
const Parasitic *&parasitic) const;
void netCaps(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
const MultiDrvrNet *multi_drvr,
// Return values.
float &pin_cap,
@ -275,7 +297,7 @@ protected:
bool incremental_;
bool delays_exist_;
// Vertices with invalid -to delays.
VertexSet *invalid_delays_;
VertexSet invalid_delays_;
// Timing check edges with invalid delays.
EdgeSet invalid_check_edges_;
// Latch D->Q edges with invalid delays.
@ -284,7 +306,6 @@ protected:
std::mutex invalid_edge_lock_;
SearchPred *search_pred_;
SearchPred *search_non_latch_pred_;
SearchPred *clk_pred_;
BfsFwdIterator *iter_;
MultiDrvrNetMap multi_drvr_net_map_;
std::mutex multi_drvr_lock_;
@ -319,13 +340,14 @@ public:
Vertex *dcalcDrvr() const { return dcalc_drvr_; }
void setDcalcDrvr(Vertex *drvr);
void netCaps(const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
// Return values.
float &pin_cap,
float &wire_cap,
float &fanout,
bool &has_net_load) const;
void findCaps(const Sdc *sdc);
void findCaps(const StaState *sta);
private:
// Driver that triggers delay calculation for all the drivers on the net.

View File

@ -24,7 +24,6 @@
#pragma once
#include "Set.hh"
#include "NetworkClass.hh"
namespace sta {

View File

@ -40,7 +40,7 @@ class InputDriveCell;
class InputDrive
{
public:
explicit InputDrive();
InputDrive();
~InputDrive();
void setSlew(const RiseFallBoth *rf,
const MinMaxAll *min_max,

View File

@ -81,7 +81,7 @@ protected:
class InternalPowerModel
{
public:
explicit InternalPowerModel(TableModel *model);
InternalPowerModel(TableModel *model);
~InternalPowerModel();
float power(const LibertyCell *cell,
const Pvt *pvt,

View File

@ -40,4 +40,80 @@ public:
virtual OBJ next() = 0;
};
template <typename VECTOR_TYPE, typename OBJ_TYPE>
class VectorIterator : public Iterator<OBJ_TYPE>
{
public:
VectorIterator(const VECTOR_TYPE *seq) :
seq_(seq)
{
if (seq_)
itr_ = seq_->begin();
}
VectorIterator(const VECTOR_TYPE &seq) :
seq_(&seq),
itr_(seq.begin())
{
}
bool hasNext() { return seq_ && itr_ != seq_->end(); }
OBJ_TYPE next() { return *itr_++; }
protected:
const VECTOR_TYPE *seq_;
VECTOR_TYPE::const_iterator itr_;
};
template <typename MAP_TYPE, typename OBJ_TYPE>
class MapIterator : public Iterator<OBJ_TYPE>
{
public:
MapIterator(const MAP_TYPE *map) :
map_(map)
{
if (map)
itr_ = map->begin();
}
MapIterator(const MAP_TYPE &map) :
map_(&map),
itr_(map.begin())
{
}
bool hasNext() { return map_ && itr_ != map_->end(); }
OBJ_TYPE next() {
OBJ_TYPE next = itr_->second;
itr_++;
return next;
}
protected:
const MAP_TYPE *map_;
MAP_TYPE::const_iterator itr_;
};
template <typename SET_TYPE, typename OBJ_TYPE>
class SetIterator : public Iterator<OBJ_TYPE>
{
public:
SetIterator(const SET_TYPE *set) :
set_(set)
{
if (set)
itr_ = set->begin();
}
SetIterator(const SET_TYPE &set) :
set_(&set),
itr_(set.begin())
{
}
bool hasNext() { return set_ && itr_ != set_->end(); }
OBJ_TYPE next() { return *itr_++; }
protected:
const SET_TYPE *set_;
SET_TYPE::const_iterator itr_;
};
} // namespace

View File

@ -27,7 +27,11 @@
#include <mutex>
#include <atomic>
#include <functional>
#include <set>
#include <map>
#include <vector>
#include "ContainerHelpers.hh"
#include "MinMax.hh"
#include "RiseFallMinMax.hh"
#include "ConcreteLibrary.hh"
@ -56,40 +60,37 @@ class OcvDerate;
class TimingArcAttrs;
class InternalPowerAttrs;
class StaState;
class Corner;
class Corners;
class DcalcAnalysisPt;
class Scene;
class DriverWaveform;
typedef Map<const char*, TableTemplate*, CharPtrLess> TableTemplateMap;
typedef Vector<TableTemplate*> TableTemplateSeq;
typedef Map<const char*, BusDcl *, CharPtrLess> BusDclMap;
typedef Vector<BusDcl *> BusDclSeq;
typedef Map<const char*, ScaleFactors*, CharPtrLess> ScaleFactorsMap;
typedef Map<const char*, Wireload*, CharPtrLess> WireloadMap;
typedef Map<const char*, WireloadSelection*, CharPtrLess> WireloadSelectionMap;
typedef Map<const char*, OperatingConditions*,
CharPtrLess> OperatingConditionsMap;
typedef Map<LibertyPort*, Sequential*> PortToSequentialMap;
typedef Vector<TimingArcSet*> TimingArcSetSeq;
typedef Set<TimingArcSet*, TimingArcSetLess> TimingArcSetMap;
typedef Map<LibertyPortPair, TimingArcSetSeq*,
LibertyPortPairLess> LibertyPortPairTimingArcMap;
typedef Vector<InternalPower*> InternalPowerSeq;
typedef Map<const LibertyPort *, InternalPowerSeq> PortInternalPowerSeq;
typedef Vector<LeakagePower*> LeakagePowerSeq;
typedef Map<const LibertyPort*, TimingArcSetSeq*> LibertyPortTimingArcMap;
typedef Map<const OperatingConditions*, LibertyCell*> ScaledCellMap;
typedef Map<const OperatingConditions*, LibertyPort*> ScaledPortMap;
typedef Map<const char *, ModeDef*, CharPtrLess> ModeDefMap;
typedef Map<const char *, ModeValueDef*, CharPtrLess> ModeValueMap;
typedef Map<const TimingArcSet*, LatchEnable*> LatchEnableMap;
typedef Vector<LatchEnable*> LatchEnableSeq;
typedef Map<const char *, OcvDerate*, CharPtrLess> OcvDerateMap;
typedef Vector<InternalPowerAttrs*> InternalPowerAttrsSeq;
typedef Map<std::string, float> SupplyVoltageMap;
typedef Map<std::string, DriverWaveform*> DriverWaveformMap;
typedef Vector<DcalcAnalysisPt*> DcalcAnalysisPtSeq;
using TableTemplateMap = std::map<const char*, TableTemplate*, CharPtrLess>;
using TableTemplateSeq = std::vector<TableTemplate*>;
using BusDclMap = std::map<const char*, BusDcl *, CharPtrLess>;
using BusDclSeq = std::vector<BusDcl *>;
using ScaleFactorsMap = std::map<const char*, ScaleFactors*, CharPtrLess>;
using WireloadMap = std::map<const char*, Wireload*, CharPtrLess>;
using WireloadSelectionMap = std::map<const char*, WireloadSelection*, CharPtrLess>;
using OperatingConditionsMap = std::map<const char*, OperatingConditions*, CharPtrLess>;
using PortToSequentialMap = std::map<LibertyPort*, Sequential*>;
using TimingArcSetSeq = std::vector<TimingArcSet*>;
using TimingArcSetSet = std::set<TimingArcSet*, TimingArcSetLess>;
using LibertyPortPairTimingArcMap = std::map<LibertyPortPair, TimingArcSetSeq*,
LibertyPortPairLess>;
using InternalPowerSeq = std::vector<InternalPower*>;
using PortInternalPowerMap = std::map<const LibertyPort *, InternalPowerSeq>;
using LeakagePowerSeq = std::vector<LeakagePower*>;
using LibertyPortTimingArcMap = std::map<const LibertyPort*, TimingArcSetSeq*>;
using ScaledCellMap = std::map<const OperatingConditions*, LibertyCell*>;
using ScaledPortMap = std::map<const OperatingConditions*, LibertyPort*>;
using ModeDefMap = std::map<const char *, ModeDef*, CharPtrLess>;
using ModeValueMap = std::map<const char *, ModeValueDef*, CharPtrLess>;
using LatchEnableMap = std::map<const TimingArcSet*, LatchEnable*>;
using LatchEnableSeq = std::vector<LatchEnable*>;
using OcvDerateMap = std::map<const char *, OcvDerate*, CharPtrLess>;
using InternalPowerAttrsSeq = std::vector<InternalPowerAttrs*>;
using SupplyVoltageMap = std::map<std::string, float>;
using DriverWaveformMap = std::map<std::string, DriverWaveform*>;
using SceneSeq = std::vector<Scene*>;
enum class ClockGateType { none, latch_posedge, latch_negedge, other };
@ -316,24 +317,24 @@ public:
const char *filename);
static void
makeCornerMap(LibertyLibrary *lib,
makeSceneMap(LibertyLibrary *lib,
int ap_index,
Network *network,
Report *report);
static void
makeCornerMap(LibertyCell *link_cell,
makeSceneMap(LibertyCell *link_cell,
LibertyCell *map_cell,
int ap_index,
Report *report);
static void
makeCornerMap(LibertyCell *cell1,
makeSceneMap(LibertyCell *cell1,
LibertyCell *cell2,
bool link,
int ap_index,
Report *report);
static void
checkCorners(LibertyCell *cell,
Corners *corners,
checkScenes(LibertyCell *cell,
const SceneSeq &scenes,
Report *report);
DriverWaveform *findDriverWaveform(const char *name);
@ -404,12 +405,12 @@ private:
class LibertyCellIterator : public Iterator<LibertyCell*>
{
public:
explicit LibertyCellIterator(const LibertyLibrary *library);
LibertyCellIterator(const LibertyLibrary *library);
bool hasNext();
LibertyCell *next();
private:
ConcreteCellMap::ConstIterator iter_;
ConcreteLibraryCellIterator iter_;
};
////////////////////////////////////////////////////////////////
@ -497,11 +498,9 @@ public:
const FuncExpr *&enable_func,
const RiseFall *&enable_rf) const;
const RiseFall *latchCheckEnableEdge(TimingArcSet *check_set);
bool isDisabledConstraint() const { return is_disabled_constraint_; }
LibertyCell *cornerCell(const Corner *corner,
LibertyCell *sceneCell(const Scene *scene,
const MinMax *min_max);
LibertyCell *cornerCell(const DcalcAnalysisPt *dcalc_ap);
LibertyCell *cornerCell(int ap_index);
LibertyCell *sceneCell(int ap_index);
// AOCV
float ocvArcDepth() const;
@ -536,8 +535,7 @@ public:
void addOcvDerate(OcvDerate *derate);
void setTestCell(TestCell *test);
void setHasInferedRegTimingArcs(bool infered);
void setIsDisabledConstraint(bool is_disabled);
void setCornerCell(LibertyCell *corner_cell,
void setSceneCell(LibertyCell *scene_cell,
int ap_index);
// Call after cell is finished being constructed.
void finish(bool infer_latches,
@ -550,9 +548,9 @@ public:
LibertyPort *&input,
LibertyPort *&output) const;
// Check all liberty cells to make sure they exist
// for all the defined corners.
static void checkLibertyCorners();
void ensureVoltageWaveforms(const DcalcAnalysisPtSeq &dcalc_aps);
// for all the defined scenes.
static void checkLibertyScenes();
void ensureVoltageWaveforms(const SceneSeq &scenes);
const char *footprint() const;
void setFootprint(const char *footprint);
const char *userFunctionClass() const;
@ -594,7 +592,7 @@ protected:
const LibertyPort *output) const;
bool hasInverterFunc(const LibertyPort *input,
const LibertyPort *output) const;
bool checkCornerCell(const Corner *corner,
bool checkSceneCell(const Scene *scene,
const MinMax *min_max) const;
LibertyLibrary *liberty_library_;
@ -612,13 +610,13 @@ protected:
bool interface_timing_;
ClockGateType clock_gate_type_;
TimingArcSetSeq timing_arc_sets_;
TimingArcSetMap timing_arc_set_map_;
TimingArcSetSet timing_arc_set_set_;
LibertyPortPairTimingArcMap port_timing_arc_set_map_;
LibertyPortTimingArcMap timing_arc_set_from_map_;
LibertyPortTimingArcMap timing_arc_set_to_map_;
bool has_infered_reg_timing_arcs_;
InternalPowerSeq internal_powers_;
PortInternalPowerSeq port_internal_powers_;
PortInternalPowerMap port_internal_powers_;
InternalPowerAttrsSeq internal_power_attrs_;
LeakagePowerSeq leakage_powers_;
SequentialSeq sequentials_;
@ -639,8 +637,7 @@ protected:
float ocv_arc_depth_;
OcvDerate *ocv_derate_;
OcvDerateMap ocv_derate_map_;
bool is_disabled_constraint_;
Vector<LibertyCell*> corner_cells_;
std::vector<LibertyCell*> scene_cells_;
float leakage_power_;
bool leakage_power_exists_;
bool has_internal_ports_;
@ -659,18 +656,18 @@ private:
class LibertyCellPortIterator : public Iterator<LibertyPort*>
{
public:
explicit LibertyCellPortIterator(const LibertyCell *cell);
LibertyCellPortIterator(const LibertyCell *cell);
bool hasNext();
LibertyPort *next();
private:
ConcretePortSeq::ConstIterator iter_;
ConcreteCellPortIterator iter_;
};
class LibertyCellPortBitIterator : public Iterator<LibertyPort*>
{
public:
explicit LibertyCellPortBitIterator(const LibertyCell *cell);
LibertyCellPortBitIterator(const LibertyCell *cell);
virtual ~LibertyCellPortBitIterator();
bool hasNext();
LibertyPort *next();
@ -814,17 +811,12 @@ public:
const RiseFall *pulseClkSense() const { return pulse_clk_sense_; }
void setPulseClk(const RiseFall *rfigger,
const RiseFall *sense);
bool isDisabledConstraint() const { return is_disabled_constraint_; }
void setIsDisabledConstraint(bool is_disabled);
LibertyPort *cornerPort(const Corner *corner,
LibertyPort *scenePort(const Scene *scene,
const MinMax *min_max);
const LibertyPort *cornerPort(const Corner *corner,
const LibertyPort *scenePort(const Scene *scene,
const MinMax *min_max) const;
LibertyPort *cornerPort(const DcalcAnalysisPt *dcalc_ap);
const LibertyPort *cornerPort(const DcalcAnalysisPt *dcalc_ap) const;
LibertyPort *cornerPort(int ap_index);
const LibertyPort *cornerPort(int ap_index) const;
void setCornerPort(LibertyPort *corner_port,
const LibertyPort *scenePort(int ap_index) const;
void setScenePort(LibertyPort *scene_port,
int ap_index);
const char *relatedGroundPin() const;
void setRelatedGroundPin(const char *related_ground_pin);
@ -881,6 +873,7 @@ protected:
float,
const MinMax *)> &setter);
LibertyPort *scenePort(int ap_index);
LibertyCell *liberty_cell_;
BusDcl *bus_dcl_;
@ -902,7 +895,7 @@ protected:
const RiseFall *pulse_clk_sense_;
std::string related_ground_pin_;
std::string related_power_pin_;
Vector<LibertyPort*> corner_ports_;
std::vector<LibertyPort*> scene_ports_;
ReceiverModelPtr receiver_model_;
DriverWaveform *driver_waveform_[RiseFall::index_count];
// Redundant with clock_tree_path_delay timing arcs but faster to access.
@ -923,7 +916,6 @@ protected:
bool isolation_cell_enable_:1;
bool level_shifter_data_:1;
bool is_switch_:1;
bool is_disabled_constraint_:1;
bool is_pad_:1;
private:
@ -939,7 +931,7 @@ sortByName(const LibertyPortSet *set);
class LibertyPortMemberIterator : public Iterator<LibertyPort*>
{
public:
explicit LibertyPortMemberIterator(const LibertyPort *port);
LibertyPortMemberIterator(const LibertyPort *port);
virtual ~LibertyPortMemberIterator();
virtual bool hasNext();
virtual LibertyPort *next();
@ -990,7 +982,7 @@ protected:
class ScaleFactors
{
public:
explicit ScaleFactors(const char *name);
ScaleFactors(const char *name);
const char *name() const { return name_.c_str(); }
float scale(ScaleFactorType type,
ScaleFactorPvt pvt,

View File

@ -25,10 +25,9 @@
#pragma once
#include <memory>
#include "Vector.hh"
#include "Map.hh"
#include "Set.hh"
#include <vector>
#include <map>
#include <set>
namespace sta {
@ -67,19 +66,19 @@ class ReceiverModel;
class Statetable;
class StatetableRow;
typedef Vector<LibertyLibrary*> LibertyLibrarySeq;
typedef Vector<LibertyCell*> LibertyCellSeq;
typedef Vector<Sequential*> SequentialSeq;
typedef Map<LibertyCell*, LibertyCellSeq*> LibertyCellEquivMap;
typedef Vector<LibertyPort*> LibertyPortSeq;
typedef Set<LibertyPort*> LibertyPortSet;
typedef std::pair<const LibertyPort*,const LibertyPort*> LibertyPortPair;
typedef Set<LibertyCell*> LibertyCellSet;
typedef std::shared_ptr<Table> TablePtr;
typedef std::shared_ptr<TimingArcAttrs> TimingArcAttrsPtr;
typedef std::shared_ptr<TableAxis> TableAxisPtr;
typedef std::shared_ptr<ReceiverModel> ReceiverModelPtr;
typedef std::vector<StatetableRow> StatetableRows;
using LibertyLibrarySeq = std::vector<LibertyLibrary*>;
using LibertyCellSeq = std::vector<LibertyCell*>;
using SequentialSeq = std::vector<Sequential*>;
using LibertyCellEquivMap = std::map<LibertyCell*, LibertyCellSeq*>;
using LibertyPortSeq = std::vector<LibertyPort*>;
using LibertyPortSet = std::set<LibertyPort*>;
using LibertyPortPair = std::pair<const LibertyPort*,const LibertyPort*>;
using LibertyCellSet = std::set<LibertyCell*>;
using TablePtr = std::shared_ptr<Table>;
using TimingArcAttrsPtr = std::shared_ptr<TimingArcAttrs>;
using TableAxisPtr = std::shared_ptr<TableAxis>;
using ReceiverModelPtr = std::shared_ptr<ReceiverModel>;
using StatetableRows = std::vector<StatetableRow>;
enum class ScaleFactorType : unsigned {
pin_cap,

View File

@ -58,7 +58,7 @@ protected:
class CheckLinearModel : public CheckTimingModel
{
public:
explicit CheckLinearModel(LibertyCell *cell,
CheckLinearModel(LibertyCell *cell,
float intrinsic);
ArcDelay checkDelay(const Pvt *pvt,
float from_slew,

View File

@ -1,191 +0,0 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software.
//
// Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// This notice may not be removed or altered from any source distribution.
#pragma once
#include <map>
#include <algorithm>
namespace sta {
// Add convenience functions around STL container.
template <class KEY, class VALUE, class CMP = std::less<KEY>>
class Map : public std::map<KEY, VALUE, CMP>
{
public:
Map() :
std::map<KEY, VALUE, CMP>()
{
}
explicit Map(const CMP &cmp) :
std::map<KEY, VALUE, CMP>(cmp)
{
}
// Find out if key is in the set.
bool
hasKey(const KEY key) const
{
return this->find(key) != this->end();
}
// Find the value corresponding to key.
VALUE
findKey(const KEY key) const
{
auto find_iter = this->find(key);
if (find_iter != this->end())
return find_iter->second;
else
return nullptr;
}
void
findKey(const KEY key,
// Return Values.
VALUE &value,
bool &exists) const
{
auto find_iter = this->find(key);
if (find_iter != this->end()) {
value = find_iter->second;
exists = true;
}
else
exists = false;
}
void
findKey(const KEY &key,
// Return Values.
KEY &map_key,
VALUE &value,
bool &exists) const
{
auto find_iter = this->find(key);
if (find_iter != this->end()) {
map_key = find_iter->first;
value = find_iter->second;
exists = true;
}
else
exists = false;
}
void
insert(const KEY &key,
VALUE value)
{
this->operator[](key) = value;
}
void
deleteContents()
{
Iterator iter(this);
while (iter.hasNext())
delete iter.next();
}
void
deleteKeysContents()
{
for (const auto [key, value] : this) {
delete key;
delete value;
}
}
void
deleteArrayContents()
{
Iterator iter(this);
while (iter.hasNext())
delete [] iter.next();
}
void
deleteContentsClear()
{
deleteContents();
std::map<KEY, VALUE, CMP>::clear();
}
// Java style container itererator
// Map::Iterator<string *, Value, stringLess> iter(map);
// while (iter.hasNext()) {
// Value *v = iter.next();
// }
class Iterator
{
public:
Iterator() : container_(nullptr) {}
explicit Iterator(std::map<KEY, VALUE, CMP> *container) :
container_(container)
{ if (container_ != nullptr) iter_ = container_->begin(); }
explicit Iterator(std::map<KEY, VALUE, CMP> &container) :
container_(&container)
{ if (container_ != nullptr) iter_ = container_->begin(); }
void init(std::map<KEY, VALUE, CMP> *container)
{ container_ = container; if (container_ != nullptr) iter_=container_->begin();}
void init(std::map<KEY, VALUE, CMP> &container)
{ container_ = &container; if (container_ != nullptr) iter_=container_->begin();}
bool hasNext() { return container_ != nullptr && iter_ != container_->end(); }
VALUE next() { return iter_++->second; }
void next(KEY &key,
VALUE &value)
{ key = iter_->first; value = iter_->second; iter_++; }
std::map<KEY, VALUE, CMP> *container() { return container_; }
private:
std::map<KEY, VALUE, CMP> *container_;
typename std::map<KEY, VALUE, CMP>::iterator iter_;
};
class ConstIterator
{
public:
ConstIterator() : container_(nullptr) {}
explicit ConstIterator(const std::map<KEY, VALUE, CMP> *container) :
container_(container)
{ if (container_ != nullptr) iter_ = container_->begin(); }
explicit ConstIterator(const std::map<KEY, VALUE, CMP> &container) :
container_(&container)
{ if (container_ != nullptr) iter_ = container_->begin(); }
void init(const std::map<KEY, VALUE, CMP> *container)
{ container_ = container; if (container_ != nullptr) iter_=container_->begin();}
void init(const std::map<KEY, VALUE, CMP> &container)
{ container_ = &container; if (container_ != nullptr) iter_=container_->begin();}
bool hasNext() { return container_ != nullptr && iter_ != container_->end(); }
VALUE next() { return iter_++->second; }
void next(KEY &key,
VALUE &value)
{ key = iter_->first; value = iter_->second; iter_++; }
const std::map<KEY, VALUE, CMP> *container() { return container_; }
private:
const std::map<KEY, VALUE, CMP> *container_;
typename std::map<KEY, VALUE, CMP>::const_iterator iter_;
};
};
} // namespace

View File

@ -36,8 +36,8 @@ class MinMax;
class MinMaxAll;
// Use typedefs to make early/late functional equivalents to min/max.
typedef MinMax EarlyLate;
typedef MinMaxAll EarlyLateAll;
using EarlyLate = MinMax;
using EarlyLateAll = MinMaxAll;
// Large value used for min/max initial values.
extern const float INF;
@ -112,6 +112,7 @@ public:
static const MinMaxAll *max() { return &max_; }
static const MinMaxAll *late() { return &max_; }
static const MinMaxAll *all() { return &all_; }
static const MinMaxAll *minMax() { return &all_; }
const std::string &to_string() const { return name_; }
int index() const { return index_; }
const MinMax *asMinMax() const;

View File

@ -197,7 +197,7 @@ private:
bool exists_[MinMax::index_count];
};
typedef MinMaxValues<float> MinMaxFloatValues;
typedef MinMaxValues<int> MinMaxIntValues;
using MinMaxFloatValues = MinMaxValues<float>;
using MinMaxIntValues = MinMaxValues<int>;
} // namespace

95
include/sta/Mode.hh Normal file
View File

@ -0,0 +1,95 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software.
//
// Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// This notice may not be removed or altered from any source distribution.
#pragma once
#include <string>
#include "StaState.hh"
namespace sta {
class Sdc;
class Sim;
class ClkNetwork;
class Genclks;
class PathGroups;
using PathGroupSeq = std::vector<PathGroup*>;
// Sdc and dependent state.
class Mode : public StaState
{
public:
Mode(const std::string &name,
size_t mode_index,
StaState *sta);
virtual ~Mode();
virtual void copyState(const StaState *sta);
void clear();
const std::string &name() const { return name_; }
size_t modeIndex() const { return mode_index_; }
const SceneSeq &scenes() const { return scenes_; }
const SceneSet sceneSet() const;
void addScene(Scene *scene);
void removeScene(Scene *scene);
Sdc *sdc() { return sdc_; }
Sdc *sdc() const { return sdc_; }
Sim *sim() { return sim_; }
Sim *sim() const { return sim_; }
ClkNetwork *clkNetwork() { return clk_network_; }
ClkNetwork *clkNetwork() const { return clk_network_; }
Genclks *genclks() { return genclks_; }
Genclks *genclks() const { return genclks_; }
PathGroups *pathGroups() { return path_groups_; }
PathGroups *pathGroups() const { return path_groups_; }
PathGroupSeq pathGroups(const PathEnd *path_end) const;
PathGroups *makePathGroups(int group_path_count,
int endpoint_path_count,
bool unique_pins,
bool unique_edges,
float min_slack,
float max_slack,
StdStringSeq &group_names,
bool setup,
bool hold,
bool recovery,
bool removal,
bool clk_gating_setup,
bool clk_gating_hold,
bool unconstrained_paths);
void deletePathGroups();
private:
std::string name_;
size_t mode_index_;
SceneSeq scenes_;
Sdc *sdc_;
Sim *sim_;
ClkNetwork *clk_network_;
Genclks *genclks_;
PathGroups *path_groups_;
};
} // namespace

View File

@ -29,6 +29,6 @@
namespace sta {
// Hide a bit of the std verbosity.
typedef std::lock_guard<std::mutex> LockGuard;
using LockGuard = std::lock_guard<std::mutex>;
} // namespace

View File

@ -25,8 +25,8 @@
#pragma once
#include <functional>
#include <map>
#include "Map.hh"
#include "StringUtil.hh"
#include "LibertyClass.hh"
#include "VertexId.hh"
@ -39,12 +39,12 @@ class Report;
class PatternMatch;
class PinVisitor;
typedef Map<const char*, LibertyLibrary*, CharPtrLess> LibertyLibraryMap;
using LibertyLibraryMap = std::map<const char*, LibertyLibrary*, CharPtrLess>;
// Link network function returns top level instance.
// Return nullptr if link fails.
typedef std::function<Instance* (const char *top_cell_name,
bool make_black_boxes)> LinkNetworkFunc;
typedef Map<const Net*, PinSet*> NetDrvrPinsMap;
using LinkNetworkFunc = std::function<Instance* (const char *top_cell_name,
bool make_black_boxes)>;
using NetDrvrPinsMap = std::map<const Net*, PinSet*>;
// The Network class defines the network API used by sta.
// The interface to a network implementation is constructed by
@ -132,10 +132,10 @@ public:
virtual LibertyLibrary *defaultLibertyLibrary() const;
void setDefaultLibertyLibrary(LibertyLibrary *library);
// Check liberty cells used by the network to make sure they exist
// for all the defined corners.
void checkNetworkLibertyCorners();
// Check liberty cells to make sure they exist for all the defined corners.
void checkLibertyCorners();
// for all the defined scenes.
void checkNetworkLibertyScenes();
// Check liberty cells to make sure they exist for all the defined scenes.
void checkLibertyScenes();
////////////////////////////////////////////////////////////////
// Cell functions.
@ -303,8 +303,8 @@ public:
virtual Term *term(const Pin *pin) const = 0;
virtual PortDirection *direction(const Pin *pin) const = 0;
virtual bool isLeaf(const Pin *pin) const;
bool isHierarchical(const Pin *pin) const;
bool isTopLevelPort(const Pin *pin) const;
[[nodiscard]] bool isHierarchical(const Pin *pin) const;
[[nodiscard]] bool isTopLevelPort(const Pin *pin) const;
// Is pin inside the instance hier_pin is attached to?
bool isInside(const Pin *pin,
const Pin *hier_pin) const;
@ -620,7 +620,7 @@ public:
NetworkConstantPinIterator(const Network *network,
NetSet &zero_nets,
NetSet &one_nets);
~NetworkConstantPinIterator();
virtual ~NetworkConstantPinIterator() {}
virtual bool hasNext();
virtual void next(const Pin *&pin, LogicValue &value);
@ -631,7 +631,7 @@ private:
const Network *network_;
PinSet constant_pins_[2];
LogicValue value_;
PinSet::Iterator *pin_iter_;
PinSet::iterator pin_iter_;
};
// Abstract base class for visitDrvrLoadsThruHierPin visitor.

View File

@ -26,10 +26,11 @@
#include <cstdint>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <unordered_set>
#include "Set.hh"
#include "Vector.hh"
#include "Iterator.hh"
namespace sta {
@ -49,30 +50,31 @@ class ConstantPinIterator;
class ViewType;
class LibertyLibrary;
typedef Iterator<Library*> LibraryIterator;
typedef Iterator<LibertyLibrary*> LibertyLibraryIterator;
typedef Vector<Cell*> CellSeq;
typedef Vector<const Port*> PortSeq;
typedef Iterator<Port*> CellPortIterator;
typedef Iterator<Port*> CellPortBitIterator;
typedef Iterator<Port*> PortMemberIterator;
using LibraryIterator = Iterator<Library*>;
using LibertyLibraryIterator = Iterator<LibertyLibrary*>;
using CellSeq = std::vector<Cell*>;
using PortSeq = std::vector<const Port*>;
using CellPortIterator = Iterator<Port*>;
using CellPortBitIterator = Iterator<Port*>;
using PortMemberIterator = Iterator<Port*>;
typedef Vector<const Pin*> PinSeq;
typedef Vector<const Instance*> InstanceSeq;
typedef Vector<const Net*> NetSeq;
typedef std::vector<const Net*> ConstNetSeq;
typedef Iterator<Instance*> InstanceChildIterator;
typedef Iterator<Pin*> InstancePinIterator;
typedef Iterator<Net*> InstanceNetIterator;
typedef Iterator<Instance*> LeafInstanceIterator;
typedef Iterator<Net*> NetIterator;
typedef Iterator<const Pin*> NetPinIterator;
typedef Iterator<Term*> NetTermIterator;
typedef Iterator<const Pin*> ConnectedPinIterator;
typedef ConnectedPinIterator NetConnectedPinIterator;
typedef ConnectedPinIterator PinConnectedPinIterator;
typedef uint32_t ObjectId;
typedef std::map<std::string, std::string> AttributeMap;
using PinSeq = std::vector<const Pin*>;
using PinUnorderedSet = std::unordered_set<const Pin*>;
using InstanceSeq = std::vector<const Instance*>;
using NetSeq = std::vector<const Net*>;
using ConstNetSeq = std::vector<const Net*>;
using InstanceChildIterator = Iterator<Instance*>;
using InstancePinIterator = Iterator<Pin*>;
using InstanceNetIterator = Iterator<Net*>;
using LeafInstanceIterator = Iterator<Instance*>;
using NetIterator = Iterator<Net*>;
using NetPinIterator = Iterator<const Pin*>;
using NetTermIterator = Iterator<Term*>;
using ConnectedPinIterator = Iterator<const Pin*>;
using NetConnectedPinIterator = ConnectedPinIterator;
using PinConnectedPinIterator = ConnectedPinIterator;
using ObjectId = uint32_t;
using AttributeMap = std::map<std::string, std::string>;
enum class LogicValue : unsigned { zero, one, unknown, rise, fall };
@ -138,55 +140,37 @@ private:
////////////////////////////////////////////////////////////////
class CellSet : public Set<const Cell*, CellIdLess>
class CellSet : public std::set<const Cell*, CellIdLess>
{
public:
CellSet(const Network *network);
};
class PortSet : public Set<const Port*, PortIdLess>
class PortSet : public std::set<const Port*, PortIdLess>
{
public:
PortSet(const Network *network);
};
class InstanceSet : public Set<const Instance*, InstanceIdLess>
class InstanceSet : public std::set<const Instance*, InstanceIdLess>
{
public:
InstanceSet();
InstanceSet(const Network *network);
static int compare(const InstanceSet *set1,
const InstanceSet *set2,
const Network *network);
static bool intersects(const InstanceSet *set1,
const InstanceSet *set2,
const Network *network);
};
class PinSet : public Set<const Pin*, PinIdLess>
class PinSet : public std::set<const Pin*, PinIdLess>
{
public:
PinSet();
PinSet(const Network *network);
static int compare(const PinSet *set1,
const PinSet *set2,
const Network *network);
static bool intersects(const PinSet *set1,
const PinSet *set2,
const Network *network);
};
class NetSet : public Set<const Net*, NetIdLess>
class NetSet : public std::set<const Net*, NetIdLess>
{
public:
NetSet();
NetSet(const Network *network);
static int compare(const NetSet *set1,
const NetSet *set2,
const Network *network);
static bool intersects(const NetSet *set1,
const NetSet *set2,
const Network *network);
};
} // namespace

View File

@ -34,7 +34,7 @@ namespace sta {
class PortNameLess
{
public:
explicit PortNameLess(const Network *network);
PortNameLess(const Network *network);
bool operator()(const Port *port1,
const Port *port2) const;
@ -45,7 +45,7 @@ private:
class PinPathNameLess
{
public:
explicit PinPathNameLess(const Network *network);
PinPathNameLess(const Network *network);
bool operator()(const Pin *pin1,
const Pin *pin2) const;
@ -56,7 +56,7 @@ private:
class InstancePathNameLess
{
public:
explicit InstancePathNameLess(const Network *network);
InstancePathNameLess(const Network *network);
bool operator()(const Instance *inst1,
const Instance *inst2) const;
@ -67,7 +67,7 @@ private:
class NetPathNameLess
{
public:
explicit NetPathNameLess(const Network *network);
NetPathNameLess(const Network *network);
bool operator()(const Net *net1,
const Net *net2) const;
@ -78,6 +78,9 @@ private:
PinSeq
sortByPathName(const PinSet *set,
const Network *network);
PinSeq
sortByPathName(const PinUnorderedSet *set,
const Network *network);
PortSeq
sortByName(const PortSet *set,
const Network *network);

View File

@ -29,11 +29,11 @@
namespace sta {
// ObjectId is block index and object index within the block.
typedef uint32_t ObjectId;
using ObjectId = uint32_t;
// Block index.
typedef uint32_t BlockIdx;
using BlockIdx = uint32_t;
// Object index within a block.
typedef uint32_t ObjectIdx;
using ObjectIdx = uint32_t;
static constexpr int object_id_bits = sizeof(ObjectId) * 8;
static constexpr BlockIdx block_idx_null = 0;

View File

@ -24,7 +24,9 @@
#pragma once
#include "Vector.hh"
#include <vector>
#include "ContainerHelpers.hh"
#include "Error.hh"
#include "ObjectId.hh"
@ -71,7 +73,7 @@ private:
size_t size_;
// Object ID of next free object.
ObjectId free_;
Vector<TableBlock<TYPE>*> blocks_;
std::vector<TableBlock<TYPE>*> blocks_;
static constexpr ObjectId idx_mask_ = block_object_count - 1;
};
@ -85,7 +87,7 @@ ObjectTable<TYPE>::ObjectTable() :
template <class TYPE>
ObjectTable<TYPE>::~ObjectTable()
{
blocks_.deleteContents();
deleteContents(blocks_);
}
template <class TYPE>
@ -181,7 +183,7 @@ template <class TYPE>
void
ObjectTable<TYPE>::clear()
{
blocks_.deleteContentsClear();
deleteContents(blocks_);;
size_ = 0;
}

View File

@ -37,40 +37,36 @@
namespace sta {
class Wireload;
class Corner;
class Scene;
typedef std::complex<float> ComplexFloat;
typedef Vector<ComplexFloat> ComplexFloatSeq;
typedef std::vector<ParasiticNode*> ParasiticNodeSeq;
typedef std::vector<ParasiticResistor*> ParasiticResistorSeq;
typedef std::vector<ParasiticCapacitor*> ParasiticCapacitorSeq;
typedef std::map<ParasiticNode *, ParasiticResistorSeq> ParasiticNodeResistorMap;
typedef std::map<ParasiticNode *, ParasiticCapacitorSeq> ParasiticNodeCapacitorMap;
using ComplexFloat = std::complex<float>;
using ComplexFloatSeq = std::vector<ComplexFloat>;
using ParasiticNodeSeq = std::vector<ParasiticNode*>;
using ParasiticResistorSeq = std::vector<ParasiticResistor*>;
using ParasiticCapacitorSeq = std::vector<ParasiticCapacitor*>;
using ParasiticNodeResistorMap = std::map<ParasiticNode *, ParasiticResistorSeq>;
using ParasiticNodeCapacitorMap = std::map<ParasiticNode *, ParasiticCapacitorSeq>;
// Parasitics API.
// All parasitic parameters can have multiple values, each corresponding
// to an analysis point.
// Parasitic annotation for a pin or net may exist for one analysis point
// and not another.
class Parasitics : public StaState
{
public:
Parasitics(StaState *sta);
virtual ~Parasitics() {}
virtual const std::string &name() const = 0;
virtual const std::string &filename() const = 0;
virtual bool haveParasitics() = 0;
// Clear all state.
virtual void clear() = 0;
// Delete all parasitics.
virtual void deleteParasitics() = 0;
// Delete all parasitics on net at analysis point.
virtual void deleteParasitics(const Net *net,
const ParasiticAnalysisPt *ap) = 0;
virtual void deleteParasitics(const Net *net) = 0;
// Delete all parasitics on pin at analysis point.
virtual void deleteParasitics(const Pin *pin,
const ParasiticAnalysisPt *ap) = 0;
virtual void deleteReducedParasitics(const Net *net,
const ParasiticAnalysisPt *ap) = 0;
virtual void deleteParasitics(const Pin *pin) = 0;
virtual void deleteReducedParasitics(const Net *net) = 0;
virtual void deleteDrvrReducedParasitics(const Pin *drvr_pin) = 0;
virtual bool isReducedParasiticNetwork(const Parasitic *parasitic) const = 0;
@ -88,10 +84,10 @@ public:
virtual bool isPiElmore(const Parasitic *parasitic) const = 0;
virtual Parasitic *findPiElmore(const Pin *drvr_pin,
const RiseFall *rf,
const ParasiticAnalysisPt *ap) const = 0;
const MinMax *min_max) const = 0;
virtual Parasitic *makePiElmore(const Pin *drvr_pin,
const RiseFall *rf,
const ParasiticAnalysisPt *ap,
const MinMax *min_max,
float c2,
float rpi,
float c1) = 0;
@ -126,10 +122,10 @@ public:
virtual bool isPiPoleResidue(const Parasitic* parasitic) const = 0;
virtual Parasitic *findPiPoleResidue(const Pin *drvr_pin,
const RiseFall *rf,
const ParasiticAnalysisPt *ap) const=0;
const MinMax *min_max) const = 0;
virtual Parasitic *makePiPoleResidue(const Pin *drvr_pin,
const RiseFall *rf,
const ParasiticAnalysisPt *ap,
const MinMax *min_max,
float c2,
float rpi,
float c1) = 0;
@ -154,22 +150,16 @@ public:
// This api assumes that parasitic networks are not rise/fall
// dependent because they do not include pin capacitances.
virtual bool isParasiticNetwork(const Parasitic *parasitic) const = 0;
virtual Parasitic *findParasiticNetwork(const Net *net,
const ParasiticAnalysisPt *ap) const = 0;
virtual Parasitic *findParasiticNetwork(const Pin *pin,
const ParasiticAnalysisPt *ap) const = 0;
virtual Parasitic *findParasiticNetwork(const Net *net) = 0;
virtual Parasitic *findParasiticNetwork(const Pin *pin) = 0;
virtual Parasitic *makeParasiticNetwork(const Net *net,
bool includes_pin_caps,
const ParasiticAnalysisPt *ap) = 0;
bool includes_pin_caps) = 0;
virtual ParasiticNodeSeq nodes(const Parasitic *parasitic) const = 0;
virtual void report(const Parasitic *parasitic) const;
virtual const Net *net(const Parasitic *parasitic) const = 0;
virtual ParasiticResistorSeq resistors(const Parasitic *parasitic) const = 0;
virtual ParasiticCapacitorSeq capacitors(const Parasitic *parasitic) const = 0;
// Delete parasitic network if it exists.
virtual void deleteParasiticNetwork(const Net *net,
const ParasiticAnalysisPt *ap) = 0;
virtual void deleteParasiticNetworks(const Net *net) = 0;
virtual void deleteParasiticNetwork(const Net *net) = 0;
// True if the parasitic network caps include pin capacitances.
virtual bool includesPinCaps(const Parasitic *parasitic) const = 0;
// Parasitic network component builders.
@ -248,17 +238,15 @@ public:
Parasitic *reduceToPiElmore(const Parasitic *parasitic,
const Pin *drvr_pin,
const RiseFall *rf,
const Corner *corner,
const MinMax *cnst_min_max,
const ParasiticAnalysisPt *ap);
const Scene *scene,
const MinMax *min_max);
// Reduce parasitic network to pi and 2nd order pole/residue models
// for drvr_pin.
Parasitic *reduceToPiPoleResidue2(const Parasitic *parasitic,
const Pin *drvr_pin,
const RiseFall *rf,
const Corner *corner,
const MinMax *cnst_min_max,
const ParasiticAnalysisPt *ap);
const Scene *scene,
const MinMax *min_max);
// Estimate parasitic as pi elmore using wireload model.
Parasitic *estimatePiElmore(const Pin *drvr_pin,
@ -266,18 +254,19 @@ public:
const Wireload *wireload,
float fanout,
float net_pin_cap,
const Corner *corner,
const Scene *scene,
const MinMax *min_max);
Parasitic *makeWireloadNetwork(const Pin *drvr_pin,
const Wireload *wireload,
float fanout,
const MinMax *min_max,
const ParasiticAnalysisPt *ap);
const Scene *scene,
const MinMax *min_max);
// Network edit before/after methods.
virtual void disconnectPinBefore(const Pin *pin,
const Network *network) = 0;
virtual void disconnectPinBefore(const Pin *pin) = 0;
virtual void deletePinBefore(const Pin *pin) = 0;
virtual void loadPinCapacitanceChanged(const Pin *pin) = 0;
float couplingCapFactor() const { return coupling_cap_factor_; }
void setCouplingCapFactor(float factor);
protected:
void makeWireloadNetworkWorst(Parasitic *parasitic,
@ -298,35 +287,16 @@ protected:
float fanout);
const Net *findParasiticNet(const Pin *pin) const;
};
// Managed by the Corner class.
class ParasiticAnalysisPt
{
public:
ParasiticAnalysisPt(const char *name,
int index,
int index_max);
const char *name() const { return name_.c_str(); }
int index() const { return index_; }
int indexMax() const { return index_max_; }
// Coupling capacitor factor used by all reduction functions.
float couplingCapFactor() const { return coupling_cap_factor_; }
void setCouplingCapFactor(float factor);
private:
std::string name_;
int index_;
int index_max_;
float coupling_cap_factor_;
};
class ParasiticNodeLess
{
public:
ParasiticNodeLess();
ParasiticNodeLess(const Parasitics *parasitics,
const Network *network);
ParasiticNodeLess(const ParasiticNodeLess &less);
bool operator()(const ParasiticNode *node1,
const ParasiticNode *node2) const;
private:

View File

@ -29,7 +29,6 @@ namespace sta {
class Parasitics;
class Parasitic;
class ParasiticNode;
class ParasiticAnalysisPt;
class ParasiticResistor;
class ParasiticCapacitor;

View File

@ -35,8 +35,6 @@
namespace sta {
class DcalcAnalysisPt;
class Path
{
public:
@ -60,7 +58,6 @@ public:
TimingArc *prev_arc,
bool is_enum,
const StaState *sta);
~Path();
std::string to_string(const StaState *sta) const;
bool isNull() const;
// prev_path null
@ -86,6 +83,9 @@ public:
VertexId vertexId(const StaState *sta) const;
Pin *pin(const StaState *sta) const;
Tag *tag(const StaState *sta) const;
Scene *scene(const StaState *sta) const;
Mode *mode(const StaState *sta) const;
Sdc *sdc(const StaState *sta) const;
TagIndex tagIndex(const StaState *sta) const;
void setTag(Tag *tag);
size_t pathIndex(const StaState *sta) const;
@ -96,9 +96,8 @@ public:
const RiseFall *transition(const StaState *sta) const;
int rfIndex(const StaState *sta) const;
const MinMax *minMax(const StaState *sta) const;
PathAnalysisPt *pathAnalysisPt(const StaState *sta) const;
PathAPIndex pathAnalysisPtIndex(const StaState *sta) const;
DcalcAnalysisPt *dcalcAnalysisPt(const StaState *sta) const;
DcalcAPIndex dcalcAnalysisPtIndex(const StaState *sta) const;
Arrival &arrival() { return arrival_; }
const Arrival &arrival() const { return arrival_; }
void setArrival(Arrival arrival);
@ -121,6 +120,8 @@ public:
void setIsEnum(bool is_enum);
void checkPrevPath(const StaState *sta) const;
const MinMax *tgtClkMinMax(const StaState *sta) const;
static Path *vertexPath(const Path *path,
const StaState *sta);
static Path *vertexPath(const Path &path,
@ -176,7 +177,7 @@ protected:
class PathLess
{
public:
explicit PathLess(const StaState *sta);
PathLess(const StaState *sta);
bool operator()(const Path *path1,
const Path *path2) const;
@ -191,11 +192,10 @@ public:
// Iterate over all vertex paths.
VertexPathIterator(Vertex *vertex,
const StaState *sta);
// Iterate over vertex paths with the same transition and
// analysis pt but different tags.
VertexPathIterator(Vertex *vertex,
const Scene *scene,
const MinMax *min_max,
const RiseFall *rf,
const PathAnalysisPt *path_ap,
const StaState *sta);
// Iterate over vertex paths with the same transition and
// analysis pt min/max but different tags.
@ -203,11 +203,6 @@ public:
const RiseFall *rf,
const MinMax *min_max,
const StaState *sta);
VertexPathIterator(Vertex *vertex,
const RiseFall *rf,
const PathAnalysisPt *path_ap,
const MinMax *min_max,
const StaState *sta);
virtual ~VertexPathIterator();
virtual bool hasNext();
virtual Path *next();
@ -216,10 +211,10 @@ private:
void findNext();
const Search *search_;
bool filtered_;
const RiseFall *rf_;
const PathAnalysisPt *path_ap_;
const Scene *scene_;
const MinMax *min_max_;
const RiseFall *rf_;
bool filtered_;
Path *paths_;
size_t path_count_;
size_t path_index_;

View File

@ -1,69 +0,0 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software.
//
// Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// This notice may not be removed or altered from any source distribution.
#pragma once
#include <string>
#include "Iterator.hh"
#include "MinMax.hh"
#include "SdcClass.hh"
#include "SearchClass.hh"
namespace sta {
class MinMax;
class DcalcAnalysisPt;
class Corner;
class PathAnalysisPt
{
public:
PathAnalysisPt(Corner *corner,
PathAPIndex index,
const MinMax *path_min_max,
DcalcAnalysisPt *dcalc_ap);
std::string to_string() const;
Corner *corner() const { return corner_; }
PathAPIndex index() const { return index_; }
const MinMax *pathMinMax() const { return path_min_max_; }
// Converging path arrival merging.
const MinMax *mergeMinMax() const { return path_min_max_; }
// Path analysis point for timing check target clock arrivals.
PathAnalysisPt *tgtClkAnalysisPt() const { return tgt_clk_ap_; }
void setTgtClkAnalysisPt(PathAnalysisPt *path_ap);
DcalcAnalysisPt *dcalcAnalysisPt() const { return dcalc_ap_; }
PathAnalysisPt *insertionAnalysisPt(const EarlyLate *early_late) const;
void setInsertionAnalysisPt(const EarlyLate *early_late, PathAnalysisPt *ap);
private:
Corner *corner_;
PathAPIndex index_;
const MinMax *path_min_max_;
PathAnalysisPt *tgt_clk_ap_;
PathAnalysisPt *insertion_aps_[EarlyLate::index_count];
DcalcAnalysisPt *dcalc_ap_;
};
} // namespace

View File

@ -59,7 +59,7 @@ class ReportPath;
class PathEnd
{
public:
enum Type { unconstrained,
enum class Type { unconstrained,
check,
data_check,
latch_check,
@ -80,8 +80,6 @@ public:
const EarlyLate *pathEarlyLate(const StaState *sta) const;
virtual const EarlyLate *clkEarlyLate(const StaState *sta) const;
const RiseFall *transition(const StaState *sta) const;
PathAnalysisPt *pathAnalysisPt(const StaState *sta) const;
PathAPIndex pathIndex(const StaState *sta) const;
virtual void reportShort(const ReportPath *report) const = 0;
virtual void reportFull(const ReportPath *report) const = 0;
PathGroup *pathGroup() const { return path_group_; }
@ -89,13 +87,13 @@ public:
// Predicates for PathEnd type.
// Default methods overridden by respective types.
virtual bool isUnconstrained() const { return false; }
virtual bool isCheck() const { return false; }
virtual bool isDataCheck() const { return false; }
virtual bool isLatchCheck() const { return false; }
virtual bool isOutputDelay() const { return false; }
virtual bool isGatedClock() const { return false; }
virtual bool isPathDelay() const { return false; }
[[nodiscard]] virtual bool isUnconstrained() const { return false; }
[[nodiscard]] virtual bool isCheck() const { return false; }
[[nodiscard]] virtual bool isDataCheck() const { return false; }
[[nodiscard]] virtual bool isLatchCheck() const { return false; }
[[nodiscard]] virtual bool isOutputDelay() const { return false; }
[[nodiscard]] virtual bool isGatedClock() const { return false; }
[[nodiscard]] virtual bool isPathDelay() const { return false; }
virtual Type type() const = 0;
virtual const char *typeName() const = 0;
virtual int exceptPathCmp(const PathEnd *path_end,
@ -187,7 +185,7 @@ public:
const ClockEdge *tgt_clk_edge,
const Path *tgt_clk_path,
const TimingRole *check_role,
const StaState *sta);
const Sdc *sdc);
// Non inter-clock uncertainty.
static float checkTgtClkUncertainty(const Path *tgt_clk_path,
const ClockEdge *tgt_clk_edge,
@ -204,7 +202,7 @@ protected:
static void checkInterClkUncertainty(const ClockEdge *src_clk_edge,
const ClockEdge *tgt_clk_edge,
const TimingRole *check_role,
const StaState *sta,
const Sdc *sdc,
float &uncertainty,
bool &exists);
static float outputDelayMargin(OutputDelay *output_delay,
@ -224,7 +222,7 @@ protected:
class PathEndUnconstrained : public PathEnd
{
public:
explicit PathEndUnconstrained(Path *path);
PathEndUnconstrained(Path *path);
virtual Type type() const;
virtual const char *typeName() const;
virtual PathEnd *copy() const;
@ -582,7 +580,7 @@ public:
virtual Required requiredTime(const StaState *sta) const;
virtual int exceptPathCmp(const PathEnd *path_end,
const StaState *sta) const;
bool hasOutputDelay() const { return output_delay_ != nullptr; }
[[nodiscard]] bool hasOutputDelay() const { return output_delay_ != nullptr; }
virtual bool ignoreClkLatency(const StaState *sta) const;
protected:
@ -613,7 +611,7 @@ protected:
class PathEndLess
{
public:
explicit PathEndLess(const StaState *sta);
PathEndLess(const StaState *sta);
bool operator()(const PathEnd *path_end1,
const PathEnd *path_end2) const;
@ -625,7 +623,7 @@ protected:
class PathEndSlackLess
{
public:
explicit PathEndSlackLess(const StaState *sta);
PathEndSlackLess(const StaState *sta);
bool operator()(const PathEnd *path_end1,
const PathEnd *path_end2) const;
@ -636,7 +634,7 @@ protected:
class PathEndNoCrprLess
{
public:
explicit PathEndNoCrprLess(const StaState *sta);
PathEndNoCrprLess(const StaState *sta);
bool operator()(const PathEnd *path_end1,
const PathEnd *path_end2) const;

View File

@ -24,10 +24,11 @@
#pragma once
#include <string>
#include <vector>
#include <map>
#include <mutex>
#include "Map.hh"
#include "Vector.hh"
#include "SdcClass.hh"
#include "StaState.hh"
#include "SearchClass.hh"
@ -37,11 +38,11 @@ namespace sta {
class MinMax;
class PathEndVisitor;
typedef PathEndSeq::Iterator PathGroupIterator;
typedef Map<const Clock*, PathGroup*> PathGroupClkMap;
typedef Map<const char*, PathGroup*, CharPtrLess> PathGroupNamedMap;
typedef std::vector<PathGroup*> PathGroupSeq;
typedef std::vector<std::string> StdStringSeq;
using PathGroupIterator = PathEndSeq::iterator;
using PathGroupClkMap = std::map<const Clock*, PathGroup*>;
using PathGroupNamedMap = std::map<const char*, PathGroup*, CharPtrLess>;
using PathGroupSeq = std::vector<PathGroup*>;
using StdStringSeq = std::vector<std::string>;
// A collection of PathEnds grouped and sorted for reporting.
class PathGroup
@ -65,7 +66,7 @@ public:
float min_slack,
float max_slack,
const StaState *sta);
const char *name() const { return name_; }
const char *name() const { return name_.c_str(); }
const MinMax *minMax() const { return min_max_;}
const PathEndSeq &pathEnds() const { return path_ends_; }
void insert(PathEnd *path_end);
@ -75,7 +76,7 @@ public:
bool saveable(PathEnd *path_end);
bool enumMinSlackUnderMin(PathEnd *path_end);
int maxPaths() const { return group_path_count_; }
PathGroupIterator *iterator();
PathEndSeq &pathEnds() { return path_ends_; }
// This does NOT delete the path ends.
void clear();
static size_t group_path_count_max;
@ -95,7 +96,7 @@ protected:
void prune();
void sort();
const char *name_;
std::string name_;
size_t group_path_count_;
size_t endpoint_path_count_;
bool unique_pins_;
@ -119,7 +120,7 @@ public:
bool unique_edges,
float slack_min,
float slack_max,
PathGroupNameSet *group_names,
StdStringSeq &group_names,
bool setup,
bool hold,
bool recovery,
@ -127,15 +128,17 @@ public:
bool clk_gating_setup,
bool clk_gating_hold,
bool unconstrained,
const StaState *sta);
const Mode *mode);
~PathGroups();
// Use corner nullptr to make PathEnds for all corners.
// Use scene nullptr to make PathEnds for all scenes.
// The PathEnds in the vector are owned by the PathGroups.
PathEndSeq makePathEnds(ExceptionTo *to,
bool unconstrained_paths,
const Corner *corner,
void makePathEnds(ExceptionTo *to,
const SceneSeq &scenes,
const MinMaxAll *min_max,
bool sort_by_slack);
bool sort_by_slack,
bool unconstrained_paths,
// Return value.
PathEndSeq &path_ends);
PathGroup *findPathGroup(const char *name,
const MinMax *min_max) const;
PathGroup *findPathGroup(const Clock *clock,
@ -154,14 +157,14 @@ protected:
int endpoint_path_count,
bool unique_pins,
bool unique_edges,
const Corner *corner,
const SceneSeq &scenes,
const MinMaxAll *min_max);
void makeGroupPathEnds(ExceptionTo *to,
const Corner *corner,
const SceneSeq &scenes,
const MinMaxAll *min_max,
PathEndVisitor *visitor);
void makeGroupPathEnds(VertexSet *endpoints,
const Corner *corner,
void makeGroupPathEnds(VertexSet &endpoints,
const SceneSeq &scenes,
const MinMaxAll *min_max,
PathEndVisitor *visitor);
void enumPathEnds(PathGroup *group,
@ -171,7 +174,7 @@ protected:
bool unique_edges,
bool cmp_slack);
void pushGroupPathEnds(PathEndSeq &path_ends);
void pushEnds(PathEndSeq &path_ends);
void pushUnconstrainedPathEnds(PathEndSeq &path_ends,
const MinMaxAll *min_max);
@ -181,15 +184,19 @@ protected:
bool unique_edges,
float slack_min,
float slack_max,
PathGroupNameSet *group_names,
StdStringSet &group_names,
bool setup_hold,
bool async,
bool gated_clk,
bool unconstrained,
const MinMax *min_max);
bool reportGroup(const char *group_name,
PathGroupNameSet *group_names) const;
StdStringSet &group_names) const;
static GroupPath *groupPathTo(const PathEnd *path_end,
const StaState *sta);
StdStringSeq pathGroupNames();
const Mode *mode_;
int group_path_count_;
int endpoint_path_count_;
bool unique_pins_;

View File

@ -29,8 +29,8 @@
#include "Error.hh"
// Don't require all of tcl.h.
typedef struct Tcl_RegExp_ *Tcl_RegExp;
typedef struct Tcl_Interp Tcl_Interp;
using Tcl_RegExp = struct Tcl_RegExp_ *;
using Tcl_Interp = struct Tcl_Interp;
namespace sta {
@ -78,7 +78,7 @@ private:
class RegexpCompileError : public Exception
{
public:
explicit RegexpCompileError(const char *pattern);
RegexpCompileError(const char *pattern);
virtual ~RegexpCompileError() noexcept {}
virtual const char *what() const noexcept;

View File

@ -24,13 +24,14 @@
#pragma once
#include <set>
#include "Hash.hh"
#include "Set.hh"
#include "NetworkClass.hh"
namespace sta {
typedef std::pair<const Pin*, const Pin*> PinPair;
using PinPair = std::pair<const Pin*, const Pin*>;
class PinPairLess
{
@ -44,7 +45,7 @@ private:
};
class PinPairSet : public Set<PinPair, PinPairLess>
class PinPairSet : public std::set<PinPair, PinPairLess>
{
public:
PinPairSet(const Network *network);

View File

@ -24,6 +24,8 @@
#pragma once
#include <vector>
#include "RiseFallMinMax.hh"
#include "SdcClass.hh"
@ -31,7 +33,7 @@ namespace sta {
class PortDelay;
typedef Vector<PortDelay*> PortDelaySeq;
using PortDelaySeq = std::vector<PortDelay*>;
// set_input_delay arrival, set_output_delay departure
class PortDelay
@ -98,7 +100,7 @@ private:
class PortDelayLess
{
public:
explicit PortDelayLess(const Network *network);
PortDelayLess(const Network *network);
bool operator()(const PortDelay *delay1,
const PortDelay *delay2) const;

View File

@ -32,39 +32,42 @@
namespace sta {
typedef MinMaxIntValues FanoutValues;
using FanoutValues = MinMaxIntValues;
// Port external pin and wire capacitance (set_load -pin_load -wire_load).
class PortExtCap
{
public:
PortExtCap(const Port *port);
PortExtCap();
const Port *port() { return port_; }
void pinCap(const RiseFall *rf,
const MinMax *min_max,
// Return values.
float &cap,
bool &exists);
RiseFallMinMax *pinCap() { return &pin_cap_; }
void setPinCap(float cap,
bool &exists) const;
const RiseFallMinMax *pinCap() const { return &pin_cap_; }
void setPinCap(const Port *port,
float cap,
const RiseFall *rf,
const MinMax *min_max);
void wireCap(const RiseFall *rf,
const MinMax *min_max,
// Return values.
float &cap,
bool &exists);
RiseFallMinMax *wireCap() { return &wire_cap_; }
void setWireCap(float cap,
bool &exists) const;
const RiseFallMinMax *wireCap() const { return &wire_cap_; }
void setWireCap(const Port *port,
float cap,
const RiseFall *rf,
const MinMax *min_max);
void setFanout(int fanout,
void setFanout(const Port *port,
int fanout,
const MinMax *min_max);
void fanout(const MinMax *min_max,
// Return values.
int &fanout,
bool &exists);
FanoutValues *fanout() { return &fanout_; }
bool &exists) const;
const FanoutValues *fanout() const { return &fanout_; }
private:
const Port *port_;

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