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