fix merge

Signed-off-by: dsengupta0628 <dsengupta@precisioninno.com>
This commit is contained in:
dsengupta0628 2026-02-25 19:48:36 +00:00
commit 03f976128f
391 changed files with 35652 additions and 34664 deletions

View File

@ -10,7 +10,7 @@ AllowAllParametersOfDeclarationOnNextLine: false
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: TopLevel
BinPackArguments: false
BinPackArguments: true
# fails
BinPackParameters: AlwaysOnePerLine
BraceWrapping:

View File

@ -0,0 +1,33 @@
---
description: C++ coding standards and formatting for OpenSTA
globs: ["**/*.cc", "**/*.hh", "**/*.h"]
alwaysApply: false
---
# C++ Coding Standards
## Line Width
- **Keep lines under 90 characters** to match `.clang-format` (ColumnLimit: 90).
- Break long lines at logical points: after commas, before operators, after opening parens.
## Naming Conventions
- **Classes**: Upper camel case (`ClassName`)
- **Member functions**: Lower camel case (`memberFunction`)
- **Member variables**: Snake case with trailing underscore (`member_variable_`)
- **Functions**: Lower camel case (`functionName`)
- **Variables**: Snake case
## Code Style
- Use `#pragma once` for header guards.
- Return type on the line before the function name; arguments on separate lines when long.
- No braces for single-line if/for; use braces for multi-line bodies.
- Prefer `std::string` over `char*` for string members.
- Prefer pass-by-value and move for sink parameters (parameters that get stored).
## File Extensions
- C++ source: `.cc`
- C++ headers: `.hh`

View File

@ -0,0 +1,43 @@
---
description: C++ function call indentation for OpenSTA
globs: ["**/*.cc", "**/*.hh", "**/*.h"]
alwaysApply: false
---
# C++ Function Call Indentation
## Short Calls — Single Line
When arguments fit within the column limit (90 chars), keep them on one line:
```cpp
// ✅ GOOD
adjusted_data_arrival = delaySum(required, data_shift_to_enable_clk, this);
// ❌ BAD
adjusted_data_arrival = delaySum(required,
data_shift_to_enable_clk,
this);
```
## Nested Function Calls — Align Under Inner Call
When breaking nested calls across lines:
- Indent continuation lines of the inner call under its first argument (align with content after `innerFunc(`).
- Place remaining outer arguments on the same line as the inner call's closing `)`, indented under the outer function.
```cpp
// ✅ GOOD
required = delayDiff(delaySum(max_delay,
search_->clkPathArrival(disable_path),
this),
margin, this);
// ❌ BAD
required = delayDiff(
delaySum(max_delay,
search_->clkPathArrival(disable_path),
this),
margin,
this);
```

16
BUILD
View File

