Commit 0746dec9 by lvzhengyang

add sta code

parent c8697fc2
# This is "close" to correct but has a number of bugs that prevent
# using it on the source tree.
Language: Cpp
BasedOnStyle: Google
AccessModifierOffset: -2
AlignOperands: false
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: TopLevel
BinPackArguments: false
# fails
BinPackParameters: false
BraceWrapping:
AfterClass: true
AfterStruct: true
AfterFunction: true
BeforeElse: true
BreakBeforeBraces: Custom
# fails if all initializers fit on one line
BreakConstructorInitializers: AfterColon
ColumnLimit: 0
# fails
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 2
IncludeBlocks: Preserve
PointerAlignment: Right
.gitignore
Dockerfile
README
INSTALL
*.rej
*.orig
TAGS
*~
\#*#
.#*
.~lock.*\.*#
.DS_Store
Makefile
gmon.out
build
pvt
include/sta/StaConfig.hh
app/sta
app/libOpenSTA.*
app/sta.exe
app/sta.dSYM
doc/._Sta.docx
test/results
# ngspice turd
test/b3v3_1check.log
FROM centos:centos7 AS base-dependencies
LABEL author="James Cherry"
LABEL maintainer="James Cherry <cherry@parallaxsw.com>"
# Install dev and runtime dependencies
RUN yum group install -y "Development Tools" \
&& yum install -y https://repo.ius.io/ius-release-el7.rpm \
&& yum install -y centos-release-scl \
&& yum install -y wget devtoolset-8 \
&& yum install -y qt5-qtbase-devel \
devtoolset-8-libatomic-devel tcl-devel tcl tk libstdc++ tk-devel pcre-devel \
python36u python36u-libs python36u-devel python36u-pip && \
yum clean -y all && \
rm -rf /var/lib/apt/lists/*
ENV CC=/opt/rh/devtoolset-8/root/usr/bin/gcc \
CPP=/opt/rh/devtoolset-8/root/usr/bin/cpp \
CXX=/opt/rh/devtoolset-8/root/usr/bin/g++ \
PATH=/opt/rh/devtoolset-8/root/usr/bin:$PATH \
LD_LIBRARY_PATH=/opt/rh/devtoolset-8/root/usr/lib64:/opt/rh/devtoolset-8/root/usr/lib:/opt/rh/devtoolset-8/root/usr/lib64/dyninst:/opt/rh/devtoolset-8/root/usr/lib/dyninst:/opt/rh/devtoolset-8/root/usr/lib64:/opt/rh/devtoolset-8/root/usr/lib:$LD_LIBRARY_PATH
# Install CMake
RUN wget https://cmake.org/files/v3.14/cmake-3.14.0-Linux-x86_64.sh && \
chmod +x cmake-3.14.0-Linux-x86_64.sh && \
./cmake-3.14.0-Linux-x86_64.sh --skip-license --prefix=/usr/local && rm -rf cmake-3.14.0-Linux-x86_64.sh \
&& yum clean -y all
# Install any git version > 2.6.5
RUN yum remove -y git* && yum install -y rh-git227
RUN rm -f /usr/bin/git; ln -s /opt/rh/rh-git227/root/bin/git /usr/bin/git
# Install SWIG
RUN yum remove -y swig \
&& wget https://github.com/swig/swig/archive/rel-4.0.1.tar.gz \
&& tar xfz rel-4.0.1.tar.gz \
&& rm -rf rel-4.0.1.tar.gz \
&& cd swig-rel-4.0.1 \
&& ./autogen.sh && ./configure --prefix=/usr && make -j $(nproc) && make install \
&& cd .. \
&& rm -rf swig-rel-4.0.1
# download CUDD
# RUN wget https://www.davidkebo.com/source/cudd_versions/cudd-3.0.0.tar.gz && \
# tar -xvf cudd-3.0.0.tar.gz && \
# rm cudd-3.0.0.tar.gz
# install CUDD
# RUN cd cudd-3.0.0 && \
# mkdir ../cudd && \
# ./configure --prefix=$HOME/cudd && \
# make && \
# make install
FROM base-dependencies AS builder
COPY . /OpenSTA
WORKDIR /OpenSTA
# Build
RUN mkdir build
#RUN cd buld && cmake .. -DCUDD=$HOME/cudd && make -j 8
RUN cd build && cmake .. && make -j 8
# Run sta on entry
ENTRYPOINT ["OpenSTA/app/sta"]
FROM ubuntu:18.04
LABEL author="James Cherry"
LABEL maintainer="James Cherry <cherry@parallaxsw.com>"
# install basics
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \
apt-get install -y wget apt-utils git cmake gcc tcl-dev swig bison flex
# download CUDD
RUN wget https://www.davidkebo.com/source/cudd_versions/cudd-3.0.0.tar.gz && \
tar -xvf cudd-3.0.0.tar.gz && \
rm cudd-3.0.0.tar.gz
# install CUDD
RUN cd cudd-3.0.0 && \
mkdir ../cudd && \
./configure --prefix=$HOME/cudd && \
make && \
make install
# copy files and install OpenSTA
RUN mkdir OpenSTA
COPY . OpenSTA
RUN cd OpenSTA && \
mkdir build && \
cd build && \
cmake .. -DCUDD=$HOME/cudd && \
make
# Run sta on entry
ENTRYPOINT ["OpenSTA/app/sta"]
pipeline {
agent any
stages {
stage('Build') {
steps {
sh './jenkins/build.sh'
}
}
stage('Test') {
steps {
sh './jenkins/test.sh'
}
}
}
}
This diff is collapsed. Click to expand it.
# Parallax Static Timing Analyzer
OpenSTA is a gate level static timing verifier. As a stand-alone
executable it can be used to verify the timing of a design using
standard file formats.
* Verilog netlist
* Liberty library
* SDC timing constraints
* SDF delay annotation
* SPEF parasitics
OpenSTA uses a TCL command interpreter to read the design, specify
timing constraints and print timing reports.
##### Clocks
* Generated
* Latency
* Source latency (insertion delay)
* Uncertainty
* Propagated/Ideal
* Gated clock checks
* Multiple frequency clocks
##### Exception paths
* False path
* Multicycle path
* Min/Max path delay
* Exception points
* -from clock/pin/instance -through pin/net -to clock/pin/instance
* Edge specific exception points
* -rise_from/-fall_from, -rise_through/-fall_through, -rise_to/-fall_to
##### Delay calculation
* Integrated Dartu/Menezes/Pileggi RC effective capacitance algorithm
* External delay calculator API
##### Analysis
* Report timing checks -from, -through, -to, multiple paths to endpoint
* Report delay calculation
* Check timing setup
##### Timing Engine
OpenSTA is architected to be easily bolted on to other tools as a
timing engine. By using a network adapter, OpenSTA can access the host
netlist data structures without duplicating them.
* Query based incremental update of delays, arrival and required times
* Simulator to propagate constants from constraints and netlist tie high/low
See doc/OpenSTA.pdf for command documentiaton.
See doc/StaApi.txt for timing engine API documentiaton.
See doc/ChangeLog.txt for changes to commands.
## Build
OpenSTA is built with CMake.
### Prerequisites
The build dependency versions are show below. Other versions may
work, but these are the versions used for development.
```
from Ubuntu Xcode
18.04.1 11.3
cmake 3.10.2 3.10.2 3.16.2
clang 9.1.0 11.0.0
gcc 3.3.2 7.3.0
tcl 8.4 8.6 8.6.6
swig 1.3.28 3.0.12 4.0.1
bison 1.35 3.0.4 3.5
flex 2.5.4 2.6.4 2.5.35
```
Note that flex versions before 2.6.4 contain 'register' declarations that
are illegal in c++17.
These packages are **optional**:
```
libz 1.1.4 1.2.5 1.2.8
cudd 2.4.1 3.0.0
```
CUDD is a binary decision diageram (BDD) package that is used to
improve conditional timing arc handling. OpenSTA does not require it
to be installed. It is available
[here](https://www.davidkebo.com/source/cudd_versions/cudd-3.0.0.tar.gz)
or [here](https://sourceforge.net/projects/cudd-mirror/).
Note that the file hierarchy of the CUDD installation changed with version 3.0.
Some changes to CMakeLists.txt are required to support older versions.
Use the USE_CUDD option to look for the cudd library.
Use the CUDD_DIR option to set the install directory if it is not in
one of the normal install directories.
When building CUDD you may use the `--prefix ` option to `configure` to
install in a location other than the default (`/usr/local/lib`).
```
cd $HOME/cudd-3.0.0
mkdir $HOME/cudd
./configure --prefix $HOME/cudd
make
make install
cd <opensta>/build
cmake .. -DUSE_CUDD=ON -DCUDD_DIR=$HOME/cudd
```
The Zlib library is an optional. If CMake finds libz, OpenSTA can
read Verilog, SDF, SPF, and SPEF files compressed with gzip.
### Installing with CMake
Use the following commands to checkout the git repository and build the
OpenSTA library and excutable.
```
git clone https://github.com/The-OpenROAD-Project/OpenSTA.git
cd OpenSTA
mkdir build
cd build
cmake ..
make
```
The default build type is release to compile optimized code.
The resulting executable is in `app/sta`.
The library without a `main()` procedure is `app/libSTA.a`.
Optional CMake variables passed as -D<var>=<value> arguments to CMake are show below.
```
CMAKE_BUILD_TYPE DEBUG|RELEASE
CMAKE_CXX_FLAGS - additional compiler flags
TCL_LIBRARY - path to tcl library
TCL_HEADER - path to tcl.h
CUDD - path to cudd installation
ZLIB_ROOT - path to zlib
CMAKE_INSTALL_PREFIX
```
If `TCL_LIBRARY` is specified the CMake script will attempt to locate
the header from the library path.
The default install directory is `/usr/local`.
To install in a different directory with CMake use:
```
cmake .. -DCMAKE_INSTALL_PREFIX=<prefix_path>
```
If you make changes to `CMakeLists.txt` you may need to clean out
existing CMake cached variable values by deleting all of the
files in the build directory.
## Bug Reports
Use the Issues tab on the github repository to report bugs.
Each issue/bug should be a separate issue. The subject of the issue
should be a short description of the problem. Attach a test case to
reproduce the issue as described below. Issues without test cases are
unlikely to get a response.
The files in the test case should be collected into a directory named
YYYYMMDD where YYYY is the year, MM is the month, and DD is the
day (this format allows "ls" to report them in chronological order).
The contents of the directory should be collected into a compressed
tarfile named YYYYMMDD.tgz.
The test case should have a tcl command file recreates the issue named
run.tcl. If there are more than one command file using the same data
files, there should be separate command files, run1.tcl, run2.tcl
etc. The bug report can refer to these command files by name.
Command files should not have absolute filenames like
"/home/cho/OpenSTA_Request/write_path_spice/dump_spice" in them.
These obviously are not portable. Use filenames relative to the test
case directory.
## Authors
* James Cherry
* William Scott authored the arnoldi delay calculator at Blaze, Inc which was subsequently licensed to Nefelus, Inc that has graciously contributed it to OpenSTA.
## Contributions
External code contributions are not supported.
https://en.wikipedia.org/wiki/Contributor_License_Agreement
https://opensource.google/docs/cla/
## License
OpenSTA is dual licensed. It is released under GPL v3 as OpenSTA and
is also licensed for commerical applications by Parallax Software without
the GPL's requirements.
OpenSTA, Static Timing Analyzer
Copyright (c) 2022, 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/>.
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2022, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "StaMain.hh"
#include <stdio.h>
#include <cstdlib> // exit
#include <tcl.h>
#include "StaConfig.hh" // STA_VERSION
#include "Sta.hh"
namespace sta {
extern const char *tcl_inits[];
}
using std::string;
using sta::stringEq;
using sta::findCmdLineFlag;
using sta::Sta;
using sta::initSta;
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" {
extern int Sta_Init(Tcl_Interp *interp);
}
static int cmd_argc;
static char **cmd_argv;
static const char *init_filename = ".sta";
static void
showUsage(const char *prog,
const char *init_filename);
static int
tclAppInit(Tcl_Interp *interp);
static int
staTclAppInit(int argc,
char *argv[],
const char *init_filename,
Tcl_Interp *interp);
static void
initStaApp(int &argc,
char *argv[],
Tcl_Interp *interp);
int
main(int argc,
char *argv[])
{
if (argc == 2 && stringEq(argv[1], "-help")) {
showUsage(argv[0], init_filename);
return 0;
}
else if (argc == 2 && stringEq(argv[1], "-version")) {
printf("%s\n", STA_VERSION);
return 0;
}
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.
cmd_argc = argc;
cmd_argv = argv;
Tcl_Main(1, argv, tclAppInit);
#endif
return 0;
}
}
static int
tclAppInit(Tcl_Interp *interp)
{
return staTclAppInit(cmd_argc, cmd_argv, init_filename, interp);
}
// Tcl init executed inside Tcl_Main.
static int
staTclAppInit(int argc,
char *argv[],
const char *init_filename,
Tcl_Interp *interp)
{
// source init.tcl
Tcl_Init(interp);
initStaApp(argc, argv, interp);
if (!findCmdLineFlag(argc, argv, "-no_splash"))
Tcl_Eval(interp, "sta::show_splash");
if (!findCmdLineFlag(argc, argv, "-no_init")) {
const char *home = getenv("HOME");
if (home) {
string init_path = home;
init_path += "/";
init_path += init_filename;
if (is_regular_file(init_path.c_str()))
sourceTclFile(init_path.c_str(), true, true, interp);
}
}
bool exit_after_cmd_file = findCmdLineFlag(argc, argv, "-exit");
if (argc > 2 ||
(argc > 1 && argv[1][0] == '-')) {
showUsage(argv[0], init_filename);
exit(1);
}
else {
if (argc == 2) {
char *cmd_file = argv[1];
if (cmd_file) {
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);
}
}
}
}
return TCL_OK;
}
static void
initStaApp(int &argc,
char *argv[],
Tcl_Interp *interp)
{
initSta();
Sta *sta = new Sta;
Sta::setSta(sta);
sta->makeComponents();
sta->setTclInterp(interp);
int thread_count = parseThreadsArg(argc, argv);
sta->setThreadCount(thread_count);
// Define swig TCL commands.
Sta_Init(interp);
// Eval encoded sta TCL sources.
evalTclInit(interp, tcl_inits);
// Import exported commands from sta namespace to global namespace.
Tcl_Eval(interp, "sta::define_sta_cmds");
Tcl_Eval(interp, "namespace import sta::*");
}
static void
showUsage(const char *prog,
const char *init_filename)
{
printf("Usage: %s [-help] [-version] [-no_init] [-exit] cmd_file\n", prog);
printf(" -help show help and exit\n");
printf(" -version show version and exit\n");
printf(" -no_init do not read %s init file\n", init_filename);
printf(" -threads count|max use count threads\n");
printf(" -no_splash do not show the license splash at startup\n");
printf(" -exit exit after reading cmd_file\n");
printf(" cmd_file source cmd_file\n");
}
%module sta
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2022, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
%include "Exception.i"
%include "StaTcl.i"
%include "Verilog.i"
%include "NetworkEdit.i"
%include "Sdf.i"
%include "DelayCalc.i"
%include "Parasitics.i"
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2022, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "StaMain.hh"
#include <tcl.h>
#include <stdlib.h>
#include <sys/stat.h>
#include "Machine.hh"
#include "StringUtil.hh"
#include "Vector.hh"
#include "Sta.hh"
namespace sta {
int
parseThreadsArg(int &argc,
char *argv[])
{
char *thread_arg = findCmdLineKey(argc, argv, "-threads");
if (thread_arg) {
if (stringEqual(thread_arg, "max"))
return processorCount();
else if (isDigits(thread_arg))
return atoi(thread_arg);
else
fprintf(stderr,"Warning: -threads must be max or a positive integer.\n");
}
return 1;
}
bool
findCmdLineFlag(int &argc,
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];
argc--;
return true;
}
}
return false;
}
char *
findCmdLineKey(int &argc,
char *argv[],
const char *key)
{
for (int i = 1; i < argc; i++) {
char *arg = argv[i];
if (stringEq(arg, key) && i + 1 < 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];
argc -= 2;
return value;
}
}
return nullptr;
}
// Use overridden version of source to echo cmds and results.
int
sourceTclFile(const char *filename,
bool echo,
bool verbose,
Tcl_Interp *interp)
{
string cmd;
stringPrint(cmd, "source %s%s%s",
echo ? "-echo " : "",
verbose ? "-verbose " : "",
filename);
int code = Tcl_Eval(interp, cmd.c_str());
const char *result = Tcl_GetStringResult(interp);
if (result[0] != '\0')
printf("%s\n", result);
return code;
}
void
evalTclInit(Tcl_Interp *interp,
const char *inits[])
{
char *unencoded = unencode(inits);
if (Tcl_Eval(interp, unencoded) != TCL_OK) {
// Get a backtrace for the error.
Tcl_Eval(interp, "$errorInfo");
const char *tcl_err = Tcl_GetStringResult(interp);
fprintf(stderr, "Error: TCL init script: %s.\n", tcl_err);
fprintf(stderr, " Try deleting TclInitVar.cc and rebuilding.\n");
exit(0);
}
delete [] unencoded;
}
char *
unencode(const char *inits[])
{
size_t length = 0;
for (const char **e = inits; *e; e++) {
const char *init = *e;
length += strlen(init);
}
char *unencoded = new char[length / 3 + 1];
char *u = unencoded;
for (const char **e = inits; *e; e++) {
const char *init = *e;
size_t init_length = strlen(init);
for (const char *s = init; s < &init[init_length]; s += 3) {
char code[4] = {s[0], s[1], s[2], '\0'};
char ch = atoi(code);
*u++ = ch;
}
}
*u = '\0';
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
# OpenSTA, Static Timing Analyzer
# Copyright (c) 2019, 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/>.
################################################################
#
# Locate TCL library.
#
# Note that the cmake findTcl module is hopeless for OSX
# because there doesn't appear to be a way to override
# searching OSX system directories before unix directories.
set(TCL_POSSIBLE_NAMES tcl87 tcl8.7
tcl86 tcl8.6
tcl85 tcl8.5
)
# tcl lib path guesses.
if (NOT TCL_LIB_PATHS)
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
set(TCL_LIB_PATHS /usr/local/lib /opt/homebrew/opt/tcl-tk/lib)
set(TCL_NO_DEFAULT_PATH TRUE)
elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(TCL_LIB_PATHS /usr/lib /usr/local/lib)
set(TCL_NO_DEFAULT_PATH FALSE)
endif()
endif()
if (NOT TCL_LIBRARY)
# bagbiter cmake doesn't have a way to pass NO_DEFAULT_PATH as a parameter.
if (TCL_NO_DEFAULT_PATH)
find_library(TCL_LIBRARY
NAMES tcl ${TCL_POSSIBLE_NAMES}
PATHS ${TCL_LIB_PATHS}
NO_DEFAULT_PATH
)
else()
find_library(TCL_LIBRARY
NAMES tcl ${TCL_POSSIBLE_NAMES}
PATHS ${TCL_LIB_PATHS}
)
endif()
endif()
message(STATUS "TCL library: ${TCL_LIBRARY}")
get_filename_component(TCL_LIB_DIR "${TCL_LIBRARY}" PATH)
get_filename_component(TCL_LIB_PARENT1 "${TCL_LIB_DIR}" PATH)
get_filename_component(TCL_LIB_PARENT2 "${TCL_LIB_PARENT1}" PATH)
# Locate tcl.h
if (NOT TCL_HEADER)
find_file(TCL_HEADER tcl.h
PATHS ${TCL_LIB_PARENT1} ${TCL_LIB_PARENT2}
PATH_SUFFIXES include include/tcl
NO_DEFAULT_PATH
)
endif()
message(STATUS "TCL header: ${TCL_HEADER}")
if (TCL_HEADER)
get_filename_component(TCL_INCLUDE_PATH "${TCL_HEADER}" PATH)
endif()
# - Returns a version string from Git
#
# These functions force a re-configure on each git commit so that you can
# trust the values of the variables in your build system.
#
# get_git_head_revision(<refspecvar> <hashvar> [<additional arguments to git describe> ...])
#
# Returns the refspec and sha hash of the current head revision
#
# git_describe(<var> [<additional arguments to git describe> ...])
#
# Returns the results of git describe on the source tree, and adjusting
# the output so that it tests false if an error occurs.
#
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
#
# Returns the results of git describe --exact-match on the source tree,
# and adjusting the output so that it tests false if there was no exact
# matching tag.
#
# git_local_changes(<var>)
#
# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes.
# Uses the return code of "git diff-index --quiet HEAD --".
# Does not regard untracked files.
#
# Requires CMake 2.6 or newer (uses the 'function' command)
#
# Original Author:
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC
#
# Copyright Iowa State University 2009-2010.
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
if(__get_git_revision_description)
return()
endif()
set(__get_git_revision_description YES)
# We must run the following at "include" time, not at function call time,
# to find the path to this module rather than the path to a calling list file
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
function(get_git_head_revision _refspecvar _hashvar)
set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories
set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}")
get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH)
if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT)
# We have reached the root directory, we are not in git
set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
return()
endif()
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
endwhile()
# check if this is a submodule
if(NOT IS_DIRECTORY ${GIT_DIR})
file(READ ${GIT_DIR} submodule)
string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule})
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE)
endif()
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
if(NOT EXISTS "${GIT_DATA}")
file(MAKE_DIRECTORY "${GIT_DATA}")
endif()
if(NOT EXISTS "${GIT_DIR}/HEAD")
return()
endif()
set(HEAD_FILE "${GIT_DATA}/HEAD")
configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY)
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
"${GIT_DATA}/grabRef.cmake"
@ONLY)
include("${GIT_DATA}/grabRef.cmake")
set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE)
set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE)
endfunction()
function(git_describe _var)
if(NOT GIT_FOUND)
find_package(Git QUIET)
endif()
get_git_head_revision(refspec hash)
if(NOT GIT_FOUND)
set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
return()
endif()
if(NOT hash)
set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
return()
endif()
# TODO sanitize
#if((${ARGN}" MATCHES "&&") OR
# (ARGN MATCHES "||") OR
# (ARGN MATCHES "\\;"))
# message("Please report the following error to the project!")
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
#endif()
#message(STATUS "Arguments to execute_process: ${ARGN}")
execute_process(COMMAND
"${GIT_EXECUTABLE}"
describe
${hash}
${ARGN}
WORKING_DIRECTORY
"${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE
res
OUTPUT_VARIABLE
out
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT res EQUAL 0)
set(out "${out}-${res}-NOTFOUND")
endif()
set(${_var} "${out}" PARENT_SCOPE)
endfunction()
function(git_get_exact_tag _var)
git_describe(out --exact-match ${ARGN})
set(${_var} "${out}" PARENT_SCOPE)
endfunction()
function(git_local_changes _var)
if(NOT GIT_FOUND)
find_package(Git QUIET)
endif()
get_git_head_revision(refspec hash)
if(NOT GIT_FOUND)
set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
return()
endif()
if(NOT hash)
set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
return()
endif()
execute_process(COMMAND
"${GIT_EXECUTABLE}"
diff-index --quiet HEAD --
WORKING_DIRECTORY
"${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE
res
OUTPUT_VARIABLE
out
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(res EQUAL 0)
set(${_var} "CLEAN" PARENT_SCOPE)
else()
set(${_var} "DIRTY" PARENT_SCOPE)
endif()
endfunction()
#
# Internal file for GetGitRevisionDescription.cmake
#
# Requires CMake 2.6 or newer (uses the 'function' command)
#
# Original Author:
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC
#
# Copyright Iowa State University 2009-2010.
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
set(HEAD_HASH)
file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
if(HEAD_CONTENTS MATCHES "ref")
# named branch
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
else()
configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
file(READ "@GIT_DATA@/packed-refs" PACKED_REFS)
if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
set(HEAD_HASH "${CMAKE_MATCH_1}")
endif()
endif()
else()
# detached HEAD
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
endif()
if(NOT HEAD_HASH)
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
string(STRIP "${HEAD_HASH}" HEAD_HASH)
endif()
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2022, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "ArcDelayCalc.hh"
#include "TimingModel.hh"
#include "TimingArc.hh"
#include "GraphDelayCalc.hh"
namespace sta {
ArcDelayCalc::ArcDelayCalc(StaState *sta):
StaState(sta)
{
}
TimingModel *
ArcDelayCalc::model(TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const
{
const OperatingConditions *op_cond = dcalc_ap->operatingConditions();
TimingArc *corner_arc = arc->cornerArc(dcalc_ap->libertyIndex());
return corner_arc->model(op_cond);
}
GateTimingModel *
ArcDelayCalc::gateModel(TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const
{
return dynamic_cast<GateTimingModel*>(model(arc, dcalc_ap));
}
CheckTimingModel *
ArcDelayCalc::checkModel(TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const
{
return dynamic_cast<CheckTimingModel*>(model(arc, dcalc_ap));
}
} // namespace
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2022, 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/>.
// (c) 2018 Nefelus, Inc.
//
// Author: W. Scott
#pragma once
#include "parasitics/ConcreteParasiticsPvt.hh"
namespace sta {
struct delay_work;
class rcmodel;
class GateTableModel;
class Pin;
//
// single-driver arnoldi model
//
class arnoldi1
{
public:
arnoldi1() { order=0; n=0; d=nullptr; e=nullptr; U=nullptr; ctot=0.0; sqc=0.0; }
~arnoldi1();
double elmore(int term_index);
//
// calculate poles/residues for given rdrive
//
void calculate_poles_res(delay_work *D,double rdrive);
public:
int order;
int n; // number of terms, including driver
double *d; // [order]
double *e; // [order-1]
double **U; // [order][n]
double ctot;
double sqc;
};
// This is the rcmodel, without Rd.
// n is the number of terms
// The vectors U[j] are of size n
class rcmodel : public ConcreteParasitic,
public arnoldi1
{
public:
rcmodel();
virtual ~rcmodel();
virtual float capacitance() const;
const Pin **pinV; // [n]
};
struct timing_table
{
GateTableModel *table;
const LibertyCell *cell;
const Pvt *pvt;
float in_slew;
float relcap;
};
} // namespace
The method is used for simulation with a time-and-voltage-dependent
current source. But it is simpler to describe with a linear driver.
Suppose we are given:
voltage nodes 1,..n initialized to V[j]=1.0
a resistor network described by a conductance matrix G[j,k]
a drive resistance from node 1 to ground, Rdrv
capacitance of the nodes, c[j], also written as a
diagonal matrix C[j,k]
The node voltages will fall to zero with time.
Matrix equation:
GV+CdV/dt = -(V[0]/Rdrv)e0
where e0 is the unit vector (1,0,0,..0).
Let G' be the matrix formed by taking G and adding 1/Rdrv in the
[0,0] position. Then we are solving G'V + CdV/dt = 0.
Let R be the inverse of G'. (In implementation, R may not actually
be formed as a matrix, instead some method of producing RV given V).
The exact solution would diagonalize sqrt(C) R sqrt(C).
The Arnoldi method takes a matrix M and a vector of interest V, and
considers the subspace of vectors near V in terms of the action of M,
that is, the space spanned by V, MV, MMV, etc, for a small number of
powers. We do this here, but instead of finding the part of MV orthogonal
to V, we find the part of RCV that is C-orthogonal of V. We use C
as the metric, so the basis vectors U0, U1, U2 that we generate satisfy
Ui.CUj = (i==j?1:0)
U0 = (1,1,..1)/sqrt(sum C)
representing the initial value of V, V[j] = sqrt(n)U0[j] at t=0.
sum(C) = C[0]+..C[n-1], so U0.C U0 = 1.
Let:
W = R C U0
d0 = U0.C W
W' = W - d0 U0
e0 = sqrt(W'.C W')
U1 = W'/e0
Then: U0.C U0 = U1.C U1 = 1, U0.C U1 = 0, and
R C U0 = d0 U0 + e0 U1
Next step:
W = R C U1
d1 = U1.C W
W' = W - d1 U1 - e0 U0
e1 = sqrt(W'.C W')
U2 = W'/e1
and we have U2.C U2 = 1, U2.C U1 = U2.C U0 = 0, and
RC U1 = e0 U0 + d1 U1 + e1 U2
In this way, RC, which in nonsymmetric in the original basis,
becomes a symmetric tridiagonal matrix in the U0,U1,.. basis.
We stop at, say, U3. The resulting 4x4 tridiagonal matrix is
positive definite, because it is the projection of sqrt(C)R sqrt(C)
to a subspace. So the eigenvalues of this small tridiagonal matrix
are guaranteed to be positive. This is the advantage over AWE.
In the actual implementation, I remember there was some way of
isolating the node 0 where drive resistance is attached, so that the
tridiagonal matrix (d,e) can be recalculated without knowing Rdrv,
and then just the first d0,e0 updated when the Rdrv is known, or
when Rdrv changes in a simulation.
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2022, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#pragma once
namespace sta {
class ArcDelayCalc;
class StaState;
ArcDelayCalc *
makeArnoldiDelayCalc(StaState *sta);
} // namespace
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2022, 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/>.
// (c) 2018 Nefelus, Inc.
//
// Author: W. Scott
#pragma once
#include "Map.hh"
#include "Transition.hh"
#include "NetworkClass.hh"
#include "ParasiticsClass.hh"
#include "SdcClass.hh"
#include "StaState.hh"
namespace sta {
class ConcreteParasiticNetwork;
class ConcreteParasiticNode;
class Corner;
class rcmodel;
struct ts_edge;
struct ts_point;
typedef Map<ConcreteParasiticNode*, int> ArnolidPtMap;
class ArnoldiReduce : public StaState
{
public:
ArnoldiReduce(StaState *sta);
~ArnoldiReduce();
Parasitic *reduceToArnoldi(Parasitic *parasitic,
const Pin *drvr_pin,
float coupling_cap_factor,
const RiseFall *rf,
const OperatingConditions *op_cond,
const Corner *corner,
const MinMax *cnst_min_max,
const ParasiticAnalysisPt *ap);
protected:
void loadWork();
rcmodel *makeRcmodelDrv();
void allocPoints();
void allocTerms(int nterms);
ts_point *findPt(ParasiticNode *node);
void makeRcmodelDfs(ts_point *pdrv);
void getRC();
float pinCapacitance(ParasiticNode *node);
void setTerms(ts_point *pdrv);
void makeRcmodelFromTs();
rcmodel *makeRcmodelFromW();
ConcreteParasiticNetwork *parasitic_network_;
const Pin *drvr_pin_;
float coupling_cap_factor_;
const RiseFall *rf_;
const OperatingConditions *op_cond_;
const Corner *corner_;
const MinMax *cnst_min_max_;
const ParasiticAnalysisPt *ap_;
// ParasiticNode -> ts_point index.
ArnolidPtMap pt_map_;
// rcWork
ts_point *ts_pointV;
int ts_pointN;
int ts_pointNmax;
static const int ts_point_count_incr_;
ts_edge *ts_edgeV;
int ts_edgeN;
int ts_edgeNmax;
static const int ts_edge_count_incr_;
ts_edge **ts_eV;
ts_edge **ts_stackV;
int *ts_ordV;
ts_point **ts_pordV;
int ts_ordN;
int termNmax;
int termN;
ts_point *pterm0;
const Pin **pinV; // fixed order, offset from pterm0
int *termV; // from drv-ordered to fixed order
int *outV; // from drv-ordered to ts_pordV
int dNmax;
double *d;
double *e;
double *U0;
double **U;
double ctot_;
double sqc_;
double *_u0, *_u1;
double *y, *iv;
double *c, *r;
int *par;
int order;
};
} // namespace
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2022, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "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
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2022, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "DelayCalc.hh"
#include "Map.hh"
#include "StringUtil.hh"
#include "UnitDelayCalc.hh"
#include "LumpedCapDelayCalc.hh"
#include "SimpleRCDelayCalc.hh"
#include "DmpDelayCalc.hh"
#include "ArnoldiDelayCalc.hh"
namespace sta {
typedef Map<const char*, MakeArcDelayCalc, CharPtrLess> DelayCalcMap;
static DelayCalcMap *delay_calcs = nullptr;
void
registerDelayCalcs()
{
registerDelayCalc("unit", makeUnitDelayCalc);
registerDelayCalc("lumped_cap", makeLumpedCapDelayCalc);
registerDelayCalc("simple_rc", makeSimpleRCDelayCalc);
registerDelayCalc("dmp_ceff_elmore", makeDmpCeffElmoreDelayCalc);
registerDelayCalc("dmp_ceff_two_pole", makeDmpCeffTwoPoleDelayCalc);
registerDelayCalc("arnoldi", makeArnoldiDelayCalc);
}
void
registerDelayCalc(const char *name,
MakeArcDelayCalc maker)
{
if (delay_calcs == nullptr)
delay_calcs = new DelayCalcMap;
(*delay_calcs)[name] = maker;
}
void
deleteDelayCalcs()
{
delete delay_calcs;
delay_calcs = nullptr;
}
ArcDelayCalc *
makeDelayCalc(const char *name,
StaState *sta)
{
MakeArcDelayCalc maker = delay_calcs->findKey(name);
if (maker)
return maker(sta);
else
return nullptr;
}
bool
isDelayCalcName(const char *name)
{
return delay_calcs->hasKey(name);
}
StringSeq *
delayCalcNames()
{
StringSeq *names = new StringSeq;
DelayCalcMap::Iterator dcalc_iter(delay_calcs);
while (dcalc_iter.hasNext()) {
MakeArcDelayCalc maker;
const char *name;
dcalc_iter.next(name, maker);
names->push_back(name);
}
return names;
}
} // namespace
%module dcalc
%{
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2022, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Sta.hh"
%}
%inline %{
TmpStringSeq *
delay_calc_names()
{
return sta::delayCalcNames();
}
bool
is_delay_calc_name(const char *alg)
{
return sta::isDelayCalcName(alg);
}
void
set_delay_calculator_cmd(const char *alg)
{
sta::Sta::sta()->setArcDelayCalc(alg);
}
void
set_delay_calc_incremental_tolerance(float tol)
{
sta::Sta::sta()->setIncrementalDelayTolerance(tol);
}
%} // inline
# OpenSTA, Static Timing Analyzer
# Copyright (c) 2022, 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/>.
namespace eval sta {
# Allow any combination of -from/-to pins.
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" \
flags {-min -max}
set corner [parse_corner keys]
set min_max [parse_min_max_flags flags]
check_argc_eq0 $cmd $cmd_args
set digits $sta_report_default_digits
if [info exists keys($digits_key)] {
set digits $keys($digits_key)
check_positive_integer $digits_key $digits
}
if {[info exists keys(-from)] && [info exists keys(-to)]} {
set from_pin [get_port_pin_error "from_pin" $keys(-from)]
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
}
}
} elseif [info exists keys(-from)] {
set from_pin [get_port_pin_error "from_pin" $keys(-from)]
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
}
$iter finish
}
} elseif [info exists keys(-to)] {
set to_pin [get_port_pin_error "to_pin" $keys(-to)]
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
}
$iter finish
}
}
}
proc report_edge_dcalc { edge corner min_max digits } {
set role [$edge role]
if { $role != "wire" } {
set from_vertex [$edge from]
set from_pin [$from_vertex pin]
set to_vertex [$edge to]
set to_pin [$to_vertex pin]
set cell [[$to_pin instance] cell]
set library [$cell library]
# Filter timing checks based on min_max.
if {!(($min_max == "max" && $role == "hold") \
|| ($min_max=="min" && $role=="setup"))} {
report_line "Library: [get_name $library]"
report_line "Cell: [get_name $cell]"
set sense [$edge sense]
if { $sense != "unknown" } {
report_line "Arc sense: $sense"
}
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 ""
}
}
}
}
################################################################
define_hidden_cmd_args "set_delay_calculator" [delay_calc_names]
proc set_delay_calculator { alg } {
if { [is_delay_calc_name $alg] } {
set_delay_calculator_cmd $alg
} else {
sta_error 435 "delay calculator $alg not found."
}
}
# sta namespace end
}
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2022, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#pragma once
#include "LibertyClass.hh"
#include "RCDelayCalc.hh"
namespace sta {
class DmpAlg;
class DmpCap;
class DmpPi;
class DmpZeroC2;
class GateTableModel;
// Delay calculator using Dartu/Menezes/Pileggi effective capacitance
// algorithm for RSPF loads.
class DmpCeffDelayCalc : public RCDelayCalc
{
public:
DmpCeffDelayCalc(StaState *sta);
virtual ~DmpCeffDelayCalc();
virtual void inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap);
virtual void gateDelay(const LibertyCell *drvr_cell,
TimingArc *arc,
const Slew &in_slew,
float load_cap,
Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// return values
ArcDelay &gate_delay,
Slew &drvr_slew);
virtual float ceff(const LibertyCell *drvr_cell,
TimingArc *arc,
const Slew &in_slew,
float load_cap,
Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap);
virtual void reportGateDelay(const LibertyCell *drvr_cell,
TimingArc *arc,
const Slew &in_slew,
float load_cap,
Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
int digits,
string *result);
virtual void copyState(const StaState *sta);
protected:
void gateDelaySlew(double &delay,
double &slew);
void loadDelaySlew(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,
GateTableModel *gate_model,
const RiseFall *rf,
double in_slew,
float related_out_cap,
double c2,
double rpi,
double c1);
bool input_port_;
static bool unsuppored_model_warned_;
private:
// Dmp algorithms for each special pi model case.
// These objects are reused to minimize make/deletes.
DmpCap *dmp_cap_;
DmpPi *dmp_pi_;
DmpZeroC2 *dmp_zero_c2_;
DmpAlg *dmp_alg_;
};
} // namespace
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2022, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#pragma once
namespace sta {
class ArcDelayCalc;
class StaState;
ArcDelayCalc *
makeDmpCeffElmoreDelayCalc(StaState *sta);
ArcDelayCalc *
makeDmpCeffTwoPoleDelayCalc(StaState *sta);
} // namespace
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2022, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "GraphDelayCalc.hh"
#include "Liberty.hh"
#include "Network.hh"
#include "Graph.hh"
#include "Sdc.hh"
#include "Corner.hh"
namespace sta {
GraphDelayCalc::GraphDelayCalc(StaState *sta) :
StaState(sta)
{
}
void
GraphDelayCalc::setObserver(DelayCalcObserver *observer)
{
// Observer not needed by GraphDelayCalc.
delete observer;
}
string *
GraphDelayCalc::reportDelayCalc(Edge *,
TimingArc *,
const Corner *,
const MinMax *,
int)
{
return new string;
}
float
GraphDelayCalc::incrementalDelayTolerance()
{
return 0.0;
}
void
GraphDelayCalc::loadCap(const Pin *,
Parasitic *,
const RiseFall *,
const DcalcAnalysisPt *,
// Return values.
float &pin_cap,
float &wire_cap) const
{
pin_cap = wire_cap = 0.0F;
}
float
GraphDelayCalc::loadCap(const Pin *,
const RiseFall *,
const DcalcAnalysisPt *) const
{
return 0.0F;
}
float
GraphDelayCalc::loadCap(const Pin *,
Parasitic *,
const RiseFall *,
const DcalcAnalysisPt *) const
{
return 0.0F;
}
float
GraphDelayCalc::loadCap(const Pin *,
const DcalcAnalysisPt *) const
{
return 0.0F;
}
void
GraphDelayCalc::netCaps(const Pin *,
const RiseFall *,
const DcalcAnalysisPt *,
// Return values.
float &pin_cap,
float &wire_cap,
float &fanout,
bool &has_set_load) const
{
pin_cap = wire_cap = fanout = 0.0F;
has_set_load = false;
}
float
GraphDelayCalc::ceff(Edge *,
TimingArc *,
const DcalcAnalysisPt *)
{
return 0.0;
}
void
GraphDelayCalc::minPulseWidth(const Pin *pin,
const RiseFall *hi_low,
DcalcAPIndex ap_index,
const MinMax *min_max,
// Return values.
float &min_width,
bool &exists)
{
// Sdf annotation.
graph_->widthCheckAnnotation(pin, hi_low, ap_index,
min_width, exists);
if (!exists) {
// Liberty library.
LibertyPort *port = network_->libertyPort(pin);
if (port) {
Instance *inst = network_->instance(pin);
Pvt *pvt = inst ? sdc_->pvt(inst, min_max) : nullptr;
OperatingConditions *op_cond=sdc_->operatingConditions(min_max);
port->minPulseWidth(hi_low, op_cond, pvt, min_width, exists);
}
}
}
void
GraphDelayCalc::minPeriod(const Pin *pin,
// Return values.
float &min_period,
bool &exists)
{
exists = false;
const MinMax *min_max = MinMax::max();
for (auto dcalc_ap : corners_->dcalcAnalysisPts()) {
// Sdf annotation.
float min_period1 = 0.0;
bool exists1 = false;
graph_->periodCheckAnnotation(pin, dcalc_ap->index(),
min_period, exists);
if (exists1
&& (!exists || min_period1 < min_period)) {
min_period = min_period1;
exists = true;
}
}
if (!exists) {
LibertyPort *port = network_->libertyPort(pin);
if (port) {
// Liberty library.
Instance *inst = network_->instance(pin);
OperatingConditions *op_cond = sdc_->operatingConditions(min_max);
Pvt *pvt = inst ? sdc_->pvt(inst, min_max) : nullptr;
port->minPeriod(op_cond, pvt, min_period, exists);
}
}
}
} // namespace
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2022, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#pragma once
#include <mutex>
#include "Delay.hh"
#include "GraphDelayCalc.hh"
namespace sta {
class MultiDrvrNet;
class FindVertexDelays;
class Corner;
typedef Map<const Vertex*, MultiDrvrNet*> MultiDrvrNetMap;
// This class traverses the graph calling the arc delay calculator and
// annotating delays on graph edges.
class GraphDelayCalc1 : public GraphDelayCalc
{
public:
GraphDelayCalc1(StaState *sta);
virtual ~GraphDelayCalc1();
virtual void copyState(const StaState *sta);
virtual void delaysInvalid();
virtual void delayInvalid(Vertex *vertex);
virtual void delayInvalid(const Pin *pin);
virtual void deleteVertexBefore(Vertex *vertex);
virtual void clear();
virtual void findDelays(Level level);
virtual void findDelays(Vertex *drvr_vertex);
virtual string *reportDelayCalc(Edge *edge,
TimingArc *arc,
const Corner *corner,
const MinMax *min_max,
int digits);
virtual float incrementalDelayTolerance();
virtual void setIncrementalDelayTolerance(float tol);
virtual void setObserver(DelayCalcObserver *observer);
// Load pin_cap + wire_cap.
virtual float loadCap(const Pin *drvr_pin,
const RiseFall *drvr_rf,
const DcalcAnalysisPt *dcalc_ap) const;
virtual float loadCap(const Pin *drvr_pin,
const DcalcAnalysisPt *dcalc_ap) const;
virtual void loadCap(const Pin *drvr_pin,
Parasitic *drvr_parasitic,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
float &pin_cap,
float &wire_cap) const;
virtual float loadCap(const Pin *drvr_pin,
Parasitic *drvr_parasitic,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) const;
virtual void netCaps(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
float &pin_cap,
float &wire_cap,
float &fanout,
bool &has_set_load) const;
float ceff(Edge *edge,
TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap);
protected:
void seedInvalidDelays();
void ensureMultiDrvrNetsFound();
void makeMultiDrvrNet(PinSet &drvr_pins);
void initSlew(Vertex *vertex);
void seedRootSlew(Vertex *vertex,
ArcDelayCalc *arc_delay_calc);
void seedRootSlews();
void seedDrvrSlew(Vertex *vertex,
ArcDelayCalc *arc_delay_calc);
void seedNoDrvrSlew(Vertex *drvr_vertex,
const Pin *drvr_pin,
const RiseFall *rf,
DcalcAnalysisPt *dcalc_ap,
ArcDelayCalc *arc_delay_calc);
void seedNoDrvrCellSlew(Vertex *drvr_vertex,
const Pin *drvr_pin,
const RiseFall *rf,
InputDrive *drive,
DcalcAnalysisPt *dcalc_ap,
ArcDelayCalc *arc_delay_calc);
void seedLoadSlew(Vertex *vertex);
void setInputPortWireDelays(Vertex *vertex);
void findInputDriverDelay(LibertyCell *drvr_cell,
const Pin *drvr_pin,
Vertex *drvr_vertex,
const RiseFall *rf,
LibertyPort *from_port,
float *from_slews,
LibertyPort *to_port,
DcalcAnalysisPt *dcalc_ap);
LibertyPort *driveCellDefaultFromPort(LibertyCell *cell,
LibertyPort *to_port);
int findPortIndex(LibertyCell *cell,
LibertyPort *port);
void findInputArcDelay(LibertyCell *drvr_cell,
const Pin *drvr_pin,
Vertex *drvr_vertex,
TimingArc *arc,
float from_slew,
DcalcAnalysisPt *dcalc_ap);
bool findDriverDelays(Vertex *drvr_vertex,
ArcDelayCalc *arc_delay_calc);
bool findDriverDelays1(Vertex *drvr_vertex,
bool init_load_slews,
MultiDrvrNet *multi_drvr,
ArcDelayCalc *arc_delay_calc);
bool findDriverEdgeDelays(LibertyCell *drvr_cell,
Instance *drvr_inst,
const Pin *drvr_pin,
Vertex *drvr_vertex,
MultiDrvrNet *multi_drvr,
Edge *edge,
ArcDelayCalc *arc_delay_calc);
void initWireDelays(Vertex *drvr_vertex,
bool init_load_slews);
void initRootSlews(Vertex *vertex);
void zeroSlewAndWireDelays(Vertex *drvr_vertex);
void findVertexDelay(Vertex *vertex,
ArcDelayCalc *arc_delay_calc,
bool propagate);
void enqueueTimingChecksEdges(Vertex *vertex);
bool findArcDelay(LibertyCell *drvr_cell,
const Pin *drvr_pin,
Vertex *drvr_vertex,
MultiDrvrNet *multi_drvr,
TimingArc *arc,
Parasitic *drvr_parasitic,
float related_out_cap,
Vertex *from_vertex,
Edge *edge,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
ArcDelayCalc *arc_delay_calc);
void annotateLoadDelays(Vertex *drvr_vertex,
const RiseFall *drvr_rf,
const ArcDelay &extra_delay,
bool merge,
const DcalcAnalysisPt *dcalc_ap,
ArcDelayCalc *arc_delay_calc);
void findLatchEdgeDelays(Edge *edge);
void findCheckEdgeDelays(Edge *edge,
ArcDelayCalc *arc_delay_calc);
void findMultiDrvrGateDelay(MultiDrvrNet *multi_drvr,
const RiseFall *drvr_rf,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
ArcDelayCalc *arc_delay_calc,
// Return values.
ArcDelay &parallel_delay,
Slew &parallel_slew);
void multiDrvrGateDelay(MultiDrvrNet *multi_drvr,
LibertyCell *drvr_cell,
const Pin *drvr_pin,
TimingArc *arc,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
const Slew from_slew,
Parasitic *drvr_parasitic,
float related_out_cap,
ArcDelayCalc *arc_delay_calc,
// Return values.
ArcDelay &gate_delay,
Slew &gate_slew);
void deleteMultiDrvrNets();
Slew edgeFromSlew(const Vertex *from_vertex,
const RiseFall *from_rf,
const Edge *edge,
const DcalcAnalysisPt *dcalc_ap);
Slew checkEdgeClkSlew(const Vertex *from_vertex,
const RiseFall *from_rf,
const DcalcAnalysisPt *dcalc_ap);
bool bidirectDrvrSlewFromLoad(const Vertex *vertex) const;
MultiDrvrNet *multiDrvrNet(const Vertex *drvr_vertex) const;
void loadCap(Parasitic *drvr_parasitic,
bool has_set_load,
// Return values.
float &pin_cap,
float &wire_cap) const;
float loadCap(const Pin *drvr_pin,
MultiDrvrNet *multi_drvr,
Parasitic *drvr_parasitic,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) const;
// Observer for edge delay changes.
DelayCalcObserver *observer_;
bool delays_seeded_;
bool incremental_;
bool delays_exist_;
// Vertices with invalid -to delays.
VertexSet *invalid_delays_;
// Timing check edges with invalid delays.
EdgeSet invalid_check_edges_;
// Latch D->Q edges with invalid delays.
EdgeSet invalid_latch_edges_;
// shared by invalid_check_edges_ and invalid_latch_edges_
std::mutex invalid_edge_lock_;
SearchPred *search_pred_;
SearchPred *search_non_latch_pred_;
SearchPred *clk_pred_;
BfsFwdIterator *iter_;
MultiDrvrNetMap multi_drvr_net_map_;
bool multi_drvr_nets_found_;
// Percentage (0.0:1.0) change in delay that causes downstream
// delays to be recomputed during incremental delay calculation.
float incremental_delay_tolerance_;
friend class FindVertexDelays;
friend class MultiDrvrNet;
};
} // namespace
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2022, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "LumpedCapDelayCalc.hh"
#include "Debug.hh"
#include "Units.hh"
#include "TimingArc.hh"
#include "TimingModel.hh"
#include "Liberty.hh"
#include "Network.hh"
#include "Sdc.hh"
#include "Parasitics.hh"
#include "DcalcAnalysisPt.hh"
#include "GraphDelayCalc.hh"
namespace sta {
ArcDelayCalc *
makeLumpedCapDelayCalc(StaState *sta)
{
return new LumpedCapDelayCalc(sta);
}
LumpedCapDelayCalc::LumpedCapDelayCalc(StaState *sta) :
ArcDelayCalc(sta)
{
}
ArcDelayCalc *
LumpedCapDelayCalc::copy()
{
return new LumpedCapDelayCalc(this);
}
Parasitic *
LumpedCapDelayCalc::findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap)
{
// set_load has precidence over parasitics.
if (!sdc_->drvrPinHasWireCap(drvr_pin)) {
Parasitic *parasitic = nullptr;
const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
if (parasitics_->haveParasitics()) {
// Prefer PiElmore.
parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap);
if (parasitic)
return parasitic;
Parasitic *parasitic_network =
parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap);
if (parasitic_network) {
parasitics_->reduceToPiElmore(parasitic_network, drvr_pin,
dcalc_ap->operatingConditions(),
dcalc_ap->corner(),
dcalc_ap->constraintMinMax(),
parasitic_ap);
parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap);
reduced_parasitic_drvrs_.push_back(drvr_pin);
return parasitic;
}
}
const MinMax *cnst_min_max = dcalc_ap->constraintMinMax();
Wireload *wireload = sdc_->wireload(cnst_min_max);
if (wireload) {
float pin_cap, wire_cap, fanout;
bool has_wire_cap;
graph_delay_calc_->netCaps(drvr_pin, rf, dcalc_ap,
pin_cap, wire_cap, fanout, has_wire_cap);
parasitic = parasitics_->estimatePiElmore(drvr_pin, rf, wireload,
fanout, pin_cap,
dcalc_ap->operatingConditions(),
dcalc_ap->corner(),
cnst_min_max,
parasitic_ap);
// Estimated parasitics are not recorded in the "database", so
// it for deletion after the drvr pin delay calc is finished.
if (parasitic)
unsaved_parasitics_.push_back(parasitic);
return parasitic;
}
}
return nullptr;
}
ReducedParasiticType
LumpedCapDelayCalc::reducedParasiticType() const
{
return ReducedParasiticType::pi_elmore;
}
void
LumpedCapDelayCalc::finishDrvrPin()
{
for (auto parasitic : unsaved_parasitics_)
parasitics_->deleteUnsavedParasitic(parasitic);
unsaved_parasitics_.clear();
for (auto drvr_pin : reduced_parasitic_drvrs_)
parasitics_->deleteDrvrReducedParasitics(drvr_pin);
reduced_parasitic_drvrs_.clear();
}
void
LumpedCapDelayCalc::inputPortDelay(const Pin *, float in_slew,
const RiseFall *rf,
Parasitic *,
const DcalcAnalysisPt *)
{
drvr_slew_ = in_slew;
drvr_rf_ = rf;
drvr_library_ = network_->defaultLibertyLibrary();
multi_drvr_slew_factor_ = 1.0F;
}
float
LumpedCapDelayCalc::ceff(const LibertyCell *,
TimingArc *,
const Slew &,
float load_cap,
Parasitic *,
float,
const Pvt *,
const DcalcAnalysisPt *)
{
return load_cap;
}
void
LumpedCapDelayCalc::gateDelay(const LibertyCell *drvr_cell,
TimingArc *arc,
const Slew &in_slew,
float load_cap,
Parasitic *,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew)
{
GateTimingModel *model = gateModel(arc, dcalc_ap);
debugPrint(debug_, "delay_calc", 3,
" in_slew = %s load_cap = %s related_load_cap = %s lumped",
delayAsString(in_slew, this),
units()->capacitanceUnit()->asString(load_cap),
units()->capacitanceUnit()->asString(related_out_cap));
if (model) {
ArcDelay gate_delay1;
Slew drvr_slew1;
float in_slew1 = delayAsFloat(in_slew);
// NaNs cause seg faults during table lookup.
if (isnan(load_cap) || isnan(related_out_cap) || isnan(in_slew))
report_->error(705, "gate delay input variable is NaN");
model->gateDelay(drvr_cell, pvt, in_slew1, load_cap, related_out_cap,
pocv_enabled_, gate_delay1, drvr_slew1);
gate_delay = gate_delay1;
drvr_slew = drvr_slew1;
drvr_slew_ = drvr_slew1;
}
else {
gate_delay = delay_zero;
drvr_slew = delay_zero;
drvr_slew_ = 0.0;
}
drvr_rf_ = arc->toEdge()->asRiseFall();
drvr_library_ = drvr_cell->libertyLibrary();
multi_drvr_slew_factor_ = 1.0F;
}
void
LumpedCapDelayCalc::loadDelay(const Pin *load_pin,
ArcDelay &wire_delay,
Slew &load_slew)
{
Delay wire_delay1 = 0.0;
Slew load_slew1 = drvr_slew_ * multi_drvr_slew_factor_;
thresholdAdjust(load_pin, wire_delay1, load_slew1);
wire_delay = wire_delay1;
load_slew = load_slew1;
}
void
LumpedCapDelayCalc::thresholdAdjust(const Pin *load_pin,
ArcDelay &load_delay,
Slew &load_slew)
{
LibertyLibrary *load_library = thresholdLibrary(load_pin);
if (load_library
&& drvr_library_
&& load_library != drvr_library_) {
float drvr_vth = drvr_library_->outputThreshold(drvr_rf_);
float load_vth = load_library->inputThreshold(drvr_rf_);
float drvr_slew_delta = drvr_library_->slewUpperThreshold(drvr_rf_)
- drvr_library_->slewLowerThreshold(drvr_rf_);
float load_delay_delta =
delayAsFloat(load_slew) * ((load_vth - drvr_vth) / drvr_slew_delta);
load_delay += (drvr_rf_ == RiseFall::rise())
? load_delay_delta
: -load_delay_delta;
float load_slew_delta = load_library->slewUpperThreshold(drvr_rf_)
- load_library->slewLowerThreshold(drvr_rf_);
float drvr_slew_derate = drvr_library_->slewDerateFromLibrary();
float load_slew_derate = load_library->slewDerateFromLibrary();
load_slew = load_slew * ((load_slew_delta / load_slew_derate)
/ (drvr_slew_delta / drvr_slew_derate));
}
}
LibertyLibrary *
LumpedCapDelayCalc::thresholdLibrary(const Pin *load_pin)
{
if (network_->isTopLevelPort(load_pin))
// Input/output slews use the default (first read) library
// for slew thresholds.
return network_->defaultLibertyLibrary();
else {
LibertyPort *lib_port = network_->libertyPort(load_pin);
if (lib_port)
return lib_port->libertyCell()->libertyLibrary();
else
return network_->defaultLibertyLibrary();
}
}
void
LumpedCapDelayCalc::reportGateDelay(const LibertyCell *drvr_cell,
TimingArc *arc,
const Slew &in_slew,
float load_cap,
Parasitic *,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
int digits,
string *result)
{
GateTimingModel *model = gateModel(arc, dcalc_ap);
if (model) {
float in_slew1 = delayAsFloat(in_slew);
model->reportGateDelay(drvr_cell, pvt, in_slew1, load_cap,
related_out_cap, false, digits, result);
}
}
void
LumpedCapDelayCalc::checkDelay(const LibertyCell *cell,
TimingArc *arc,
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &margin)
{
CheckTimingModel *model = checkModel(arc, dcalc_ap);
if (model) {
float from_slew1 = delayAsFloat(from_slew);
float to_slew1 = delayAsFloat(to_slew);
model->checkDelay(cell, pvt, from_slew1, to_slew1, related_out_cap,
pocv_enabled_, margin);
}
else
margin = delay_zero;
}
void
LumpedCapDelayCalc::reportCheckDelay(const LibertyCell *cell,
TimingArc *arc,
const Slew &from_slew,
const char *from_slew_annotation,
const Slew &to_slew,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
int digits,
string *result)
{
CheckTimingModel *model = checkModel(arc, dcalc_ap);
if (model) {
float from_slew1 = delayAsFloat(from_slew);
float to_slew1 = delayAsFloat(to_slew);
model->reportCheckDelay(cell, pvt, from_slew1, from_slew_annotation, to_slew1,
related_out_cap, false, digits, result);
}
}
void
LumpedCapDelayCalc::setMultiDrvrSlewFactor(float factor)
{
multi_drvr_slew_factor_ = factor;
}
} // namespace
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2022, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#pragma once
#include "ArcDelayCalc.hh"
namespace sta {
// Liberty table model lumped capacitance arc delay calculator.
// Wire delays are zero.
class LumpedCapDelayCalc : public ArcDelayCalc
{
public:
LumpedCapDelayCalc(StaState *sta);
virtual ArcDelayCalc *copy();
virtual Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap);
virtual ReducedParasiticType reducedParasiticType() const;
virtual void inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap);
virtual void gateDelay(const LibertyCell *drvr_cell,
TimingArc *arc,
const Slew &in_slew,
float load_cap,
Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew);
virtual void setMultiDrvrSlewFactor(float factor);
virtual void loadDelay(const Pin *load_pin,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew);
virtual void checkDelay(const LibertyCell *cell,
TimingArc *arc,
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &margin);
virtual float ceff(const LibertyCell *drvr_cell,
TimingArc *arc,
const Slew &in_slew,
float load_cap,
Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap);
virtual void reportGateDelay(const LibertyCell *drvr_cell,
TimingArc *arc,
const Slew &in_slew,
float load_cap,
Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
int digits,
string *result);
virtual void reportCheckDelay(const LibertyCell *cell,
TimingArc *arc,
const Slew &from_slew,
const char *from_slew_annotation,
const Slew &to_slew,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
int digits,
string *result);
virtual void finishDrvrPin();
protected:
// Find the liberty library to use for logic/slew thresholds.
LibertyLibrary *thresholdLibrary(const Pin *load_pin);
// Adjust load_delay and load_slew from driver thresholds to load thresholds.
void thresholdAdjust(const Pin *load_pin,
ArcDelay &load_delay,
Slew &load_slew);
Slew drvr_slew_;
float multi_drvr_slew_factor_;
const LibertyLibrary *drvr_library_;
const RiseFall *drvr_rf_;
// Parasitics returned by findParasitic that are reduced or estimated
// that can be deleted after delay calculation for the driver pin
// is finished.
Vector<Parasitic*> unsaved_parasitics_;
Vector<const Pin *> reduced_parasitic_drvrs_;
};
ArcDelayCalc *
makeLumpedCapDelayCalc(StaState *sta);
} // namespace
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2022, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "NetCaps.hh"
namespace sta {
NetCaps::NetCaps()
{
}
NetCaps::NetCaps(float pin_cap,
float wire_cap,
float fanout,
bool has_set_load) :
pin_cap_(pin_cap),
wire_cap_(wire_cap),
fanout_(fanout),
has_set_load_(has_set_load)
{
}
void
NetCaps::init(float pin_cap,
float wire_cap,
float fanout,
bool has_set_load)
{
pin_cap_ = pin_cap;
wire_cap_ = wire_cap;
fanout_ = fanout;
has_set_load_ = has_set_load;
}
} // namespace
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2022, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#pragma once
namespace sta {
// Constraints::pinNetCap return values.
class NetCaps
{
public:
NetCaps();
NetCaps(float pin_cap,
float wire_cap,
float fanout,
bool has_set_load);
void init(float pin_cap,
float wire_cap,
float fanout,
bool has_set_load);
float pinCap() const { return pin_cap_; }
float wireCap() const{ return wire_cap_; }
float fanout() const{ return fanout_; }
bool hasSetLoad() const { return has_set_load_; }
private:
float pin_cap_;
float wire_cap_;
float fanout_;
bool has_set_load_;
};
} // namespace
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2022, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "RCDelayCalc.hh"
#include "Liberty.hh"
#include "Network.hh"
#include "Sdc.hh"
#include "Parasitics.hh"
#include "GraphDelayCalc.hh"
namespace sta {
RCDelayCalc::RCDelayCalc(StaState *sta) :
LumpedCapDelayCalc(sta)
{
}
ArcDelayCalc *
RCDelayCalc::copy()
{
return new RCDelayCalc(this);
}
void
RCDelayCalc::inputPortDelay(const Pin *,
float in_slew,
const RiseFall *rf,
Parasitic *parasitic,
const DcalcAnalysisPt *)
{
drvr_parasitic_ = parasitic;
drvr_slew_ = in_slew;
drvr_rf_ = rf;
drvr_cell_ = nullptr;
drvr_library_ = network_->defaultLibertyLibrary();
multi_drvr_slew_factor_ = 1.0F;
}
// For DSPF on an input port the elmore delay is used as the time
// constant of an exponential waveform. The delay to the logic
// threshold and slew are computed for the exponential waveform.
// Note that this uses the driver thresholds and relies on
// thresholdAdjust to convert the delay and slew to the load's thresholds.
void
RCDelayCalc::dspfWireDelaySlew(const Pin *,
float elmore,
ArcDelay &wire_delay,
Slew &load_slew)
{
float vth = .5;
float vl = .2;
float vh = .8;
float slew_derate = 1.0;
if (drvr_library_) {
vth = drvr_library_->inputThreshold(drvr_rf_);
vl = drvr_library_->slewLowerThreshold(drvr_rf_);
vh = drvr_library_->slewUpperThreshold(drvr_rf_);
slew_derate = drvr_library_->slewDerateFromLibrary();
}
wire_delay = static_cast<float>(-elmore * log(1.0 - vth));
load_slew = (drvr_slew_ + elmore * log((1.0 - vl) / (1.0 - vh))
/ slew_derate) * multi_drvr_slew_factor_;
}
} // namespace
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2022, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#pragma once
#include "LumpedCapDelayCalc.hh"
namespace sta {
// Base class for delay calculators with RC wire delay.
class RCDelayCalc : public LumpedCapDelayCalc
{
public:
RCDelayCalc(StaState *sta);
virtual ArcDelayCalc *copy();
virtual void inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap);
protected:
// Helper function for input ports driving dspf parasitic.
void dspfWireDelaySlew(const Pin *load_pin,
float elmore,
ArcDelay &wire_delay,
Slew &load_slew);
const LibertyCell *drvr_cell_;
Parasitic *drvr_parasitic_;
};
} // namespace
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2022, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "SimpleRCDelayCalc.hh"
#include "TimingArc.hh"
#include "Liberty.hh"
#include "Network.hh"
#include "Sdc.hh"
#include "Parasitics.hh"
#include "DcalcAnalysisPt.hh"
namespace sta {
ArcDelayCalc *
makeSimpleRCDelayCalc(StaState *sta)
{
return new SimpleRCDelayCalc(sta);
}
SimpleRCDelayCalc::SimpleRCDelayCalc(StaState *sta) :
RCDelayCalc(sta)
{
}
ArcDelayCalc *
SimpleRCDelayCalc::copy()
{
return new SimpleRCDelayCalc(this);
}
void
SimpleRCDelayCalc::inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap)
{
pvt_ = dcalc_ap->operatingConditions();
RCDelayCalc::inputPortDelay(port_pin, in_slew, rf, parasitic, dcalc_ap);
}
void
SimpleRCDelayCalc::gateDelay(const LibertyCell *drvr_cell,
TimingArc *arc,
const Slew &in_slew,
float load_cap,
Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew)
{
drvr_parasitic_ = drvr_parasitic;
drvr_rf_ = arc->toEdge()->asRiseFall();
drvr_cell_ = drvr_cell;
drvr_library_ = drvr_cell->libertyLibrary();
pvt_ = pvt;
LumpedCapDelayCalc::gateDelay(drvr_cell, arc, in_slew,
load_cap, drvr_parasitic, related_out_cap,
pvt, dcalc_ap,
gate_delay, drvr_slew);
}
void
SimpleRCDelayCalc::loadDelay(const Pin *load_pin,
ArcDelay &wire_delay,
Slew &load_slew)
{
ArcDelay wire_delay1 = 0.0;
Slew load_slew1 = drvr_slew_;
bool elmore_exists = false;
float elmore = 0.0;
if (drvr_parasitic_)
parasitics_->findElmore(drvr_parasitic_, load_pin, elmore, elmore_exists);
if (elmore_exists) {
if (drvr_library_ && drvr_library_->wireSlewDegradationTable(drvr_rf_)) {
wire_delay1 = elmore;
load_slew1 = drvr_library_->degradeWireSlew(drvr_cell_, drvr_rf_,
pvt_,
delayAsFloat(drvr_slew_),
delayAsFloat(wire_delay1));
}
else if (parasitics_->isReducedParasiticNetwork(drvr_parasitic_))
dspfWireDelaySlew(load_pin, elmore, wire_delay1, load_slew1);
else {
// For RSPF on an input port the elmore delay is used for the
// wire delay and the slew is copied from the driver.
wire_delay1 = elmore;
load_slew1 = drvr_slew_;
}
}
thresholdAdjust(load_pin, wire_delay1, load_slew1);
wire_delay = wire_delay1;
load_slew = load_slew1 * multi_drvr_slew_factor_;
}
} // namespace
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2022, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#pragma once
#include "RCDelayCalc.hh"
namespace sta {
// Liberty table model lumped capacitance arc delay calculator.
// Effective capacitance is the pi model total capacitance (C1+C2).
// Wire delays are elmore delays.
// Driver slews are degraded to loads by rise/fall transition_degradation
// tables.
class SimpleRCDelayCalc : public RCDelayCalc
{
public:
SimpleRCDelayCalc(StaState *sta);
virtual ArcDelayCalc *copy();
virtual void inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap);
virtual void gateDelay(const LibertyCell *drvr_cell,
TimingArc *arc,
const Slew &in_slew,
float load_cap,
Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew);
virtual void loadDelay(const Pin *load_pin,
ArcDelay &wire_delay,
Slew &load_slew);
using RCDelayCalc::gateDelay;
using RCDelayCalc::reportGateDelay;
private:
const Pvt *pvt_;
};
ArcDelayCalc *
makeSimpleRCDelayCalc(StaState *sta);
} // namespace
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2022, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "UnitDelayCalc.hh"
#include "Units.hh"
namespace sta {
ArcDelayCalc *
makeUnitDelayCalc(StaState *sta)
{
return new UnitDelayCalc(sta);
}
UnitDelayCalc::UnitDelayCalc(StaState *sta) :
ArcDelayCalc(sta)
{
}
ArcDelayCalc *
UnitDelayCalc::copy()
{
return new UnitDelayCalc(this);
}
Parasitic *
UnitDelayCalc::findParasitic(const Pin *,
const RiseFall *,
const DcalcAnalysisPt *)
{
return nullptr;
}
ReducedParasiticType
UnitDelayCalc::reducedParasiticType() const
{
return ReducedParasiticType::none;
}
void
UnitDelayCalc::inputPortDelay(const Pin *,
float,
const RiseFall *,
Parasitic *,
const DcalcAnalysisPt *)
{
}
void
UnitDelayCalc::gateDelay(const LibertyCell *,
TimingArc *,
const Slew &,
float,
Parasitic *,
float,
const Pvt *, const DcalcAnalysisPt *,
// Return values.
ArcDelay &gate_delay, Slew &drvr_slew)
{
gate_delay = units_->timeUnit()->scale();
drvr_slew = 0.0;
}
void
UnitDelayCalc::loadDelay(const Pin *,
ArcDelay &wire_delay,
Slew &load_slew)
{
wire_delay = 0.0;
load_slew = 0.0;
}
float
UnitDelayCalc::ceff(const LibertyCell *,
TimingArc *,
const Slew &,
float,
Parasitic *,
float,
const Pvt *,
const DcalcAnalysisPt *)
{
return 0.0;
}
void
UnitDelayCalc::reportGateDelay(const LibertyCell *,
TimingArc *,
const Slew &,
float,
Parasitic *,
float,
const Pvt *,
const DcalcAnalysisPt *,
int,
string *result)
{
*result += "Delay = 1.0\n";
*result += "Slew = 0.0\n";
}
void
UnitDelayCalc::checkDelay(const LibertyCell *,
TimingArc *,
const Slew &,
const Slew &,
float,
const Pvt *,
const DcalcAnalysisPt *,
// Return values.
ArcDelay &margin)
{
margin = units_->timeUnit()->scale();
}
void
UnitDelayCalc::reportCheckDelay(const LibertyCell *,
TimingArc *,
const Slew &,
const char *,
const Slew &,
float,
const Pvt *,
const DcalcAnalysisPt *,
int,
string *result)
{
*result += "Check = 1.0\n";
}
void
UnitDelayCalc::finishDrvrPin()
{
}
} // namespace
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2022, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#pragma once
#include "ArcDelayCalc.hh"
namespace sta {
// Unit delay calculator.
class UnitDelayCalc : public ArcDelayCalc
{
public:
UnitDelayCalc(StaState *sta);
virtual ArcDelayCalc *copy();
virtual Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap);
virtual ReducedParasiticType reducedParasiticType() const;
virtual void gateDelay(const LibertyCell *drvr_cell,
TimingArc *arc,
const Slew &in_slew,
float load_cap,
Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew);
virtual void loadDelay(const Pin *load_pin,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew);
virtual void setMultiDrvrSlewFactor(float) {}
virtual float ceff(const LibertyCell *drvr_cell,
TimingArc *arc,
const Slew &in_slew,
float load_cap,
Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap);
virtual void inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap);
virtual void checkDelay(const LibertyCell *cell,
TimingArc *arc,
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &margin);
virtual void reportGateDelay(const LibertyCell *drvr_cell,
TimingArc *arc,
const Slew &in_slew,
float load_cap,
Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
int digits,
string *result);
virtual void reportCheckDelay(const LibertyCell *cell,
TimingArc *arc,
const Slew &from_slew,
const char *from_slew_annotation,
const Slew &to_slew,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
int digits,
string *result);
virtual void finishDrvrPin();
};
ArcDelayCalc *
makeUnitDelayCalc(StaState *sta);
} // namespace
# OpenSTA, Static Timing Analyzer
# Copyright (c) 2022, 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/>.
This file summarizes STA API changes for each release.
Release 2.3.1 2022/06/12
LibertyCellTimingArcSetIterator has been removed.
Use range iteration as shown below:
for (TimingArcSet *arc_set : cell->timingArcSets())
for (TimingArcSet *arc_set : cell->timingArcSets(from, to))
TimingArcSetArcIterator has been removed.
Use range iteration as shown below:
for (TimingArc *arc : arc_set->arcs())
LibertyCellSequentialIterator has been removed.
for (Sequential *seq : cell->sequentials())
Release 2.1.1 2020/12/13
Report::error, Report::warn functions now take a unique message ID as a first argument.
InternalError has been renamed Report::cricical.
Release 2.1.0 2020/04/05
All public headers files have been moved to include/sta.
The following iterators have been removed.
Use range iteration on the returned collection shown next to them instead.
LibertyCellInternalPowerIterator cell->internalPowers()
LibertyCellLeakagePowerIterator cell->leakagePowers()
Release 2.0.18 2020/02/15
-------------------------
The following iterator functions are deprecated:
TimingArcSet::timingArcIterator()
Sdc::clockIterator()
Use the iterator class constructor instead. This avoids new/deletes of
the iterators by stack allocating them. For example,
Instead of
TimingArcSetArcIterator *arc_iter = arc_set->timingArcIterator();
while (arc_iter->hasNext()) {
TimingArc *arc = arc_iter->next();
}
delete arc_iter;
use the following:
TimingArcSetArcIterator arc_iter(arc_set);
while (arc_iter.hasNext()) {
TimingArc *arc = arc_iter.next();
}
StaException renamed to Exception
Release 2.0.17 2019/11/11
-------------------------
Network::setVertexIndex renamed to setVertexId
Network::vertexIndex renamed to vertexId
TransRiseFall renamed to RiseFall
TransRiseFallBoth renamed to RiseFallBoth
Release 2.0.0 2018/06/11
-------------------------
Initial release.
# Local Variables:
# mode:text
# End:
OpenSTA Timing Analyzer Release Notes
---------------------------------------------
This file summarizes user visible changes for each release.
The report_parasitics_annotation command reports SPEF annotation completeness.
report_parasitics_annotation [-report_unannotated]
Release 2.3.2 2022/07/03
-------------------------
The liberty default_wire_load is now ignored. You must explicitly set the wire load
model with the set_wire_load_model command to apply wire load model based parasitics.
Release 2.3.1 2020/11/08
-------------------------
The read_sdf command no longer supports the -analysis_type, -type, -min_type,
and -max_type arguments. Use the set_operating_conditions -analysis_type
command to set the analysis type before read_sdf.
Release 2.2.0 2020/07/18
-------------------------
The report_units reports the current units used by commands.
report_units
The report_check_types -min_fanout -max_fanout -max_capacitance -min_capacitance
report_check_types [-min_fanout] [-max_fanout] [-max_capacitance] [-min_capacitance]
The insert_buffer command is no longer supported.
Release 2.0.0 2018/09/28
-------------------------
The command line options have changed to the following:
-help show help and exit
-version show version and exit
-no_init do not read .sta init file
-threads count|max use count threads
-no_splash do not show the license splash at startup
-exit exit after reading cmd_file
cmd_file source cmd_file
....
Builds using Autotools/configure are no longer supported.
Use CMake as documented in README.md.
....
The check_timing command -no_output_delay checks output ports for
set_output_delay.
....
The report_power command reports the power consumption of the design
or a specific instance.
report_power [-instances inst] [-digits digits] [> filename] [>> filename]
The internal, switching, leakage and total power are reported. Design
power is reported separately for combinational, sequential, macro and
pad groups.
Use -instances to report power for a specific instance.
Use the set_power_activity command to specify activity/duty
globally using -global, the input port default using -input,
or for input ports using -input_ports, or pins using -pins.
set_power_activity [-global]
[-input]
[-input_ports ports]
[-pins pins]
[-activiity activity]
[-duty duty]
....
The write_path_spice command writes a spice netlist for a timing path.
write_path_spice -path_args path_args
-spice_directory spice_directory
-subckt_file subckt_file
-lib_subckt_file lib_subckts_file\
-model_file model_file
-power power
-ground ground
Use path_args to specify -from/-through/-to as arguments to the
find_timing_paths command. For each path, a spice netlist and the
subckts referenced by the path are written in spice_directory. The
spice netlist is written in path_<id>.sp and subckt file is
path_<id>.subckt.
Spice netlists for liberty library cells are read from
lib_subckts_file. The spice netlists used by the path are written to
subckt_file, which spice_file .includes. The device models used by the
spice subckt netlists in model_file are .included in spice_file. Power
and ground names are specified with the -power and -ground arguments.
The spice netlist includes a piecewise linear voltage source at the
input and .measure statement for each gate delay and pin slew.
....
The report_checks and report_check_types commands now support an
-unconstrained flag.
report_checks -unconstrained
report_check_types -unconstrained
The sta_report_unconstrained_paths variable will be supported for
for compatibility in the current release.
....
The transition_time path reporting field has been renamed to slew.
report_checks -fields {slew}
report_check_types -fields {slew}
...
The read_parasitics command has been renamed read_spef and no longer
supports the SPF format.
....
The make_instance command now takes a single instance name argument
and returns the instance.
make_instance instance_name
The make_net command now takes a single net name argument and returns
the net.
make_net net_name
The delete_instance command deletes a single instance instead of a list
of instances.
delete_instance instance
The delete_net command deletes a single net instead of a list
of nets.
delete_net net
The disconnect_pins command is renamed disconnect_pin and disconnects a
single pin.
disconnect_pin net pin
The report_tns and report_wns commands print the value returned by
total_negative_slack and worst_negative_slack respectively.
report_tns
report_wns
report_worst_slack
The set_clock_sense command was deprecated by SDC 2.1.
Use set_sense -type clock instead.
# Local Variables:
# mode:text
# End:
Naming conventions
directory - lowercase (directory)
filename - corresponding class name without prefix (Filename)
class - capitalized (ClassName)
member function - lowercase/capitalized (memberFunction)
member variable - lowercase/underscore/trailing underscore (member_variable_)
Trailing underscore prevents conflict with accessor
member function name.
function - lowercase/capitalized (functionName)
comments - use capitalized sentences that end with periods
C++ code files should use a .cc file extension
C++ header files should use a .hh file extension
Use ifdef/define's to protect headers from being read more than once.
Name the define variable the same as the header in uppercase.
For example, for Clock.hh
#ifndef STA_CLOCK_H
#define STA_CLOCK_H
...
#endif
In general it is better to for class variables to use pointers to
objects of other classes rather than embedding the instance directly.
This only requires that the class be declared rather than defined,
many times breaking a dependency on another header file.
Header files that define the classes of a sub-directory allow other
headers to have pointers to the objects without pulling in the details
of the class definitions. These headers are named "DirectoryClass.hh"
where Directory is the capitalized name of the sub-directory.
Place comments describing public functions and classes in header files
rather than code files because a consumer is more likely to have
access to the header and that is the first place they will look.
Comments for private functions can be in the source file.
The return type of a function should be on the line before the
function name. Spaces should be added after commas in the argument
list. Split the function arguments to fit on one line. For example:
return_type
function(type1 arg1, type2, arg2)
{
}
Functions should be less than one screen long. Break long functions
up into smaller ones. Lines should be less than 80 characters long.
Try to avoid assignments inside `if'-conditions. For example, don't
write this:
if ((foo = (char *) malloc (sizeof *foo)) == 0)
fatal ("virtual memory exhausted");
instead, write this:
foo = (char *) malloc (sizeof *foo);
if (foo == 0)
fatal ("virtual memory exhausted");
Use braces around if/for bodies that are more than one line.
IE,
if (pred)
for (int i = 0; i < len; i++) { // this body should be in {}'s
...
}
Add a default clause to all switches calling switchCaseNotHandled:
switch (type) {
case edge_interconnect:
...
default:
switchCaseNotHandled();
}
Put return types for functions on the line before the function name:
Cell *
Library::findCell(char *name)
{
...
}
Class member functions should be grouped in public, protected and then
private order.
class Frob
{
public:
protected:
private:
friend class Frobulator;
}
Don't declare class variables as const. It means any downstream code
that accesses the member cannot modify it, which is overly
restrictive.
Never use [] to lookup a map value because it creates a key/null value
pair if the lookup fails. Use sta::Map::findKey instead.
Avoid nested classes/enums because SWIG has trouble with them.
................................................................
Warning
get_<object> not found
sdf timing arc not found
disabling timing arcs to break loops
virtual clock with no sources (no pins)
invalid endpoint for constrained paths
sdf DESIGN does not match top level cell name
set_input_delay on clk port (deprecation warning)
link cannot resolve reference (module/cell not found)
Errors
cannot open file
file syntax error
cmd illegal command option combinations
cmd extra positional args
cmd unknown keyword option
cmd unknown
sdf pin not found
................................................................
if configure.ac changes
autoconf
if Makefile.am changes
automake
Adding a new source file
Add header and source to source_dir/Makefile.am
cd source_dir; make clean
Adding a new source directory
Add to configure.ac STA_SUBDIRS, AC_CONFIG_FILES
bootstrap
configure
make
................................................................
Swig notes
C null pointers (zero) turn into "NULL" values in TCL.
TCL "NULL" strings turn into NULL (zero) pointers in C.
# TCL lexpr-funcall
eval exec $prog $args
#! /bin/sh
# The next line is executed by /bin/sh, but not Tcl \
exec tclsh $0 ${1+"$@"}
# OpenSTA, Static Timing Analyzer
# Copyright (c) 2022, 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/>.
# Usage: TclEncode encoded_filename var_name tcl_init_dir tcl_filename...
# Encode the contents of tcl_filenames into a C character array
# named var_name in the file encoded_filename.
# Each TCL file is encoded as a separate string of three digit decimal numbers
# that is unencoded and evaled on startup of the application.
# The init variable character array is terminated with a NULL pointer.
set encoded_filename [lindex $argv 0]
set init_var [lindex $argv 1]
set init_filenames [lrange $argv 2 end]
# Microcruft Visual C-- ridiculously short max string constant length.
set max_string_length 2000
set out_stream [open $encoded_filename w]
puts $out_stream "// TCL init file encoded by TclEncode.tcl"
puts $out_stream "namespace sta {"
puts $out_stream "const char *$init_var\[\] = {"
puts -nonewline $out_stream "\""
set encoded_length 0
binary scan "\n" c newline_enc
proc encode_line { line } {
global encoded_length max_string_length
global newline_enc out_stream
set length [string length $line]
set i 0
while { $i < $length } {
set ch [string index $line $i]
binary scan $ch c enc
puts -nonewline $out_stream [format "%03d" $enc]
incr i
incr encoded_length 3
if { $encoded_length > $max_string_length } {
puts $out_stream "\","
puts -nonewline $out_stream "\""
set encoded_length 0
}
}
puts -nonewline $out_stream [format "%03d" $newline_enc]
incr encoded_length 3
}
proc encode_file { filename } {
set in_stream [open $filename r]
while {![eof $in_stream]} {
gets $in_stream line
encode_line $line
}
close $in_stream
}
foreach filename $init_filenames {
encode_file $filename
}
puts $out_stream "\","
# NULL string to terminate char* array.
puts $out_stream "0"
puts $out_stream "};"
puts $out_stream "} // namespace"
close $out_stream
*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 PF
*R_UNIT 1.0 OHM
*L_UNIT 1.0 HENRY
*POWER_NETS VDD
*GROUND_NETS VSS
*PORTS
in1 I
in2 I
clk1 I
clk2 I
clk3 I
out O
*D_NET in1 0.275
*CONN
*P in1 I
*I r1:D I *L .0036
*CAP
1 in1 .243
2 r1:D .032
*RES
3 in1 r1:D 40
*END
*D_NET in2 0.275
*CONN
*P in2 I
*I r2:D I *L .0036
*CAP
1 in2 .243
2 r2:D .032
*RES
3 in2 r2:D 40
*END
*D_NET clk1 0.275
*CONN
*P clk1 I
*I r1:CK I *L .0036
*CAP
1 clk1 .243
2 r1:CK .032
*RES
3 clk1 r1:CK 40
*END
*D_NET clk2 0.275
*CONN
*P clk2 I
*I r2:CK I *L .0036
*CAP
1 clk2 .243
2 r2:CK .032
*RES
3 clk2 r2:CK 40
*END
*D_NET clk3 0.275
*CONN
*P clk3 I
*I r3:CK I *L .0036
*CAP
1 clk3 .243
2 r3:CK .032
*RES
3 clk3 r3:CK 40
*END
*D_NET r1q 0.275
*CONN
*I r1:Q O
*I u2:A1 I *L .0086
*CAP
1 r1:Q .243
2 u2:A1 .032
*RES
3 r1:Q u2:A1 40
*END
*D_NET r2q 0.275
*CONN
*I r2:Q O
*I u1:A I *L .0086
*CAP
1 r2:Q .243
2 u1:A .032
*RES
3 r2:Q u1:A 40
*END
*D_NET u1z 0.275
*CONN
*I u1:Z O
*I u2:A2 I *L .0086
*CAP
1 u1:Z .243
2 u2:A2 .032
*RES
3 u1:Z u2:A2 40
*END
*D_NET u2z 0.275
*CONN
*I u2:ZN O
*I r3:D I *L .0086
*CAP
1 u2:ZN .243
2 r3:D .032
*RES
3 u2:ZN r3:D 40
*END
*D_NET out 0.275
*CONN
*I r3:Q O
*P out O
*CAP
1 r3:Q .243
2 out .032
*RES
3 r3:Q out 40
*END
(DELAYFILE
(SDFVERSION "OVI 2.1")
(DESIGN "top")
(DATE "Thu Mar 2 20:33:26 2000")
(VENDOR "slow")
(PROGRAM "Hand job")
(VERSION "69")
(DIVIDER /)
(VOLTAGE 2.25:2.25:2.25)
(PROCESS "1.000:1.000:1.000")
(TEMPERATURE 125.00:125.00:125.00)
(TIMESCALE 1ns)
(CELL
(CELLTYPE "top")
(INSTANCE)
(DELAY
(ABSOLUTE
// Offset in1 vs in2, rise vs fall arrivals so results are deterministic.
(INTERCONNECT in1 r1/D (0.011:0.011:0.011) (0.01:0.01:0.01))
(INTERCONNECT in2 r2/D (0.021:0.021:0.021) (0.02:0.02:0.02))
(INTERCONNECT clk1 r1/CK (0.0:0.0:0.0) (0.0:0.0:0.0))
(INTERCONNECT clk2 r2/CK (0.0:0.0:0.0) (0.0:0.0:0.0))
(INTERCONNECT clk3 r3/CK (0.0:0.0:0.0) (0.0:0.0:0.0))
(INTERCONNECT r1/Q u2/A1 (0.0:0.0:0.0) (0.0:0.0:0.0))
(INTERCONNECT r2/Q u1/A (0.0:0.0:0.0) (0.0:0.0:0.0))
(INTERCONNECT u1/Z u2/A2 (0.0:0.0:0.0) (0.0:0.0:0.0))
(INTERCONNECT u2/ZN r3/D (0.0:0.0:0.0) (0.0:0.0:0.0))
(INTERCONNECT r3/Q out (0.0:0.0:0.0) (0.0:0.0:0.0))
)
)
)
(CELL
(CELLTYPE "DFF_X1")
(INSTANCE r1)
(DELAY
(ABSOLUTE
(IOPATH CK Q (1:1:1) (1.1:1.1:1.1))
)
)
(TIMINGCHECK
(SETUP D (posedge CK) (.5:.5:.5))
(HOLD D (posedge CK) (.1:.1:.1))
(PERIOD (posedge CK) (1.0:2.0:3.0))
)
)
(CELL
(CELLTYPE "DFF_X1")
(INSTANCE r2)
(DELAY
(ABSOLUTE
(IOPATH CK Q (1:1:1) (1.1:1.1:1.1))
)
)
(TIMINGCHECK
(SETUP D (posedge CK) (.5:.5:.5))
(HOLD D (posedge CK) (.1:.1:.1))
(PERIOD (posedge CK) (1.0:2.0:3.0))
)
)
(CELL
(CELLTYPE "DFF_X1")
(INSTANCE r3)
(DELAY
(ABSOLUTE
(IOPATH CK Q (1:1:1) (1.1:1.1:1.1))
)
)
(TIMINGCHECK
(SETUP D (posedge CK) (.5:.5:.5))
(HOLD D (posedge CK) (.1:.1:.1))
(PERIOD (posedge CK) (1.0:2.0:3.0))
)
)
(CELL
(CELLTYPE "BUF_X1")
(INSTANCE u1)
(DELAY
(ABSOLUTE
(IOPATH A Z (1:1:1) (1.1:1.1:1.1))
)
)
)
(CELL
(CELLTYPE "AND2_X1")
(INSTANCE u2)
(DELAY
(ABSOLUTE
(IOPATH A1 ZN (1:1:1) (1.1:1.1:1.1))
(IOPATH A2 ZN (1:1:1) (1.1:1.1:1.1))
)
)
)
)
# sdf example
read_liberty example1_slow.lib
read_verilog example1.v
link_design top
read_sdf example1.sdf
create_clock -name clk -period 10 {clk1 clk2 clk3}
set_input_delay -clock clk 0 {in1 in2}
report_checks
module top (in1, in2, clk1, clk2, clk3, out);
input in1, in2, clk1, clk2, clk3;
output out;
wire r1q, r2q, u1z, u2z;
DFF_X1 r1 (.D(in1), .CK(clk1), .Q(r1q));
DFF_X1 r2 (.D(in2), .CK(clk2), .Q(r2q));
BUF_X1 u1 (.A(r2q), .Z(u1z));
AND2_X1 u2 (.A1(r1q), .A2(u1z), .ZN(u2z));
DFF_X1 r3 (.D(u2z), .CK(clk3), .Q(out));
endmodule // top
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
# delay calc example
read_liberty example1_slow.lib
read_verilog example1.v
link_design top
create_clock -name clk -period 10 {clk1 clk2 clk3}
set_input_delay -clock clk 0 {in1 in2}
report_checks
# min/max delay calc example
read_liberty -max example1_slow.lib
read_liberty -min example1_fast.lib
read_verilog example1.v
link_design top
create_clock -name clk -period 10 {clk1 clk2 clk3}
set_input_delay -clock clk 0 {in1 in2}
report_checks -path_delay min_max
# delay calc example with parasitics
read_liberty example1_slow.lib
read_verilog example1.v
link_design top
read_spef example1.dspef
create_clock -name clk -period 10 {clk1 clk2 clk3}
set_input_delay -clock clk 0 {in1 in2}
report_checks
# 3 corners with +/- 10% derating example
define_corners ss tt ff
read_liberty -corner ss example1_slow.lib
read_liberty -corner tt example1_typ.lib
read_liberty -corner ff example1_fast.lib
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
report_checks -path_delay min_max
# report typical corner
report_checks -corner tt
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2022, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Machine.hh"
#include "StringUtil.hh"
#include "Units.hh"
#include "StaState.hh"
#include "Delay.hh"
namespace sta {
const char *
delayAsString(const Delay &delay,
const StaState *sta)
{
return delayAsString(delay, sta, sta->units()->timeUnit()->digits());
}
} // namespace
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2022, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Delay.hh"
#include "StaConfig.hh"
#include "Fuzzy.hh"
#include "Units.hh"
#include "StaState.hh"
// Non-SSTA compilation.
#if !SSTA
namespace sta {
static Delay delay_init_values[MinMax::index_count];
void
initDelayConstants()
{
delay_init_values[MinMax::minIndex()] = MinMax::min()->initValue();
delay_init_values[MinMax::maxIndex()] = MinMax::max()->initValue();
}
const char *
delayAsString(const Delay &delay,
const StaState *sta)
{
return delayAsString(delay, sta, sta->units()->timeUnit()->digits());
}
const char *
delayAsString(const Delay &delay,
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 Unit *unit = sta->units()->timeUnit();
return unit->asString(delay, digits);
}
const Delay &
delayInitValue(const MinMax *min_max)
{
return delay_init_values[min_max->index()];
}
bool
delayIsInitValue(const Delay &delay,
const MinMax *min_max)
{
return fuzzyEqual(delay, min_max->initValue());
}
bool
delayZero(const Delay &delay)
{
return fuzzyZero(delay);
}
bool
delayInf(const Delay &delay)
{
return fuzzyInf(delay);
}
bool
delayEqual(const Delay &delay1,
const Delay &delay2)
{
return fuzzyEqual(delay1, delay2);
}
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const StaState *)
{
return fuzzyLess(delay1, delay2);
}
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *)
{
if (min_max == MinMax::max())
return fuzzyLess(delay1, delay2);
else
return fuzzyGreater(delay1, delay2);
}
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const StaState *)
{
return fuzzyLessEqual(delay1, delay2);
}
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *)
{
if (min_max == MinMax::max())
return fuzzyLessEqual(delay1, delay2);
else
return fuzzyGreaterEqual(delay1, delay2);
}
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const StaState *)
{
return fuzzyGreater(delay1, delay2);
}
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *)
{
if (min_max == MinMax::max())
return fuzzyGreater(delay1, delay2);
else
return fuzzyLess(delay1, delay2);
}
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const StaState *)
{
return fuzzyGreaterEqual(delay1, delay2);
}
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *)
{
if (min_max == MinMax::max())
return fuzzyGreaterEqual(delay1, delay2);
else
return fuzzyLessEqual(delay1, delay2);
}
Delay
delayRemove(const Delay &delay1,
const Delay &delay2)
{
return delay1 - delay2;
}
float
delayRatio(const Delay &delay1,
const Delay &delay2)
{
return delay1 / delay2;
}
} // namespace
#endif // !SSTA
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2022, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Delay.hh"
#include <cmath> // sqrt
#include "StaConfig.hh"
#include "Error.hh"
#include "StringUtil.hh"
#include "Fuzzy.hh"
#include "Units.hh"
#include "StaState.hh"
// SSTA compilation.
#if (SSTA == 1)
namespace sta {
inline float
square(float x)
{
return x * x;
}
static Delay delay_init_values[MinMax::index_count];
void
initDelayConstants()
{
delay_init_values[MinMax::minIndex()] = MinMax::min()->initValue();
delay_init_values[MinMax::maxIndex()] = MinMax::max()->initValue();
}
const Delay &
delayInitValue(const MinMax *min_max)
{
return delay_init_values[min_max->index()];
}
Delay::Delay() :
mean_(0.0),
sigma2_(0.0)
{
}
Delay::Delay(const Delay &delay) :
mean_(delay.mean_),
sigma2_(delay.sigma2_)
{
}
Delay::Delay(float mean) :
mean_(mean),
sigma2_(0.0)
{
}
Delay::Delay(float mean,
float sigma2) :
mean_(mean),
sigma2_(sigma2)
{
}
float
Delay::sigma() const
{
if (sigma2_ < 0.0)
// Sigma is negative for crpr to offset sigmas in the common
// clock path.
return -sqrt(-sigma2_);
else
return sqrt(sigma2_);
}
float
Delay::sigma2() const
{
return sigma2_;
}
void
Delay::operator=(const Delay &delay)
{
mean_ = delay.mean_;
sigma2_ = delay.sigma2_;
}
void
Delay::operator=(float delay)
{
mean_ = delay;
sigma2_ = 0.0;
}
void
Delay::operator+=(const Delay &delay)
{
mean_ += delay.mean_;
sigma2_ += delay.sigma2_;
}
void
Delay::operator+=(float delay)
{
mean_ += delay;
}
Delay
Delay::operator+(const Delay &delay) const
{
return Delay(mean_ + delay.mean_,
sigma2_ + delay.sigma2_);
}
Delay
Delay::operator+(float delay) const
{
return Delay(mean_ + delay, sigma2_);
}
Delay
Delay::operator-(const Delay &delay) const
{
return Delay(mean_ - delay.mean_,
sigma2_ + delay.sigma2_);
}
Delay
Delay::operator-(float delay) const
{
return Delay(mean_ - delay, sigma2_);
}
Delay
Delay::operator-() const
{
return Delay(-mean_, sigma2_);
}
void
Delay::operator-=(float delay)
{
mean_ -= delay;
}
void
Delay::operator-=(const Delay &delay)
{
mean_ -= delay.mean_;
sigma2_ += delay.sigma2_;
}
bool
Delay::operator==(const Delay &delay) const
{
return delayEqual(*this, delay);
}
////////////////////////////////////////////////////////////////
Delay
makeDelay(float delay,
float sigma,
float)
{
return Delay(delay, square(sigma));
}
Delay
makeDelay2(float delay,
float sigma2,
float )
{
return Delay(delay, sigma2);
}
float
delayAsFloat(const Delay &delay,
const EarlyLate *early_late,
const StaState *sta)
{
if (sta->pocvEnabled()) {
if (early_late == EarlyLate::early())
return delay.mean() - delay.sigma() * sta->sigmaFactor();
else if (early_late == EarlyLate::late())
return delay.mean() + delay.sigma() * sta->sigmaFactor();
else
sta->report()->critical(594, "unknown early/late value.");
}
return delay.mean();
}
float
delaySigma2(const Delay &delay,
const EarlyLate *)
{
return delay.sigma2();
}
const char *
delayAsString(const Delay &delay,
const StaState *sta)
{
return delayAsString(delay, sta, sta->units()->timeUnit()->digits());
}
const char *
delayAsString(const Delay &delay,
const StaState *sta,
int digits)
{
const Unit *unit = sta->units()->timeUnit();
if (sta->pocvEnabled()) {
float sigma = delay.sigma();
return stringPrintTmp("%s[%s]",
unit->asString(delay.mean(), digits),
unit->asString(sigma, digits));
}
else
return unit->asString(delay.mean(), digits);
}
const char *
delayAsString(const Delay &delay,
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);
}
bool
delayIsInitValue(const Delay &delay,
const MinMax *min_max)
{
return fuzzyEqual(delay.mean(), min_max->initValue())
&& delay.sigma2() == 0.0;
}
bool
delayZero(const Delay &delay)
{
return fuzzyZero(delay.mean())
&& fuzzyZero(delay.sigma2());
}
bool
delayInf(const Delay &delay)
{
return fuzzyInf(delay.mean());
}
bool
delayEqual(const Delay &delay1,
const Delay &delay2)
{
return fuzzyEqual(delay1.mean(), delay2.mean())
&& fuzzyEqual(delay1.sigma2(), delay2.sigma2());
}
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const StaState *sta)
{
return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta),
delayAsFloat(delay2, EarlyLate::early(), sta));
}
bool
delayLess(const Delay &delay1,
float delay2,
const StaState *sta)
{
return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta),
delay2);
}
bool
delayLess(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
{
if (min_max == MinMax::max())
return delayLess(delay1, delay2, sta);
else
return delayGreater(delay1, delay2, sta);
}
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta)
{
return fuzzyLessEqual(delayAsFloat(delay1, EarlyLate::early(), sta),
delayAsFloat(delay2, EarlyLate::early(), sta));
}
bool
delayLessEqual(const Delay &delay1,
float delay2,
const StaState *sta)
{
return fuzzyLessEqual(delayAsFloat(delay1, EarlyLate::early(), sta),
delay2);
}
bool
delayLessEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
{
if (min_max == MinMax::max())
return delayLessEqual(delay1, delay2, sta);
else
return delayGreaterEqual(delay1, delay2, sta);
}
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const StaState *sta)
{
return fuzzyGreater(delayAsFloat(delay1, EarlyLate::late(), sta),
delayAsFloat(delay2, EarlyLate::late(), sta));
}
bool
delayGreater(const Delay &delay1,
float delay2,
const StaState *sta)
{
return fuzzyGreater(delayAsFloat(delay1, EarlyLate::late(), sta),
delay2);
}
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const StaState *sta)
{
return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta),
delayAsFloat(delay2, EarlyLate::late(), sta));
}
bool
delayGreaterEqual(const Delay &delay1,
float delay2,
const StaState *sta)
{
return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta),
delay2);
}
bool
delayGreater(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
{
if (min_max == MinMax::max())
return delayGreater(delay1, delay2, sta);
else
return delayLess(delay1, delay2, sta);
}
bool
delayGreaterEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max,
const StaState *sta)
{
if (min_max == MinMax::max())
return delayGreaterEqual(delay1, delay2, sta);
else
return delayLessEqual(delay1, delay2, sta);
}
Delay
delayRemove(const Delay &delay1,
const Delay &delay2)
{
return Delay(delay1.mean() - delay2.mean(),
delay1.sigma2() - delay2.sigma2());
}
float
delayRatio(const Delay &delay1,
const Delay &delay2)
{
return delay1.mean() / delay2.mean();
}
Delay
operator+(float delay1,
const Delay &delay2)
{
return Delay(delay1 + delay2.mean(),
delay2.sigma2());
}
Delay
operator/(float delay1,
const Delay &delay2)
{
return Delay(delay1 / delay2.mean(),
delay2.sigma2());
}
Delay
operator*(const Delay &delay1,
float delay2)
{
return Delay(delay1.mean() * delay2,
delay1.sigma2() * delay2 * delay2);
}
} // namespace
#endif // (SSTA == 1)
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment