fix merge
Signed-off-by: dsengupta0628 <dsengupta@precisioninno.com>
This commit is contained in:
commit
03f976128f
|
|
@ -10,7 +10,7 @@ AllowAllParametersOfDeclarationOnNextLine: false
|
|||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterReturnType: TopLevel
|
||||
BinPackArguments: false
|
||||
BinPackArguments: true
|
||||
# fails
|
||||
BinPackParameters: AlwaysOnePerLine
|
||||
BraceWrapping:
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
@ -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
16
BUILD
|
|
@ -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",
|
||||
],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
43
app/Main.cc
43
app/Main.cc
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
429
dcalc/DmpCeff.cc
429
dcalc/DmpCeff.cc
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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 "";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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_; }
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
6694
doc/OpenSTA.fodt
6694
doc/OpenSTA.fodt
File diff suppressed because it is too large
Load Diff
BIN
doc/OpenSTA.pdf
BIN
doc/OpenSTA.pdf
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,2 @@
|
|||
create_clock -name m1_clk -period 1000 {clk1 clk2 clk3}
|
||||
set_input_delay -clock m1_clk 100 {in1 in2}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
create_clock -name m2_clk -period 500 {clk1 clk3}
|
||||
set_output_delay -clock m2_clk 100 out
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
448
graph/Graph.cc
448
graph/Graph.cc
|
|
@ -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
|
||||
|
|
|
|||
253
graph/Graph.i
253
graph/Graph.i
|
|
@ -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 *
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_; }
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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 ¶siticAnalysisPts();
|
||||
|
||||
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
|
||||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ®ClkVertices() { 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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 *¶sitic) 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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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_; }
|
||||
|
|
|
|||
|
|
@ -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_; }
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in New Issue