@ -3,8 +3,8 @@
load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_hdl//dependency_support/com_github_westes_flex:flex.bzl", "genlex")
load("@rules_hdl//dependency_support/org_gnu_bison:bison.bzl", "genyacc")
load("//bazel:bison.bzl", "genyacc")
load("//bazel:flex.bzl", "genlex")
load("//bazel:tcl_encode_sta.bzl", "tcl_encode_sta")
load("//bazel:tcl_wrap_cc.bzl", "tcl_wrap_cc")
@ -177,8 +177,9 @@ tcl_encode_sta(
genrule(
name = "StaConfig",
srcs = [],
outs = ["util/StaConfig.hh"],
outs = ["include/sta/StaConfig.hh"],
cmd = """echo -e '
#pragma once
#define STA_VERSION "2.7.0"
#define STA_GIT_SHA1 "f21d4a3878e2531e3af4930818d9b5968aad9416"
#define SSTA 0
@ -296,7 +297,7 @@ cc_binary(
deps = [
":opensta_lib",
"@rules_cc//cc/runfiles",
"@tk_tcl//:tcl",
"@tcl_lang//:tcl",
],
)
@ -390,14 +391,17 @@ cc_library(
"util",
"verilog",
],
textual_hdrs = ["util/MachineLinux.cc"],
textual_hdrs = select({
"@platforms//os:osx": ["util/MachineApple.cc"],
"//conditions:default": ["util/MachineLinux.cc"],
}),
visibility = ["//:__subpackages__"],
deps = [
"@cudd",
"@eigen",
"@openmp",
"@rules_flex//flex:current_flex_toolchain",
"@tk_tcl//:tcl",
"@tcl_lang//:tcl",
"@zlib",
],
)

View File

@ -39,7 +39,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
)
@ -70,6 +70,16 @@ message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
message(STATUS "Build CXX_FLAGS: ${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}}")
message(STATUS "Install prefix: ${CMAKE_INSTALL_PREFIX}")
# Enable Link-Time Optimization (LTO) for Release builds.
include(CheckIPOSupported)
check_ipo_supported(RESULT ipo_supported OUTPUT ipo_error)
if(ipo_supported)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE)
message(STATUS "IPO/LTO: enabled for Release builds")
else()
message(STATUS "IPO/LTO: not supported - ${ipo_error}")
endif()
################################################################
#
# Source files.
@ -84,7 +94,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
@ -142,6 +151,7 @@ set(STA_SOURCE
parasitics/SpefReaderPvt.hh
power/Power.cc
power/ReportPower.cc
power/VcdReader.cc
power/SaifReader.cc
power/VcdParse.cc
@ -161,7 +171,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
@ -175,15 +184,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
@ -191,8 +199,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
@ -202,6 +210,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
@ -229,6 +238,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
@ -319,6 +329,20 @@ bison_target(SaifParse ${STA_HOME}/power/SaifParse.yy
${CMAKE_CURRENT_BINARY_DIR}/SaifParse.cc)
add_flex_bison_dependency(SaifLex SaifParse)
# Suppress -Wsign-compare in flex-generated code (yyleng vs int loop counter).
# Only needed with older GCC (e.g. CentOS 7 stock 4.8.5); newer GCC/flex handle it.
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set_source_files_properties(
${FLEX_VerilogLex_OUTPUTS}
${FLEX_LibertyLex_OUTPUTS}
${FLEX_LibExprLex_OUTPUTS}
${FLEX_SdfLex_OUTPUTS}
${FLEX_SpefLex_OUTPUTS}
${FLEX_SaifLex_OUTPUTS}
PROPERTIES COMPILE_FLAGS "-Wno-sign-compare"
)
endif()
################################################################
set(STA_TCL_INIT ${CMAKE_CURRENT_BINARY_DIR}/StaTclInitVar.cc)
@ -556,14 +580,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

@ -14,6 +14,8 @@ RUN sed -i s/mirror.centos.org/vault.centos.org/g /etc/yum.repos.d/*.repo \
&& yum install -y devtoolset-11 wget cmake3 make eigen3-devel tcl swig3 flex zlib-devel valgrind \
&& yum clean -y all
RUN ln -sf /usr/bin/cmake3 /usr/bin/cmake
# Download Bison
RUN wget https://ftp.gnu.org/gnu/bison/bison-3.8.2.tar.gz && \
tar -xvf bison-3.8.2.tar.gz && \
@ -60,8 +62,9 @@ WORKDIR /OpenSTA
RUN rm -rf build && mkdir build
RUN source /opt/rh/devtoolset-11/enable && \
cd build && \
cmake3 .. && \
make -j`nproc`
cmake .. && \
# LTO fails with -j
make
# Run sta on entry
ENTRYPOINT ["/OpenSTA/build/sta"]

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" {
@ -60,18 +60,18 @@ static const char *init_filename = ".sta";
static void
showUsage(const char *prog,
const char *init_filename);
const char *init_filename);
static int
tclAppInit(Tcl_Interp *interp);
static int
staTclAppInit(int argc,
char *argv[],
const char *init_filename,
Tcl_Interp *interp);
char *argv[],
const char *init_filename,
Tcl_Interp *interp);
static void
initStaApp(int &argc,
char *argv[],
Tcl_Interp *interp);
char *argv[],
Tcl_Interp *interp);
int
main(int argc,
@ -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;
}
}
@ -114,9 +105,9 @@ tclAppInit(Tcl_Interp *interp)
// Tcl init executed inside Tcl_Main.
static int
staTclAppInit(int argc,
char *argv[],
const char *init_filename,
Tcl_Interp *interp)
char *argv[],
const char *init_filename,
Tcl_Interp *interp)
{
// source init.tcl
if (Tcl_Init(interp) == TCL_ERROR)
@ -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);
}
}
@ -157,7 +148,7 @@ staTclAppInit(int argc,
if (argc == 2) {
char *cmd_file = argv[1];
if (cmd_file) {
int result = sourceTclFile(cmd_file, false, false, interp);
int result = sourceTclFile(cmd_file, false, false, interp);
if (exit_after_cmd_file) {
int exit_code = (result == TCL_OK) ? EXIT_SUCCESS : EXIT_FAILURE;
exit(exit_code);
@ -174,8 +165,8 @@ staTclAppInit(int argc,
static void
initStaApp(int &argc,
char *argv[],
Tcl_Interp *interp)
char *argv[],
Tcl_Interp *interp)
{
initSta();
Sta *sta = new Sta;
@ -194,7 +185,7 @@ initStaApp(int &argc,
static void
showUsage(const char *prog,
const char *init_filename)
const char *init_filename)
{
printf("Usage: %s [-help] [-version] [-no_init] [-exit] cmd_file\n", prog);
printf(" -help show help and exit\n");

View File

@ -30,14 +30,13 @@
#include "Machine.hh"
#include "StringUtil.hh"
#include "Vector.hh"
#include "Sta.hh"
namespace sta {
int
parseThreadsArg(int &argc,
char *argv[])
char *argv[])
{
char *thread_arg = findCmdLineKey(argc, argv, "-threads");
if (thread_arg) {
@ -53,15 +52,15 @@ parseThreadsArg(int &argc,
bool
findCmdLineFlag(int &argc,
char *argv[],
const char *flag)
char *argv[],
const char *flag)
{
for (int i = 1; i < argc; i++) {
char *arg = argv[i];
if (stringEq(arg, flag)) {
// Remove flag from argv.
for (int j = i + 1; j < argc; j++, i++)
argv[i] = argv[j];
argv[i] = argv[j];
argc--;
argv[argc] = nullptr;
return true;
@ -72,8 +71,8 @@ findCmdLineFlag(int &argc,
char *
findCmdLineKey(int &argc,
char *argv[],
const char *key)
char *argv[],
const char *key)
{
for (int i = 1; i < argc; i++) {
char *arg = argv[i];
@ -81,7 +80,7 @@ findCmdLineKey(int &argc,
char *value = argv[i + 1];
// Remove key and value from argv.
for (int j = i + 2; j < argc; j++, i++)
argv[i] = argv[j];
argv[i] = argv[j];
argc -= 2;
argv[argc] = nullptr;
return value;
@ -93,15 +92,15 @@ findCmdLineKey(int &argc,
// Use overridden version of source to echo cmds and results.
int
sourceTclFile(const char *filename,
bool echo,
bool verbose,
Tcl_Interp *interp)
bool echo,
bool verbose,
Tcl_Interp *interp)
{
std::string cmd;
stringPrint(cmd, "sta::include_file %s %s %s",
filename,
echo ? "1" : "0",
verbose ? "1" : "0");
filename,
echo ? "1" : "0",
verbose ? "1" : "0");
int code = Tcl_Eval(interp, cmd.c_str());
const char *result = Tcl_GetStringResult(interp);
if (result[0] != '\0')
@ -111,7 +110,7 @@ sourceTclFile(const char *filename,
void
evalTclInit(Tcl_Interp *interp,
const char *inits[])
const char *inits[])
{
char *unencoded = unencode(inits);
if (Tcl_Eval(interp, unencoded) != TCL_OK) {
@ -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;
@ -64,10 +65,11 @@ ArcDcalcWaveforms::inputWaveform(ArcDcalcArg &dcalc_arg,
report->error(1751, "VDD not defined in library %s", library->name());
Waveform in_waveform = driver_waveform->waveform(delayAsFloat(in_slew));
// Delay time axis.
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);
FloatSeq time_values;
for (float time : in_waveform.axis1()->values())
time_values.push_back(time + dcalc_arg.inputDelay());
TableAxisPtr time_axis = make_shared<TableAxis>(TableAxisVariable::time,
std::move(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

@ -66,7 +66,7 @@ public:
// n is the number of terms
// The vectors U[j] are of size n
class rcmodel : public ConcreteParasitic,
public arnoldi1
public arnoldi1
{
public:
rcmodel();

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"
@ -78,7 +77,7 @@ static void
delay_work_destroy(delay_work *D);
static double *
delay_work_get_residues(delay_work *D,
int term_index);
int term_index);
static bool
tridiagEV(int n,double *d,double *e,double *p,double **v);
@ -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,21 +149,23 @@ 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,
double lo,
double hi,
bool rising,
double derate);
double lo,
double hi,
bool rising,
double derate);
private:
ArcDcalcResult gateDelaySlew(const LibertyCell *drvr_cell,
@ -173,61 +177,61 @@ private:
void ar1_ceff_delay(delay_work *D,
timing_table *tab,
arnoldi1 *mod,
double *delays,
double *delays,
double *slews);
double ra_rdelay_1(timing_table *tab,
double ctot);
double ctot);
double ra_get_r(delay_work *D,
timing_table *tab,
double rdelay,
double ctot);
timing_table *tab,
double rdelay,
double ctot);
double ra_get_s(delay_work *D,
timing_table *tab,
double r,
double c);
timing_table *tab,
double r,
double c);
void ra_solve_for_s(delay_work *D,
double p,
double tlohi,
double &s);
double p,
double tlohi,
double &s);
// from poles and residues, solve for t20,t50,t80
void pr_solve1(double s,
int order,
double *p,
double *rr,
double v1,
double *t1);
int order,
double *p,
double *rr,
double v1,
double *t1);
void pr_solve3(double s,
int order,
double *p,
double *rr,
double vhi,
double *thi,
double vmid,
double *tmid,
double vlo,
double *tlo);
int order,
double *p,
double *rr,
double vhi,
double *thi,
double vmid,
double *tmid,
double vlo,
double *tlo);
//
// routines for linear drive model and ceff
//
double pr_ceff(double s,
double rdrive,
int order,
double *p,
double *rr,
double ceff_time);
double rdrive,
int order,
double *p,
double *rr,
double ceff_time);
double ra_solve_for_t(double p,
double s,
double v);
double s,
double v);
void ra_solve_for_pt(double ps,
double v,
double *pt,
double *d);
double v,
double *pt,
double *d);
void ra_calc_c(double lo,
double hi,
double *c_smin,
double *c_x1,
double *c_y1);
double hi,
double *c_smin,
double *c_x1,
double *c_y1);
rcmodel *rcmodel_;
int _pinNmax;
@ -272,36 +276,35 @@ ArnoldiDelayCalc::~ArnoldiDelayCalc()
Parasitic *
ArnoldiDelayCalc::findParasitic(const Pin *drvr_pin,
const RiseFall *drvr_rf,
const DcalcAnalysisPt *dcalc_ap)
const RiseFall *drvr_rf,
const Scene *scene,
const MinMax *min_max)
{
Parasitic *parasitic = nullptr;
const Corner *corner = dcalc_ap->corner();
// set_load net has precedence 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;
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,28 +394,29 @@ 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
ArnoldiDelayCalc::gateDelaySlew(const LibertyCell *drvr_cell,
const TimingArc *arc,
const GateTableModel *table_model,
const Slew &in_slew,
const GateTableModel *table_model,
const Slew &in_slew,
const LoadPinIndexMap &load_pin_index_map,
const Pvt *pvt)
{
@ -432,7 +438,7 @@ ArnoldiDelayCalc::gateDelaySlew(const LibertyCell *drvr_cell,
double hi_thresh = drvr_library->slewUpperThreshold(rf);
bool rising = (rf == RiseFall::rise());
delay_work_set_thresholds(delay_work_, lo_thresh, hi_thresh, rising,
slew_derate);
slew_derate);
if (rcmodel_->order > 0) {
timing_table tab;
tab.table = table_model;
@ -440,7 +446,7 @@ ArnoldiDelayCalc::gateDelaySlew(const LibertyCell *drvr_cell,
tab.pvt = pvt;
tab.in_slew = delayAsFloat(in_slew);
ar1_ceff_delay(delay_work_, &tab, rcmodel_,
_delayV, _slewV);
_delayV, _slewV);
}
dcalc_result.setGateDelay(_delayV[0]);
dcalc_result.setDrvrSlew(_slewV[0]);
@ -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);
}
////////////////////////////////////////////////////////////////
@ -560,10 +567,10 @@ delay_work_alloc(delay_work *D,int n)
void
ArnoldiDelayCalc::delay_work_set_thresholds(delay_work *D,
double lo,
double hi,
bool rising,
double derate)
double lo,
double hi,
bool rising,
double derate)
{
double mid = 0.5; // 0.0:1.0
int i = rising?1:0;
@ -582,7 +589,7 @@ ArnoldiDelayCalc::delay_work_set_thresholds(delay_work *D,
D->c->vmid = mid;
D->c->vlg = log(hi/lo);
ra_calc_c(lo,hi,
&(D->c->smin), &(D->c->x1),&(D->c->y1));
&(D->c->smin), &(D->c->x1),&(D->c->y1));
}
D->lo_thresh = D->c->vlo;
D->hi_thresh = D->c->vhi;
@ -790,7 +797,7 @@ get_dv(double t, double s, int order, double *p, double *rr,
static double
solve_t_bracketed(double s,int order,double *p,double *rr,
double val,double x1,double x2,double v1,double v2)
double val,double x1,double x2,double v1,double v2)
{
int j;
double df,dx,dxold,f,f2,f1;
@ -859,17 +866,17 @@ solve_t_bracketed(double s,int order,double *p,double *rr,
void
ArnoldiDelayCalc::pr_solve1(double s,
int order,
double *p,
double *rr,
double v1,
double *t1)
int order,
double *p,
double *rr,
double v1,
double *t1)
{
double tmin = 0.0,tmax = 0.0,vmin = 0.0,vmax = 0.0;
int h, h0 = 0;
while (order>1
&& rr[order-1]<1e-8 // 1e-8V
&& rr[order-1]>-1e-8)
&& rr[order-1]<1e-8 // 1e-8V
&& rr[order-1]>-1e-8)
order--;
if (rr[0]<0.5) {
for (h=1;h<order;h++) if (rr[h]>0.3 && rr[h]>rr[0]) { h0 = h; break; }
@ -893,7 +900,7 @@ ArnoldiDelayCalc::pr_solve1(double s,
// ignoring a typical error at drive node, that comes
// from slight inaccuracies in rr
if (!(rr[order-1]>1.0 && p[order-1]>500.0 && va>v1-0.002))
debugPrint(debug_, "arnoldi", 1, "err, pr_solve1, va<v1");
debugPrint(debug_, "arnoldi", 1, "err, pr_solve1, va<v1");
}
tmin = ta; vmin = va;
} else {
@ -906,7 +913,7 @@ ArnoldiDelayCalc::pr_solve1(double s,
pr_get_v(ta,s,order,p,rr,&va);
}
if (va>v1)
debugPrint(debug_, "arnoldi", 1, "err, pr_solve1, va>v1");
debugPrint(debug_, "arnoldi", 1, "err, pr_solve1, va>v1");
tmax = ta; vmax = va;
}
} else {
@ -925,15 +932,15 @@ ArnoldiDelayCalc::pr_solve1(double s,
void
ArnoldiDelayCalc::pr_solve3(double s,
int order,
double *p,
double *rr,
double vhi,
double *thi,
double vmid,
double *tmid,
double vlo,
double *tlo)
int order,
double *p,
double *rr,
double vhi,
double *thi,
double vmid,
double *tmid,
double vlo,
double *tlo)
{
// falling, thi<tmin<tlo
double tmin2,tmax2,vmin2,vmax2;
@ -941,8 +948,8 @@ ArnoldiDelayCalc::pr_solve3(double s,
double tmin8,tmax8,vmin8,vmax8;
int h, h0 = 0;
while (order>1
&& rr[order-1]<1e-8 // 1e-8V
&& rr[order-1]>-1e-8)
&& rr[order-1]<1e-8 // 1e-8V
&& rr[order-1]>-1e-8)
order--;
if (rr[0]<0.5) {
for (h=1;h<order;h++) if (rr[h]>0.3 && rr[h]>rr[0]) { h0 = h; break; }
@ -1111,11 +1118,11 @@ calc_integ(double p,double s,double t)
double
ArnoldiDelayCalc::pr_ceff(double s,
double rdrive,
int order,
double *p,
double *rr,
double ceff_time)
double rdrive,
int order,
double *p,
double *rr,
double ceff_time)
{
double integi = 0.0;
double ceff, v0;
@ -1133,7 +1140,7 @@ ArnoldiDelayCalc::pr_ceff(double s,
static double
ra_hinv(double y,
Debug *debug)
Debug *debug)
{
double x;
if (y<1.0) {
@ -1160,8 +1167,8 @@ ra_hinv(double y,
double
ArnoldiDelayCalc::ra_solve_for_t(double p,
double s,
double v)
double s,
double v)
{
double t;
double ps = p*s;
@ -1180,9 +1187,9 @@ ArnoldiDelayCalc::ra_solve_for_t(double p,
void
ArnoldiDelayCalc::ra_solve_for_pt(double ps,
double v,
double *pt,
double *d)
double v,
double *pt,
double *d)
{
if (ps>30.0) {
*pt = 1.0+ps*(1.0-v);
@ -1201,10 +1208,10 @@ ArnoldiDelayCalc::ra_solve_for_pt(double ps,
void
ArnoldiDelayCalc::ra_calc_c(double vlo,
double vhi,
double *c_smin,
double *c_x1,
double *c_y1)
double vhi,
double *c_smin,
double *c_x1,
double *c_y1)
{
double a = log(1.0/vhi);
*c_smin = a + ra_hinv((1.0-vhi)/vhi - a, debug_);
@ -1224,9 +1231,9 @@ ArnoldiDelayCalc::ra_calc_c(double vlo,
void
ArnoldiDelayCalc::ra_solve_for_s(delay_work *D,
double p,
double tlohi,
double &s)
double p,
double tlohi,
double &s)
{
delay_c *c = D->c;
double vhi = c->vhi;
@ -1258,28 +1265,28 @@ ArnoldiDelayCalc::ra_solve_for_s(delay_work *D,
f = (ptlo-pthi)/p - tlohi;
df = dlo-dhi;
s = s - f/df;
if (abs(f)<.001e-12) return; // .001ps
if (abs(f)<.001e-12) return; // .001ps
ra_solve_for_pt(p*s,vlo,&ptlo,&dlo);
ra_solve_for_pt(p*s,vhi,&pthi,&dhi);
f = (ptlo-pthi)/p - tlohi;
df = dlo-dhi;
s = s - f/df;
if (abs(f)<.001e-12) return; // .001ps
if (abs(f)<.001e-12) return; // .001ps
ra_solve_for_pt(p*s,vlo,&ptlo,&dlo);
ra_solve_for_pt(p*s,vhi,&pthi,&dhi);
f = (ptlo-pthi)/p - tlohi;
df = dlo-dhi;
s = s - f/df;
if (abs(f)<.001e-12) return; // .001ps
if (abs(f)<.001e-12) return; // .001ps
ra_solve_for_pt(p*s,vlo,&ptlo,&dlo);
ra_solve_for_pt(p*s,vhi,&pthi,&dhi);
f = (ptlo-pthi)/p - tlohi;
df = dlo-dhi;
s = s - f/df;
if (abs(f)<.001e-12) return; // .001ps
if (abs(f)<.001e-12) return; // .001ps
ra_solve_for_pt(p*s,vlo,&ptlo,&dlo);
ra_solve_for_pt(p*s,vhi,&pthi,&dhi);
@ -1308,9 +1315,9 @@ ArnoldiDelayCalc::ra_solve_for_s(delay_work *D,
// Rough translation of ra_get_r(sy_table) used by ar1_ceff_delay.
double
ArnoldiDelayCalc::ra_get_r(delay_work *D,
timing_table *tab,
double rdelay,
double ctot)
timing_table *tab,
double rdelay,
double ctot)
{
// find the maximum r that allows a solution for s of
// (s,r,ctot)-> output_slew
@ -1333,9 +1340,9 @@ ArnoldiDelayCalc::ra_get_r(delay_work *D,
double
ArnoldiDelayCalc::ra_get_s(delay_work *D,
timing_table *tab,
double r,
double c)
timing_table *tab,
double r,
double c)
{
delay_c *con = D->c;
double slew_derate = con->slew_derate;
@ -1367,7 +1374,7 @@ ArnoldiDelayCalc::ra_get_s(delay_work *D,
double
ArnoldiDelayCalc::ra_rdelay_1(timing_table *tab,
double ctot)
double ctot)
{
// determine the drive resistance from change in delay versus ctot
float c1 = ctot;
@ -1387,10 +1394,10 @@ ArnoldiDelayCalc::ra_rdelay_1(timing_table *tab,
void
ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
timing_table *tab,
arnoldi1 *mod,
double *delays,
double *slews)
timing_table *tab,
arnoldi1 *mod,
double *delays,
double *slews)
{
delay_c *con = D->c;
double slew_derate = con->slew_derate;
@ -1411,13 +1418,13 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
r = rdelay;
r = ra_get_r(D,tab,rdelay,ctot);
if (! (r>0.0
&& r<100e+3)) // 100khom
&& r<100e+3)) // 100khom
rdelay = 1e+3; // 1kohm
bool bad = (r<rdelay);
s = ra_get_s(D,tab,r,ctot);
if (! (s>0.0
&& s<100e-9)) // 100ns
&& s<100e-9)) // 100ns
s = 0.5e-9; // .5ns
if (debug_->check("arnoldi", 1)) {
@ -1464,9 +1471,9 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
ceff = pr_ceff(s,r,mod->order,p,rr,ceff_time);
if ((ceff-1e-20) < 0.0) { // 1e-8pf
debugPrint(debug_, "arnoldi", 1,
debugPrint(debug_, "arnoldi", 1,
"Invalid effective capacitance, using total capacitance");
ceff = ctot;
ceff = ctot;
}
// new mvs at ceff

View File

@ -151,20 +151,20 @@ ArnoldiReduce::~ArnoldiReduce()
rcmodel *
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 Pin *drvr_pin,
float coupling_cap_factor,
const RiseFall *rf,
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();
}
@ -426,17 +426,17 @@ ArnoldiReduce::getRC()
if (p->node_) {
ParasiticNode *node = p->node_;
double cap = parasitics_->nodeGndCap(node)
+ pinCapacitance(node);
+ pinCapacitance(node);
if (cap > 0.0) {
p->c = cap;
ctot_ += cap;
p->c = cap;
ctot_ += cap;
}
else
p->c = 0.0;
p->c = 0.0;
if (p->in_edge && p->in_edge->resistor_)
p->r = parasitics_->value(p->in_edge->resistor_);
if (!(p->r>=0.0 && p->r<100e+3)) { // 0 < r < 100kohm
debugPrint(debug_, "arnoldi", 1,
debugPrint(debug_, "arnoldi", 1,
"R value %g out of range, drvr pin %s",
p->r,
network_->pathName(drvr_pin_));
@ -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;
}
@ -510,7 +511,7 @@ ArnoldiReduce::makeRcmodelFromTs()
if (p->is_term)
debugPrint(debug_, "arnoldi", 1, " term %d", p->tindex);
if (p->in_edge)
debugPrint(debug_, "arnoldi", 1, " from T%d,P%ld r=%s",
debugPrint(debug_, "arnoldi", 1, " from T%d,P%ld r=%s",
p->in_edge->from->ts,
p->in_edge->from-p0,
units_->resistanceUnit()->asString(p->r));
@ -610,19 +611,19 @@ ArnoldiReduce::makeRcmodelFromTs()
report_->reportLine("order %d n %d",order,n);
for (h=0;h<order;h++) {
if (h<order-1)
report_->reportLine(" d[%d] %s e[%d] %s",
report_->reportLine(" d[%d] %s e[%d] %s",
h,
units_->timeUnit()->asString(d[h]),
h,
units_->timeUnit()->asString(e[h]));
else
report_->reportLine(" d[%d] %s",
report_->reportLine(" d[%d] %s",
h,
units_->timeUnit()->asString(d[h]));
string line = stdstrPrint("U[%d]",h);
for (i=0;i<nterms;i++)
line += stdstrPrint(" %6.2e",U[h][i]);
line += stdstrPrint(" %6.2e",U[h][i]);
report_->reportLineString(line);
}
}

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
@ -529,12 +530,13 @@ CcsCeffDelayCalc::drvrWaveform()
}
}
TableAxisPtr drvr_time_axis = make_shared<TableAxis>(TableAxisVariable::time,
drvr_times);
Table1 drvr_table(drvr_volts, drvr_time_axis);
std::move(*drvr_times));
delete drvr_times;
Table drvr_table(drvr_volts, drvr_time_axis);
return drvr_table;
}
else
return Table1();
return Table();
}
Waveform
@ -560,12 +562,13 @@ CcsCeffDelayCalc::loadWaveform(const Pin *load_pin)
load_volts->push_back(v1);
}
TableAxisPtr load_time_axis = make_shared<TableAxis>(TableAxisVariable::time,
load_times);
Table1 load_table(load_volts, load_time_axis);
std::move(*load_times));
delete load_times;
Table load_table(load_volts, load_time_axis);
return load_table;
}
}
return Table1();
return Table();
}
Waveform
@ -574,7 +577,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 +585,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;
@ -604,12 +607,13 @@ CcsCeffDelayCalc::drvrRampWaveform(const Pin *in_pin,
load_volts->push_back(v1);
}
TableAxisPtr load_time_axis = make_shared<TableAxis>(TableAxisVariable::time,
load_times);
Table1 load_table(load_volts, load_time_axis);
std::move(*load_times));
delete load_times;
Table load_table(load_volts, load_time_axis);
return load_table;
}
}
return Table1();
return Table();
}
bool
@ -617,7 +621,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 +645,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 +670,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;
@ -53,7 +55,7 @@ registerDelayCalcs()
void
registerDelayCalc(const char *name,
MakeArcDelayCalc maker)
MakeArcDelayCalc maker)
{
if (delay_calcs == nullptr)
delay_calcs = new DelayCalcMap;
@ -69,9 +71,9 @@ deleteDelayCalcs()
ArcDelayCalc *
makeDelayCalc(const char *name,
StaState *sta)
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 MinMax *min_max,
int digits)
TimingArc *arc,
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
@ -52,14 +52,14 @@ proc report_dcalc_cmd { cmd cmd_args digits_key } {
set to_pin [get_port_pin_error "to_pin" $keys(-to)]
foreach from_vertex [$from_pin vertices] {
foreach to_vertex [$to_pin vertices] {
set iter [$from_vertex out_edge_iterator]
while {[$iter has_next]} {
set edge [$iter next]
if { [$edge to] == $to_vertex } {
report_edge_dcalc $edge $corner $min_max $digits
}
}
$iter finish
set iter [$from_vertex out_edge_iterator]
while {[$iter has_next]} {
set edge [$iter next]
if { [$edge to] == $to_vertex } {
report_edge_dcalc $edge $scene $min_max $digits
}
}
$iter finish
}
}
} elseif [info exists keys(-from)] {
@ -67,8 +67,8 @@ proc report_dcalc_cmd { cmd cmd_args digits_key } {
foreach from_vertex [$from_pin vertices] {
set iter [$from_vertex out_edge_iterator]
while {[$iter has_next]} {
set edge [$iter next]
report_edge_dcalc $edge $corner $min_max $digits
set edge [$iter next]
report_edge_dcalc $edge $scene $min_max $digits
}
$iter finish
}
@ -77,15 +77,15 @@ proc report_dcalc_cmd { cmd cmd_args digits_key } {
foreach to_vertex [$to_pin vertices] {
set iter [$to_vertex in_edge_iterator]
while {[$iter has_next]} {
set edge [$iter next]
report_edge_dcalc $edge $corner $min_max $digits
set edge [$iter next]
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]
@ -96,7 +96,7 @@ proc report_edge_dcalc { edge corner min_max digits } {
set library [$cell library]
# Filter timing checks based on min_max.
if {!(($min_max == "max" && $role == "hold") \
|| ($min_max=="min" && $role=="setup"))} {
|| ($min_max=="min" && $role=="setup"))} {
report_line "Library: [get_name $library]"
report_line "Cell: [get_name $cell]"
set sense [$edge sense]
@ -106,18 +106,18 @@ proc report_edge_dcalc { edge corner min_max digits } {
report_line "Arc type: $role"
foreach arc [$edge timing_arcs] {
set from [get_name [$from_pin port]]
set from_rf [$arc from_edge]
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 "Annotated value = [format_time $delay $digits]"
}
report_line "............................................."
report_line ""
set from [get_name [$from_pin port]]
set from_rf [$arc from_edge]
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 $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 "............................................."
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]
@ -176,14 +176,14 @@ proc set_assigned_delay { args } {
if { $from_pins != {} } {
set inst [[lindex $from_pins 0] instance]
foreach pin $from_pins {
if {[$pin instance] != $inst} {
sta_error 185 "set_assigned_delay pin [get_full_name $pin] is not attached to instance [get_full_name $inst]."
}
if {[$pin instance] != $inst} {
sta_error 185 "set_assigned_delay pin [get_full_name $pin] is not attached to instance [get_full_name $inst]."
}
}
foreach pin $to_pins {
if {[$pin instance] != $inst} {
sta_error 186 "set_assigned_delay pin [get_full_name $pin] is not attached to instance [get_full_name $inst]"
}
if {[$pin instance] != $inst} {
sta_error 186 "set_assigned_delay pin [get_full_name $pin] is not attached to instance [get_full_name $inst]"
}
}
}
} elseif {![info exists flags(-net)]} {
@ -192,40 +192,40 @@ 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]} {
set edge [$edge_iter next]
if { [$edge to] == $to_vertex \
&& ![timing_role_is_check [$edge role]] } {
&& ![timing_role_is_check [$edge role]] } {
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
if { $to_rf == "rise_fall" \
|| $to_rf eq [$arc to_edge_name] } {
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
@ -258,7 +258,7 @@ proc set_assigned_check { args } {
if { [info exists keys(-clock)] } {
set clk_arg $keys(-clock)
if { $clk_arg eq "rise" \
|| $clk_arg eq "fall" } {
|| $clk_arg eq "fall" } {
set from_rf $clk_arg
} else {
sta_error 189 "set_assigned_check -clock must be rise or fall."
@ -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,46 +298,46 @@ 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 \
$cond $check_value
[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]} {
set edge [$edge_iter next]
if { [$edge to] == $to_vertex } {
foreach arc [$edge timing_arcs] {
if { ($from_rf eq "rise_fall" \
|| $from_rf eq [$arc from_edge_name]) \
&& ($to_rf eq "rise_fall" \
|| $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
if { ($from_rf eq "rise_fall" \
|| $from_rf eq [$arc from_edge_name]) \
&& ($to_rf eq "rise_fall" \
|| $to_rf eq [$arc to_edge_name]) \
&& [$arc role] eq $role \
&& ($cond eq "" || [$arc sdf_cond] eq $cond) } {
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);
}
}
}
@ -136,7 +131,7 @@ DelayCalcBase::thresholdAdjust(const Pin *load_pin,
float drvr_slew_derate = drvr_library->slewDerateFromLibrary();
float load_slew_derate = load_library->slewDerateFromLibrary();
load_slew = load_slew * ((load_slew_delta / load_slew_derate)
/ (drvr_slew_delta / drvr_slew_derate));
/ (drvr_slew_delta / drvr_slew_derate));
}
}
@ -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:
@ -68,18 +72,19 @@ protected:
void thresholdAdjust(const Pin *load_pin,
const LibertyLibrary *drvr_library,
const RiseFall *rf,
ArcDelay &load_delay,
Slew &load_slew);
ArcDelay &load_delay,
Slew &load_slew);
// Helper function for input ports driving dspf parasitic.
void dspfWireDelaySlew(const Pin *load_pin,
const RiseFall *rf,
const RiseFall *rf,
Slew drvr_slew,
float elmore,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew);
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"
@ -95,36 +94,36 @@ private:
static double
gateModelRd(const LibertyCell *cell,
const GateTableModel *gate_model,
const RiseFall *rf,
double in_slew,
double c2,
double c1,
const Pvt *pvt,
bool pocv_enabled);
const GateTableModel *gate_model,
const RiseFall *rf,
double in_slew,
double c2,
double c1,
const Pvt *pvt,
bool pocv_enabled);
static void
newtonRaphson(const int max_iter,
double x[],
const int n,
const double x_tol,
// eval(state) is called to fill fvec and fjac.
function<void ()> eval,
// Temporaries supplied by caller.
double *fvec,
double **fjac,
int *index,
double *p,
double *scale);
double x[],
const int n,
const double x_tol,
// eval(state) is called to fill fvec and fjac.
function<void ()> eval,
// Temporaries supplied by caller.
double *fvec,
double **fjac,
int *index,
double *p,
double *scale);
static void
luSolve(double **a,
const int size,
const int *index,
double b[]);
const int size,
const int *index,
double b[]);
static void
luDecomp(double **a,
const int size,
int *index,
double *scale);
const int size,
int *index,
double *scale);
////////////////////////////////////////////////////////////////
@ -138,23 +137,23 @@ public:
virtual const char *name() = 0;
// Set driver model and pi model parameters for delay calculation.
virtual void init(const LibertyLibrary *library,
const LibertyCell *drvr_cell,
const Pvt *pvt,
const GateTableModel *gate_model,
const RiseFall *rf,
double rd,
double in_slew,
double c2,
double rpi,
double c1);
const LibertyCell *drvr_cell,
const Pvt *pvt,
const GateTableModel *gate_model,
const RiseFall *rf,
double rd,
double in_slew,
double c2,
double rpi,
double c1);
virtual void gateDelaySlew(// Return values.
double &delay,
double &slew) = 0;
double &slew) = 0;
virtual void loadDelaySlew(const Pin *load_pin,
double elmore,
double elmore,
// Return values.
ArcDelay &delay,
Slew &slew);
ArcDelay &delay,
Slew &slew);
double ceff() { return ceff_; }
// Given x_ as a vector of input parameters, fill fvec_ with the
@ -176,32 +175,32 @@ protected:
void findDriverParams(double ceff);
void gateCapDelaySlew(double cl,
// Return values.
double &delay,
double &slew);
double &delay,
double &slew);
void gateDelays(double ceff,
// Return values.
double &t_vth,
double &t_vl,
double &slew);
double &t_vth,
double &t_vl,
double &slew);
// Partial derivatives of y(t) (jacobian).
void dy(double t,
double t0,
double dt,
double cl,
double t0,
double dt,
double cl,
// Return values.
double &dydt0,
double &dyddt,
double &dydcl);
double &dydt0,
double &dyddt,
double &dydcl);
double y0dt(double t,
double cl);
double cl);
double y0dcl(double t,
double cl);
double cl);
void showX();
void showFvec();
void showJacobian();
void findDriverDelaySlew(// Return values.
double &delay,
double &slew);
double &slew);
double findVoCrossing(double vth,
double lower_bound,
double upper_bound);
@ -214,12 +213,12 @@ protected:
// Output response to vs(t) ramp driving capacitive load.
double y(double t,
double t0,
double dt,
double cl);
double t0,
double dt,
double cl);
// Output response to unit ramp driving capacitive load.
double y0(double t,
double cl);
double cl);
// Output response to unit ramp driving pi model load.
virtual void V0(double t,
// Return values.
@ -285,7 +284,7 @@ protected:
};
DmpAlg::DmpAlg(int nr_order,
StaState *sta):
StaState *sta):
StaState(sta),
c2_(0.0),
rpi_(0.0),
@ -301,16 +300,16 @@ DmpAlg::~DmpAlg() = default;
void
DmpAlg::init(const LibertyLibrary *drvr_library,
const LibertyCell *drvr_cell,
const Pvt *pvt,
const GateTableModel *gate_model,
const RiseFall *rf,
double rd,
double in_slew,
// Pi model.
double c2,
double rpi,
double c1)
const LibertyCell *drvr_cell,
const Pvt *pvt,
const GateTableModel *gate_model,
const RiseFall *rf,
double rd,
double in_slew,
// Pi model.
double c2,
double rpi,
double c1)
{
drvr_library_ = drvr_library;
drvr_cell_ = drvr_cell;
@ -343,7 +342,7 @@ DmpAlg::findDriverParams(double ceff)
x_[DmpParam::t0] = t0;
newtonRaphson(100, x_, nr_order_, driver_param_tol,
[this] () { evalDmpEqns(); },
fvec_, fjac_, index_, p_, scale_);
fvec_, fjac_, index_, p_, scale_);
t0_ = x_[DmpParam::t0];
dt_ = x_[DmpParam::dt];
debugPrint(debug_, "dmp_ceff", 3, " t0 = %s dt = %s ceff = %s",
@ -356,9 +355,9 @@ DmpAlg::findDriverParams(double ceff)
void
DmpAlg::gateCapDelaySlew(double ceff,
// Return values.
// Return values.
double &delay,
double &slew)
double &slew)
{
ArcDelay model_delay;
Slew model_slew;
@ -371,10 +370,10 @@ DmpAlg::gateCapDelaySlew(double ceff,
void
DmpAlg::gateDelays(double ceff,
// Return values.
// Return values.
double &t_vth,
double &t_vl,
double &slew)
double &t_vl,
double &slew)
{
double table_slew;
gateCapDelaySlew(ceff, t_vth, table_slew);
@ -385,9 +384,9 @@ DmpAlg::gateDelays(double ceff,
double
DmpAlg::y(double t,
double t0,
double dt,
double cl)
double t0,
double dt,
double cl)
{
double t1 = t - t0;
if (t1 <= 0.0)
@ -400,20 +399,20 @@ DmpAlg::y(double t,
double
DmpAlg::y0(double t,
double cl)
double cl)
{
return t - rd_ * cl * (1.0 - exp2(-t / (rd_ * cl)));
}
void
DmpAlg::dy(double t,
double t0,
double dt,
double cl,
// Return values.
double &dydt0,
double &dyddt,
double &dydcl)
double t0,
double dt,
double cl,
// Return values.
double &dydt0,
double &dyddt,
double &dydcl)
{
double t1 = t - t0;
if (t1 <= 0.0)
@ -433,14 +432,14 @@ DmpAlg::dy(double t,
double
DmpAlg::y0dt(double t,
double cl)
double cl)
{
return 1.0 - exp2(-t / (rd_ * cl));
}
double
DmpAlg::y0dcl(double t,
double cl)
double cl)
{
return rd_ * ((1.0 + t / (rd_ * cl)) * exp2(-t / (rd_ * cl)) - 1);
}
@ -478,7 +477,7 @@ DmpAlg::showJacobian()
void
DmpAlg::findDriverDelaySlew(// Return values.
double &delay,
double &slew)
double &slew)
{
double t_upper = voCrossingUpperBound();
delay = findVoCrossing(vth_, t0_, t_upper);
@ -554,9 +553,9 @@ DmpAlg::showVo()
void
DmpAlg::loadDelaySlew(const Pin *,
double elmore,
ArcDelay &delay,
Slew &slew)
double elmore,
ArcDelay &delay,
Slew &slew)
{
if (!driver_valid_
|| elmore == 0.0
@ -570,7 +569,7 @@ DmpAlg::loadDelaySlew(const Pin *,
// convert the delay and slew to the load's thresholds.
try {
if (debug_->check("dmp_ceff", 4))
showVl();
showVl();
elmore_ = elmore;
p3_ = 1.0 / elmore;
double t_lower = t0_;
@ -583,17 +582,17 @@ DmpAlg::loadDelaySlew(const Pin *,
// Convert measured slew to reported/table slew.
double slew1 = (th - tl) / slew_derate_;
if (delay1 < 0.0) {
// Only report a problem if the difference is significant.
if (-delay1 > vth_time_tol * vo_delay_)
fail("load delay less than zero");
// Use elmore delay.
delay1 = elmore;
// Only report a problem if the difference is significant.
if (-delay1 > vth_time_tol * vo_delay_)
fail("load delay less than zero");
// Use elmore delay.
delay1 = elmore;
}
if (slew1 < drvr_slew_) {
// Only report a problem if the difference is significant.
if ((drvr_slew_ - slew1) > vth_time_tol * drvr_slew_)
fail("load slew less than driver slew");
slew1 = drvr_slew_;
// Only report a problem if the difference is significant.
if ((drvr_slew_ - slew1) > vth_time_tol * drvr_slew_)
fail("load slew less than driver slew");
slew1 = drvr_slew_;
}
delay = delay1;
slew = slew1;
@ -735,26 +734,26 @@ DmpCap::DmpCap(StaState *sta):
void
DmpCap::init(const LibertyLibrary *drvr_library,
const LibertyCell *drvr_cell,
const Pvt *pvt,
const GateTableModel *gate_model,
const RiseFall *rf,
double rd,
double in_slew,
double c2,
double rpi,
double c1)
const LibertyCell *drvr_cell,
const Pvt *pvt,
const GateTableModel *gate_model,
const RiseFall *rf,
double rd,
double in_slew,
double c2,
double rpi,
double c1)
{
debugPrint(debug_, "dmp_ceff", 3, "Using DMP cap");
DmpAlg::init(drvr_library, drvr_cell, pvt, gate_model, rf,
rd, in_slew, c2, rpi, c1);
rd, in_slew, c2, rpi, c1);
ceff_ = c1 + c2;
}
void
DmpCap::gateDelaySlew(// Return values.
double &delay,
double &slew)
double &slew)
{
debugPrint(debug_, "dmp_ceff", 3, " ceff = %s",
units_->capacitanceUnit()->asString(ceff_));
@ -764,9 +763,9 @@ DmpCap::gateDelaySlew(// Return values.
void
DmpCap::loadDelaySlew(const Pin *,
double elmore,
ArcDelay &delay,
Slew &slew)
double elmore,
ArcDelay &delay,
Slew &slew)
{
delay = elmore;
slew = drvr_slew_;
@ -830,9 +829,9 @@ public:
private:
void findDriverParamsPi();
double ipiIceff(double t0,
double dt,
double ceff_time,
double ceff);
double dt,
double ceff_time,
double ceff);
void V0(double t,
// Return values.
double &vo,
@ -876,19 +875,19 @@ DmpPi::DmpPi(StaState *sta) :
void
DmpPi::init(const LibertyLibrary *drvr_library,
const LibertyCell *drvr_cell,
const Pvt *pvt,
const GateTableModel *gate_model,
const RiseFall *rf,
double rd,
double in_slew,
double c2,
double rpi,
double c1)
const LibertyCell *drvr_cell,
const Pvt *pvt,
const GateTableModel *gate_model,
const RiseFall *rf,
double rd,
double in_slew,
double c2,
double rpi,
double c1)
{
debugPrint(debug_, "dmp_ceff", 3, "Using DMP Pi");
DmpAlg::init(drvr_library, drvr_cell, pvt, gate_model, rf, rd,
in_slew, c2, rpi, c1);
in_slew, c2, rpi, c1);
// Find poles/zeros.
z1_ = 1.0 / (rpi_ * c1_);
@ -914,7 +913,7 @@ DmpPi::init(const LibertyLibrary *drvr_library,
void
DmpPi::gateDelaySlew(// Return values.
double &delay,
double &slew)
double &slew)
{
driver_valid_ = false;
try {
@ -1000,7 +999,7 @@ DmpPi::evalDmpEqns()
(-A_ * dt + B_ * dt * exp_p1_dt - (2 * B_ / p1_) * (1.0 - exp_p1_dt)
+ D_ * dt * exp_p2_dt - (2 * D_ / p2_) * (1.0 - exp_p2_dt)
+ rd_ * ceff * (dt + dt * exp_dt_rd_ceff
- 2 * rd_ * ceff * (1.0 - exp_dt_rd_ceff)))
- 2 * rd_ * ceff * (1.0 - exp_dt_rd_ceff)))
/ (rd_ * dt * dt * dt);
fjac_[DmpFunc::ipi][DmpParam::ceff] =
(2 * rd_ * ceff - dt - (2 * rd_ * ceff + dt) * exp2(-dt / (rd_ * ceff)))
@ -1027,17 +1026,17 @@ DmpPi::evalDmpEqns()
// Eqn 13, Eqn 14.
double
DmpPi::ipiIceff(double, double dt,
double ceff_time,
double ceff)
double ceff_time,
double ceff)
{
double exp_p1_dt = exp2(-p1_ * ceff_time);
double exp_p2_dt = exp2(-p2_ * ceff_time);
double exp_dt_rd_ceff = exp2(-ceff_time / (rd_ * ceff));
double ipi = (A_ * ceff_time + (B_ / p1_) * (1.0 - exp_p1_dt)
+ (D_ / p2_) * (1.0 - exp_p2_dt))
+ (D_ / p2_) * (1.0 - exp_p2_dt))
/ (rd_ * ceff_time * dt);
double iceff = (rd_ * ceff * ceff_time - (rd_ * ceff) * (rd_ * ceff)
* (1.0 - exp_dt_rd_ceff))
* (1.0 - exp_dt_rd_ceff))
/ (rd_ * ceff_time * dt);
return ipi - iceff;
}
@ -1064,7 +1063,7 @@ DmpPi::Vl0(double t,
double D3 = -p3_ * k0_ * k3_ / (p1_ - p3_);
double D4 = -p3_ * k0_ * k4_ / (p2_ - p3_);
double D5 = k0_ * (k2_ / p3_ - k1_ + p3_ * k3_ / (p1_ - p3_)
+ p3_ * k4_ / (p2_ - p3_));
+ p3_ * k4_ / (p2_ - p3_));
double exp_p1 = exp2(-p1_ * t);
double exp_p2 = exp2(-p2_ * t);
double exp_p3 = exp2(-p3_ * t);
@ -1194,19 +1193,19 @@ DmpZeroC2::DmpZeroC2(StaState *sta) :
void
DmpZeroC2::init(const LibertyLibrary *drvr_library,
const LibertyCell *drvr_cell,
const Pvt *pvt,
const GateTableModel *gate_model,
const RiseFall *rf,
double rd,
double in_slew,
double c2,
double rpi,
double c1)
const LibertyCell *drvr_cell,
const Pvt *pvt,
const GateTableModel *gate_model,
const RiseFall *rf,
double rd,
double in_slew,
double c2,
double rpi,
double c1)
{
debugPrint(debug_, "dmp_ceff", 3, "Using DMP C2=0");
DmpAlg::init(drvr_library, drvr_cell, pvt, gate_model, rf, rd,
in_slew, c2, rpi, c1);
in_slew, c2, rpi, c1);
ceff_ = c1;
z1_ = 1.0 / (rpi_ * c1_);
@ -1221,7 +1220,7 @@ DmpZeroC2::init(const LibertyLibrary *drvr_library,
void
DmpZeroC2::gateDelaySlew(// Return values.
double &delay,
double &slew)
double &slew)
{
try {
findDriverParams(c1_);
@ -1280,16 +1279,16 @@ DmpZeroC2::voCrossingUpperBound()
// Return error msg on failure.
static void
newtonRaphson(const int max_iter,
double x[],
const int size,
const double x_tol,
function<void ()> eval,
// Temporaries supplied by caller.
double *fvec,
double **fjac,
int *index,
double *p,
double *scale)
double x[],
const int size,
const double x_tol,
function<void ()> eval,
// Temporaries supplied by caller.
double *fvec,
double **fjac,
int *index,
double *p,
double *scale)
{
for (int k = 0; k < max_iter; k++) {
eval();
@ -1302,7 +1301,7 @@ newtonRaphson(const int max_iter,
bool all_under_x_tol = true;
for (int i = 0; i < size; i++) {
if (abs(p[i]) > abs(x[i]) * x_tol)
all_under_x_tol = false;
all_under_x_tol = false;
x[i] += p[i];
}
if (all_under_x_tol)
@ -1325,11 +1324,11 @@ newtonRaphson(const int max_iter,
// Return error msg on failure.
void
luDecomp(double **a,
const int size,
int *index,
// Temporary supplied by caller.
// scale stores the implicit scaling of each row.
double *scale)
const int size,
int *index,
// Temporary supplied by caller.
// scale stores the implicit scaling of each row.
double *scale)
{
// Find implicit scaling factors.
for (int i = 0; i < size; i++) {
@ -1337,7 +1336,7 @@ luDecomp(double **a,
for (int j = 0; j < size; j++) {
double temp = abs(a[i][j]);
if (temp > big)
big = temp;
big = temp;
}
if (big == 0.0)
throw DmpError("LU decomposition: no non-zero row element");
@ -1349,7 +1348,7 @@ luDecomp(double **a,
for (int i = 0; i < j; i++) {
double sum = a[i][j];
for (int k = 0; k < i; k++)
sum -= a[i][k] * a[k][j];
sum -= a[i][k] * a[k][j];
a[i][j] = sum;
}
// Run down jth subdiag to form the residuals after the elimination
@ -1362,21 +1361,21 @@ luDecomp(double **a,
for (int i = j; i < size; i++) {
double sum = a[i][j];
for (int k = 0; k < j; k++)
sum -= a[i][k] * a[k][j];
sum -= a[i][k] * a[k][j];
a[i][j] = sum;
double dum = scale[i] * abs(sum);
if (dum >= big) {
big = dum;
imax = i;
big = dum;
imax = i;
}
}
// Permute current row with imax.
if (j != imax) {
// Yes, do so...
for (int k = 0; k < size; k++) {
double dum = a[imax][k];
a[imax][k] = a[j][k];
a[j][k] = dum;
double dum = a[imax][k];
a[imax][k] = a[j][k];
a[j][k] = dum;
}
scale[imax] = scale[j];
}
@ -1387,7 +1386,7 @@ luDecomp(double **a,
if (j != size_1) {
double pivot = 1.0 / a[j][j];
for (int i = j + 1; i < size; i++)
a[i][j] *= pivot;
a[i][j] *= pivot;
}
}
}
@ -1399,9 +1398,9 @@ luDecomp(double **a,
// a and index are not modified.
void
luSolve(double **a,
const int size,
const int *index,
double b[])
const int size,
const int *index,
double b[])
{
// Transform b allowing for leading zeros.
int non_zero = -1;
@ -1411,11 +1410,11 @@ luSolve(double **a,
b[iperm] = b[i];
if (non_zero != -1) {
for (int j = non_zero; j <= i - 1; j++)
sum -= a[i][j] * b[j];
sum -= a[i][j] * b[j];
}
else {
if (sum != 0.0)
non_zero = i;
non_zero = i;
}
b[i] = sum;
}
@ -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,12 +1530,12 @@ 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_) {
unsuppored_model_warned_ = true;
report_->warn(1041, "cell %s delay model not supported on SPF parasitics by DMP delay calculator",
drvr_cell->name());
drvr_cell->name());
}
return dcalc_result;
}
@ -1542,25 +1543,25 @@ DmpCeffDelayCalc::gateDelay(const Pin *drvr_pin,
void
DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library,
const LibertyCell *drvr_cell,
const Pvt *pvt,
const GateTableModel *gate_model,
const RiseFall *rf,
double in_slew,
double c2,
double rpi,
double c1)
const LibertyCell *drvr_cell,
const Pvt *pvt,
const GateTableModel *gate_model,
const RiseFall *rf,
double in_slew,
double c2,
double rpi,
double c1)
{
double rd = 0.0;
if (gate_model) {
rd = gateModelRd(drvr_cell, gate_model, rf, in_slew, c2, c1,
pvt, variables_->pocvEnabled());
pvt, variables_->pocvEnabled());
// Zero Rd means the table is constant and thus independent of load cap.
if (rd < 1e-2
// Rpi is small compared to Rd, which makes the load capacitive.
|| rpi < rd * 1e-3
// c1/Rpi can be ignored.
|| (c1 == 0.0 || c1 < c2 * 1e-3 || rpi == 0.0))
// Rpi is small compared to Rd, which makes the load capacitive.
|| rpi < rd * 1e-3
// c1/Rpi can be ignored.
|| (c1 == 0.0 || c1 < c2 * 1e-3 || rpi == 0.0))
dmp_alg_ = dmp_cap_;
else if (c2 < c1 * 1e-3)
dmp_alg_ = dmp_zero_c2_;
@ -1571,7 +1572,7 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library,
else
dmp_alg_ = dmp_cap_;
dmp_alg_->init(drvr_library, drvr_cell, pvt, gate_model,
rf, rd, in_slew, c2, rpi, c1);
rf, rd, in_slew, c2, rpi, c1);
debugPrint(debug_, "dmp_ceff", 3,
" DMP in_slew = %s c2 = %s rpi = %s c1 = %s Rd = %s (%s alg)",
units_->timeUnit()->asString(in_slew),
@ -1585,16 +1586,17 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library,
string
DmpCeffDelayCalc::reportGateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *parasitic,
const Slew &in_slew,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
int digits)
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());
@ -1633,13 +1638,13 @@ DmpCeffDelayCalc::reportGateDelay(const Pin *drvr_pin,
static double
gateModelRd(const LibertyCell *cell,
const GateTableModel *gate_model,
const RiseFall *rf,
double in_slew,
double c2,
double c1,
const Pvt *pvt,
bool pocv_enabled)
const GateTableModel *gate_model,
const RiseFall *rf,
double in_slew,
double c2,
double c1,
const Pvt *pvt,
bool pocv_enabled)
{
float cap1 = c1 + c2;
float cap2 = cap1 + 1e-15;
@ -1655,7 +1660,7 @@ gateModelRd(const LibertyCell *cell,
void
DmpCeffDelayCalc::gateDelaySlew(// Return values.
double &delay,
double &slew)
double &slew)
{
dmp_alg_->gateDelaySlew(delay, slew);
}

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;
@ -71,22 +73,23 @@ protected:
Slew &load_slew) = 0;
void gateDelaySlew(// Return values.
double &delay,
double &slew);
double &slew);
void loadDelaySlewElmore(const Pin *load_pin,
double elmore,
ArcDelay &delay,
Slew &slew);
// Select the appropriate special case Dartu/Menezes/Pileggi algorithm.
void setCeffAlgorithm(const LibertyLibrary *library,
const LibertyCell *cell,
const Pvt *pvt,
const GateTableModel *gate_model,
const RiseFall *rf,
double in_slew,
double c2,
double rpi,
double c1);
const LibertyCell *cell,
const Pvt *pvt,
const GateTableModel *gate_model,
const RiseFall *rf,
double in_slew,
double c2,
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,
@ -166,20 +171,20 @@ private:
Slew &load_slew) override;
void loadDelay(double drvr_slew,
Parasitic *pole_residue,
double p1,
double k1,
ArcDelay &wire_delay,
Slew &load_slew);
double p1,
double k1,
ArcDelay &wire_delay,
Slew &load_slew);
float loadDelay(double vth,
double p1,
double p2,
double k1,
double k2,
double B,
double k1_p1_2,
double k2_p2_2,
double tt,
double y_tt);
double p1,
double p2,
double k1,
double k2,
double B,
double k1_p1_2,
double k2_p2_2,
double tt,
double y_tt);
bool parasitic_is_pole_residue_;
float vth_;
@ -212,43 +217,41 @@ DmpCeffTwoPoleDelayCalc::copy()
Parasitic *
DmpCeffTwoPoleDelayCalc::findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap)
const RiseFall *rf,
const Scene *scene,
const MinMax *min_max)
{
Parasitic *parasitic = nullptr;
const Corner *corner = dcalc_ap->corner();
// set_load net has precedence 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;
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
@ -333,9 +340,9 @@ DmpCeffTwoPoleDelayCalc::loadDelaySlew(const Pin *load_pin,
// Find the 1st (elmore) pole.
parasitics_->poleResidue(pole_residue, 0, pole1, residue1);
if (pole1.imag() == 0.0
&& residue1.imag() == 0.0) {
float p1 = pole1.real();
float k1 = residue1.real();
&& residue1.imag() == 0.0) {
float p1 = pole1.real();
float k1 = residue1.real();
if (pole_count >= 2)
loadDelay(drvr_slew, pole_residue, p1, k1, wire_delay, load_slew);
else {
@ -352,11 +359,11 @@ DmpCeffTwoPoleDelayCalc::loadDelaySlew(const Pin *load_pin,
void
DmpCeffTwoPoleDelayCalc::loadDelay(double drvr_slew,
Parasitic *pole_residue,
double p1,
double p1,
double k1,
// Return values.
// Return values.
ArcDelay &wire_delay,
Slew &load_slew)
Slew &load_slew)
{
ComplexFloat pole2, residue2;
parasitics_->poleResidue(pole_residue, 1, pole2, residue2);
@ -371,7 +378,7 @@ DmpCeffTwoPoleDelayCalc::loadDelay(double drvr_slew,
// Convert tt to 0:1 range.
float tt = delayAsFloat(drvr_slew) * slew_derate_ / (vh_ - vl_);
double y_tt = (tt - B + k1_p1_2 * exp(-p1 * tt)
+ k2_p2_2 * exp(-p2 * tt)) / tt;
+ k2_p2_2 * exp(-p2 * tt)) / tt;
wire_delay = loadDelay(vth_, p1, p2, k1, k2, B, k1_p1_2, k2_p2_2, tt, y_tt)
- tt * vth_;
@ -383,15 +390,15 @@ DmpCeffTwoPoleDelayCalc::loadDelay(double drvr_slew,
float
DmpCeffTwoPoleDelayCalc::loadDelay(double vth,
double p1,
double p2,
double k1,
double k2,
double B,
double k1_p1_2,
double k2_p2_2,
double tt,
double y_tt)
double p1,
double p2,
double k1,
double k2,
double B,
double k1_p1_2,
double k2_p2_2,
double tt,
double y_tt)
{
if (y_tt < vth) {
// t1 > tt
@ -403,9 +410,9 @@ DmpCeffTwoPoleDelayCalc::loadDelay(double vth,
double exp_p1_t1_tt = exp(-p1 * (t1 - tt));
double exp_p2_t1_tt = exp(-p2 * (t1 - tt));
double y_t1 = (tt - k1_p1_2 * (exp_p1_t1_tt - exp_p1_t1)
- k2_p2_2 * (exp_p2_t1_tt - exp_p2_t1)) / tt;
- k2_p2_2 * (exp_p2_t1_tt - exp_p2_t1)) / tt;
double yp_t1 = (k1 / p1 * (exp_p1_t1_tt - exp_p1_t1)
- k2 / p2 * (exp_p2_t1_tt - exp_p2_t1)) / tt;
- k2 / p2 * (exp_p2_t1_tt - exp_p2_t1)) / tt;
double delay = t1 - (y_t1 - vth) / yp_t1;
return static_cast<float>(delay);
}
@ -417,9 +424,9 @@ DmpCeffTwoPoleDelayCalc::loadDelay(double vth,
double exp_p1_t1 = exp(-p1 * t1);
double exp_p2_t1 = exp(-p2 * t1);
double y_t1 = (t1 - B + k1_p1_2 * exp_p1_t1
+ k2_p2_2 * exp_p1_t1) / tt;
+ k2_p2_2 * exp_p1_t1) / tt;
double yp_t1 = (1 - k1 / p1 * exp_p1_t1
- k2 / p2 * exp_p2_t1) / tt;
- k2 / p2 * exp_p2_t1) / tt;
double delay = t1 - (y_t1 - vth) / yp_t1;
return static_cast<float>(delay);
}

View File

@ -32,10 +32,10 @@ using std::abs;
double
findRoot(FindRootFunc func,
double x1,
double x2,
double x_tol,
int max_iter,
double x1,
double x2,
double x_tol,
int max_iter,
// Return value.
bool &fail)
{
@ -47,12 +47,12 @@ findRoot(FindRootFunc func,
double
findRoot(FindRootFunc func,
double x1,
double y1,
double x1,
double y1,
double x2,
double y2,
double y2,
double x_tol,
int max_iter,
int max_iter,
// Return value.
bool &fail)
{
@ -83,8 +83,8 @@ findRoot(FindRootFunc func,
for (int iter = 0; iter < max_iter; iter++) {
// Newton/raphson out of range.
if ((((root - x2) * dy - y) * ((root - x1) * dy - y) > 0.0)
// Not decreasing fast enough.
|| (abs(2.0 * y) > abs(dx_prev * dy))) {
// Not decreasing fast enough.
|| (abs(2.0 * y) > abs(dx_prev * dy))) {
// Bisect x1/x2 interval.
dx_prev = dx;
dx = (x2 - x1) * 0.5;

View File

@ -28,28 +28,28 @@
namespace sta {
typedef const std::function<void (double x,
// Return values.
double &y,
double &dy)> FindRootFunc;
using FindRootFunc = const std::function<void (double x,
// Return values.
double &y,
double &dy)>;
double
findRoot(FindRootFunc func,
double x1,
double x2,
double x_tol,
int max_iter,
double x1,
double x2,
double x_tol,
int max_iter,
// Return value.
bool &fail);
double
findRoot(FindRootFunc func,
double x1,
double y1,
double x1,
double y1,
double x2,
double y2,
double x_tol,
int max_iter,
double y2,
double x_tol,
int max_iter,
// Return value.
bool &fail);

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"
@ -63,36 +62,38 @@ LumpedCapDelayCalc::copy()
Parasitic *
LumpedCapDelayCalc::findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap)
const RiseFall *rf,
const Scene *scene,
const MinMax *min_max)
{
Parasitic *parasitic = nullptr;
const Corner *corner = dcalc_ap->corner();
// set_load net has precedence over parasitics.
if (sdc_->drvrPinHasWireCap(drvr_pin, corner)
Parasitics *parasitics = scene->parasitics(min_max);
const Sdc *sdc = scene->sdc();
if (parasitics == nullptr
// set_load net has precedence over parasitics.
|| sdc->drvrPinHasWireCap(drvr_pin)
|| network_->direction(drvr_pin)->isInternal())
return nullptr;
const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
return nullptr;
// 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);
@ -126,13 +127,14 @@ LumpedCapDelayCalc::inputPortDelay(const Pin *,
ArcDcalcResult
LumpedCapDelayCalc::gateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *,
const Slew &in_slew,
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

@ -31,9 +31,9 @@ NetCaps::NetCaps()
}
NetCaps::NetCaps(float pin_cap,
float wire_cap,
float fanout,
bool has_net_load) :
float wire_cap,
float fanout,
bool has_net_load) :
pin_cap_(pin_cap),
wire_cap_(wire_cap),
fanout_(fanout),
@ -43,9 +43,9 @@ NetCaps::NetCaps(float pin_cap,
void
NetCaps::init(float pin_cap,
float wire_cap,
float fanout,
bool has_net_load)
float wire_cap,
float fanout,
bool has_net_load)
{
pin_cap_ = pin_cap;
wire_cap_ = wire_cap;

View File

@ -32,13 +32,13 @@ class NetCaps
public:
NetCaps();
NetCaps(float pin_cap,
float wire_cap,
float fanout,
bool has_net_load);
float wire_cap,
float fanout,
bool has_net_load);
void init(float pin_cap,
float wire_cap,
float fanout,
bool has_net_load);
float wire_cap,
float fanout,
bool has_net_load);
float pinCap() const { return pin_cap_; }
float wireCap() const{ return wire_cap_; }
float fanout() const{ return fanout_; }

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,38 @@ 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 +241,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 +271,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 +395,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 +464,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 +915,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 "";
}
@ -954,8 +960,8 @@ PrimaDelayCalc::watchWaveform(const Pin *pin)
{
FloatSeq &voltages = watch_pin_values_[pin];
TableAxisPtr time_axis = make_shared<TableAxis>(TableAxisVariable::time,
new FloatSeq(times_));
Table1 waveform(new FloatSeq(voltages), time_axis);
FloatSeq(times_));
Table waveform(new FloatSeq(voltages), time_axis);
return waveform;
}

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 = Table;
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_;
@ -243,4 +250,4 @@ protected:
using ArcDelayCalc::reduceParasitic;
};
} // namespacet
} // namespace

View File

@ -49,8 +49,9 @@ UnitDelayCalc::copy()
Parasitic *
UnitDelayCalc::findParasitic(const Pin *,
const RiseFall *,
const DcalcAnalysisPt *)
const RiseFall *,
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,30 +69,33 @@ 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 *)
{
}
ArcDcalcResult
UnitDelayCalc::inputPortDelay(const Pin *,
float,
const RiseFall *,
const Parasitic *,
float,
const RiseFall *,
const Parasitic *,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
const Scene *,
const MinMax *)
{
return unitDelayResult(load_pin_index_map);
}
@ -98,11 +103,12 @@ UnitDelayCalc::inputPortDelay(const Pin *,
ArcDcalcResult
UnitDelayCalc::gateDelay(const Pin *,
const TimingArc *,
const Slew &,
float,
const Parasitic *,
const Slew &,
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);
@ -138,12 +145,13 @@ UnitDelayCalc::unitDelayResult(const LoadPinIndexMap &load_pin_index_map)
string
UnitDelayCalc::reportGateDelay(const Pin *,
const TimingArc *,
const Slew &,
float,
const Parasitic *,
const Slew &,
float,
const Parasitic *,
const LoadPinIndexMap &,
const DcalcAnalysisPt *,
int)
const Scene *,
const MinMax *,
int)
{
string result("Delay = 1.0\n");
result += "Slew = 0.0\n";
@ -153,10 +161,11 @@ UnitDelayCalc::reportGateDelay(const Pin *,
ArcDelay
UnitDelayCalc::checkDelay(const Pin *,
const TimingArc *,
const Slew &,
const Slew &,
float,
const DcalcAnalysisPt *)
const Slew &,
const Slew &,
float,
const Scene *,
const MinMax *)
{
return units_->timeUnit()->scale();
}
@ -164,12 +173,13 @@ UnitDelayCalc::checkDelay(const Pin *,
string
UnitDelayCalc::reportCheckDelay(const Pin *,
const TimingArc *,
const Slew &,
const char *,
const Slew &,
float,
const DcalcAnalysisPt *,
int)
const Slew &,
const char *,
const Slew &,
float,
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,44 @@
This file summarizes STA API changes for each release.
Release 3.0.0 2025/01/03
------------------------
OpenSTA now requires c++ 20.
Corner replaced by Scene
mode()
parasitics(min_max)
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,187 @@ OpenSTA Timing Analyzer Release Notes
This file summarizes user visible changes for each release.
2025/02/24
----------
The define_scene -library argument now takes a the library name or a
library filename. If a filename is used, it must be the same as the
filename used to read the library with read_liberty.
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 +200,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 +277,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 NangateOpenCellLibrary_slow
define_scene tt -liberty NangateOpenCellLibrary
define_scene ff -liberty NangateOpenCellLibrary_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

@ -32,7 +32,7 @@ namespace sta {
const char *
delayAsString(const Delay &delay,
const StaState *sta)
const StaState *sta)
{
return delayAsString(delay, sta, sta->units()->timeUnit()->digits());
}

View File

@ -45,24 +45,24 @@ initDelayConstants()
const char *
delayAsString(const Delay &delay,
const StaState *sta)
const StaState *sta)
{
return delayAsString(delay, sta, sta->units()->timeUnit()->digits());
}
const char *
delayAsString(const Delay &delay,
const StaState *sta,
int digits)
const StaState *sta,
int digits)
{
return sta->units()->timeUnit()->asString(delay, digits);
}
const char *
delayAsString(const Delay &delay,
const EarlyLate *,
const StaState *sta,
int digits)
const EarlyLate *,
const StaState *sta,
int digits)
{
const Unit *unit = sta->units()->timeUnit();
return unit->asString(delay, digits);
@ -76,7 +76,7 @@ delayInitValue(const MinMax *min_max)
bool
delayIsInitValue(const Delay &delay,
const MinMax *min_max)
const MinMax *min_max)
{
return fuzzyEqual(delay, min_max->initValue());
}
@ -95,24 +95,24 @@ delayInf(const Delay &delay)
bool
delayEqual(const Delay &delay1,
const Delay &delay2)
const Delay &delay2)
{
return fuzzyEqual(delay1, delay2);
}
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const StaState *)
const Delay &delay2,
const StaState *)
{
return fuzzyLess(delay1, delay2);
}
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *)
const Delay &delay2,
const MinMax *min_max,
const StaState *)
{
if (min_max == MinMax::max())
return fuzzyLess(delay1, delay2);
@ -122,17 +122,17 @@ delayLess(const Delay &delay1,
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const StaState *)
const Delay &delay2,
const StaState *)
{
return fuzzyLessEqual(delay1, delay2);
}
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *)
const Delay &delay2,
const MinMax *min_max,
const StaState *)
{
if (min_max == MinMax::max())
return fuzzyLessEqual(delay1, delay2);
@ -142,17 +142,17 @@ delayLessEqual(const Delay &delay1,
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const StaState *)
const Delay &delay2,
const StaState *)
{
return fuzzyGreater(delay1, delay2);
}
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *)
const Delay &delay2,
const MinMax *min_max,
const StaState *)
{
if (min_max == MinMax::max())
return fuzzyGreater(delay1, delay2);
@ -162,17 +162,17 @@ delayGreater(const Delay &delay1,
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const StaState *)
const Delay &delay2,
const StaState *)
{
return fuzzyGreaterEqual(delay1, delay2);
}
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *)
const Delay &delay2,
const MinMax *min_max,
const StaState *)
{
if (min_max == MinMax::max())
return fuzzyGreaterEqual(delay1, delay2);
@ -182,14 +182,14 @@ delayGreaterEqual(const Delay &delay1,
Delay
delayRemove(const Delay &delay1,
const Delay &delay2)
const Delay &delay2)
{
return delay1 - delay2;
}
float
delayRatio(const Delay &delay1,
const Delay &delay2)
const Delay &delay2)
{
return delay1 / delay2;
}

View File

@ -85,7 +85,7 @@ Delay::Delay(float mean) :
}
Delay::Delay(float mean,
float sigma2) :
float sigma2) :
mean_(mean),
sigma2_(sigma2)
{
@ -139,7 +139,7 @@ Delay
Delay::operator+(const Delay &delay) const
{
return Delay(mean_ + delay.mean_,
sigma2_ + delay.sigma2_);
sigma2_ + delay.sigma2_);
}
Delay
@ -152,7 +152,7 @@ Delay
Delay::operator-(const Delay &delay) const
{
return Delay(mean_ - delay.mean_,
sigma2_ + delay.sigma2_);
sigma2_ + delay.sigma2_);
}
Delay
@ -219,24 +219,24 @@ DelayDbl::operator-=(const Delay &delay)
Delay
makeDelay(float delay,
float sigma,
float)
float sigma,
float)
{
return Delay(delay, square(sigma));
}
Delay
makeDelay2(float delay,
float sigma2,
float )
float sigma2,
float )
{
return Delay(delay, sigma2);
}
float
delayAsFloat(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta)
const EarlyLate *early_late,
const StaState *sta)
{
if (sta->variables()->pocvEnabled()) {
if (early_late == EarlyLate::early())
@ -251,29 +251,29 @@ delayAsFloat(const Delay &delay,
float
delaySigma2(const Delay &delay,
const EarlyLate *)
const EarlyLate *)
{
return delay.sigma2();
}
const char *
delayAsString(const Delay &delay,
const StaState *sta)
const StaState *sta)
{
return delayAsString(delay, sta, sta->units()->timeUnit()->digits());
}
const char *
delayAsString(const Delay &delay,
const StaState *sta,
int digits)
const StaState *sta,
int digits)
{
const Unit *unit = sta->units()->timeUnit();
if (sta->variables()->pocvEnabled()) {
float sigma = delay.sigma();
return stringPrintTmp("%s[%s]",
unit->asString(delay.mean(), digits),
unit->asString(sigma, digits));
unit->asString(delay.mean(), digits),
unit->asString(sigma, digits));
}
else
return unit->asString(delay.mean(), digits);
@ -281,9 +281,9 @@ delayAsString(const Delay &delay,
const char *
delayAsString(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta,
int digits)
const EarlyLate *early_late,
const StaState *sta,
int digits)
{
float mean_sigma = delayAsFloat(delay, early_late, sta);
return sta->units()->timeUnit()->asString(mean_sigma, digits);
@ -291,7 +291,7 @@ delayAsString(const Delay &delay,
bool
delayIsInitValue(const Delay &delay,
const MinMax *min_max)
const MinMax *min_max)
{
return fuzzyEqual(delay.mean(), min_max->initValue())
&& delay.sigma2() == 0.0;
@ -312,7 +312,7 @@ delayInf(const Delay &delay)
bool
delayEqual(const Delay &delay1,
const Delay &delay2)
const Delay &delay2)
{
return fuzzyEqual(delay1.mean(), delay2.mean())
&& fuzzyEqual(delay1.sigma2(), delay2.sigma2());
@ -320,27 +320,27 @@ delayEqual(const Delay &delay1,
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const StaState *sta)
const Delay &delay2,
const StaState *sta)
{
return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta),
delayAsFloat(delay2, EarlyLate::early(), sta));
delayAsFloat(delay2, EarlyLate::early(), sta));
}
bool
delayLess(const Delay &delay1,
float delay2,
const StaState *sta)
float delay2,
const StaState *sta)
{
return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta),
delay2);
delay2);
}
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
{
if (min_max == MinMax::max())
return delayLess(delay1, delay2, sta);
@ -350,27 +350,27 @@ delayLess(const Delay &delay1,
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta)
const Delay &delay2,
const StaState *sta)
{
return fuzzyLessEqual(delayAsFloat(delay1, EarlyLate::early(), sta),
delayAsFloat(delay2, EarlyLate::early(), sta));
delayAsFloat(delay2, EarlyLate::early(), sta));
}
bool
delayLessEqual(const Delay &delay1,
float delay2,
const StaState *sta)
float delay2,
const StaState *sta)
{
return fuzzyLessEqual(delayAsFloat(delay1, EarlyLate::early(), sta),
delay2);
delay2);
}
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
{
if (min_max == MinMax::max())
return delayLessEqual(delay1, delay2, sta);
@ -380,46 +380,46 @@ delayLessEqual(const Delay &delay1,
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const StaState *sta)
const Delay &delay2,
const StaState *sta)
{
return fuzzyGreater(delayAsFloat(delay1, EarlyLate::late(), sta),
delayAsFloat(delay2, EarlyLate::late(), sta));
delayAsFloat(delay2, EarlyLate::late(), sta));
}
bool
delayGreater(const Delay &delay1,
float delay2,
const StaState *sta)
float delay2,
const StaState *sta)
{
return fuzzyGreater(delayAsFloat(delay1, EarlyLate::late(), sta),
delay2);
delay2);
}
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta)
const Delay &delay2,
const StaState *sta)
{
return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta),
delayAsFloat(delay2, EarlyLate::late(), sta));
delayAsFloat(delay2, EarlyLate::late(), sta));
}
bool
delayGreaterEqual(const Delay &delay1,
float delay2,
const StaState *sta)
float delay2,
const StaState *sta)
{
return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta),
delay2);
delay2);
}
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
{
if (min_max == MinMax::max())
return delayGreater(delay1, delay2, sta);
@ -429,9 +429,9 @@ delayGreater(const Delay &delay1,
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
{
if (min_max == MinMax::max())
return delayGreaterEqual(delay1, delay2, sta);
@ -441,41 +441,41 @@ delayGreaterEqual(const Delay &delay1,
Delay
delayRemove(const Delay &delay1,
const Delay &delay2)
const Delay &delay2)
{
return Delay(delay1.mean() - delay2.mean(),
delay1.sigma2() - delay2.sigma2());
delay1.sigma2() - delay2.sigma2());
}
float
delayRatio(const Delay &delay1,
const Delay &delay2)
const Delay &delay2)
{
return delay1.mean() / delay2.mean();
}
Delay
operator+(float delay1,
const Delay &delay2)
const Delay &delay2)
{
return Delay(delay1 + delay2.mean(),
delay2.sigma2());
delay2.sigma2());
}
Delay
operator/(float delay1,
const Delay &delay2)
const Delay &delay2)
{
return Delay(delay1 / delay2.mean(),
delay2.sigma2());
delay2.sigma2());
}
Delay
operator*(const Delay &delay1,
float delay2)
float delay2)
{
return Delay(delay1.mean() * delay2,
delay1.sigma2() * delay2 * delay2);
delay1.sigma2() * delay2 * delay2);
}
} // namespace

View File

@ -86,8 +86,8 @@ Delay::Delay(float mean) :
}
Delay::Delay(float mean,
float sigma2_early,
float sigma2_late) :
float sigma2_early,
float sigma2_late) :
mean_(mean),
sigma2_{sigma2_early, sigma2_late}
{
@ -157,8 +157,8 @@ Delay
Delay::operator+(const Delay &delay) const
{
return Delay(mean_ + delay.mean_,
sigma2_[early_index] + delay.sigma2_[early_index],
sigma2_[late_index] + delay.sigma2_[late_index]);
sigma2_[early_index] + delay.sigma2_[early_index],
sigma2_[late_index] + delay.sigma2_[late_index]);
}
Delay
@ -171,8 +171,8 @@ Delay
Delay::operator-(const Delay &delay) const
{
return Delay(mean_ - delay.mean_,
sigma2_[early_index] + delay.sigma2_[late_index],
sigma2_[late_index] + delay.sigma2_[early_index]);
sigma2_[early_index] + delay.sigma2_[late_index],
sigma2_[late_index] + delay.sigma2_[early_index]);
}
Delay
@ -245,23 +245,23 @@ DelayDbl::operator-=(const Delay &delay)
Delay
makeDelay(float delay,
float sigma_early,
float sigma_late)
float sigma_early,
float sigma_late)
{
return Delay(delay, square(sigma_early), square(sigma_late));
}
Delay
makeDelay2(float delay,
float sigma2_early,
float sigma2_late)
float sigma2_early,
float sigma2_late)
{
return Delay(delay, sigma2_early, sigma2_late);
}
bool
delayIsInitValue(const Delay &delay,
const MinMax *min_max)
const MinMax *min_max)
{
return fuzzyEqual(delay.mean(), min_max->initValue())
&& fuzzyZero(delay.sigma2Early())
@ -284,7 +284,7 @@ delayInf(const Delay &delay)
bool
delayEqual(const Delay &delay1,
const Delay &delay2)
const Delay &delay2)
{
return fuzzyEqual(delay1.mean(), delay2.mean())
&& fuzzyEqual(delay1.sigma2Early(), delay2.sigma2Early())
@ -293,27 +293,27 @@ delayEqual(const Delay &delay1,
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const StaState *sta)
const Delay &delay2,
const StaState *sta)
{
return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta),
delayAsFloat(delay2, EarlyLate::early(), sta));
delayAsFloat(delay2, EarlyLate::early(), sta));
}
bool
delayLess(const Delay &delay1,
float delay2,
const StaState *sta)
float delay2,
const StaState *sta)
{
return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta),
delay2);
delay2);
}
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
{
if (min_max == MinMax::max())
return delayLess(delay1, delay2, sta);
@ -323,27 +323,27 @@ delayLess(const Delay &delay1,
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta)
const Delay &delay2,
const StaState *sta)
{
return fuzzyLessEqual(delayAsFloat(delay1, EarlyLate::early(), sta),
delayAsFloat(delay2, EarlyLate::early(), sta));
delayAsFloat(delay2, EarlyLate::early(), sta));
}
bool
delayLessEqual(const Delay &delay1,
float delay2,
const StaState *sta)
float delay2,
const StaState *sta)
{
return fuzzyLessEqual(delayAsFloat(delay1, EarlyLate::early(), sta),
delay2);
delay2);
}
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
{
if (min_max == MinMax::max())
return delayLessEqual(delay1, delay2, sta);
@ -353,45 +353,45 @@ delayLessEqual(const Delay &delay1,
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const StaState *sta)
const Delay &delay2,
const StaState *sta)
{
return fuzzyGreater(delayAsFloat(delay1, EarlyLate::late(), sta),
delayAsFloat(delay2, EarlyLate::late(), sta));
delayAsFloat(delay2, EarlyLate::late(), sta));
}
bool
delayGreater(const Delay &delay1,
float delay2,
const StaState *sta)
float delay2,
const StaState *sta)
{
return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta),
delayAsFloat(delay2, EarlyLate::late(), sta));
delayAsFloat(delay2, EarlyLate::late(), sta));
}
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta)
const Delay &delay2,
const StaState *sta)
{
return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta),
delayAsFloat(delay2, EarlyLate::late(), sta));
delayAsFloat(delay2, EarlyLate::late(), sta));
}
bool
delayGreaterEqual(const Delay &delay1,
float delay2,
const StaState *sta)
float delay2,
const StaState *sta)
{
return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta),
delay2);
delay2);
}
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
{
if (min_max == MinMax::max())
return delayGreater(delay1, delay2, sta);
@ -401,9 +401,9 @@ delayGreater(const Delay &delay1,
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
{
if (min_max == MinMax::max())
return delayGreaterEqual(delay1, delay2, sta);
@ -413,8 +413,8 @@ delayGreaterEqual(const Delay &delay1,
float
delayAsFloat(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta)
const EarlyLate *early_late,
const StaState *sta)
{
if (sta->pocvEnabled()) {
if (early_late == EarlyLate::early())
@ -429,31 +429,31 @@ delayAsFloat(const Delay &delay,
float
delaySigma2(const Delay &delay,
const EarlyLate *early_late)
const EarlyLate *early_late)
{
return delay.sigma2(early_late);
}
const char *
delayAsString(const Delay &delay,
const StaState *sta)
const StaState *sta)
{
return delayAsString(delay, sta, sta->units()->timeUnit()->digits());
}
const char *
delayAsString(const Delay &delay,
const StaState *sta,
int digits)
const StaState *sta,
int digits)
{
const Unit *unit = sta->units()->timeUnit();
if (sta->pocvEnabled()) {
float sigma_early = delay.sigma(EarlyLate::early());
float sigma_late = delay.sigma(EarlyLate::late());
return stringPrintTmp("%s[%s:%s]",
unit->asString(delay.mean(), digits),
unit->asString(sigma_early, digits),
unit->asString(sigma_late, digits));
unit->asString(delay.mean(), digits),
unit->asString(sigma_early, digits),
unit->asString(sigma_late, digits));
}
else
return unit->asString(delay.mean(), digits);
@ -461,9 +461,9 @@ delayAsString(const Delay &delay,
const char *
delayAsString(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta,
int digits)
const EarlyLate *early_late,
const StaState *sta,
int digits)
{
float mean_sigma = delayAsFloat(delay, early_late, sta);
return sta->units()->timeUnit()->asString(mean_sigma, digits);
@ -471,45 +471,45 @@ delayAsString(const Delay &delay,
Delay
delayRemove(const Delay &delay1,
const Delay &delay2)
const Delay &delay2)
{
return Delay(delay1.mean() - delay2.mean(),
delay1.sigma2Early() - delay2.sigma2Early(),
delay1.sigma2Late() - delay2.sigma2Late());
delay1.sigma2Early() - delay2.sigma2Early(),
delay1.sigma2Late() - delay2.sigma2Late());
}
float
delayRatio(const Delay &delay1,
const Delay &delay2)
const Delay &delay2)
{
return delay1.mean() / delay2.mean();
}
Delay
operator+(float delay1,
const Delay &delay2)
const Delay &delay2)
{
return Delay(delay1 + delay2.mean(),
delay2.sigma2Early(),
delay2.sigma2Late());
delay2.sigma2Early(),
delay2.sigma2Late());
}
Delay
operator/(float delay1,
const Delay &delay2)
const Delay &delay2)
{
return Delay(delay1 / delay2.mean(),
delay2.sigma2Early(),
delay2.sigma2Late());
delay2.sigma2Early(),
delay2.sigma2Late());
}
Delay
operator*(const Delay &delay1,
float delay2)
float delay2)
{
return Delay(delay1.mean() * delay2,
delay1.sigma2Early() * delay2 * delay2,
delay1.sigma2Late() * delay2 * delay2);
delay1.sigma2Early() * delay2 * delay2,
delay1.sigma2Late() * delay2 * delay2);
}
} // namespace

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 {
@ -48,15 +48,15 @@ using std::string;
////////////////////////////////////////////////////////////////
Graph::Graph(StaState *sta,
int slew_rf_count,
DcalcAPIndex ap_count) :
int slew_rf_count,
DcalcAPIndex ap_count) :
StaState(sta),
vertices_(nullptr),
edges_(nullptr),
slew_rf_count_(slew_rf_count),
ap_count_(ap_count),
period_check_annotations_(nullptr),
reg_clk_vertices_(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();
}
@ -105,11 +104,11 @@ class FindNetDrvrLoadCounts : public PinVisitor
{
public:
FindNetDrvrLoadCounts(Pin *drvr_pin,
PinSet &visited_drvrs,
int &drvr_count,
int &bidirect_count,
int &load_count,
const Network *network);
PinSet &visited_drvrs,
int &drvr_count,
int &bidirect_count,
int &load_count,
const Network *network);
virtual void operator()(const Pin *pin);
protected:
@ -122,11 +121,11 @@ protected:
};
FindNetDrvrLoadCounts::FindNetDrvrLoadCounts(Pin *drvr_pin,
PinSet &visited_drvrs,
int &drvr_count,
int &bidirect_count,
int &load_count,
const Network *network) :
PinSet &visited_drvrs,
int &drvr_count,
int &bidirect_count,
int &load_count,
const Network *network) :
drvr_pin_(drvr_pin),
visited_drvrs_(visited_drvrs),
drvr_count_(drvr_count),
@ -186,48 +185,48 @@ Graph::makePinInstanceEdges(const Pin *pin)
void
Graph::makePortInstanceEdges(const Instance *inst,
LibertyCell *cell,
LibertyPort *from_to_port)
LibertyCell *cell,
LibertyPort *from_to_port)
{
for (TimingArcSet *arc_set : cell->timingArcSets()) {
LibertyPort *from_port = arc_set->from();
LibertyPort *to_port = arc_set->to();
if ((from_to_port == nullptr
|| from_port == from_to_port
|| to_port == from_to_port)
&& from_port) {
|| from_port == from_to_port
|| to_port == from_to_port)
&& from_port) {
Pin *from_pin = network_->findPin(inst, from_port);
Pin *to_pin = network_->findPin(inst, to_port);
if (from_pin && to_pin) {
Vertex *from_vertex, *from_bidirect_drvr_vertex;
Vertex *to_vertex, *to_bidirect_drvr_vertex;
pinVertices(from_pin, from_vertex, from_bidirect_drvr_vertex);
pinVertices(to_pin, to_vertex, to_bidirect_drvr_vertex);
// From pin and/or to pin can be bidirect.
// For combinational arcs edge is to driver.
// For timing checks edge is to load.
// Vertices can be missing from the graph if the pins
// are power or ground.
if (from_vertex) {
Vertex *from_vertex, *from_bidirect_drvr_vertex;
Vertex *to_vertex, *to_bidirect_drvr_vertex;
pinVertices(from_pin, from_vertex, from_bidirect_drvr_vertex);
pinVertices(to_pin, to_vertex, to_bidirect_drvr_vertex);
// From pin and/or to pin can be bidirect.
// For combinational arcs edge is to driver.
// For timing checks edge is to load.
// Vertices can be missing from the graph if the pins
// are power or ground.
if (from_vertex) {
const TimingRole *role = arc_set->role();
bool is_check = role->isTimingCheckBetween();
if (to_bidirect_drvr_vertex && !is_check)
makeEdge(from_vertex, to_bidirect_drvr_vertex, arc_set);
else if (to_vertex) {
makeEdge(from_vertex, to_vertex, arc_set);
if (is_check) {
to_vertex->setHasChecks(true);
from_vertex->setIsCheckClk(true);
}
}
if (from_bidirect_drvr_vertex && to_vertex) {
// Internal path from bidirect output back into the
// instance.
Edge *edge = makeEdge(from_bidirect_drvr_vertex, to_vertex,
arc_set);
edge->setIsBidirectInstPath(true);
}
}
bool is_check = role->isTimingCheckBetween();
if (to_bidirect_drvr_vertex && !is_check)
makeEdge(from_vertex, to_bidirect_drvr_vertex, arc_set);
else if (to_vertex) {
makeEdge(from_vertex, to_vertex, arc_set);
if (is_check) {
to_vertex->setHasChecks(true);
from_vertex->setIsCheckClk(true);
}
}
if (from_bidirect_drvr_vertex && to_vertex) {
// Internal path from bidirect output back into the
// instance.
Edge *edge = makeEdge(from_bidirect_drvr_vertex, to_vertex,
arc_set);
edge->setIsBidirectInstPath(true);
}
}
}
}
}
@ -248,13 +247,13 @@ Graph::makeWireEdges()
void
Graph::makeInstDrvrWireEdges(const Instance *inst,
PinSet &visited_drvrs)
PinSet &visited_drvrs)
{
InstancePinIterator *pin_iter = network_->pinIterator(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;
@ -276,7 +275,7 @@ Graph::makeWireEdgesFromPin(const Pin *drvr_pin)
void
Graph::makeWireEdgesFromPin(const Pin *drvr_pin,
PinSet &visited_drvrs)
PinSet &visited_drvrs)
{
// Find all drivers and loads on the net to avoid N*M run time
// for large fanin/fanout nets.
@ -296,7 +295,7 @@ Graph::makeWireEdgesFromPin(const Pin *drvr_pin,
for (auto drvr_pin : drvrs) {
for (auto load_pin : loads) {
if (drvr_pin != load_pin)
makeWireEdge(drvr_pin, load_pin);
makeWireEdge(drvr_pin, load_pin);
}
}
}
@ -337,7 +336,7 @@ Graph::makeWireEdgesToPin(const Pin *to_pin)
if (drvrs) {
for (auto drvr : *drvrs) {
if (drvr != to_pin)
makeWireEdge(drvr, to_pin);
makeWireEdge(drvr, to_pin);
}
}
}
@ -349,7 +348,7 @@ public:
private:
virtual void visit(const Pin *drvr,
const Pin *load);
const Pin *load);
Graph *graph_;
};
@ -362,7 +361,7 @@ MakeEdgesThruHierPin::MakeEdgesThruHierPin(Graph *graph) :
void
MakeEdgesThruHierPin::visit(const Pin *drvr,
const Pin *load)
const Pin *load)
{
graph_->makeWireEdge(drvr, load);
}
@ -376,7 +375,7 @@ Graph::makeWireEdgesThruPin(const Pin *hpin)
void
Graph::makeWireEdge(const Pin *from_pin,
const Pin *to_pin)
const Pin *to_pin)
{
TimingArcSet *arc_set = TimingArcSet::wireTimingArcSet();
Vertex *from_vertex, *from_bidirect_drvr_vertex;
@ -391,6 +390,13 @@ Graph::makeWireEdge(const Pin *from_pin,
}
}
void
Graph::makeSceneAfter()
{
ap_count_ = dcalcAnalysisPtCount();
initSlews();
}
////////////////////////////////////////////////////////////////
Vertex *
@ -414,8 +420,8 @@ Graph::makePinVertices(Pin *pin)
void
Graph::makePinVertices(Pin *pin,
Vertex *&vertex,
Vertex *&bidir_drvr_vertex)
Vertex *&vertex,
Vertex *&bidir_drvr_vertex)
{
PortDirection *dir = network_->direction(pin);
if (!dir->isPowerGround()) {
@ -433,26 +439,26 @@ Graph::makePinVertices(Pin *pin,
Vertex *
Graph::makeVertex(Pin *pin,
bool is_bidirect_drvr,
bool is_reg_clk)
bool is_bidirect_drvr,
bool is_reg_clk)
{
Vertex *vertex = vertices_->make();
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;
}
void
Graph::pinVertices(const Pin *pin,
// Return values.
Vertex *&vertex,
Vertex *&bidirect_drvr_vertex) const
// Return values.
Vertex *&vertex,
Vertex *&bidirect_drvr_vertex) const
{
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,11 +482,11 @@ 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_
.find(pin));
.find(pin));
else
network_->setVertexId(pin, vertex_id_null);
// Delete edges to vertex.
@ -513,7 +519,7 @@ Graph::hasFaninOne(Vertex *vertex) const
void
Graph::deleteInEdge(Vertex *vertex,
Edge *edge)
Edge *edge)
{
EdgeId edge_id = id(edge);
EdgeId prev = 0;
@ -529,7 +535,7 @@ Graph::deleteInEdge(Vertex *vertex,
void
Graph::deleteOutEdge(Vertex *vertex,
Edge *edge)
Edge *edge)
{
EdgeId next = edge->vertex_out_next_;
EdgeId prev = edge->vertex_out_prev_;
@ -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,
@ -652,8 +634,8 @@ Graph::id(const Edge *edge) const
Edge *
Graph::makeEdge(Vertex *from,
Vertex *to,
TimingArcSet *arc_set)
Vertex *to,
TimingArcSet *arc_set)
{
Edge *edge = edges_->make();
edge->init(id(from), id(to), arc_set);
@ -687,8 +669,8 @@ Graph::deleteEdge(Edge *edge)
ArcDelay
Graph::arcDelay(const Edge *edge,
const TimingArc *arc,
DcalcAPIndex ap_index) const
const TimingArc *arc,
DcalcAPIndex ap_index) const
{
ArcDelay *delays = edge->arcDelays();
size_t index = arc->index() * ap_count_ + ap_index;
@ -697,9 +679,9 @@ Graph::arcDelay(const Edge *edge,
void
Graph::setArcDelay(Edge *edge,
const TimingArc *arc,
DcalcAPIndex ap_index,
ArcDelay delay)
const TimingArc *arc,
DcalcAPIndex ap_index,
ArcDelay delay)
{
ArcDelay *arc_delays = edge->arcDelays();
size_t index = arc->index() * ap_count_ + ap_index;
@ -708,8 +690,8 @@ Graph::setArcDelay(Edge *edge,
const ArcDelay &
Graph::wireArcDelay(const Edge *edge,
const RiseFall *rf,
DcalcAPIndex ap_index)
const RiseFall *rf,
DcalcAPIndex ap_index)
{
ArcDelay *delays = edge->arcDelays();
size_t index = rf->index() * ap_count_ + ap_index;
@ -718,9 +700,9 @@ Graph::wireArcDelay(const Edge *edge,
void
Graph::setWireArcDelay(Edge *edge,
const RiseFall *rf,
DcalcAPIndex ap_index,
const ArcDelay &delay)
const RiseFall *rf,
DcalcAPIndex ap_index,
const ArcDelay &delay)
{
ArcDelay *delays = edge->arcDelays();
size_t index = rf->index() * ap_count_ + ap_index;
@ -731,25 +713,25 @@ Graph::setWireArcDelay(Edge *edge,
bool
Graph::arcDelayAnnotated(const Edge *edge,
const TimingArc *arc,
DcalcAPIndex ap_index) const
const TimingArc *arc,
DcalcAPIndex ap_index) const
{
return edge->arcDelayAnnotated(arc, ap_index, ap_count_);
}
void
Graph::setArcDelayAnnotated(Edge *edge,
const TimingArc *arc,
DcalcAPIndex ap_index,
bool annotated)
const TimingArc *arc,
DcalcAPIndex ap_index,
bool annotated)
{
return edge->setArcDelayAnnotated(arc, ap_index, ap_count_, annotated);
}
bool
Graph::wireDelayAnnotated(const Edge *edge,
const RiseFall *rf,
DcalcAPIndex ap_index) const
const RiseFall *rf,
DcalcAPIndex ap_index) const
{
int arc_index = TimingArcSet::wireArcIndex(rf);
TimingArc *arc = TimingArcSet::wireTimingArcSet()->findTimingArc(arc_index);
@ -758,9 +740,9 @@ Graph::wireDelayAnnotated(const Edge *edge,
void
Graph::setWireDelayAnnotated(Edge *edge,
const RiseFall *rf,
DcalcAPIndex ap_index,
bool annotated)
const RiseFall *rf,
DcalcAPIndex ap_index,
bool annotated)
{
int arc_index = TimingArcSet::wireArcIndex(rf);
TimingArc *arc = TimingArcSet::wireTimingArcSet()->findTimingArc(arc_index);
@ -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
@ -873,10 +842,10 @@ Graph::minPulseWidthArc(Vertex *vertex,
void
Graph::minPeriodArc(Vertex *vertex,
const RiseFall *rf,
// Return values.
Edge *&edge,
TimingArc *&arc)
const RiseFall *rf,
// Return values.
Edge *&edge,
TimingArc *&arc)
{
VertexOutEdgeIterator edge_iter(vertex, this);
while (edge_iter.hasNext()) {
@ -899,30 +868,30 @@ Graph::minPeriodArc(Vertex *vertex,
void
Graph::periodCheckAnnotation(const Pin *pin,
DcalcAPIndex ap_index,
// Return values.
float &period,
bool &exists)
DcalcAPIndex ap_index,
// Return values.
float &period,
bool &exists)
{
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)
exists = true;
exists = true;
}
}
}
void
Graph::setPeriodCheckAnnotation(const Pin *pin,
DcalcAPIndex ap_index,
float period)
DcalcAPIndex ap_index,
float period)
{
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.
@ -974,8 +943,8 @@ Vertex::Vertex()
void
Vertex::init(Pin *pin,
bool is_bidirect_drvr,
bool is_reg_clk)
bool is_bidirect_drvr,
bool is_reg_clk)
{
pin_ = pin;
is_reg_clk_ = is_reg_clk;
@ -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;
}
@ -1046,15 +1012,15 @@ Vertex::isDriver(const Network *network) const
PortDirection *dir = network->direction(pin_);
bool top_level_port = network->isTopLevelPort(pin_);
return ((top_level_port
&& (dir->isInput()
|| (dir->isBidirect()
&& is_bidirect_drvr_)))
|| (!top_level_port
&& (dir->isOutput()
|| dir->isTristate()
|| (dir->isBidirect()
&& is_bidirect_drvr_)
|| dir->isInternal())));
&& (dir->isInput()
|| (dir->isBidirect()
&& is_bidirect_drvr_)))
|| (!top_level_port
&& (dir->isOutput()
|| dir->isTristate()
|| (dir->isBidirect()
&& is_bidirect_drvr_)
|| dir->isInternal())));
}
void
@ -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
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;
}
@ -1098,14 +1070,14 @@ Vertex::slewAnnotated() const
void
Vertex::setSlewAnnotated(bool annotated,
const RiseFall *rf,
DcalcAPIndex ap_index)
const RiseFall *rf,
DcalcAPIndex ap_index)
{
// Track rise/fall/min/max annotations separately, but after that
// 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)
{
@ -1213,7 +1164,7 @@ Vertex::bfsInQueue(BfsIndex index) const
void
Vertex::setBfsInQueue(BfsIndex index,
bool value)
bool value)
{
if (value)
bfs_in_queue_ |= 1 << int(index);
@ -1235,8 +1186,8 @@ Edge::Edge()
void
Edge::init(VertexId from,
VertexId to,
TimingArcSet *arc_set)
VertexId to,
TimingArcSet *arc_set)
{
from_ = from;
to_ = to;
@ -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()
@ -1377,55 +1327,13 @@ Edge::isWire() const
{
return arc_set_->role()->isWire();
}
TimingSense
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;
@ -1518,14 +1438,14 @@ VertexIterator::findNext()
}
VertexInEdgeIterator::VertexInEdgeIterator(Vertex *vertex,
const Graph *graph) :
const Graph *graph) :
next_(graph->edge(vertex->in_edges_)),
graph_(graph)
{
}
VertexInEdgeIterator::VertexInEdgeIterator(VertexId vertex_id,
const Graph *graph) :
const Graph *graph) :
next_(graph->edge(graph->vertex(vertex_id)->in_edges_)),
graph_(graph)
{
@ -1541,7 +1461,7 @@ VertexInEdgeIterator::next()
}
VertexOutEdgeIterator::VertexOutEdgeIterator(Vertex *vertex,
const Graph *graph) :
const Graph *graph) :
next_(graph->edge(vertex->out_edges_)),
graph_(graph)
{
@ -1562,9 +1482,9 @@ class FindEdgesThruHierPinVisitor : public HierPinThruVisitor
{
public:
FindEdgesThruHierPinVisitor(EdgeSet &edges,
Graph *graph);
Graph *graph);
virtual void visit(const Pin *drvr,
const Pin *load);
const Pin *load);
protected:
EdgeSet &edges_;
@ -1572,7 +1492,7 @@ protected:
};
FindEdgesThruHierPinVisitor::FindEdgesThruHierPinVisitor(EdgeSet &edges,
Graph *graph) :
Graph *graph) :
HierPinThruVisitor(),
edges_(edges),
graph_(graph)
@ -1581,7 +1501,7 @@ FindEdgesThruHierPinVisitor::FindEdgesThruHierPinVisitor(EdgeSet &edges,
void
FindEdgesThruHierPinVisitor::visit(const Pin *drvr,
const Pin *load)
const Pin *load)
{
Vertex *drvr_vertex = graph_->pinDrvrVertex(drvr);
Vertex *load_vertex = graph_->pinLoadVertex(load);
@ -1595,12 +1515,24 @@ FindEdgesThruHierPinVisitor::visit(const Pin *drvr,
}
EdgesThruHierPinIterator::EdgesThruHierPinIterator(const Pin *hpin,
Network *network,
Graph *graph)
Network *network,
Graph *graph)
{
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;
@ -92,22 +93,22 @@ vertex_iterator()
void
set_arc_delay(Edge *edge,
TimingArc *arc,
const Corner *corner,
const MinMaxAll *min_max,
float delay)
TimingArc *arc,
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 MinMaxAll *min_max,
const RiseFallBoth *rf,
float slew)
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)
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,62 +180,85 @@ 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;
}
StringSeq
arc_delay_strings(TimingArc *arc,
int digits)
int digits)
{
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 MinMax *min_max)
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 MinMax *min_max)
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();
@ -396,13 +271,13 @@ cond()
const char *
mode_name()
{
return self->timingArcSet()->modeName();
return self->timingArcSet()->modeName().c_str();
}
const char *
mode_value()
{
return self->timingArcSet()->modeValue();
return self->timingArcSet()->modeValue().c_str();
}
const char *

View File

@ -37,20 +37,20 @@ proc report_edges { args } {
set to_pin [get_port_pin_error "to_pin" $keys(-to)]
foreach from_vertex [$from_pin vertices] {
foreach to_vertex [$to_pin vertices] {
report_edges_between_ $from_vertex $to_vertex
report_edges_between_ $from_vertex $to_vertex
}
}
} elseif [info exists keys(-from)] {
set from_pin [get_port_pin_error "from_pin" $keys(-from)]
foreach from_vertex [$from_pin vertices] {
report_edges_ $from_vertex out_edge_iterator \
vertex_port_name vertex_path_name
vertex_port_name vertex_path_name
}
} elseif [info exists keys(-to)] {
set to_pin [get_port_pin_error "to_pin" $keys(-to)]
foreach to_vertex [$to_pin vertices] {
report_edges_ $to_vertex in_edge_iterator \
vertex_path_name vertex_port_name
vertex_path_name vertex_port_name
}
}
}
@ -61,9 +61,9 @@ proc report_edges_between_ { from_vertex to_vertex } {
set edge [$iter next]
if { [$edge to] == $to_vertex } {
if { [$edge role] == "wire" } {
report_edge_ $edge vertex_path_name vertex_path_name
report_edge_ $edge vertex_path_name vertex_path_name
} else {
report_edge_ $edge vertex_port_name vertex_port_name
report_edge_ $edge vertex_port_name vertex_port_name
}
}
}
@ -78,11 +78,11 @@ proc report_edges_ { vertex iter_proc wire_from_name_proc wire_to_name_proc } {
set edge [$iter next]
if { [$edge role] != "wire" } {
if { !$device_header } {
set pin [$vertex pin]
if { ![$pin is_top_level_port] } {
set inst [$pin instance]
}
set device_header 1
set pin [$vertex pin]
if { ![$pin is_top_level_port] } {
set inst [$pin instance]
}
set device_header 1
}
report_edge_ $edge vertex_port_name vertex_port_name
}
@ -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"
@ -252,7 +248,7 @@ proc_redirect report_disabled_edges {
set to_port_name [get_name [$to_pin port]]
set cond [$edge cond]
if { $cond != "" } {
set when " when: $cond"
set when " when: $cond"
} else {
set when ""
}
@ -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]
@ -348,8 +322,8 @@ proc hier_pins_crossed_by_edge { edge } {
set to_pins [hier_pins_above [[$edge to] pin]]
foreach p $to_pins { report_line [$p path_name] }
while { [llength $from_pins] > 0 \
&& [llength $to_pins] > 0 \
&& [lindex $from_pins 0] == [lindex $to_pins 0] } {
&& [llength $to_pins] > 0 \
&& [lindex $from_pins 0] == [lindex $to_pins 0] } {
set from_pins [lrange $from_pins 1 end]
set to_pins [lrange $to_pins 1 end]
}
@ -367,9 +341,9 @@ proc hier_pins_above { pin } {
while {[$parent_pin_iter has_next]} {
set parent_pin [$parent_pin_iter next]
if {[$parent_pin net] == $net} {
set pins_above [concat [list $parent_pin] $pins_above]
set found 1
break
set pins_above [concat [list $parent_pin] $pins_above]
set found 1
break
}
}
$parent_pin_iter finish

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"
@ -37,7 +38,7 @@ VertexNameLess::VertexNameLess(Network *network) :
bool
VertexNameLess::operator()(const Vertex *vertex1,
const Vertex *vertex2)
const Vertex *vertex2)
{
return network_->pathNameLess(vertex1->pin(), vertex2->pin());
}
@ -45,7 +46,7 @@ VertexNameLess::operator()(const Vertex *vertex1,
////////////////////////////////////////////////////////////////
EdgeLess::EdgeLess(const Network *network,
Graph *&graph) :
Graph *&graph) :
pin_less_(network),
graph_(graph)
{
@ -53,7 +54,7 @@ EdgeLess::EdgeLess(const Network *network,
bool
EdgeLess::operator()(const Edge *edge1,
const Edge *edge2) const
const Edge *edge2) const
{
const Pin *from1 = edge1->from(graph_)->pin();
const Pin *from2 = edge2->from(graph_)->pin();
@ -61,13 +62,13 @@ EdgeLess::operator()(const Edge *edge1,
const Pin *to2 = edge2->to(graph_)->pin();
return pin_less_(from1, from2)
|| (from1 == from2
&& pin_less_(to1, to2));
&& pin_less_(to1, to2));
}
void
sortEdges(EdgeSeq *edges,
Network *network,
Graph *graph)
Network *network,
Graph *graph)
{
sort(edges, EdgeLess(network, graph));
}

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;
@ -168,26 +166,30 @@ public:
// Find the parasitic for drvr_pin that is acceptable to the delay
// calculator by probing parasitics_.
virtual Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) = 0;
const RiseFall *rf,
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,23 +208,26 @@ 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,
float load_cap,
const Parasitic *parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew) __attribute__ ((deprecated));
const Slew &in_slew,
float load_cap,
const Parasitic *parasitic,
float related_out_cap,
const Pvt *pvt,
const Scene *scene,
const MinMax *min_max,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew) __attribute__ ((deprecated));
// 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,9 +69,11 @@ protected:
friend class Sta;
private:
Mode *mode_;
void findClkPins();
void findClkPins(bool ideal_only,
PinClksMap &clk_pin_map);
PinClksMap &clk_pin_map);
bool clk_pins_valid_;
// pin -> clks

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
{
@ -63,40 +65,40 @@ public:
bool isIdeal() const { return !is_propagated_; }
// Ideal clock slew.
void slew(const RiseFall *rf,
const MinMax *min_max,
// Return values.
float &slew,
bool &exists) const;
const MinMax *min_max,
// Return values.
float &slew,
bool &exists) const;
// Return zero (default) if no slew exists.
float slew(const RiseFall *rf,
const MinMax *min_max) const;
const MinMax *min_max) const;
void setSlew(const RiseFall *rf,
const MinMax *min_max,
float slew);
const MinMax *min_max,
float slew);
void setSlew(const RiseFallBoth *rf,
const MinMaxAll *min_max,
float slew);
const MinMaxAll *min_max,
float slew);
void removeSlew();
const RiseFallMinMax &slews() const { return slews_; }
void setSlewLimit(const RiseFallBoth *rf,
const PathClkOrData clk_data,
const MinMax *min_max,
float slew);
const PathClkOrData clk_data,
const MinMax *min_max,
float slew);
void slewLimit(const RiseFall *rf,
const PathClkOrData clk_data,
const MinMax *min_max,
// Return values.
float &slew,
bool &exists) const;
const PathClkOrData clk_data,
const MinMax *min_max,
// Return values.
float &slew,
bool &exists) const;
ClockUncertainties *uncertainties() const { return uncertainties_; }
void uncertainty(const SetupHold *setup_hold,
// Return values.
float &uncertainty,
bool &exists) const;
// Return values.
float &uncertainty,
bool &exists) const;
void setUncertainty(const SetupHoldAll *setup_hold,
float uncertainty);
float uncertainty);
void setUncertainty(const SetupHold *setup_hold,
float uncertainty);
float uncertainty);
void removeUncertainty(const SetupHoldAll *setup_hold);
void setPeriod(float period);
@ -124,8 +126,8 @@ public:
bool isDivideByOneCombinational() const;
bool generatedUpToDate() const;
void srcPinVertices(VertexSet &src_vertices,
const Network *network,
Graph *graph);
const Network *network,
Graph *graph);
// True if the generated clock waveform is up to date.
bool waveformValid() const { return waveform_valid_; }
void waveformInvalid();
@ -133,36 +135,36 @@ public:
protected:
// Private to Sdc::makeClock.
Clock(const char *name,
int index,
int index,
const Network *network);
void initClk(PinSet *pins,
bool add_to_pins,
float period,
FloatSeq *waveform,
const char *comment,
const Network *network);
bool add_to_pins,
float period,
FloatSeq *waveform,
const char *comment,
const Network *network);
void initGeneratedClk(PinSet *pins,
bool add_to_pins,
Pin *src_pin,
Clock *master_clk,
int divide_by,
int multiply_by,
float duty_cycle,
bool invert,
bool combinational,
IntSeq *edges,
FloatSeq *edge_shifts,
bool is_propagated,
const char *comment,
const Network *network);
bool add_to_pins,
Pin *src_pin,
Clock *master_clk,
int divide_by,
int multiply_by,
float duty_cycle,
bool invert,
bool combinational,
IntSeq *edges,
FloatSeq *edge_shifts,
bool is_propagated,
const char *comment,
const Network *network);
void setPins(PinSet *pins,
const Network *network);
const Network *network);
void setMasterClk(Clock *master);
void makeClkEdges();
void setClkEdgeTimes();
void setClkEdgeTime(const RiseFall *rf);
void generateScaledClk(const Clock *src_clk,
float scale);
float scale);
void generateEdgesClk(const Clock *src_clk);
const char *name_;
@ -229,10 +231,10 @@ clkCmp(const Clock *clk1,
const Clock *clk2);
int
clkEdgeCmp(const ClockEdge *clk_edge1,
const ClockEdge *clk_edge2);
const ClockEdge *clk_edge2);
bool
clkEdgeLess(const ClockEdge *clk_edge1,
const ClockEdge *clk_edge2);
const ClockEdge *clk_edge2);
class ClockNameLess
{
@ -247,24 +249,24 @@ class InterClockUncertainty
{
public:
InterClockUncertainty(const Clock *src,
const Clock *target);
const Clock *target);
const Clock *src() const { return src_; }
const Clock *target() const { return target_; }
void uncertainty(const RiseFall *src_rf,
const RiseFall *tgt_rf,
const SetupHold *setup_hold,
// Return values.
float &uncertainty,
bool &exists) const;
const RiseFall *tgt_rf,
const SetupHold *setup_hold,
// Return values.
float &uncertainty,
bool &exists) const;
void setUncertainty(const RiseFallBoth *src_rf,
const RiseFallBoth *tgt_rf,
const SetupHoldAll *setup_hold,
float uncertainty);
const RiseFallBoth *tgt_rf,
const SetupHoldAll *setup_hold,
float uncertainty);
void removeUncertainty(const RiseFallBoth *src_rf,
const RiseFallBoth *tgt_rf,
const SetupHoldAll *setup_hold);
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_;
@ -276,14 +278,14 @@ class InterClockUncertaintyLess
{
public:
bool operator()(const InterClockUncertainty *inter1,
const InterClockUncertainty *inter2) const;
const InterClockUncertainty *inter2) const;
};
class ClkNameLess
{
public:
bool operator()(const Clock *clk1,
const Clock *clk2) const
const Clock *clk2) const
{
return stringLess(clk1->name(), clk2->name());
}

View File

@ -33,11 +33,11 @@ class ClockGroups : public SdcCmdComment
{
public:
ClockGroups(const char *name,
bool logically_exclusive,
bool physically_exclusive,
bool asynchronous,
bool allow_paths,
const char *comment);
bool logically_exclusive,
bool physically_exclusive,
bool asynchronous,
bool allow_paths,
const char *comment);
~ClockGroups();
void makeClockGroup(ClockSet *clks);
const char *name() const { return name_; }

View File

@ -39,16 +39,16 @@ public:
const Clock *clock() const { return clk_; }
const Pin *pin() const { return pin_; }
float delay(const RiseFall *rf, const MinMax *min_max,
const EarlyLate *early_late);
const EarlyLate *early_late);
void delay(const RiseFall *rf, const MinMax *min_max,
const EarlyLate *early_late,
// Return values.
float &insertion, bool &exists);
const EarlyLate *early_late,
// Return values.
float &insertion, bool &exists);
RiseFallMinMax *delays(const EarlyLate *early_late);
void setDelay(const RiseFall *rf, const MinMax *min_max,
const EarlyLate *early_late, float delay);
const EarlyLate *early_late, float delay);
void setDelay(const RiseFallBoth *rf, const MinMaxAll *min_max,
const EarlyLateAll *early_late, float delay);
const EarlyLateAll *early_late, float delay);
void setDelays(RiseFallMinMax *delays);
private:

View File

@ -36,23 +36,23 @@ class ClockLatency
{
public:
ClockLatency(const Clock *clk,
const Pin *pin);
const Pin *pin);
const Clock *clock() const { return clk_; }
const Pin *pin() const { return pin_; }
float delay(const RiseFall *rf,
const MinMax *min_max);
const MinMax *min_max);
void delay(const RiseFall *rf,
const MinMax *min_max,
// Return values.
float &latency,
bool &exists);
const MinMax *min_max,
// Return values.
float &latency,
bool &exists);
RiseFallMinMax *delays();
void setDelay(const RiseFall *rf,
const MinMax *min_max,
float delay);
const MinMax *min_max,
float delay);
void setDelay(const RiseFallBoth *rf,
const MinMaxAll *min_max,
float delay);
const MinMaxAll *min_max,
float delay);
void setDelays(RiseFallMinMax *delays);
private:

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,19 +45,19 @@ 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,
const char *filename,
bool is_liberty);
ConcreteLibrary(const char *name,
const char *filename,
bool is_liberty);
virtual ~ConcreteLibrary();
const char *name() const { return name_.c_str(); }
void setName(const char *name);
@ -66,8 +66,8 @@ public:
const char *filename() const { return filename_.c_str(); }
void addCell(ConcreteCell *cell);
ConcreteCell *makeCell(const char *name,
bool is_leaf,
const char *filename);
bool is_leaf,
const char *filename);
void deleteCell(ConcreteCell *cell);
ConcreteLibraryCellIterator *cellIterator() const;
ConcreteCell *findCell(const char *name) const;
@ -75,11 +75,11 @@ public:
char busBrktLeft() const { return bus_brkt_left_; }
char busBrktRight() const { return bus_brkt_right_; }
void setBusBrkts(char left,
char right);
char right);
protected:
void renameCell(ConcreteCell *cell,
const char *cell_name);
const char *cell_name);
std::string name_;
ObjectId id_;
@ -122,14 +122,14 @@ public:
ConcretePort *makePort(const char *name);
// Bus port.
ConcretePort *makeBusPort(const char *name,
int from_index,
int to_index);
int from_index,
int to_index);
// Bundle port.
ConcretePort *makeBundlePort(const char *name,
ConcretePortSeq *members);
ConcretePortSeq *members);
// Group previously defined bus bit ports together.
void groupBusPorts(const char bus_brkt_left,
const char bus_brkt_right,
const char bus_brkt_right,
std::function<bool(const char*)> port_msb_first);
size_t portCount() const;
void setName(const char *name);
@ -138,23 +138,23 @@ public:
protected:
ConcreteCell(const char *name,
const char *filename,
const char *filename,
bool is_leaf,
ConcreteLibrary *library);
ConcretePort *makeBusPort(const char *name,
int from_index,
int to_index,
ConcretePortSeq *members);
int from_index,
int to_index,
ConcretePortSeq *members);
void makeBusPortBits(ConcretePort *bus_port,
const char *name,
int from_index,
int to_index);
const char *name,
int from_index,
int to_index);
// Bus port bit (internal to makeBusPortBits).
ConcretePort *makePort(const char *bit_name,
int bit_index);
int bit_index);
void makeBusPortBit(ConcretePort *bus_port,
const char *name,
int index);
const char *name,
int index);
std::string name_;
ObjectId id_;
@ -233,10 +233,10 @@ protected:
// Constructors for factory in cell class.
ConcretePort(const char *name,
bool is_bus,
int from_index,
int to_index,
bool is_bundle,
ConcretePortSeq *member_ports,
int from_index,
int to_index,
bool is_bundle,
ConcretePortSeq *member_ports,
ConcreteCell *cell);
std::string name_;
@ -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.
@ -172,7 +171,7 @@ public:
ConstantPinIterator *constantPinIterator() override;
void addConstantNet(Net *net,
LogicValue value) override;
LogicValue value) override;
// Edit methods.
Library *makeLibrary(const char *name,
@ -270,12 +269,12 @@ protected:
PinVisitor &visitor,
NetSet &visited_nets) const override;
Instance *makeConcreteInstance(ConcreteCell *cell,
const char *name,
Instance *parent);
const char *name,
Instance *parent);
void disconnectNetPin(ConcreteNet *cnet,
ConcretePin *cpin);
ConcretePin *cpin);
void connectNetPin(ConcreteNet *cnet,
ConcretePin *cpin);
ConcretePin *cpin);
// Cell lookup search order sequence.
ConcreteLibrarySeq library_seq_;
@ -315,14 +314,14 @@ public:
void deletePin(ConcretePin *pin);
void addNet(ConcreteNet *net);
void addNet(const char *name,
ConcreteNet *net);
ConcreteNet *net);
void deleteNet(ConcreteNet *net);
void setCell(ConcreteCell *cell);
void initPins();
protected:
ConcreteInstance(const char *name,
ConcreteCell *cell,
ConcreteCell *cell,
ConcreteInstance *parent);
~ConcreteInstance();
@ -356,8 +355,8 @@ public:
protected:
~ConcretePin() {}
ConcretePin(ConcreteInstance *instance,
ConcretePort *port,
ConcreteNet *net);
ConcretePort *port,
ConcreteNet *net);
ConcreteInstance *instance_;
ConcretePort *port_;
@ -386,7 +385,7 @@ public:
protected:
~ConcreteTerm() {}
ConcreteTerm(ConcretePin *pin,
ConcreteNet *net);
ConcreteNet *net);
ConcretePin *pin_;
ConcreteNet *net_;
@ -415,7 +414,7 @@ public:
protected:
ConcreteNet(const char *name,
ConcreteInstance *instance);
ConcreteInstance *instance);
~ConcreteNet();
const char *name_;
ObjectId id_;

View File

@ -0,0 +1,429 @@
// 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 pointer value in a reference to 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 pointer value in a pointer to 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;
}
////////////////////////////////////////////////////////////////
// Find a value reference in a container. Returns reference to the value if found,
// otherwise returns reference to a static empty value of the same type.
template<typename AssocContainer>
auto
findKeyValue(const AssocContainer& c,
typename AssocContainer::key_type key)
-> const typename find_return<AssocContainer>::type &
{
auto it = c.find(key);
if (it != c.end()) {
if constexpr (has_mapped_type<AssocContainer>::value)
return it->second;
else
return *it;
}
static const typename find_return<AssocContainer>::type empty{};
return empty;
}
// Find an value reference in a reference to a contaiiner of objects.
// Return exists.
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;
}
}
// Find an value reference in a pointer to a contaiiner of objects.
// Return exists.
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;
}
}
////////////////////////////////////////////////////////////////
// Find an value pointer in a reference to a contaiiner of objects.
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;
}
// Find an pointger to a value in a const reference to a contaiiner objects.
// Return nullptr if not found.
template<typename AssocContainer>
auto
findKeyValuePtr(const AssocContainer& c,
typename AssocContainer::key_type key)
-> const 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::stable_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::stable_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"
@ -42,17 +43,19 @@ class CycleAcctingEqual
{
public:
bool operator()(const CycleAccting *acct1,
const CycleAccting *acct2) const;
const CycleAccting *acct2) const;
};
class CycleAcctingLess
{
public:
bool operator()(const CycleAccting *acct1,
const CycleAccting *acct2) const;
const CycleAccting *acct2) const;
};
typedef UnorderedSet<CycleAccting*, CycleAcctingHash, CycleAcctingEqual> CycleAcctingSet;
using CycleAcctingSet = std::unordered_set<CycleAccting*,
CycleAcctingHash,
CycleAcctingEqual>;
class CycleAcctings
{
@ -63,7 +66,7 @@ public:
// Find the cycle accounting info for paths that start at src clock
// edge and end at target clock edge.
CycleAccting *cycleAccting(const ClockEdge *src,
const ClockEdge *tgt);
const ClockEdge *tgt);
void reportClkToClkMaxCycleWarnings(Report *report);
private:
@ -75,7 +78,7 @@ class CycleAccting
{
public:
CycleAccting(const ClockEdge *src,
const ClockEdge *tgt);
const ClockEdge *tgt);
// Fill in required times.
void findDelays(StaState *sta);
// Find delays when source clk edge is the default arrival clock edge
@ -92,26 +95,26 @@ public:
private:
void setHoldAccting(int src_cycle,
int tgt_cycle,
float delay,
float req);
int tgt_cycle,
float delay,
float req);
void setAccting(const TimingRole *role,
int src_cycle,
int tgt_cycle,
float delay,
float req);
int src_cycle,
int tgt_cycle,
float delay,
float req);
void setSetupAccting(int src_cycle,
int tgt_cycle,
float delay,
float req);
int tgt_cycle,
float delay,
float req);
void setDefaultSetupAccting(int src_cycle,
int tgt_cycle,
float delay,
float req);
int tgt_cycle,
float delay,
float req);
void setDefaultHoldAccting(int src_cycle,
int tgt_cycle,
float delay,
float req);
int tgt_cycle,
float delay,
float req);
int firstCycle(const ClockEdge *clk_edge) const;
const ClockEdge *src_;

View File

@ -37,29 +37,29 @@ class DataCheck
{
public:
DataCheck(Pin *from,
Pin *to,
Clock *clk);
Pin *to,
Clock *clk);
Pin *from() const { return from_; }
Pin *to() const { return to_; }
Clock *clk() const { return clk_; }
void margin(const RiseFall *from_rf,
const RiseFall *to_rf,
const SetupHold *setup_hold,
// Return values.
float &margin,
bool &exists) const;
const RiseFall *to_rf,
const SetupHold *setup_hold,
// Return values.
float &margin,
bool &exists) const;
void setMargin(const RiseFallBoth *from_rf,
const RiseFallBoth *to_rf,
const SetupHoldAll *setup_hold,
float margin);
const RiseFallBoth *to_rf,
const SetupHoldAll *setup_hold,
float margin);
void removeMargin(const RiseFallBoth *from_rf,
const RiseFallBoth *to_rf,
const SetupHoldAll *setup_hold);
bool empty() const;
const RiseFallBoth *to_rf,
const SetupHoldAll *setup_hold);
[[nodiscard]] bool empty() const;
void marginIsOneValue(const SetupHold *setup_hold,
// Return values.
float &value,
bool &one_value) const;
// Return values.
float &value,
bool &one_value) const;
private:
Pin *from_;
@ -73,7 +73,7 @@ class DataCheckLess
public:
DataCheckLess(const Network *network);
bool operator()(const DataCheck *check1,
const DataCheck *check2) const;
const DataCheck *check2) const;
private:
const Network *network_;

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,18 +36,17 @@ 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);
int level);
bool check(const char *what,
int level) const;
int level) const;
int statsLevel() const { return stats_level_; }
void reportLine(const char *what,
const char *fmt,
@ -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
@ -39,7 +39,7 @@ registerDelayCalcs();
// Register a delay calculator for the set_delay_calc command.
void
registerDelayCalc(const char *name,
MakeArcDelayCalc maker);
MakeArcDelayCalc maker);
bool
isDelayCalcName(const char *name);
StringSeq
@ -50,6 +50,6 @@ deleteDelayCalcs();
// Make a registered delay calculator by name.
ArcDelayCalc *
makeDelayCalc(const char *name,
StaState *sta);
StaState *sta);
} // namespace

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;
@ -43,29 +43,29 @@ initDelayConstants();
const char *
delayAsString(const Delay &delay,
const StaState *sta);
const StaState *sta);
const char *
delayAsString(const Delay &delay,
const StaState *sta,
int digits);
const StaState *sta,
int digits);
const char *
delayAsString(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta,
int digits);
const EarlyLate *early_late,
const StaState *sta,
int digits);
inline Delay
makeDelay(float delay,
float,
float)
float,
float)
{
return delay;
}
inline Delay
makeDelay2(float delay,
float,
float)
float,
float)
{
return delay;
}
@ -79,15 +79,15 @@ delayAsFloat(const Delay &delay)
// mean late+/early- sigma
inline float
delayAsFloat(const Delay &delay,
const EarlyLate *,
const StaState *)
const EarlyLate *,
const StaState *)
{
return delay;
}
inline float
delaySigma2(const Delay &,
const EarlyLate *)
const EarlyLate *)
{
return 0.0;
}
@ -96,57 +96,57 @@ const Delay &
delayInitValue(const MinMax *min_max);
bool
delayIsInitValue(const Delay &delay,
const MinMax *min_max);
const MinMax *min_max);
bool
delayZero(const Delay &delay);
bool
delayInf(const Delay &delay);
bool
delayEqual(const Delay &delay1,
const Delay &delay2);
const Delay &delay2);
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
const Delay &delay2,
const StaState *sta);
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
const Delay &delay2,
const StaState *sta);
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
const Delay &delay2,
const StaState *sta);
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
const Delay &delay2,
const StaState *sta);
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
// delay1-delay2 subtracting sigma instead of addiing.
Delay
delayRemove(const Delay &delay1,
const Delay &delay2);
const Delay &delay2);
float
delayRatio(const Delay &delay1,
const Delay &delay2);
const Delay &delay2);
} // namespace

View File

@ -41,7 +41,7 @@ public:
Delay(const DelayDbl &delay);
Delay(float mean);
Delay(float mean,
float sigma2);
float sigma2);
float mean() const { return mean_; }
float sigma() const;
// sigma^2
@ -95,27 +95,27 @@ initDelayConstants();
const char *
delayAsString(const Delay &delay,
const StaState *sta);
const StaState *sta);
const char *
delayAsString(const Delay &delay,
const StaState *sta,
int digits);
const StaState *sta,
int digits);
const char *
delayAsString(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta,
int digits);
const EarlyLate *early_late,
const StaState *sta,
int digits);
Delay
makeDelay(float delay,
float sigma_early,
float sigma_late);
float sigma_early,
float sigma_late);
Delay
makeDelay2(float delay,
// sigma^2
float sigma_early,
float sigma_late);
// sigma^2
float sigma_early,
float sigma_late);
inline float
delayAsFloat(const Delay &delay)
@ -126,78 +126,78 @@ delayAsFloat(const Delay &delay)
// mean late+/early- sigma
float
delayAsFloat(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta);
const EarlyLate *early_late,
const StaState *sta);
float
delaySigma2(const Delay &delay,
const EarlyLate *early_late);
const EarlyLate *early_late);
const Delay &
delayInitValue(const MinMax *min_max);
bool
delayIsInitValue(const Delay &delay,
const MinMax *min_max);
const MinMax *min_max);
bool
delayZero(const Delay &delay);
bool
delayInf(const Delay &delay);
bool
delayEqual(const Delay &delay1,
const Delay &delay2);
const Delay &delay2);
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
const Delay &delay2,
const StaState *sta);
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
const Delay &delay2,
const StaState *sta);
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
const Delay &delay2,
const StaState *sta);
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
const Delay &delay2,
const StaState *sta);
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
// delay1-delay2 subtracting sigma instead of addiing.
Delay delayRemove(const Delay &delay1,
const Delay &delay2);
const Delay &delay2);
float
delayRatio(const Delay &delay1,
const Delay &delay2);
const Delay &delay2);
// Most non-operator functions on Delay are not defined as member
// functions so they can be defined on floats, where there is no class
// to define them.
Delay operator+(float delay1,
const Delay &delay2);
const Delay &delay2);
// Used for parallel gate delay calc.
Delay operator/(float delay1,
const Delay &delay2);
const Delay &delay2);
// Used for parallel gate delay calc.
Delay operator*(const Delay &delay1,
float delay2);
float delay2);
} // namespace

View File

@ -41,8 +41,8 @@ public:
Delay(const DelayDbl &delay);
Delay(float mean);
Delay(float mean,
float sigma2_early,
float sigma2_late);
float sigma2_early,
float sigma2_late);
float mean() const { return mean_; }
float sigma(const EarlyLate *early_late) const;
// sigma^2
@ -106,27 +106,27 @@ initDelayConstants();
const char *
delayAsString(const Delay &delay,
const StaState *sta);
const StaState *sta);
const char *
delayAsString(const Delay &delay,
const StaState *sta,
int digits);
const StaState *sta,
int digits);
const char *
delayAsString(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta,
int digits);
const EarlyLate *early_late,
const StaState *sta,
int digits);
Delay
makeDelay(float delay,
float sigma_early,
float sigma_late);
float sigma_early,
float sigma_late);
Delay
makeDelay2(float delay,
// sigma^2
float sigma_early,
float sigma_late);
// sigma^2
float sigma_early,
float sigma_late);
inline float
delayAsFloat(const Delay &delay)
@ -137,78 +137,78 @@ delayAsFloat(const Delay &delay)
// mean late+/early- sigma
float
delayAsFloat(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta);
const EarlyLate *early_late,
const StaState *sta);
float
delaySigma2(const Delay &delay,
const EarlyLate *early_late);
const EarlyLate *early_late);
const Delay &
delayInitValue(const MinMax *min_max);
bool
delayIsInitValue(const Delay &delay,
const MinMax *min_max);
const MinMax *min_max);
bool
delayZero(const Delay &delay);
bool
delayInf(const Delay &delay);
bool
delayEqual(const Delay &delay1,
const Delay &delay2);
const Delay &delay2);
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
const Delay &delay2,
const StaState *sta);
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
const Delay &delay2,
const StaState *sta);
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
const Delay &delay2,
const StaState *sta);
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta);
const Delay &delay2,
const StaState *sta);
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
const Delay &delay2,
const MinMax *min_max,
const StaState *sta);
// delay1-delay2 subtracting sigma instead of addiing.
Delay delayRemove(const Delay &delay1,
const Delay &delay2);
const Delay &delay2);
float
delayRatio(const Delay &delay1,
const Delay &delay2);
const Delay &delay2);
// Most non-operator functions on Delay are not defined as member
// functions so they can be defined on floats, where there is no class
// to define them.
Delay operator+(float delay1,
const Delay &delay2);
const Delay &delay2);
// Used for parallel gate delay calc.
Delay operator/(float delay1,
const Delay &delay2);
const Delay &delay2);
// Used for parallel gate delay calc.
Delay operator*(const Delay &delay1,
float delay2);
float delay2);
} // namespace

View File

@ -36,22 +36,22 @@ class DeratingFactors
public:
DeratingFactors();
void setFactor(PathClkOrData clk_data,
const RiseFallBoth *rf,
const EarlyLate *early_late,
float factor);
const RiseFallBoth *rf,
const EarlyLate *early_late,
float factor);
void factor(PathClkOrData clk_data,
const RiseFall *rf,
const EarlyLate *early_late,
float &factor,
bool &exists) const;
const RiseFall *rf,
const EarlyLate *early_late,
float &factor,
bool &exists) const;
void clear();
void isOneValue(const EarlyLate *early_late,
bool &is_one_value,
float &value) const;
bool &is_one_value,
float &value) const;
void isOneValue(PathClkOrData clk_data,
const EarlyLate *early_late,
bool &is_one_value,
float &value) const;
const EarlyLate *early_late,
bool &is_one_value,
float &value) const;
bool hasValue() const;
private:
@ -63,22 +63,22 @@ class DeratingFactorsGlobal
public:
DeratingFactorsGlobal();
void setFactor(TimingDerateType type,
PathClkOrData clk_data,
const RiseFallBoth *rf,
const EarlyLate *early_late,
float factor);
PathClkOrData clk_data,
const RiseFallBoth *rf,
const EarlyLate *early_late,
float factor);
void factor(TimingDerateType type,
PathClkOrData clk_data,
const RiseFall *rf,
const EarlyLate *early_late,
float &factor,
bool &exists) const;
PathClkOrData clk_data,
const RiseFall *rf,
const EarlyLate *early_late,
float &factor,
bool &exists) const;
void factor(TimingDerateCellType type,
PathClkOrData clk_data,
const RiseFall *rf,
const EarlyLate *early_late,
float &factor,
bool &exists) const;
PathClkOrData clk_data,
const RiseFall *rf,
const EarlyLate *early_late,
float &factor,
bool &exists) const;
DeratingFactors *factors(TimingDerateType type);
void clear();
@ -91,21 +91,21 @@ class DeratingFactorsCell
public:
DeratingFactorsCell();
void setFactor(TimingDerateCellType type,
PathClkOrData clk_data,
const RiseFallBoth *rf,
const EarlyLate *early_late,
float factor);
PathClkOrData clk_data,
const RiseFallBoth *rf,
const EarlyLate *early_late,
float factor);
void factor(TimingDerateCellType type,
PathClkOrData clk_data,
const RiseFall *rf,
const EarlyLate *early_late,
float &factor,
bool &exists) const;
PathClkOrData clk_data,
const RiseFall *rf,
const EarlyLate *early_late,
float &factor,
bool &exists) const;
DeratingFactors *factors(TimingDerateCellType type);
void clear();
void isOneValue(const EarlyLate *early_late,
bool &is_one_value,
float &value) const;
bool &is_one_value,
float &value) const;
private:
DeratingFactors factors_[timing_derate_cell_type_count];

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,
LibertyPort *to,
const TimingRole *role);
[[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

@ -37,11 +37,11 @@ public:
EnumNameMap(std::initializer_list<std::pair<const ENUM, std::string>> enum_names);
const char *find(ENUM key) const;
ENUM find(std::string name,
ENUM unknown_key) const;
ENUM unknown_key) const;
void find(std::string name,
// Return values.
ENUM &key,
bool &exists) const;
// Return values.
ENUM &key,
bool &exists) const;
private:
std::map<ENUM, std::string> enum_map_;
@ -70,9 +70,9 @@ EnumNameMap<ENUM>::find(ENUM key) const
template <class ENUM>
void
EnumNameMap<ENUM>::find(std::string name,
// Return values.
ENUM &key,
bool &exists) const
// Return values.
ENUM &key,
bool &exists) const
{
auto find_iter = name_map_.find(name);
if (find_iter != name_map_.end()) {
@ -86,7 +86,7 @@ EnumNameMap<ENUM>::find(std::string name,
template <class ENUM>
ENUM
EnumNameMap<ENUM>::find(std::string name,
ENUM unknown_key) const
ENUM unknown_key) const
{
auto find_iter = name_map_.find(name);
if (find_iter != name_map_.end())

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
{
@ -40,16 +40,16 @@ public:
// Find equivalent cells in equiv_libs.
// Optionally add mappings for cells in map_libs.
EquivCells(LibertyLibrarySeq *equiv_libs,
LibertyLibrarySeq *map_libs);
LibertyLibrarySeq *map_libs);
~EquivCells();
// Find equivalents for cell (member of from_libs) in to_libs.
LibertyCellSeq *equivs(LibertyCell *cell);
protected:
void findEquivCells(const LibertyLibrary *library,
LibertyCellHashMap &hash_matches);
LibertyCellHashMap &hash_matches);
void mapEquivCells(const LibertyLibrary *library,
LibertyCellHashMap &hash_matches);
LibertyCellHashMap &hash_matches);
EquivCellMap equiv_cells_;
// Unique cell for each equiv cell group.
@ -60,7 +60,7 @@ protected:
// functions or timing arcs match.
bool
equivCells(const LibertyCell *cell1,
const LibertyCell *cell2);
const LibertyCell *cell2);
// Predicate that is true when the ports, functions, sequentials and
// timing arcs match.
@ -71,7 +71,7 @@ equivCellsArcs(const LibertyCell *cell1,
// Predicate that is true when the ports match.
bool
equivCellPorts(const LibertyCell *cell1,
const LibertyCell *cell2);
const LibertyCell *cell2);
// Predicate that is true cell functions match.
bool
@ -81,10 +81,10 @@ equivCellFuncs(const LibertyCell *cell1,
// Predicate that is true when the timing arc sets match.
bool
equivCellTimingArcSets(const LibertyCell *cell1,
const LibertyCell *cell2);
const LibertyCell *cell2);
bool
equivCellSequentials(const LibertyCell *cell1,
const LibertyCell *cell2);
const LibertyCell *cell2);
} // namespace

View File

@ -56,7 +56,7 @@ class ExceptionLine : public Exception
{
public:
ExceptionLine(const char *filename,
int line);
int line);
protected:
const char *filename_;
@ -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,18 +45,18 @@ class ExceptionThru;
class ExceptionTo;
class ExceptionState;
typedef Vector<ExceptionPath*> ExceptionPathSeq;
using ExceptionPathSeq = std::vector<ExceptionPath*>;
class ExceptionPath : public SdcCmdComment
{
public:
ExceptionPath(ExceptionFrom *from,
ExceptionThruSeq *thrus,
ExceptionTo *to,
const MinMaxAll *min_max,
bool own_pts,
int priority,
const char *comment);
ExceptionThruSeq *thrus,
ExceptionTo *to,
const MinMaxAll *min_max,
bool own_pts,
int priority,
const char *comment);
virtual ~ExceptionPath();
size_t id() const { return id_; }
void setId(size_t id);
@ -75,14 +76,14 @@ public:
const Network *network) const;
const MinMaxAll *minMax() const { return min_max_; }
virtual bool matches(const MinMax *min_max,
bool exact) const;
bool exact) const;
bool matchesFirstPt(const RiseFall *to_rf,
const MinMax *min_max);
const MinMax *min_max);
ExceptionState *firstState();
virtual bool resetMatch(ExceptionFrom *from,
ExceptionThruSeq *thrus,
ExceptionTo *to,
const MinMaxAll *min_max,
ExceptionThruSeq *thrus,
ExceptionTo *to,
const MinMaxAll *min_max,
const Network *network);
// The priority remains the same even though pin/clock/net/inst objects
// are added to the exceptions points during exception merging because
@ -103,22 +104,22 @@ public:
// they cannot be coded into the priority.
virtual bool tighterThan(ExceptionPath *exception) const = 0;
static int fromThruToPriority(ExceptionFrom *from,
ExceptionThruSeq *thrus,
ExceptionTo *to);
ExceptionThruSeq *thrus,
ExceptionTo *to);
size_t hash() const;
size_t hash(ExceptionPt *missing_pt) const;
// Mergeable properties (independent of exception points).
virtual bool mergeable(ExceptionPath *exception) const;
bool mergeablePts(ExceptionPath *exception) const;
bool mergeablePts(ExceptionPath *exception2,
ExceptionPt *missing_pt2,
ExceptionPt *&missing_pt) const;
ExceptionPt *missing_pt2,
ExceptionPt *&missing_pt) const;
// Overrides properties (independent of exception points).
virtual bool overrides(ExceptionPath *exception) const = 0;
virtual ExceptionPath *clone(ExceptionFrom *from,
ExceptionThruSeq *thrus,
ExceptionTo *to,
bool own_pts) = 0;
ExceptionThruSeq *thrus,
ExceptionTo *to,
bool own_pts) = 0;
void deleteInstance(const Instance *inst,
const Network *network);
@ -151,22 +152,22 @@ class FalsePath : public ExceptionPath
{
public:
FalsePath(ExceptionFrom *from,
ExceptionThruSeq *thrus,
ExceptionTo *to,
const MinMaxAll *min_max,
bool own_pts,
const char *comment);
ExceptionThruSeq *thrus,
ExceptionTo *to,
const MinMaxAll *min_max,
bool own_pts,
const char *comment);
FalsePath(ExceptionFrom *from,
ExceptionThruSeq *thrus,
ExceptionTo *to,
const MinMaxAll *min_max,
bool own_pts,
int priority,
const char *comment);
ExceptionThruSeq *thrus,
ExceptionTo *to,
const MinMaxAll *min_max,
bool own_pts,
int priority,
const char *comment);
virtual ExceptionPath *clone(ExceptionFrom *from,
ExceptionThruSeq *thrus,
ExceptionTo *to,
bool own_pts);
ExceptionThruSeq *thrus,
ExceptionTo *to,
bool own_pts);
virtual bool isFalse() const { return true; }
virtual ExceptionPathType type() const { return ExceptionPathType::false_path; }
virtual const char *typeString() const;
@ -182,7 +183,7 @@ class LoopPath : public FalsePath
{
public:
LoopPath(ExceptionThruSeq *thrus,
bool own_pts);
bool own_pts);
virtual bool isLoop() const { return true; }
virtual ExceptionPathType type() const { return ExceptionPathType::loop; }
virtual const char *typeString() const;
@ -194,18 +195,18 @@ class PathDelay : public ExceptionPath
{
public:
PathDelay(ExceptionFrom *from,
ExceptionThruSeq *thrus,
ExceptionTo *to,
const MinMax *min_max,
bool ignore_clk_latency,
ExceptionThruSeq *thrus,
ExceptionTo *to,
const MinMax *min_max,
bool ignore_clk_latency,
bool break_path,
float delay,
bool own_pts,
const char *comment);
float delay,
bool own_pts,
const char *comment);
virtual ExceptionPath *clone(ExceptionFrom *from,
ExceptionThruSeq *thrus,
ExceptionTo *to,
bool own_pts);
ExceptionThruSeq *thrus,
ExceptionTo *to,
bool own_pts);
virtual bool isPathDelay() const { return true; }
virtual ExceptionPathType type() const { return ExceptionPathType::path_delay; }
virtual const char *asString(const Network *network) const;
@ -229,21 +230,21 @@ class MultiCyclePath : public ExceptionPath
{
public:
MultiCyclePath(ExceptionFrom *from,
ExceptionThruSeq *thrus,
ExceptionTo *to,
const MinMaxAll *min_max,
bool use_end_clk,
int path_multiplier,
bool own_pts,
const char *comment);
ExceptionThruSeq *thrus,
ExceptionTo *to,
const MinMaxAll *min_max,
bool use_end_clk,
int path_multiplier,
bool own_pts,
const char *comment);
virtual ExceptionPath *clone(ExceptionFrom *from,
ExceptionThruSeq *thrus,
ExceptionTo *to,
bool own_pts);
ExceptionThruSeq *thrus,
ExceptionTo *to,
bool own_pts);
virtual bool isMultiCycle() const { return true; }
virtual ExceptionPathType type() const { return ExceptionPathType::multi_cycle; }
virtual bool matches(const MinMax *min_max,
bool exactly) const;
bool exactly) const;
virtual const char *asString(const Network *network) const;
virtual const char *typeString() const;
virtual bool mergeable(ExceptionPath *exception) const;
@ -267,22 +268,22 @@ class FilterPath : public ExceptionPath
{
public:
FilterPath(ExceptionFrom *from,
ExceptionThruSeq *thrus,
ExceptionTo *to,
bool own_pts);
ExceptionThruSeq *thrus,
ExceptionTo *to,
bool own_pts);
virtual ExceptionPath *clone(ExceptionFrom *from,
ExceptionThruSeq *thrus,
ExceptionTo *to,
bool own_pts);
ExceptionThruSeq *thrus,
ExceptionTo *to,
bool own_pts);
virtual bool isFilter() const { return true; }
virtual ExceptionPathType type() const { return ExceptionPathType::filter; }
virtual const char *typeString() const;
virtual bool mergeable(ExceptionPath *exception) const;
virtual bool overrides(ExceptionPath *exception) const;
virtual bool resetMatch(ExceptionFrom *from,
ExceptionThruSeq *thrus,
ExceptionTo *to,
const MinMaxAll *min_max,
ExceptionThruSeq *thrus,
ExceptionTo *to,
const MinMaxAll *min_max,
const Network *network);
virtual int typePriority() const;
virtual bool tighterThan(ExceptionPath *exception) const;
@ -292,17 +293,17 @@ class GroupPath : public ExceptionPath
{
public:
GroupPath(const char *name,
bool is_default,
ExceptionFrom *from,
ExceptionThruSeq *thrus,
ExceptionTo *to,
bool own_pts,
const char *comment);
bool is_default,
ExceptionFrom *from,
ExceptionThruSeq *thrus,
ExceptionTo *to,
bool own_pts,
const char *comment);
virtual ~GroupPath();
virtual ExceptionPath *clone(ExceptionFrom *from,
ExceptionThruSeq *thrus,
ExceptionTo *to,
bool own_pts);
ExceptionThruSeq *thrus,
ExceptionTo *to,
bool own_pts);
virtual bool isGroupPath() const { return true; }
virtual ExceptionPathType type() const { return ExceptionPathType::group_path; }
virtual const char *typeString() const;
@ -323,7 +324,7 @@ class ExceptionPt
{
public:
ExceptionPt(const RiseFallBoth *rf,
bool own_pts);
bool own_pts);
virtual ~ExceptionPt() {};
virtual bool isFrom() const { return false; }
virtual bool isThru() const { return false; }
@ -379,9 +380,9 @@ class ExceptionFromTo : public ExceptionPt
public:
ExceptionFromTo(PinSet *pins,
ClockSet *clks,
InstanceSet *insts,
const RiseFallBoth *rf,
bool own_pts,
InstanceSet *insts,
const RiseFallBoth *rf,
bool own_pts,
const Network *network);
~ExceptionFromTo();
virtual PinSet *pins() { return pins_; }
@ -398,7 +399,7 @@ public:
virtual PinSet allPins(const Network *network);
bool equal(ExceptionFromTo *from_to) const;
virtual int compare(ExceptionPt *pt,
const Network *network) const;
const Network *network) const;
virtual void mergeInto(ExceptionPt *pt,
const Network *network);
virtual const char *asString(const Network *network) const;
@ -436,10 +437,10 @@ class ExceptionFrom : public ExceptionFromTo
{
public:
ExceptionFrom(PinSet *pins,
ClockSet *clks,
InstanceSet *insts,
const RiseFallBoth *rf,
bool own_pts,
ClockSet *clks,
InstanceSet *insts,
const RiseFallBoth *rf,
bool own_pts,
const Network *network);
ExceptionFrom *clone(const Network *network);
virtual bool isFrom() const { return true; }
@ -456,13 +457,13 @@ class ExceptionTo : public ExceptionFromTo
{
public:
ExceptionTo(PinSet *pins,
ClockSet *clks,
InstanceSet *insts,
// -to|-rise_to|-fall_to
const RiseFallBoth *rf,
// -rise|-fall endpoint transition.
const RiseFallBoth *end_rf,
bool own_pts,
ClockSet *clks,
InstanceSet *insts,
// -to|-rise_to|-fall_to
const RiseFallBoth *rf,
// -rise|-fall endpoint transition.
const RiseFallBoth *end_rf,
bool own_pts,
const Network *network);
ExceptionTo *clone(const Network *network);
virtual bool isTo() const { return true; }
@ -472,28 +473,28 @@ public:
const Network *network) const;
virtual int typePriority() const { return 1; }
bool matches(const Pin *pin,
const ClockEdge *clk_edge,
const RiseFall *end_rf,
const Network *network) const;
const ClockEdge *clk_edge,
const RiseFall *end_rf,
const Network *network) const;
bool matches(const Pin *pin,
const RiseFall *end_rf) const;
const RiseFall *end_rf) const;
bool matches(const Clock *clk) const;
bool matches(const Pin *pin,
const RiseFall *end_rf,
const Network *network) const;
bool matchesFilter(const Pin *pin,
const ClockEdge *clk_edge,
const RiseFall *end_rf,
const Network *network) const;
const ClockEdge *clk_edge,
const RiseFall *end_rf,
const Network *network) const;
virtual int compare(ExceptionPt *pt,
const Network *network) const;
protected:
bool matches(const Pin *pin,
const ClockEdge *clk_edge,
const RiseFall *end_rf,
bool inst_matches_reg_clk_pin,
const Network *network) const;
const ClockEdge *clk_edge,
const RiseFall *end_rf,
bool inst_matches_reg_clk_pin,
const Network *network) const;
virtual const char *cmdKeyword() const;
// -rise|-fall endpoint transition.
@ -504,11 +505,11 @@ class ExceptionThru : public ExceptionPt
{
public:
ExceptionThru(PinSet *pins,
NetSet *nets,
InstanceSet *insts,
const RiseFallBoth *rf,
bool own_pts,
const Network *network);
NetSet *nets,
InstanceSet *insts,
const RiseFallBoth *rf,
bool own_pts,
const Network *network);
~ExceptionThru();
ExceptionThru *clone(const Network *network);
virtual const char *asString(const Network *network) const;
@ -523,12 +524,12 @@ public:
const Network *network);
virtual PinSet allPins(const Network *network);
bool matches(const Pin *from_pin,
const Pin *to_pin,
const RiseFall *to_rf,
const Network *network);
const Pin *to_pin,
const RiseFall *to_rf,
const Network *network);
bool equal(ExceptionThru *thru) const;
virtual int compare(ExceptionPt *pt,
const Network *network) const;
const Network *network) const;
virtual void mergeInto(ExceptionPt *pt,
const Network *network);
bool intersectsPts(ExceptionThru *thru,
@ -563,19 +564,19 @@ protected:
void makeNetEdges(const Network *network);
void makeInstEdges(const Network *network);
void makeHpinEdges(const Pin *pin,
const Network *network);
const Network *network);
void makePinEdges(const Pin *pin,
const Network *network);
const Network *network);
void makeNetEdges(const Net *net,
const Network *network);
const Network *network);
void makeInstEdges(Instance *inst,
Network *network);
Network *network);
void deletePinEdges(const Pin *pin,
Network *network);
Network *network);
void deleteNetEdges(Net *net,
const Network *network);
const Network *network);
void deleteInstEdges(Instance *inst,
Network *network);
Network *network);
// Leaf/port pins.
PinSet *pins_;
@ -587,20 +588,20 @@ protected:
ExceptionThruSeq *
exceptionThrusClone(ExceptionThruSeq *thrus,
const Network *network);
const Network *network);
// Iterate uniformly across exception from/thru/to's.
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_;
};
@ -616,13 +617,13 @@ class ExpandedExceptionVisitor
{
public:
ExpandedExceptionVisitor(ExceptionPath *exception,
const Network *network);
const Network *network);
virtual ~ExpandedExceptionVisitor() {}
void visitExpansions();
// From/thrus/to have a single exception point (pin/instance/net/clock).
virtual void visit(ExceptionFrom *from,
ExceptionThruSeq *thrus,
ExceptionTo *to) = 0;
ExceptionThruSeq *thrus,
ExceptionTo *to) = 0;
protected:
ExceptionPath *exception_;
@ -632,10 +633,10 @@ private:
void expandFrom();
void expandThrus(ExceptionFrom *expanded_from);
void expandThru(ExceptionFrom *expanded_from,
size_t next_thru_idx,
ExceptionThruSeq *expanded_thrus);
size_t next_thru_idx,
ExceptionThruSeq *expanded_thrus);
void expandTo(ExceptionFrom *expanded_from,
ExceptionThruSeq *expanded_thrus);
ExceptionThruSeq *expanded_thrus);
};
// States used by tags to know what exception points have been seen
@ -644,15 +645,15 @@ class ExceptionState
{
public:
ExceptionState(ExceptionPath *exception,
ExceptionThru *next_thru,
int index);
ExceptionThru *next_thru,
int index);
ExceptionPath *exception() { return exception_; }
const ExceptionPath *exception() const { return exception_; }
bool matchesNextThru(const Pin *from_pin,
const Pin *to_pin,
const RiseFall *to_rf,
const MinMax *min_max,
const Network *network) const;
const Pin *to_pin,
const RiseFall *to_rf,
const MinMax *min_max,
const Network *network) const;
bool isComplete() const;
ExceptionThru *nextThru() const { return next_thru_; }
ExceptionState *nextState() const { return next_state_; }
@ -667,9 +668,9 @@ private:
int index_;
};
bool
exceptionStateLess(const ExceptionState *state1,
const ExceptionState *state2);
int
exceptionStateCmp(const ExceptionState *state1,
const ExceptionState *state2);
// Exception thrown by check.
class EmptyExpceptionPt : public Exception
@ -683,7 +684,7 @@ class ExceptionPathLess
public:
ExceptionPathLess(const Network *network);
bool operator()(const ExceptionPath *except1,
const ExceptionPath *except2) const;
const ExceptionPath *except2) const;
private:
const Network *network_;
@ -692,7 +693,7 @@ private:
// Throws EmptyExpceptionPt it finds an empty exception point.
void
checkFromThrusTo(ExceptionFrom *from,
ExceptionThruSeq *thrus,
ExceptionTo *to);
ExceptionThruSeq *thrus,
ExceptionTo *to);
} // namespace

View File

@ -26,7 +26,6 @@
#include <string>
#include "Set.hh"
#include "NetworkClass.hh"
#include "LibertyClass.hh"
@ -35,46 +34,49 @@ 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 *left,
FuncExpr *right,
LibertyPort *port);
FuncExpr(Op op,
FuncExpr *left,
FuncExpr *right,
LibertyPort *port);
~FuncExpr();
void shallowDelete();
static FuncExpr *makePort(LibertyPort *port);
static FuncExpr *makeNot(FuncExpr *expr);
static FuncExpr *makeAnd(FuncExpr *left,
FuncExpr *right);
FuncExpr *right);
static FuncExpr *makeOr(FuncExpr *left,
FuncExpr *right);
FuncExpr *right);
static FuncExpr *makeXor(FuncExpr *left,
FuncExpr *right);
FuncExpr *right);
static FuncExpr *makeZero();
static FuncExpr *makeOne();
static bool equiv(const FuncExpr *expr1,
const FuncExpr *expr2);
const FuncExpr *expr2);
static bool less(const FuncExpr *expr1,
const FuncExpr *expr2);
const FuncExpr *expr2);
// Invert expr by deleting leading NOT if found.
FuncExpr *invert();
// Deep copy.
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 +88,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 +105,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

@ -30,21 +30,21 @@ namespace sta {
bool
fuzzyEqual(float v1,
float v2);
float v2);
bool
fuzzyZero(float v);
bool
fuzzyLess(float v1,
float v2);
float v2);
bool
fuzzyLessEqual(float v1,
float v2);
float v2);
bool
fuzzyGreater(float v1,
float v2);
float v2);
bool
fuzzyGreaterEqual(float v1,
float v2);
float v2);
bool
fuzzyInf(float value);

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;
@ -65,8 +64,8 @@ public:
// 2 rise/fall slews
// ap_count is the dcalc analysis point count.
Graph(StaState *sta,
int slew_rf_count,
DcalcAPIndex ap_count);
int slew_rf_count,
DcalcAPIndex ap_count);
void makeGraph();
~Graph();
@ -80,13 +79,13 @@ public:
VertexId id(const Vertex *vertex) const;
void makePinVertices(Pin *pin);
void makePinVertices(Pin *pin,
Vertex *&vertex,
Vertex *&bidir_drvr_vertex);
Vertex *&vertex,
Vertex *&bidir_drvr_vertex);
// Both vertices for bidirects.
void pinVertices(const Pin *pin,
// Return values.
Vertex *&vertex,
Vertex *&bidirect_drvr_vertex) const;
// Return values.
Vertex *&vertex,
Vertex *&bidirect_drvr_vertex) const;
// Driver vertex for bidirects.
Vertex *pinDrvrVertex(const Pin *pin) const;
// Load vertex for bidirects.
@ -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
@ -150,21 +145,19 @@ public:
const ArcDelay &delay);
// Is timing arc delay annotated.
bool arcDelayAnnotated(const Edge *edge,
const TimingArc *arc,
DcalcAPIndex ap_index) const;
const TimingArc *arc,
DcalcAPIndex ap_index) const;
void setArcDelayAnnotated(Edge *edge,
const TimingArc *arc,
DcalcAPIndex ap_index,
bool annotated);
const TimingArc *arc,
DcalcAPIndex ap_index,
bool annotated);
bool wireDelayAnnotated(const Edge *edge,
const RiseFall *rf,
DcalcAPIndex ap_index) const;
const RiseFall *rf,
DcalcAPIndex ap_index) const;
void setWireDelayAnnotated(Edge *edge,
const RiseFall *rf,
DcalcAPIndex ap_index,
bool annotated);
// True if any edge arc is annotated.
bool delayAnnotated(Edge *edge);
const RiseFall *rf,
DcalcAPIndex ap_index,
bool annotated);
void minPulseWidthArc(Vertex *vertex,
const RiseFall *hi_low,
@ -172,23 +165,24 @@ public:
Edge *&edge,
TimingArc *&arc);
void minPeriodArc(Vertex *vertex,
const RiseFall *rf,
// Return values.
Edge *&edge,
TimingArc *&arc);
const RiseFall *rf,
// Return values.
Edge *&edge,
TimingArc *&arc);
// Sdf period check annotation.
void periodCheckAnnotation(const Pin *pin,
DcalcAPIndex ap_index,
// Return values.
float &period,
bool &exists);
DcalcAPIndex ap_index,
// Return values.
float &period,
bool &exists);
void setPeriodCheckAnnotation(const Pin *pin,
DcalcAPIndex ap_index,
float period);
DcalcAPIndex ap_index,
float period);
// 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;
@ -196,12 +190,12 @@ public:
protected:
void makeVerticesAndEdges();
Vertex *makeVertex(Pin *pin,
bool is_bidirect_drvr,
bool is_reg_clk);
bool is_bidirect_drvr,
bool is_reg_clk);
void makeEdgeArcDelays(Edge *edge);
void makePinVertices(const Instance *inst);
void makeWireEdgesFromPin(const Pin *drvr_pin,
PinSet &visited_drvrs);
PinSet &visited_drvrs);
bool isIsolatedNet(PinSeq &drvrs,
PinSeq &loads) const;
void makeWireEdges();
@ -213,9 +207,9 @@ protected:
void removePeriodCheckAnnotations();
void makeVertexSlews(Vertex *vertex);
void deleteInEdge(Vertex *vertex,
Edge *edge);
Edge *edge);
void deleteOutEdge(Vertex *vertex,
Edge *edge);
Edge *edge);
void initSlews();
void initSlews(Vertex *vertex);
void initArcDelays(Edge *edge);
@ -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,74 +247,62 @@ 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.
bool slewAnnotated(const RiseFall *rf,
const MinMax *min_max) const;
const MinMax *min_max) const;
// True if any rise/fall analysis pt slew is annotated.
bool slewAnnotated() const;
void setSlewAnnotated(bool annotated,
const RiseFall *rf,
DcalcAPIndex ap_index);
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,
bool is_reg_clk);
bool is_bidirect_drvr,
bool is_reg_clk);
void clear();
void setSlews(Slew *slews);
Pin *pin_;
EdgeId in_edges_; // Edges to this vertex.
EdgeId out_edges_; // Edges from this vertex.
EdgeId in_edges_; // Edges to this vertex.
EdgeId out_edges_; // Edges from this vertex.
// Delay calc
Slew *slews_;
@ -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_; }
@ -408,8 +380,8 @@ public:
protected:
void init(VertexId from,
VertexId to,
TimingArcSet *arc_set);
VertexId to,
TimingArcSet *arc_set);
void clear();
bool arcDelayAnnotated(const TimingArc *arc,
DcalcAPIndex ap_index,
@ -423,8 +395,8 @@ protected:
TimingArcSet *arc_set_;
VertexId from_;
VertexId to_;
EdgeId vertex_in_link_; // Vertex in edges list.
EdgeId vertex_out_next_; // Vertex out edges doubly linked list.
EdgeId vertex_in_link_; // Vertex in edges list.
EdgeId vertex_out_next_; // Vertex out edges doubly linked list.
EdgeId vertex_out_prev_;
ArcDelay *arc_delays_;
union {
@ -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();
@ -477,9 +447,9 @@ class VertexInEdgeIterator : public VertexEdgeIterator
{
public:
VertexInEdgeIterator(Vertex *vertex,
const Graph *graph);
const Graph *graph);
VertexInEdgeIterator(VertexId vertex_id,
const Graph *graph);
const Graph *graph);
bool hasNext() { return (next_ != nullptr); }
Edge *next();
@ -492,7 +462,7 @@ class VertexOutEdgeIterator : public VertexEdgeIterator
{
public:
VertexOutEdgeIterator(Vertex *vertex,
const Graph *graph);
const Graph *graph);
bool hasNext() { return (next_ != nullptr); }
Edge *next();
@ -506,31 +476,21 @@ class EdgesThruHierPinIterator : public Iterator<Edge*>
{
public:
EdgesThruHierPinIterator(const Pin *hpin,
Network *network,
Graph *graph);
virtual bool hasNext() { return edge_iter_.hasNext(); }
virtual Edge *next() { return edge_iter_.next(); }
Network *network,
Graph *graph);
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,9 +33,9 @@ namespace sta {
class VertexNameLess
{
public:
explicit VertexNameLess(Network *network);
VertexNameLess(Network *network);
bool operator()(const Vertex *vertex1,
const Vertex *vertex2);
const Vertex *vertex2);
private:
Network *network_;
@ -45,9 +45,9 @@ class EdgeLess
{
public:
EdgeLess(const Network *network,
Graph *&graph);
Graph *&graph);
bool operator()(const Edge *edge1,
const Edge *edge2) const;
const Edge *edge2) const;
private:
const PinPathNameLess pin_less_;
@ -56,7 +56,7 @@ private:
void
sortEdges(EdgeSeq *edges,
Network *network,
Graph *graph);
Network *network,
Graph *graph);
} // namespace

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

@ -34,7 +34,7 @@ const size_t hash_init_value = 5381;
// Dan Bernstein, comp.lang.c.
inline size_t
hashSum(size_t hash,
size_t add)
size_t add)
{
// hash * 31 ^ add.
return ((hash << 5) + hash) ^ add;
@ -42,7 +42,7 @@ hashSum(size_t hash,
inline void
hashIncr(size_t &hash,
size_t add)
size_t add)
{
// hash * 31 ^ add.
hash = ((hash << 5) + hash) ^ add;

View File

@ -24,7 +24,6 @@
#pragma once
#include "Set.hh"
#include "NetworkClass.hh"
namespace sta {
@ -34,14 +33,14 @@ class HpinDrvrLoadVisitor;
void
visitHpinDrvrLoads(const Pin *pin,
const Network *network,
HpinDrvrLoadVisitor *visitor);
const Network *network,
HpinDrvrLoadVisitor *visitor);
class HpinDrvrLoadLess
{
public:
bool operator()(const HpinDrvrLoad *drvr_load1,
const HpinDrvrLoad *drvr_load2) const;
const HpinDrvrLoad *drvr_load2) const;
};
// Abstract base class for visitDrvrLoadsThruHierPin visitor.
@ -57,13 +56,13 @@ class HpinDrvrLoad
{
public:
HpinDrvrLoad(const Pin *drvr,
const Pin *load,
PinSet *hpins_from_drvr,
PinSet *hpins_to_load);
const Pin *load,
PinSet *hpins_from_drvr,
PinSet *hpins_to_load);
~HpinDrvrLoad();
void report(const Network *network);
HpinDrvrLoad(const Pin *drvr,
const Pin *load);
const Pin *load);
const Pin *drvr() const { return drvr_; }
const Pin *load() const { return load_; }
PinSet *hpinsFromDrvr() { return hpins_from_drvr_; }

View File

@ -40,45 +40,45 @@ class InputDriveCell;
class InputDrive
{
public:
explicit InputDrive();
InputDrive();
~InputDrive();
void setSlew(const RiseFallBoth *rf,
const MinMaxAll *min_max,
float slew);
const MinMaxAll *min_max,
float slew);
void setDriveResistance(const RiseFallBoth *rf,
const MinMaxAll *min_max,
float res);
const MinMaxAll *min_max,
float res);
void driveResistance(const RiseFall *rf,
const MinMax *min_max,
float &res,
bool &exists) const;
const MinMax *min_max,
float &res,
bool &exists) const;
bool hasDriveResistance(const RiseFall *rf,
const MinMax *min_max) const;
const MinMax *min_max) const;
bool driveResistanceMinMaxEqual(const RiseFall *rf) const;
void setDriveCell(const LibertyLibrary *library,
const LibertyCell *cell,
const LibertyPort *from_port,
float *from_slews,
const LibertyPort *to_port,
const RiseFallBoth *rf,
const MinMaxAll *min_max);
const LibertyCell *cell,
const LibertyPort *from_port,
float *from_slews,
const LibertyPort *to_port,
const RiseFallBoth *rf,
const MinMaxAll *min_max);
void driveCell(const RiseFall *rf,
const MinMax *min_max,
const MinMax *min_max,
// Return values.
const LibertyCell *&cell,
const LibertyPort *&from_port,
float *&from_slews,
const LibertyPort *&to_port) const;
const LibertyCell *&cell,
const LibertyPort *&from_port,
float *&from_slews,
const LibertyPort *&to_port) const;
InputDriveCell *driveCell(const RiseFall *rf,
const MinMax *min_max) const;
const MinMax *min_max) const;
bool hasDriveCell(const RiseFall *rf,
const MinMax *min_max) const;
const MinMax *min_max) const;
// True if rise/fall/min/max drive cells are equal.
bool driveCellsEqual() const;
void slew(const RiseFall *rf,
const MinMax *min_max,
float &slew,
bool &exists) const;
const MinMax *min_max,
float &slew,
bool &exists) const;
const RiseFallMinMax *slews() const { return &slews_; }
private:
@ -92,10 +92,10 @@ class InputDriveCell
{
public:
InputDriveCell(const LibertyLibrary *library,
const LibertyCell *cell,
const LibertyPort *from_port,
float *from_slews,
const LibertyPort *to_port);
const LibertyCell *cell,
const LibertyPort *from_port,
float *from_slews,
const LibertyPort *to_port);
const LibertyLibrary *library() const { return library_; }
void setLibrary(const LibertyLibrary *library);
const LibertyCell *cell() const { return cell_; }

View File

@ -24,85 +24,74 @@
#pragma once
#include <array>
#include <memory>
#include <string>
#include "LibertyClass.hh"
#include "Transition.hh"
namespace sta {
class InternalPowerAttrs;
class InternalPowerModel;
class InternalPowerAttrs
{
public:
InternalPowerAttrs();
virtual ~InternalPowerAttrs();
void deleteContents();
FuncExpr *when() const { return when_; }
void setWhen(FuncExpr *when);
void setModel(const RiseFall *rf,
InternalPowerModel *model);
InternalPowerModel *model(const RiseFall *rf) const;
const char *relatedPgPin() const { return related_pg_pin_; }
void setRelatedPgPin(const char *related_pg_pin);
protected:
FuncExpr *when_;
InternalPowerModel *models_[RiseFall::index_count];
const char *related_pg_pin_;
};
using InternalPowerModels =
std::array<std::shared_ptr<InternalPowerModel>, RiseFall::index_count>;
class InternalPower
{
public:
InternalPower(LibertyCell *cell,
LibertyPort *port,
LibertyPort *related_port,
InternalPowerAttrs *attrs);
~InternalPower();
InternalPower(LibertyPort *port,
LibertyPort *related_port,
LibertyPort *related_pg_pin,
const std::shared_ptr<FuncExpr> &when,
InternalPowerModels &models);
//InternalPower(InternalPower &&other) noexcept;
LibertyCell *libertyCell() const;
LibertyPort *port() const { return port_; }
LibertyPort *relatedPort() const { return related_port_; }
FuncExpr *when() const { return when_; }
const char *relatedPgPin() const { return related_pg_pin_; }
FuncExpr *when() const { return when_.get(); }
LibertyPort *relatedPgPin() const { return related_pg_pin_; }
float power(const RiseFall *rf,
const Pvt *pvt,
float in_slew,
float load_cap);
const Pvt *pvt,
float in_slew,
float load_cap) const;
const InternalPowerModel *model(const RiseFall *rf) const;
protected:
LibertyPort *port_;
LibertyPort *related_port_;
FuncExpr *when_;
const char *related_pg_pin_;
InternalPowerModel *models_[RiseFall::index_count];
LibertyPort *related_pg_pin_;
std::shared_ptr<FuncExpr> when_;
InternalPowerModels models_;
};
class InternalPowerModel
{
public:
explicit InternalPowerModel(TableModel *model);
InternalPowerModel(TableModel *model);
~InternalPowerModel();
float power(const LibertyCell *cell,
const Pvt *pvt,
float in_slew,
float load_cap) const;
const Pvt *pvt,
float in_slew,
float load_cap) const;
std::string reportPower(const LibertyCell *cell,
const Pvt *pvt,
float in_slew,
float load_cap,
int digits) const;
const TableModel *model() const { return model_; }
protected:
void findAxisValues(float in_slew,
float load_cap,
// Return values.
float &axis_value1,
float &axis_value2,
float &axis_value3) const;
float load_cap,
// Return values.
float &axis_value1,
float &axis_value2,
float &axis_value3) const;
float axisValue(const TableAxis *axis,
float in_slew,
float load_cap) const;
float in_slew,
float load_cap) const;
bool checkAxes(const TableModel *model);
bool checkAxis(const TableAxis *axis);

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

@ -36,6 +36,7 @@ public:
LibertyPort *related_pg_port,
FuncExpr *when,
float power);
LeakagePower(LeakagePower &&other) noexcept;
~LeakagePower();
LibertyCell *libertyCell() const { return cell_; }
LibertyPort *relatedPgPort() const { return related_pg_port_; }

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