and then there was light...

This commit is contained in:
James Cherry 2018-09-28 08:54:21 -07:00
commit 1154fb89fd
372 changed files with 135394 additions and 0 deletions

92
.gitignore vendored Normal file
View File

@ -0,0 +1,92 @@
*.o
*.a
*.lo
*.la
*.gcov
*.gcda
*.gcno
*.rej
*.orig
TAGS
*~
\#*#
.~lock.*#
.DS_Store
Makefile
Makefile.in
.libs
.deps
# /
/build
/configure
/m4
/compile
/config.*
/libtool
/ltmain.sh
/install-sh
/missing
/depcomp
/ylwrap
/aclocal.m4
/autom4te.cache
/stamp-h1
/ylwrap
# /app/
/app/StaApp_wrap.cc
/app/TclInitVar.cc
/app/sta
/app/sta.exe
/app/sta.dSYM
/app/.dirstamp
# /doc/
/doc/._Sta.docx
/doc/.~lock.Sta.doc#
/doc/.~lock.Sta.odt#
# /liberty/
/liberty/LibertyExprLex.cc
/liberty/LibertyExprParse.cc
/liberty/LibertyExprParse.h
/liberty/LibertyLex.cc
/liberty/LibertyParse.cc
/liberty/LibertyParse.h
/liberty/LibertyExprParse.hh
/liberty/LibertyParse.hh
# /parasitics/
/parasitics/SpefLex.cc
/parasitics/SpefParse.cc
/parasitics/SpefParse.h
/parasitics/SpfLex.cc
/parasitics/SpfParse.cc
/parasitics/SpfParse.h
/parasitics/SpefParse.hh
/parasitics/SpfParse.hh
# /sdf/
/sdf/SdfLex.cc
/sdf/SdfParse.cc
/sdf/SdfParse.h
/sdf/SdfParse.hh
# /tcl/
/tcl/history.tcl
/tcl/init.tcl
# /test/
/test/gmon.out
/test/results
/test_native
# /verilog/
/verilog/VerilogLex.cc
/verilog/VerilogParse.cc
/verilog/VerilogParse.h
/verilog/VerilogParse.output
/verilog/VerilogParse.hh

1
AUTHORS Normal file
View File

@ -0,0 +1 @@
James Cherry, Parallax Software, Inc.

16
COPYING Normal file
View File

@ -0,0 +1,16 @@
# OpenSTA, Static Timing Analyzer
# Copyright (c) 2018, 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/>.

11
ChangeLog Normal file
View File

@ -0,0 +1,11 @@
OpenSTA Static Timing Analyzer Release Notes
--------------------------------------------
This file summarizes user visible changes for each release.
Release 2.0 2018/06/27
----------------------
# Local Variables:
# mode:text
# End:

130
INSTALL Normal file
View File

@ -0,0 +1,130 @@
# OpenSTA, Static Timing Analyzer
# Copyright (c) 2018, 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/>.
Build requirements
------------------
Other versions may work, but these are the versions used for
developing the code.
from Ubuntu Xcode
16.04 9.4
clang 9.1.0
lldb 902.0.79.7
gcc 3.3.2 5.4.0
tcl 8.2 8.6 8.6.6
autoconf 2.53 2.69 2.69
automake 1.6.3 1.15 1.16.1
libtool 1.4.2 2.4.6 2.4.6
swig 1.3.28 3.0.8 3.0.12
bison 1.35 3.04 2.3
flex 2.5.4 2.6.0 2.5.35
These packages are optional:
gdb 5.3 7.11 8.0
valgrind 1.9.6 3.11.0 N/A
libz 1.1.4 1.2.5 1.2.8
cudd 2.4.1 2.5.0
Building from the git repository:
git clone https://xp-dev.com/git/opensta
set branch = master
or
set branch = rel_<version>
git checkout $branch
./bootstrap
./configure [options...]
make
With no options, configure builds an optimized executable.
The resulting executable is app/sta.
configure options:
-h, --help display configure help and exit
--enable-debug enable debug
--enable-asan enable AddressSanitizer
--enable-gprof enable gprof profiling
--enable-gcov enable gcov profiling
--enable-32bit force 32 bit compile
--with-include=dirs directories to search for include files
--with-lib=dirs directories to search for libraries
--with-tcl=dirs directories to search for Tcl init files
--with-cudd=path use Cudd BDD package, defaults to $CUDD
--with-visualstudio use Microcruft Visual Studio C++ compiler
CUDD is a BDD package that is used to improve conditional timing arc
handling. The version used for developing the sta is 2.5.0. It is
available from the following url:
ftp://vlsi.colorado.edu/pub/cudd-2.5.0.tar.gz
The Zlib library is an optional. If it is used, Verilog, SDF, SPF,
and SPEF files compressed with gzip can be read by the STA.
If the configure script fails to find any of the TCL or Zlib files,
use the --with-include, --with-lib, --with-tcl options to add directories
to search for the files.
The -help option lists the generic configure options that are not
described above. The default arguments to configure disable shared
libraries. To build with shared libraries use the --enable-shared
option.
Building on Windoz
------------------
The Win32 API does not natively support the pthreads API. The
pthreads-win32 package is one way to get support for pthreads for 32
bit builds. It is available from www.sourceware.org/pthreads-win32.
If the configure script does not find pthreads.h the build proceeds
without thread support.
Use a .bat file to start a cygwin shell that has its path set to
support the Microcruft cl compiler by calling the vsvars32.bat script
from the Visual C++ installation.
tcsh-startup.bat
@echo off
call "c:\Microsoft Visual Studio 9.0\Common7\Tools\vsvars.bat"
set path=c:\cygwin\bin;%PATH%
c:\cygwin\bin\tcsh
Configure and build from the shell. Note that tcl and zlib must be
built with the Visual C++ compiler to link to the sta libraries.
./bootstrap
./configure --with-visualstudio
# Rebuild flex/bison files because include files are different.
make maintainer-clean
Good luck and don't bother me with windoz specific issues.
I am happy to say I haven't owned a windoz machine in 20 years.
Submitting Bug Reports
----------------------
Mail bug reports to bugs@parallaxsw.com.
All bug reports should attach a testcase, preferably in the following
form:
A gzip'd tar file that unpacks into a directory with the same name as the tar file
A file named README that describes the problem
All commands in one .tcl file (usually run.tcl) for small cases
No calls to "exit"
No shell scripts to envoke the sta

35
Makefile.am Normal file
View File

@ -0,0 +1,35 @@
# OpenSTA, Static Timing Analyzer
# Copyright (c) 2018, 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/>.
ACLOCAL_AMFLAGS = -I m4
# app has to follow all library subdirs
SUBDIRS = $(STA_SUBDIRS)
libs:
for subdir in $(SUBDIRS); do \
(cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) libs); \
done
include_HEADERS = config.h
# The automake target uses include directives, which don't work in xemacs.
xtags:
rm -rf TAGS; \
for subdir in $(SUBDIRS); do \
(cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) xtags); \
done

1
NEWS Normal file
View File

@ -0,0 +1 @@
See doc/BugLog for bug fixes in this release.

59
README Normal file
View File

@ -0,0 +1,59 @@
# OpenSTA, Static Timing Analyzer
# Copyright (c) 2018, 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/>.
Parallax Gate Level Static Timing Analyzer
See INSTALL for build instructions.
Standard file formats
Verilog
Liberty
SDC
SDF
RSPF/DSPF/SPEF
Exception path support
False path
Multicycle path
Min/Max 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
Clocks
Generated
Latency
Source latency (insertion delay)
Uncertainty
Propagated/Ideal
Gated clock checks
Multiple frequency clocks
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
Search Engine
Query based incremental update of delays, arrival and required times
Simulator to propagate constants from constraints and netlist tie high/low
Timing engine library
Network adapter uses external netlist database without duplicating any data

50
app/Main.cc Normal file
View File

@ -0,0 +1,50 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 <stdio.h>
#include "Machine.hh"
#include "config.h" // VERSION
#include "StringUtil.hh"
#include "Sta.hh"
#include "StaMain.hh"
using sta::stringEq;
using sta::Sta;
using sta::staMain;
using sta::showUseage;
// Swig uses C linkage for init functions.
extern "C" {
extern int Sta_Init(Tcl_Interp *interp);
}
int
main(int argc, char **argv)
{
if (argc == 2 && stringEq(argv[1], "-help")) {
showUseage(argv[0]);
return 0;
}
else if (argc == 2 && stringEq(argv[1], "-version")) {
printf("%s\n", VERSION);
return 0;
}
else {
Sta *sta = new Sta;
staMain(sta, argc, argv, Sta_Init);
return 0;
}
}

62
app/Makefile.am Normal file
View File

@ -0,0 +1,62 @@
# OpenSTA, Static Timing Analyzer
# Copyright (c) 2018, 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/>.
bin_PROGRAMS = sta
include_HEADERS = \
StaMain.hh
sta_SOURCES = \
Main.cc \
StaMain.cc \
StaApp_wrap.cc \
TclInitVar.cc
NETWORK_LIBS = \
../verilog/libverilog.la
sta_DEPENDENCIES = $(NETWORK_LIBS) $(STA_LIBS) $(CUDD_LIBS)
sta_LDADD = $(NETWORK_LIBS) $(STA_LIBS) $(CUDD_LIBS)
StaApp_wrap.cc: $(SWIG_DEPEND) StaApp.i ../verilog/Verilog.i
$(SWIG) $(SWIG_FLAGS) -namespace -prefix sta \
-o StaApp_wrap.cc StaApp.i
../etc/SwigCleanup.tcl StaApp_wrap.cc
# TCL files included as part of the executable.
# These files are encoded and shipped as part of the executable
# so that they do not have to be installed on the client host.
TclInitVar.cc: ../etc/TclEncode.tcl $(TCL_INIT_FILES)
../etc/TclEncode.tcl TclInitVar.cc "tcl_inits" $(TCL_INIT_DIR) \
$(TCL_INIT_FILES) ../verilog/Verilog.tcl
EXTRA_DIST = \
StaApp.i
# TclInitVar.cc is derived and TCL version specific, so don't dist it.
dist-hook:
rm -rf $(distdir)/TclInitVar.cc
MAINTAINERCLEANFILES = \
StaApp_wrap.cc \
TclInitVar.cc
libs: $(sta_OBJECTS)
xtags: $(SOURCES) $(HEADERS)
etags -a -o ../TAGS $(SOURCES) $(HEADERS)

25
app/StaApp.i Normal file
View File

@ -0,0 +1,25 @@
%module sta
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 "../tcl/StaException.i"
%include "../tcl/StaTcl.i"
%include "../verilog/Verilog.i"
%include "../tcl/NetworkEdit.i"
%include "../sdf/Sdf.i"
%include "../dcalc/DelayCalc.i"
%include "../parasitics/Parasitics.i"

239
app/StaMain.cc Normal file
View File

@ -0,0 +1,239 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 <tcl.h>
#include <stdlib.h>
#include "Machine.hh"
#include "StringUtil.hh"
#include "Vector.hh"
#include "Sta.hh"
#include "StaMain.hh"
namespace sta {
typedef sta::Vector<SwigInitFunc> SwigInitFuncSeq;
// "Arguments" passed to staTclAppInit.
static int sta_argc;
static char **sta_argv;
static SwigInitFunc sta_swig_init;
static bool sta_native_cmds;
static bool sta_compatibility_cmds;
static const char *init_filename = "[file join $env(HOME) .sta]";
extern const char *tcl_inits[];
static void
sourceTclFileEchoVerbose(const char *filename,
Tcl_Interp *interp);
void
staMain(Sta *sta,
int argc,
char **argv,
SwigInitFunc swig_init)
{
initSta();
Sta::setSta(sta);
sta->makeComponents();
int thread_count = 1;
bool threads_exists = false;
parseThreadsArg(argc, argv, thread_count, threads_exists);
if (threads_exists)
sta->setThreadCount(thread_count);
bool native_cmds, compatibility_cmds;
parseCmdsArg(argc, argv, native_cmds, compatibility_cmds);
staSetupAppInit(argc, argv, swig_init, native_cmds, compatibility_cmds);
// Set argc to 1 so Tcl_Main doesn't source any files.
// Tcl_Main never returns.
Tcl_Main(1, argv, staTclAppInit);
}
void
parseThreadsArg(int argc,
char **argv,
int &thread_count,
bool &exists)
{
char *thread_arg = findCmdLineKey(argc, argv, "-threads");
if (thread_arg) {
if (stringEqual(thread_arg, "max")) {
thread_count = processorCount();
exists = true;
}
else if (isDigits(thread_arg)) {
thread_count = atoi(thread_arg);
exists = true;
}
else
fprintf(stderr,"Warning: -threads must be max or a positive integer.\n");
}
}
void
parseCmdsArg(int argc,
char **argv,
bool &native_cmds,
bool &compatibility_cmds)
{
native_cmds = findCmdLineFlag(argc, argv, "-native");
compatibility_cmds = findCmdLineFlag(argc, argv, "-compatibility");
if (!native_cmds && !compatibility_cmds)
compatibility_cmds = true; // default
}
// Set globals to pass to staTclAppInit.
void
staSetupAppInit(int argc,
char **argv,
SwigInitFunc swig_init,
bool native_cmds,
bool compatibility_cmds)
{
sta_argc = argc;
sta_argv = argv;
sta_swig_init = swig_init;
sta_native_cmds = native_cmds;
sta_compatibility_cmds = compatibility_cmds;
}
// Tcl init executed inside Tcl_Main.
int
staTclAppInit(Tcl_Interp *interp)
{
int argc = sta_argc;
char **argv = sta_argv;
// Define swig commands.
sta_swig_init(interp);
Sta *sta = Sta::sta();
sta->setTclInterp(interp);
// Eval encoded sta TCL sources.
evalTclInit(interp, tcl_inits);
if (!findCmdLineFlag(argc, argv, "-no_splash"))
Tcl_Eval(interp, "sta::show_splash");
// Import exported commands from sta namespace to global namespace.
Tcl_Eval(interp, "sta::define_sta_cmds");
const char *export_cmds = "namespace import sta::*";
Tcl_Eval(interp, export_cmds);
if (!findCmdLineFlag(argc, argv, "-no_init"))
sourceTclFileEchoVerbose(init_filename, interp);
// "-x cmd" is evaled before -f file is sourced.
char *cmd = findCmdLineKey(argc, argv, "-x");
if (cmd)
Tcl_Eval(interp, cmd);
// "-f cmd_file" is evaled as "source -echo -verbose file".
char *file = findCmdLineKey(argc, argv, "-f");
if (file)
sourceTclFileEchoVerbose(file, interp);
return TCL_OK;
}
bool
findCmdLineFlag(int argc,
char **argv,
const char *flag)
{
for (int argi = 1; argi < argc; argi++) {
char *arg = argv[argi];
if (stringEq(arg, flag))
return true;
}
return false;
}
char *
findCmdLineKey(int argc,
char **argv,
const char *key)
{
for (int argi = 1; argi < argc; argi++) {
char *arg = argv[argi];
if (stringEq(arg, key) && argi + 1 < argc)
return argv[argi + 1];
}
return 0;
}
// Use overridden version of source to echo cmds and results.
static void
sourceTclFileEchoVerbose(const char *filename,
Tcl_Interp *interp)
{
const char *source_cmd = "source -echo -verbose ";
size_t cmd_length = strlen(source_cmd) + strlen(filename) + 1;
char *cmd = stringPrint(cmd_length, "%s%s", source_cmd, filename);
Tcl_Eval(interp, cmd);
delete [] cmd;
}
void
evalTclInit(Tcl_Interp *interp,
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';
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 app/TclInitVar.cc and rebuilding.\n");
exit(0);
}
delete [] unencoded;
}
void
showUseage(char *prog)
{
printf("Usage: %s [-help] [-version] [-no_init] [-f cmd_file]\n", prog);
printf(" -help show help and exit\n");
printf(" -version show version and exit\n");
printf(" -no_init do not read .sta init file\n");
printf(" -x cmd evaluate cmd\n");
printf(" -f cmd_file source cmd_file\n");
printf(" -threads count|max use count threads\n");
}
} // namespace

79
app/StaMain.hh Normal file
View File

@ -0,0 +1,79 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_APP_H
#define STA_APP_H
struct Tcl_Interp;
namespace sta {
typedef int (*SwigInitFunc)(Tcl_Interp *);
// The swig_init function is called to define the swig interface
// functions to the tcl interpreter.
void
staMain(Sta *sta,
int argc,
char **argv,
SwigInitFunc swig_init);
// Set arguments passed to staTclAppInit inside the tcl interpreter.
void
staSetupAppInit(int argc,
char **argv,
SwigInitFunc swig_init,
bool native_cmds,
bool compatibility_cmds);
// The variable tcl_init is an implicit argument to this function that
// provides the definitions for builtin tcl commands encoded by
// etc/TclEncode.tcl.
int
staTclAppInit(Tcl_Interp *interp);
// TCL init files are encoded into the string init using the three
// digit decimal equivalent for each ascii character. This function
// unencodes the string and evals it. This packages the TCL init
// files as part of the executable so they don't have to be shipped as
// separate files that have to be located and loaded at run time.
void
evalTclInit(Tcl_Interp *interp,
const char *inits[]);
bool
findCmdLineFlag(int argc,
char **argv,
const char *flag);
char *
findCmdLineKey(int argc,
char **argv,
const char *key);
void
showUseage(char *prog);
void
parseThreadsArg(int argc,
char **argv,
int &threads,
bool &exists);
void
parseCmdsArg(int argc,
char **argv,
bool &native_cmds,
bool &compatibility_cmds);
} // namespace
#endif

3
bootstrap Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
autoreconf --install

580
configure.ac Normal file
View File

@ -0,0 +1,580 @@
# OpenSTA, Static Timing Analyzer
# Copyright (c) 2018, 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/>.
# Process this file with autoconf to produce a configure script.
AC_INIT(sta, 2.0)
AM_INIT_AUTOMAKE
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS(config.h)
#--------------------------------------------------------------------
# Set default paths.
#--------------------------------------------------------------------
AC_ARG_ENABLE(32bit,
[AS_HELP_STRING([--enable-32bit],[force 32 bit compile])],
[case "${enableval}" in
yes) force32bit=true ;;
no) force32bit=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-32bit) ;;
esac],
[force32bit=false])
HOST_ARCH=`uname -m`
HOST_OS=`uname -s`
if test x$force32bit = xtrue; then
HOST_ARCH=i686
fi
echo -n "checking host... "
case "${HOST_OS}" in
*Linux*)
case "${HOST_ARCH}" in
i?86)
echo "Linux 32bit"
INCLUDE_DIRS="/usr/include"
LIB_DIRS="/usr/lib /usr/local/lib /usr/lib/i386-linux-gnu"
LIB_EXTS="a so .so.1"
TCL_INIT_DIRS="/usr/lib/tcl /usr/lib /usr/share/tcltk"
;;
x86_64)
echo "Linux 64bit"
INCLUDE_DIRS="/usr/include"
LIB_DIRS="/usr/lib64 /usr/lib /usr/lib/x86_64-linux-gnu"
LIB_EXTS="a so"
TCL_INIT_DIRS="/usr/lib64/tcl /usr/lib /usr/share/tcltk /usr/share"
;;
*)
echo "Linux unknown"
INCLUDE_DIRS="/usr/include"
LIB_DIRS="/usr/lib"
LIB_EXTS="a so"
TCL_INIT_DIRS="/usr/lib/tcl /usr/lib"
;;
esac
;;
CYGWIN*)
echo "Cygwin"
INCLUDE_DIRS="/usr/include"
LIB_DIRS="/usr/lib"
LIB_EXTS="a so"
TCL_INIT_DIRS="/usr/share"
;;
Darwin)
echo "Darwin"
use_clang=true
if test x$use_clang = xtrue; then
# clang/gcc-apple llvm
CXX=clang++
CC=clang++
INCLUDE_DIRS="/usr/local/include /usr/include"
LIB_DIRS="/usr/local/lib /usr/lib"
TCL_INIT_DIRS="/usr/local/lib/tcl8.6"
else
# gcc
CXX=g++
CC=g++
INCLUDE_DIRS="/usr/local/opt/tcl-tk/include /usr/local/opt/zlib/include /usr/include"
LIB_DIRS="/usr/local/opt/tcl-tk/lib /usr/local/opt/zlib/lib /usr/local/lib"
TCL_INIT_DIRS="/usr/local/opt/tcl-tk/lib/tcl8.6"
fi
LIB_EXTS="dylib"
;;
*)
echo "Unknown"
INCLUDE_DIRS="/usr/include /usr/local/include"
LIB_DIRS="/usr/lib /usr/local/lib"
LIB_EXTS="a so"
TCL_INIT_DIRS="/usr/lib/tcl /usr/share /usr/share/tcl"
;;
esac
#--------------------------------------------------------------------
AC_ARG_ENABLE(debug,
[AS_HELP_STRING([--enable-debug],[enable debug])],
[case "${enableval}" in
yes) debug=true ;;
no) debug=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-debug) ;;
esac],
[debug=false])
AC_ARG_ENABLE(gprof,
[AS_HELP_STRING([--enable-gprof],[enable gprof profiling])],
[case "${enableval}" in
yes) gprof=true ;;
no) gprof=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-gprof) ;;
esac],
[gprof=false])
AC_ARG_ENABLE(gcov,
[AS_HELP_STRING([--enable-gcov],[enable gcov profiling])],
[case "${enableval}" in
yes) gcov=true ;;
no) gcov=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --with-gcov) ;;
esac],
[gcov=false])
AC_ARG_ENABLE(asan,
[AS_HELP_STRING([--enable-asan],[enable AddressSanitizer])],
[case "${enableval}" in
yes) asan=true ;;
no) asan=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-asan) ;;
esac],
[asan=false])
AC_ARG_WITH(include,
[AS_HELP_STRING([--with-include=dirs],[directories to search for include files])],
[INCLUDE_DIRS="${withval}"],
[])
AC_ARG_WITH(lib,
[AS_HELP_STRING([--with-lib=dirs],[directories to search for libraries])],
[LIB_DIRS="${withval}"],
[])
AC_ARG_WITH(tcl,
[AS_HELP_STRING([--with-tcl=dirs],[directories to search for Tcl init files])],
[TCL_INIT_DIRS="${withval}"],
[])
AC_ARG_WITH(cudd,
[AS_HELP_STRING([--with-cudd=path],[use Cudd BDD package, defaults to $CUDD])],
[CUDD_ARG="${withval}"],
[CUDD_ARG=$CUDD])
AC_ARG_WITH(visualstudio,
[AS_HELP_STRING([--with-visualstudio],[use Microcruft Visual Studio C++ compiler])],
[case "${withval}" in
yes) visualstudio=true ;;
no) visualstudio=false ;;
*) AC_MSG_ERROR(bad value ${withval} for --with-visualstudio) ;;
esac],
[visualstudio=false])
if test x$visualstudio = xtrue; then
CXX=cl
CC=cl
LIB_EXTS="lib"
fi
AC_ARG_WITH(optimize,
[AS_HELP_STRING([--with-optimize],[obsolete; optimization is on by default])],
[],
[])
#--------------------------------------------------------------------
# Locate the Tcl package
#--------------------------------------------------------------------
TCL_INCLUDE=""
tcl_major="8"
tcl_minors="6 5 4 3 2"
for tcl_minor in $tcl_minors; do
AC_MSG_CHECKING(for Tcl $tcl_major.$tcl_minor header file)
found_tcl_header=false
for dir in $INCLUDE_DIRS ; do
tcl_header=$dir/tcl.h
if test -r $tcl_header; then
AC_MSG_RESULT($tcl_header)
TCL_INCLUDE=$dir
found_tcl_header=true
break
fi
dir2=$dir/tcl$tcl_major.$tcl_minor
tcl_header=$dir2/tcl.h
if test -r $tcl_header; then
AC_MSG_RESULT($tcl_header)
TCL_INCLUDE=$dir2
found_tcl_header=true
break
fi
done
if test -z "$TCL_INCLUDE"; then
AC_MSG_RESULT(not found)
fi
AC_MSG_CHECKING(for Tcl $tcl_major.$tcl_minor library)
TCL_LIB=""
for dir in $LIB_DIRS ; do
for ext in $LIB_EXTS; do
# With period between tcl_major/tcl_minor.
lib=tcl$tcl_major.$tcl_minor
lib_path="$dir/lib$lib.$ext"
if test -r $lib_path; then
AC_MSG_RESULT($lib_path)
TCL_LIB_DIR=$dir
TCL_LIB=$lib
break 2
fi
# Without period between major/minor.
lib=tcl$tcl_major$tcl_minor
lib_path="$dir/lib$lib.$ext"
if test -r $lib_path; then
AC_MSG_RESULT($lib_path)
TCL_LIB_DIR=$dir
TCL_LIB=$lib
break 2
fi
# Without leading lib or period between major/minor (windoz).
lib=tcl$tcl_major$tcl_minor
lib_path="$dir/$lib.$ext"
if test -r $lib_path; then
AC_MSG_RESULT($lib_path)
TCL_LIB_DIR=$dir
TCL_LIB=$lib
break 2
fi
done
done
if test -z "$TCL_LIB"; then
AC_MSG_RESULT(not found)
fi
AC_MSG_CHECKING(for Tcl $tcl_major.$tcl_minor init files)
TCL_INIT_DIR=""
for dir in $TCL_INIT_DIRS ; do
init_dir=$dir
init_path="$dir/init.tcl"
if test -r $init_path; then
AC_MSG_RESULT($init_path)
TCL_INIT_DIR="$init_dir"
break
fi
init_dir="$dir/tcl$tcl_major.$tcl_minor"
init_path="$init_dir/init.tcl"
if test -r $init_path; then
AC_MSG_RESULT($init_path)
TCL_INIT_DIR="$init_dir"
break
fi
done
if test -z "$TCL_INIT_DIR"; then
AC_MSG_RESULT(not found)
fi
if test $found_tcl_header = true &&
test -n "$TCL_LIB" &&
test -n "$TCL_INIT_DIR"; then
break
fi
done
AC_SUBST(TCL_INIT_DIR, $TCL_INIT_DIR)
#--------------------------------------------------------------------
# Locate the Zlib package
#--------------------------------------------------------------------
AC_MSG_CHECKING(for Zlib header file)
ZLIB_INCLUDE=""
for dir in $INCLUDE_DIRS ; do
if test -r $dir/zlib.h; then
AC_MSG_RESULT($dir)
ZLIB_INCLUDE=$dir
AC_DEFINE(ZLIB, 1, "Zlib compressed file reader")
break
fi
done
if test -z "$ZLIB_INCLUDE"; then
AC_MSG_RESULT(not found)
fi
AC_MSG_CHECKING(for Zlib library)
ZLIB_LIB=""
for dir in $LIB_DIRS ; do
for ext in $LIB_EXTS; do
lib_path="$dir/libz.$ext"
if test -r $lib_path; then
AC_MSG_RESULT($lib_path)
ZLIB_DIR=$dir
ZLIB_LIB="z"
break 2
fi
done
done
if test -z "$ZLIB_LIB"; then
AC_MSG_RESULT(not found)
fi
AC_SUBST(ZLIB_INCLUDE)
AC_SUBST(ZLIB_LIB)
#--------------------------------------------------------------------
# Locate the Cudd package
#--------------------------------------------------------------------
CUDD_INCLUDE=""
CUDD_LIBS=""
if test "$CUDD_ARG"; then
AC_MSG_CHECKING(for Cudd header file)
CUDD_INCLUDE_DIR="$CUDD_ARG/include"
CUDD_HEADER="$CUDD_INCLUDE_DIR/cudd.h"
if test -r "$CUDD_HEADER"; then
AC_MSG_RESULT($CUDD_HEADER)
CUDD_INCLUDE=$CUDD_INCLUDE_DIR
AC_DEFINE(CUDD, 1, "Cudd bdd package")
else
AC_MSG_RESULT(not found)
fi
AC_MSG_CHECKING(for Cudd library)
CUDD_LIB_EXT="a"
CUDD_LIB="$CUDD_ARG/cudd/libcudd.$CUDD_LIB_EXT"
if test -r $CUDD_LIB; then
AC_MSG_RESULT($CUDD_LIB)
CUDD_LIBS="$CUDD_ARG/cudd/libcudd.$CUDD_LIB_EXT $CUDD_ARG/mtr/libmtr.$CUDD_LIB_EXT $CUDD_ARG/st/libst.$CUDD_LIB_EXT $CUDD_ARG/util/libutil.$CUDD_LIB_EXT $CUDD_ARG/epd/libepd.$CUDD_LIB_EXT"
else
AC_MSG_RESULT(not found)
fi
fi
AC_SUBST(CUDD_LIBS)
#--------------------------------------------------------------------
# Checks for programs.
AC_PROG_CXX
# Disable shared libraries by default.
AC_DISABLE_SHARED
AC_PROG_AWK
AC_PROG_YACC
AM_PROG_LEX
AC_PROG_INSTALL
AC_PROG_LN_S
AC_PROG_MAKE_SET
# Checks for header files.
AC_CHECK_HEADERS(malloc.h)
AC_CHECK_HEADERS(limits.h)
AC_CHECK_HEADERS(strings.h)
AC_CHECK_HEADERS(stddef.h)
AC_CHECK_HEADERS(inttypes.h)
AC_CHECK_HEADERS(float.h)
AC_CHECK_HEADERS(pthread.h, HAVE_PTHREAD=true, HAVE_PTHREAD=false)
AC_CHECK_HEADERS([sys/time.h])
AC_HEADER_STDBOOL
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
# Checks for library functions.
AC_FUNC_MALLOC
AC_FUNC_VPRINTF
AC_FUNC_STRTOD
AC_TYPE_SIZE_T
AC_CHECK_FUNC(strdup)
AC_CHECK_FUNC(strstr)
AC_CHECK_FUNC(strchr)
AC_CHECK_FUNC(strrchr)
AC_CHECK_FUNC(strpbrk)
AC_CHECK_FUNC(strtol)
AC_CHECK_FUNC(strtoul)
AC_CHECK_FUNC(strcasecmp)
AC_CHECK_FUNC(strncasecmp)
AC_CHECK_FUNC(gettimeofday)
AC_CHECK_FUNC(sqrt)
AC_CHECK_FUNC(memset)
AC_C_INLINE
AC_FUNC_ERROR_AT_LINE
#--------------------------------------------------------------------
if test $CXX = clang++; then
# -Wno-deprecated-register to suppress warnings in flex files
CXXFLAGS="-std=c++11 -Wno-deprecated-register -Wcast-qual -pipe"
CXX_OPT="-O3"
CXX_DEBUG="-g"
CXX_ASAN="-fsanitize=address -O1 -fno-omit-frame-pointer"
CXX_LD=$CXX
LDFLAGS="-stdlib=libc++"
if test x$HAVE_PTHREAD = xtrue; then
LDFLAGS="$LDFLAGS -lpthread"
fi
if test "$TCL_LIB"; then
LDFLAGS="$LDFLAGS -L$TCL_LIB_DIR -l$TCL_LIB"
fi
if test "$ZLIB_LIB"; then
LDFLAGS="$LDFLAGS -L$ZLIB_DIR -l$ZLIB_LIB"
fi
elif test x$GXX = xyes; then
# Use GCC_EXTRA_FLAGS for local flags.
# -Wno-deprecated-register to suppress warnings in flex files
CXXFLAGS="-std=c++11 -Wall -Wextra -Wpointer-arith -Wcast-qual -Wno-deprecated-register -pipe $GCC_EXTRA_FLAGS"
if test x$force32bit = xtrue; then
CXXFLAGS="$CXXCFLAGS -m32"
fi
CXX_OPT="-O3"
CXX_DEBUG="-g"
CXX_GPROF="-pg -g"
CXX_GCOV="-fprofile-arcs -ftest-coverage"
CXX_LD=$CXX
LDFLAGS=""
if test x$HAVE_PTHREAD = xtrue; then
LDFLAGS="$LDFLAGS -lpthread"
fi
if test "$TCL_LIB"; then
LDFLAGS="$LDFLAGS -L$TCL_LIB_DIR -l$TCL_LIB"
fi
if test "$ZLIB_LIB"; then
LDFLAGS="$LDFLAGS -L$ZLIB_DIR -l$ZLIB_LIB"
fi
elif test x$visualstudio = xtrue; then
# /Zc:forScope force conformance in for Loop scope
# /EHa use c++ exception handling
# /W3 display level 3 warnings
# /WL one line diagnostics
# /c compiles without linking
# /GR enable run time type info (RTTI)
CXX_FLAGS="/nologo /Zc:forScope /EHa /W3 /WL /c /GR"
# /MDd use debug version of vc runtime library.
# /RTC1 run time error check use of uninitialized variable, initialize stack
# variables to non-zero value
# /GS buffer security check
# /Z7 symbolic debugging info
# /Od disable optimization
CXX_DEBUG="/MDd /RTC1 /GS /Z7 /Od"
# /MD use optimized version of vc runtime library.
# /Ox full optimization
# /G7 ??
# /Gy enable function level linking
CXX_OPT="/MD /Ox /G7 /Gy"
CXX_GPROF=""
CXX_GCOV=""
CXX_LD="link"
LDFLAGS="/nologo /SUBSYSTEM:CONSOLE /OPT:REF /IGNORE:4089 /NODEFAULTLIB:MSVCRT user32.lib advapi32.lib /OUT:sta"
if test "$TCL_LIB"; then
LDFLAGS="$LDFLAGS `cygpath -m $TCL_LIB_DIR/$TCL_LIB.$LIB_EXTS`"
fi
if test "$ZLIB_LIB"; then
LDFLAGS="$LDFLAGS `cygpath -m $ZLIB_DIR/$ZLIB_LIB.$LIB_EXTS`"
fi
if test "$TCL_INCLUDE"; then
TCL_INCLUDE=`cygpath -m $TCL_INCLUDE`
fi
if test "$ZLIB_INCLUDE"; then
ZLIB_INCLUDE=`cygpath -m $ZLIB_INCLUDE`
fi
if test "$CUDD_INCLUDE"; then
CUDD_INCLUDE=`cygpath -m $CUDD_INCLUDE`
fi
fi
if test x$debug = xtrue; then
CXXFLAGS+=" $CXX_DEBUG"
elif test x$optimize = xtrue; then
CXXFLAGS+=" $CXX_OPT"
elif test x$gprof = xtrue; then
if test $CXX = clang++; then
echo "clang does not support gprof"
exit
fi
CXXFLAGS+=" $CXX_GPROF"
LDFLAGS+=" $CXX_GPROF"
elif test x$asan = xtrue; then
CXXFLAGS+=" $CXX_ASAN"
elif test x$gcov = xtrue; then
CXXFLAGS+=" $CXX_GCOV"
LDFLAGS+=" $CXX_GCOV"
else
# optimize by default
CXXFLAGS+=" $CXX_OPT"
fi
YFLAGS="-d -p \$*_"
AC_SUBST(YFLAGS)
SWIG=swig
AC_SUBST(SWIG)
SWIG_FLAGS="-tcl8 -c++"
AC_SUBST(SWIG_FLAGS)
# The subdirectory app has to follow all library subdirs.
STA_SUBDIRS="util liberty network graph sdc sdf parasitics dcalc search tcl doc etc verilog app"
STA_INCLUDE="-I.. -I../util -I../liberty -I../network -I../graph -I../sdc -I../sdf -I../parasitics -I../dcalc -I../search -I../verilog -I../app"
STA_LIBS="../search/libsearch.la ../sdf/libsdf.la ../graph/libgraph.la ../dcalc/libdcalc.la ../parasitics/libparasitics.la ../sdc/libsdc.la ../liberty/libliberty.la ../network/libnetwork.la ../util/libutil.la"
SWIG_DEPEND="../tcl/StaException.i ../tcl/StaTcl.i ../tcl/NetworkEdit.i ../sdf/Sdf.i ../dcalc/DelayCalc.i ../parasitics/Parasitics.i ../tcl/StaTcl.i"
TCL_INIT_FILES="../tcl/Util.tcl ../dcalc/DelayCalc.tcl ../tcl/Graph.tcl ../tcl/Liberty.tcl ../tcl/Link.tcl ../tcl/Network.tcl ../tcl/NetworkEdit.tcl ../parasitics/Parasitics.tcl ../tcl/Sdc.tcl ../sdf/Sdf.tcl ../tcl/Search.tcl ../tcl/Cmds.tcl ../tcl/Variables.tcl ../tcl/Sta.tcl ../tcl/Splash.tcl"
if test "$TCL_INCLUDE"; then
STA_INCLUDE="$STA_INCLUDE -I$TCL_INCLUDE"
fi
if test "$ZLIB_INCLUDE"; then
STA_INCLUDE="$STA_INCLUDE -I$ZLIB_INCLUDE"
fi
if test "$CUDD_INCLUDE"; then
STA_INCLUDE="$STA_INCLUDE -I$CUDD_INCLUDE"
fi
AC_SUBST(STA_INCLUDE)
AC_SUBST(STA_LIBS)
AC_SUBST(TCL_INIT_FILES)
AC_SUBST(SWIG_DEPEND)
AM_CPPFLAGS=$STA_INCLUDE
AC_SUBST(AM_CPPFLAGS)
# libtool generation has to be after AR/AR_FLAGS are set.
AC_PROG_LIBTOOL
AC_CONFIG_FILES(Makefile)
AC_CONFIG_FILES(util/Makefile)
AC_CONFIG_FILES(liberty/Makefile)
AC_CONFIG_FILES(network/Makefile)
AC_CONFIG_FILES(verilog/Makefile)
AC_CONFIG_FILES(graph/Makefile)
AC_CONFIG_FILES(sdc/Makefile)
AC_CONFIG_FILES(sdf/Makefile)
AC_CONFIG_FILES(parasitics/Makefile)
AC_CONFIG_FILES(dcalc/Makefile)
AC_CONFIG_FILES(search/Makefile)
AC_CONFIG_FILES(tcl/Makefile)
AC_CONFIG_FILES(doc/Makefile)
AC_CONFIG_FILES(etc/Makefile)
AC_CONFIG_FILES(app/Makefile)
# Pass $STA_SUBDIRS to Makefile.am.
AC_SUBST(STA_SUBDIRS)
AC_OUTPUT

54
dcalc/ArcDelayCalc.cc Normal file
View File

@ -0,0 +1,54 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 "TimingModel.hh"
#include "TimingArc.hh"
#include "GraphDelayCalc.hh"
#include "ArcDelayCalc.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

143
dcalc/ArcDelayCalc.hh Normal file
View File

@ -0,0 +1,143 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_ARC_DELAY_CALC_H
#define STA_ARC_DELAY_CALC_H
#include <string>
#include "DisallowCopyAssign.hh"
#include "MinMax.hh"
#include "Delay.hh"
#include "StaState.hh"
#include "LibertyClass.hh"
#include "NetworkClass.hh"
namespace sta {
using std::string;
class Parasitic;
class DcalcAnalysisPt;
// Delay calculator class hierarchy.
// ArcDelayCalc
// UnitDelayCalc
// LumpedCapDelayCalc
// RCDelayCalc
// SimpleRCDelayCalc
// DmpCeffDelayCalc
// DmpCeffElmoreDelayCalc
// DmpCeffTwoPoleDelayCalc
// Abstract class to interface to a delay calculator primitive.
class ArcDelayCalc : public StaState
{
public:
explicit ArcDelayCalc(StaState *sta);
virtual ~ArcDelayCalc() {}
virtual ArcDelayCalc *copy() = 0;
// Find the parasitic for drvr_pin that is acceptable to the delay
// calculator by probing parasitics_.
virtual void findParasitic(const Pin *drvr_pin,
const TransRiseFall *tr,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
Parasitic *&parasitic,
bool &delete_at_finish) = 0;
// Call after the parasitic returned by findParasitic is no longer
// needed. This gives the arc delay calculator a chance to delete
// temporary estimated or reduced parasitics. The default action is
// to do nothing.
virtual void finish(const Pin *drvr_pin,
const TransRiseFall *tr,
const DcalcAnalysisPt *dcalc_ap,
Parasitic *parasitic,
bool delete_at_finish) = 0;
// Find the wire delays and slews for an input port without a driving cell.
// This call primarily initializes the load delay/slew iterator.
virtual void inputPortDelay(const Pin *port_pin,
float in_slew,
const TransRiseFall *tr,
Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap) = 0;
// Find the delay and slew for arc driving drvr_pin.
virtual void gateDelay(const LibertyCell *drvr_cell,
TimingArc *arc,
const Slew &in_slew,
// Pass in load_cap or drvr_parasitic.
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) = 0;
// Find the wire delay and load slew of a load pin.
// Called after inputPortDelay or gateDelay.
virtual void loadDelay(const Pin *load_pin,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew) = 0;
virtual void setMultiDrvrSlewFactor(float factor) = 0;
// Find the delay for a timing check arc given the arc's
// from/clock, to/data slews and related output pin parasitic.
virtual ArcDelay checkDelay(const LibertyCell *drvr_cell,
TimingArc *arc,
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap) = 0;
// Report delay and slew calculation.
virtual void reportGateDelay(const LibertyCell *drvr_cell,
TimingArc *arc,
const Slew &in_slew,
// Pass in load_cap or drvr_parasitic.
float load_cap,
Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
int digits,
string *result) = 0;
// Report timing check delay calculation.
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) = 0;
protected:
GateTimingModel *gateModel(TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const;
CheckTimingModel *checkModel(TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const;
TimingModel *model(TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const;
private:
DISALLOW_COPY_AND_ASSIGN(ArcDelayCalc);
};
} // namespace
#endif

67
dcalc/DcalcAnalysisPt.cc Normal file
View File

@ -0,0 +1,67 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 "DcalcAnalysisPt.hh"
namespace sta {
DcalcAnalysisPt::DcalcAnalysisPt(Corner *corner,
DcalcAPIndex index,
const OperatingConditions *op_cond,
const MinMax *cnst_min_max,
const MinMax *delay_min_max,
const MinMax *slew_min_max,
const MinMax *check_clk_slew_min_max,
const ParasiticAnalysisPt *parasitic_ap) :
corner_(corner),
index_(index),
op_cond_(op_cond),
cnst_min_max_(cnst_min_max),
delay_min_max_(delay_min_max),
slew_min_max_(slew_min_max),
check_clk_slew_min_max_(check_clk_slew_min_max),
parasitic_ap_(parasitic_ap)
{
}
void
DcalcAnalysisPt::setOperatingConditions(const OperatingConditions *op_cond)
{
op_cond_ = op_cond;
}
void
DcalcAnalysisPt::
setParasiticAnalysisPt(const ParasiticAnalysisPt *parasitic_ap)
{
parasitic_ap_ = parasitic_ap;
}
void
DcalcAnalysisPt::setCheckClkSlewIndex(DcalcAPIndex index)
{
check_clk_slew_index_ = index;
}
int
DcalcAnalysisPt::libertyIndex() const
{
return index_; // same for now
}
} // namespace

85
dcalc/DcalcAnalysisPt.hh Normal file
View File

@ -0,0 +1,85 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_DCALC_ANALYSIS_PT_H
#define STA_DCALC_ANALYSIS_PT_H
#include "DisallowCopyAssign.hh"
#include "Iterator.hh"
#include "MinMax.hh"
#include "LibertyClass.hh"
#include "SdcClass.hh"
#include "ParasiticsClass.hh"
#include "GraphClass.hh"
#include "StaState.hh"
namespace sta {
class Corner;
// Delay calculation analysis point.
// This collects all of the parameters used to find one set of
// delay calculation results.
class DcalcAnalysisPt
{
public:
DcalcAnalysisPt(Corner *corner,
DcalcAPIndex index,
const OperatingConditions *op_cond,
const MinMax *cnst_min_max,
const MinMax *delay_min_max,
const MinMax *slew_min_max,
const MinMax *check_clk_slew_min_max,
const ParasiticAnalysisPt *parasitic_ap);
Corner *corner() const { return corner_; }
// Which of the delay_count results this analysis point corresponds to.
DcalcAPIndex index() const { return index_; }
// Slew index of timing check data.
DcalcAPIndex checkDataSlewIndex() const { return index_; }
// Slew index of timing check clock.
DcalcAPIndex checkClkSlewIndex() const { return check_clk_slew_index_; }
// Slew min/max of timing check clock.
const MinMax *checkClkSlewMinMax() const { return check_clk_slew_min_max_; }
// Constraint min/max values to use.
const MinMax *constraintMinMax() const { return cnst_min_max_; }
// Constraints::operatingCondition(cnst_min_max_)
const OperatingConditions *operatingConditions() const { return op_cond_; }
void setOperatingConditions(const OperatingConditions *op_cond);
// Delay merging min/max operator (for wires).
const MinMax *delayMinMax() const { return delay_min_max_; }
// Merge min/max slews across timing arcs.
const MinMax *slewMinMax() const { return slew_min_max_; }
const ParasiticAnalysisPt *parasiticAnalysisPt()const{return parasitic_ap_;}
void setParasiticAnalysisPt(const ParasiticAnalysisPt *parasitic_ap);
void setCheckClkSlewIndex(DcalcAPIndex index);
int libertyIndex() const;
private:
DISALLOW_COPY_AND_ASSIGN(DcalcAnalysisPt);
Corner *corner_;
DcalcAPIndex index_;
DcalcAPIndex check_clk_slew_index_;
const OperatingConditions *op_cond_;
const MinMax *cnst_min_max_;
const MinMax *delay_min_max_;
const MinMax *slew_min_max_;
const MinMax *check_clk_slew_min_max_;
const ParasiticAnalysisPt *parasitic_ap_;
};
} // namespace
#endif

89
dcalc/DelayCalc.cc Normal file
View File

@ -0,0 +1,89 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 "Map.hh"
#include "StringUtil.hh"
#include "UnitDelayCalc.hh"
#include "LumpedCapDelayCalc.hh"
#include "SimpleRCDelayCalc.hh"
#include "DmpDelayCalc.hh"
#include "DelayCalc.hh"
namespace sta {
typedef Map<const char*, MakeArcDelayCalc, CharPtrLess> DelayCalcMap;
static DelayCalcMap *delay_calcs = NULL;
void
registerDelayCalcs()
{
registerDelayCalc("unit", makeUnitDelayCalc);
registerDelayCalc("lumped_cap", makeLumpedCapDelayCalc);
registerDelayCalc("simple_rc", makeSimpleRCDelayCalc);
registerDelayCalc("dmp_ceff_elmore", makeDmpCeffElmoreDelayCalc);
registerDelayCalc("dmp_ceff_two_pole", makeDmpCeffTwoPoleDelayCalc);
}
void
registerDelayCalc(const char *name,
MakeArcDelayCalc maker)
{
if (delay_calcs == NULL)
delay_calcs = new DelayCalcMap;
(*delay_calcs)[name] = maker;
}
void
deleteDelayCalcs()
{
delete delay_calcs;
delay_calcs = NULL;
}
ArcDelayCalc *
makeDelayCalc(const char *name,
StaState *sta)
{
MakeArcDelayCalc maker = delay_calcs->findKey(name);
if (maker)
return maker(sta);
else
return NULL;
}
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

50
dcalc/DelayCalc.hh Normal file
View File

@ -0,0 +1,50 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_DELAY_CALC_H
#define STA_DELAY_CALC_H
#include "StringSeq.hh"
namespace sta {
class ArcDelayCalc;
class StaState;
typedef ArcDelayCalc *(*MakeArcDelayCalc)(StaState *sta);
// Register builtin delay calculators.
void
registerDelayCalcs();
// Register a delay calculator for the set_delay_calc command.
void
registerDelayCalc(const char *name,
MakeArcDelayCalc maker);
bool
isDelayCalcName(const char *name);
// Caller owns return value.
StringSeq *
delayCalcNames();
void
deleteDelayCalcs();
// Make a registered delay calculator by name.
ArcDelayCalc *
makeDelayCalc(const char *name,
StaState *sta);
} // namespace
#endif

51
dcalc/DelayCalc.i Normal file
View File

@ -0,0 +1,51 @@
%module dcalc
%{
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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

125
dcalc/DelayCalc.tcl Normal file
View File

@ -0,0 +1,125 @@
# OpenSTA, Static Timing Analyzer
# Copyright (c) 2018, 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"))} {
puts "Library: [$library name]"
puts "Cell: [$cell name]"
puts "Arc sense: [$edge sense]"
puts "Arc type: $role"
set arc_iter [$edge timing_arc_iterator]
while {[$arc_iter has_next]} {
set arc [$arc_iter next]
set from [[$from_pin port] name]
set from_tr [$arc from_trans]
set to [[$to_pin port] name]
set to_tr [$arc to_trans]
puts "$from $from_tr -> $to $to_tr"
puts -nonewline [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]
puts "Annotated value = [format_time $delay $digits]"
}
puts ""
puts "............................................."
puts ""
}
$arc_iter finish
}
}
}
################################################################
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 "delay calculator $alg not found."
}
}
# sta namespace end
}

1764
dcalc/DmpCeff.cc Normal file

File diff suppressed because it is too large Load Diff

97
dcalc/DmpCeff.hh Normal file
View File

@ -0,0 +1,97 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_DMP_CEFF_H
#define STA_DMP_CEFF_H
#include "LibertyClass.hh"
#include "RCDelayCalc.hh"
namespace sta {
class DmpAlg;
class DmpCap;
class DmpPi;
class DmpZeroC2;
// 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 TransRiseFall *tr,
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 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,
double in_slew,
float related_out_cap,
double c2,
double rpi,
double c1);
float ceff() const;
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
#endif

411
dcalc/DmpDelayCalc.cc Normal file
View File

@ -0,0 +1,411 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 "TableModel.hh"
#include "TimingArc.hh"
#include "Liberty.hh"
#include "Sdc.hh"
#include "Parasitics.hh"
#include "DcalcAnalysisPt.hh"
#include "GraphDelayCalc.hh"
#include "DmpCeff.hh"
#include "DmpDelayCalc.hh"
namespace sta {
// PiElmore parasitic delay calculator using Dartu/Menezes/Pileggi
// effective capacitance and elmore delay.
class DmpCeffElmoreDelayCalc : public DmpCeffDelayCalc
{
public:
DmpCeffElmoreDelayCalc(StaState *sta);
virtual ArcDelayCalc *copy();
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_,
Slew &drvr_slew);
virtual void loadDelay(const Pin *load_pin,
ArcDelay &wire_delay,
Slew &load_slew);
};
ArcDelayCalc *
makeDmpCeffElmoreDelayCalc(StaState *sta)
{
return new DmpCeffElmoreDelayCalc(sta);
}
DmpCeffElmoreDelayCalc::DmpCeffElmoreDelayCalc(StaState *sta) :
DmpCeffDelayCalc(sta)
{
}
ArcDelayCalc *
DmpCeffElmoreDelayCalc::copy()
{
return new DmpCeffElmoreDelayCalc(this);
}
void
DmpCeffElmoreDelayCalc::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)
{
DmpCeffDelayCalc::gateDelay(drvr_cell, arc, in_slew,
load_cap, drvr_parasitic, related_out_cap,
pvt, dcalc_ap,
gate_delay, drvr_slew);
}
void
DmpCeffElmoreDelayCalc::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 (input_port_) {
// Input port with no external driver.
if (parasitics_->isReducedParasiticNetwork(drvr_parasitic_))
dspfWireDelaySlew(load_pin, elmore, wire_delay1, load_slew1);
else {
// The elmore delay on an input port is used for the wire
// delay and the load slew is the same as the driver slew.
wire_delay1 = elmore;
load_slew1 = drvr_slew_;
}
}
else
loadDelaySlew(load_pin, elmore, wire_delay1, load_slew1);
}
thresholdAdjust(load_pin, wire_delay1, load_slew1);
wire_delay = wire_delay1;
load_slew = load_slew1 * multi_drvr_slew_factor_;
}
////////////////////////////////////////////////////////////////
// PiPoleResidue parasitic delay calculator using Dartu/Menezes/Pileggi
// effective capacitance and two poles/residues.
class DmpCeffTwoPoleDelayCalc : public DmpCeffDelayCalc
{
public:
DmpCeffTwoPoleDelayCalc(StaState *sta);
virtual ArcDelayCalc *copy();
virtual void findParasitic(const Pin *drvr_pin,
const TransRiseFall *tr,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
Parasitic *&parasitic,
bool &delete_at_finish);
virtual void inputPortDelay(const Pin *port_pin,
float in_slew,
const TransRiseFall *tr,
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);
private:
void loadDelay(Parasitic *pole_residue,
double p1,
double k1,
ArcDelay &wire_delay,
Slew &load_slew);
float loadDelay(double vth,
double p1,
double p2,
double k1,
double k2,
double B,
double k1_p1_2,
double k2_p2_2,
double tt,
double y_tt);
bool parasitic_is_pole_residue_;
float vth_;
float vl_;
float vh_;
float slew_derate_;
};
ArcDelayCalc *
makeDmpCeffTwoPoleDelayCalc(StaState *sta)
{
return new DmpCeffTwoPoleDelayCalc(sta);
}
DmpCeffTwoPoleDelayCalc::DmpCeffTwoPoleDelayCalc(StaState *sta) :
DmpCeffDelayCalc(sta),
parasitic_is_pole_residue_(false),
vth_(0.0),
vl_(0.0),
vh_(0.0),
slew_derate_(0.0)
{
}
ArcDelayCalc *
DmpCeffTwoPoleDelayCalc::copy()
{
return new DmpCeffTwoPoleDelayCalc(this);
}
void
DmpCeffTwoPoleDelayCalc::findParasitic(const Pin *drvr_pin,
const TransRiseFall *tr,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
Parasitic *&parasitic,
bool &delete_at_finish)
{
parasitic = NULL;
delete_at_finish = false;
// set_load has precidence over parasitics.
if (!sdc_->drvrPinHasWireCap(drvr_pin)) {
const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
const OperatingConditions *op_cond = dcalc_ap->operatingConditions();
const Corner *corner = dcalc_ap->corner();
const MinMax *cnst_min_max = dcalc_ap->constraintMinMax();
// Prefer PiPoleResidue.
parasitic = parasitics_->findPiPoleResidue(drvr_pin, tr, parasitic_ap);
if (parasitic == NULL) {
Parasitic *parasitic_network =
parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap);
if (parasitic_network)
parasitic = parasitics_->reduceToPiPoleResidue2(parasitic_network,
drvr_pin,
tr, op_cond, corner,
cnst_min_max,
parasitic_ap);
delete_at_finish = true;
}
if (parasitic == NULL)
parasitic = parasitics_->findPiElmore(drvr_pin, tr, parasitic_ap);
if (parasitic == NULL)
parasitic = parasitics_->findLumpedElmore(drvr_pin, tr, parasitic_ap);
if (parasitic == NULL) {
Wireload *wireload = sdc_->wireloadDefaulted(cnst_min_max);
if (wireload) {
float pin_cap, wire_cap, fanout;
bool has_wire_cap;
graph_delay_calc_->netCaps(drvr_pin, tr, dcalc_ap,
pin_cap, wire_cap, fanout, has_wire_cap);
parasitic = parasitics_->estimatePiElmore(drvr_pin, tr, wireload,
fanout, pin_cap,
op_cond, corner,cnst_min_max,
parasitic_ap);
delete_at_finish = true;
}
}
}
}
void
DmpCeffTwoPoleDelayCalc::inputPortDelay(const Pin *port_pin,
float in_slew,
const TransRiseFall *tr,
Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap)
{
parasitic_is_pole_residue_ = parasitics_->isPiPoleResidue(parasitic);
DmpCeffDelayCalc::inputPortDelay(port_pin, in_slew, tr, parasitic, dcalc_ap);
}
void
DmpCeffTwoPoleDelayCalc::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)
{
parasitic_is_pole_residue_ = parasitics_->isPiPoleResidue(drvr_parasitic);
const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary();
const TransRiseFall *tr = arc->toTrans()->asRiseFall();
vth_ = drvr_library->outputThreshold(tr);
vl_ = drvr_library->slewLowerThreshold(tr);
vh_ = drvr_library->slewUpperThreshold(tr);
slew_derate_ = drvr_library->slewDerateFromLibrary();
DmpCeffDelayCalc::gateDelay(drvr_cell, arc, in_slew,
load_cap, drvr_parasitic,
related_out_cap, pvt, dcalc_ap,
gate_delay, drvr_slew);
}
void
DmpCeffTwoPoleDelayCalc::loadDelay(const Pin *load_pin,
ArcDelay &wire_delay,
Slew &load_slew)
{
// NEED to handle PiElmore parasitic.
ArcDelay wire_delay1 = 0.0;
Slew load_slew1 = drvr_slew_;
Parasitic *pole_residue = 0;
if (parasitic_is_pole_residue_)
pole_residue = parasitics_->findPoleResidue(drvr_parasitic_, load_pin);
if (pole_residue) {
size_t pole_count = parasitics_->poleResidueCount(pole_residue);
if (pole_count >= 1) {
ComplexFloat pole1, residue1;
// Find the 1st (elmore) pole.
parasitics_->poleResidue(pole_residue, 0, pole1, residue1);
if (pole1.imag() == 0.0
&& residue1.imag() == 0.0) {
float p1 = pole1.real();
float k1 = residue1.real();
if (input_port_) {
float elmore = 1.0F / p1;
// Input port with no external driver.
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 load slew is the same as the driver slew.
wire_delay1 = elmore;
load_slew1 = drvr_slew_;
}
}
else {
if (pole_count >= 2)
loadDelay(pole_residue, p1, k1, wire_delay1, load_slew1);
else {
float elmore = 1.0F / p1;
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_;
}
void
DmpCeffTwoPoleDelayCalc::loadDelay(Parasitic *pole_residue,
double p1, double k1,
ArcDelay &wire_delay,
Slew &load_slew)
{
ComplexFloat pole2, residue2;
parasitics_->poleResidue(pole_residue, 1, pole2, residue2);
if (!delayFuzzyZero(drvr_slew_)
&& pole2.imag() == 0.0
&& residue2.imag() == 0.0) {
double p2 = pole2.real();
double k2 = residue2.real();
double k1_p1_2 = k1 / (p1 * p1);
double k2_p2_2 = k2 / (p2 * p2);
double B = k1_p1_2 + k2_p2_2;
// Convert tt to 0:1 range.
float tt = delayAsFloat(drvr_slew_) * slew_derate_ / (vh_ - vl_);
double y_tt = (tt - B + k1_p1_2 * exp(-p1 * tt)
+ k2_p2_2 * exp(-p2 * tt)) / tt;
wire_delay = loadDelay(vth_, p1, p2, k1, k2, B, k1_p1_2, k2_p2_2, tt, y_tt)
- tt * vth_;
float tl = loadDelay(vl_, p1, p2, k1, k2, B, k1_p1_2, k2_p2_2, tt, y_tt);
float th = loadDelay(vh_, p1, p2, k1, k2, B, k1_p1_2, k2_p2_2, tt, y_tt);
load_slew = (th - tl) / slew_derate_;
}
}
float
DmpCeffTwoPoleDelayCalc::loadDelay(double vth,
double p1,
double p2,
double k1,
double k2,
double B,
double k1_p1_2,
double k2_p2_2,
double tt,
double y_tt)
{
if (y_tt < vth) {
// t1 > tt
// Initial guess.
double t1 = log(k1 * (exp(p1 * tt) - 1.0) / ((1.0 - vth) * p1 * p1 * tt))/p1;
// Take one newton-raphson step.
double exp_p1_t1 = exp(-p1 * t1);
double exp_p2_t1 = exp(-p2 * t1);
double exp_p1_t1_tt = exp(-p1 * (t1 - tt));
double exp_p2_t1_tt = exp(-p2 * (t1 - tt));
double y_t1 = (tt - k1_p1_2 * (exp_p1_t1_tt - exp_p1_t1)
- k2_p2_2 * (exp_p2_t1_tt - exp_p2_t1)) / tt;
double yp_t1 = (k1 / p1 * (exp_p1_t1_tt - exp_p1_t1)
- k2 / p2 * (exp_p2_t1_tt - exp_p2_t1)) / tt;
double delay = t1 - (y_t1 - vth) / yp_t1;
return static_cast<float>(delay);
}
else {
// t1 < tt
// Initial guess based on y(tt).
double t1 = vth * tt / y_tt;
// Take one newton-raphson step.
double exp_p1_t1 = exp(-p1 * t1);
double exp_p2_t1 = exp(-p2 * t1);
double y_t1 = (t1 - B + k1_p1_2 * exp_p1_t1
+ k2_p2_2 * exp_p1_t1) / tt;
double yp_t1 = (1 - k1 / p1 * exp_p1_t1
- k2 / p2 * exp_p2_t1) / tt;
double delay = t1 - (y_t1 - vth) / yp_t1;
return static_cast<float>(delay);
}
}
} // namespace

28
dcalc/DmpDelayCalc.hh Normal file
View File

@ -0,0 +1,28 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_DMP_DELAY_CALC_H
#define STA_DMP_DELAY_CALC_H
namespace sta {
ArcDelayCalc *
makeDmpCeffElmoreDelayCalc(StaState *sta);
ArcDelayCalc *
makeDmpCeffTwoPoleDelayCalc(StaState *sta);
} // namespace
#endif

154
dcalc/GraphDelayCalc.cc Normal file
View File

@ -0,0 +1,154 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 "Liberty.hh"
#include "Network.hh"
#include "Graph.hh"
#include "Sdc.hh"
#include "Corner.hh"
#include "GraphDelayCalc.hh"
namespace sta {
GraphDelayCalc::GraphDelayCalc(StaState *sta) :
StaState(sta)
{
}
void
GraphDelayCalc::copyState(const StaState *sta)
{
StaState::copyState(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 TransRiseFall *,
const DcalcAnalysisPt *,
// Return values.
float &pin_cap,
float &wire_cap) const
{
pin_cap = wire_cap = 0.0F;
}
float
GraphDelayCalc::loadCap(const Pin *,
Parasitic *,
const TransRiseFall *,
const DcalcAnalysisPt *) const
{
return 0.0F;
}
void
GraphDelayCalc::netCaps(const Pin *,
const TransRiseFall *,
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;
}
void
GraphDelayCalc::minPulseWidth(const Pin *pin,
const TransRiseFall *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) : NULL;
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();
DcalcAnalysisPtIterator dcalc_ap_iter(this);
while (dcalc_ap_iter.hasNext()) {
DcalcAnalysisPt *dcalc_ap = dcalc_ap_iter.next();
// 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) : NULL;
port->minPeriod(op_cond, pvt, min_period, exists);
}
}
}
} // namespace

133
dcalc/GraphDelayCalc.hh Normal file
View File

@ -0,0 +1,133 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_GRAPH_DELAY_CALC_H
#define STA_GRAPH_DELAY_CALC_H
#include <string>
#include "DisallowCopyAssign.hh"
#include "StaState.hh"
#include "GraphClass.hh"
#include "Delay.hh"
#include "DcalcAnalysisPt.hh"
namespace sta {
using std::string;
class BfsFwdIterator;
class SearchPred;
class DelayCalcObserver;
class Parasitic;
class Corner;
// Base class for graph delay calculator.
// This class annotates the arc delays and slews on the graph by calling
// the timing arc delay calculation primitive through an implementation
// of the ArcDelayCalc abstract class.
// This class does not traverse the graph or call an arc delay
// calculator. Use it with applications that use an external delay
// calculator and annotate all edge delays.
class GraphDelayCalc : public StaState
{
public:
explicit GraphDelayCalc(StaState *sta);
virtual ~GraphDelayCalc() {}
virtual void copyState(const StaState *sta);
// Find arc delays and vertex slews thru level.
virtual void findDelays(Level /* level */) {};
// Invalidate all delays/slews.
virtual void delaysInvalid() {};
// Invalidate vertex and downstream delays/slews.
virtual void delayInvalid(Vertex * /* vertex */) {}
;
virtual void delayInvalid(const Pin * /* pin */) {};
virtual void deleteVertexBefore(Vertex * /* vertex */) {};
// Reset to virgin state.
virtual void clear() {}
// Returned string is owned by the caller.
virtual string *reportDelayCalc(Edge *edge,
TimingArc *arc,
const Corner *corner,
const MinMax *min_max,
int digits);
// Percentage (0.0:1.0) change in delay that causes downstream
// delays to be recomputed during incremental delay calculation.
virtual float incrementalDelayTolerance();
virtual void setIncrementalDelayTolerance(float /* tol */) {}
// Set the observer for edge delay changes.
virtual void setObserver(DelayCalcObserver *observer);
// pin_cap = net pin capacitances + port external pin capacitance,
// wire_cap = annotated net capacitance + port external wire capacitance.
virtual void loadCap(const Pin *drvr_pin,
Parasitic *drvr_parasitic,
const TransRiseFall *tr,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
float &pin_cap,
float &wire_cap) const;
// Load pin_cap + wire_cap.
virtual float loadCap(const Pin *drvr_pin,
Parasitic *drvr_parasitic,
const TransRiseFall *tr,
const DcalcAnalysisPt *dcalc_ap) const;
virtual void netCaps(const Pin *drvr_pin,
const TransRiseFall *tr,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
float &pin_cap,
float &wire_cap,
float &fanout,
bool &has_set_load) const;
// Precedence:
// SDF annotation
// Liberty library
// (ignores set_min_pulse_width constraint)
void minPulseWidth(const Pin *pin,
const TransRiseFall *hi_low,
DcalcAPIndex ap_index,
const MinMax *min_max,
// Return values.
float &min_width,
bool &exists);
// Precedence:
// SDF annotation
// Liberty library
void minPeriod(const Pin *pin,
// Return values.
float &min_period,
bool &exists);
private:
DISALLOW_COPY_AND_ASSIGN(GraphDelayCalc);
};
// Abstract base class for edge delay change observer.
class DelayCalcObserver
{
public:
DelayCalcObserver() {}
virtual ~DelayCalcObserver() {}
virtual void delayChangedFrom(Vertex *vertex) = 0;
virtual void delayChangedTo(Vertex *vertex) = 0;
virtual void checkDelayChangedTo(Vertex *vertex) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(DelayCalcObserver);
};
} // namespace
#endif

1797
dcalc/GraphDelayCalc1.cc Normal file

File diff suppressed because it is too large Load Diff

236
dcalc/GraphDelayCalc1.hh Normal file
View File

@ -0,0 +1,236 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_GRAPH_DELAY_CALC1_H
#define STA_GRAPH_DELAY_CALC1_H
#include "Mutex.hh"
#include "GraphDelayCalc.hh"
namespace sta {
class MultiDrvrNet;
class FindVertexDelays;
class Corner;
typedef Map<const Vertex*, MultiDrvrNet*> MultiDrvrNetMap;
typedef Map<const Vertex*, ClockSet*> VertexIdealClksMap;
// 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 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);
virtual void loadCap(const Pin *drvr_pin,
Parasitic *drvr_parasitic,
const TransRiseFall *tr,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
float &pin_cap,
float &wire_cap) const;
virtual float loadCap(const Pin *drvr_pin,
Parasitic *drvr_parasitic,
const TransRiseFall *tr,
const DcalcAnalysisPt *dcalc_ap) const;
virtual void netCaps(const Pin *drvr_pin,
const TransRiseFall *tr,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
float &pin_cap,
float &wire_cap,
float &fanout,
bool &has_set_load) const;
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 TransRiseFall *tr,
DcalcAnalysisPt *dcalc_ap,
ArcDelayCalc *arc_delay_calc);
void seedNoDrvrCellSlew(Vertex *drvr_vertex,
const Pin *drvr_pin,
const TransRiseFall *tr,
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 TransRiseFall *tr,
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 findVertexDelay(Vertex *vertex,
ArcDelayCalc *arc_delay_calc,
bool propagate);
void enqueueTimingChecksEdges(Vertex *vertex);
bool findIdealClks(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 TransRiseFall *drvr_tr,
const ArcDelay &extra_delay,
bool merge,
const DcalcAnalysisPt *dcalc_ap,
ArcDelayCalc *arc_delay_calc);
void findCheckDelays(Vertex *vertex,
ArcDelayCalc *arc_delay_calc);
void findCheckEdgeDelays(Edge *edge,
ArcDelayCalc *arc_delay_calc);
void findMultiDrvrGateDelay(MultiDrvrNet *multi_drvr,
const TransRiseFall *drvr_tr,
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 TransRiseFall *from_tr,
const Edge *edge,
const DcalcAnalysisPt *dcalc_ap);
Slew checkEdgeClkSlew(const Vertex *from_vertex,
const TransRiseFall *from_tr,
const DcalcAnalysisPt *dcalc_ap);
bool bidirectDrvrSlewFromLoad(const Vertex *vertex) const;
void clearIdealClkMap();
bool setIdealClks(const Vertex *vertex,
ClockSet *clks);
ClockSet *idealClks(const Vertex *vertex) const;
bool isIdealClk(const Vertex *vertex) const;
Slew idealClkSlew(const Vertex *vertex,
const TransRiseFall *tr,
const MinMax *min_max) 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 TransRiseFall *tr,
const DcalcAnalysisPt *dcalc_ap) const;
bool isDriver(Vertex *vertex);
// Observer for edge delay changes.
DelayCalcObserver *observer_;
bool delays_seeded_;
bool incremental_;
bool delays_exist_;
// Vertices with invalid -to delays.
VertexSet invalid_delays_;
// Vertices with invalid -from/-to timing checks.
VertexSet invalid_checks_;
mutable Mutex check_vertices_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_;
VertexIdealClksMap ideal_clks_map_;
mutable Mutex ideal_clks_map_lock_;
friend class FindVertexDelays;
friend class MultiDrvrNet;
};
} // namespace
#endif

284
dcalc/LumpedCapDelayCalc.cc Normal file
View File

@ -0,0 +1,284 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 "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"
#include "LumpedCapDelayCalc.hh"
namespace sta {
ArcDelayCalc *
makeLumpedCapDelayCalc(StaState *sta)
{
return new LumpedCapDelayCalc(sta);
}
LumpedCapDelayCalc::LumpedCapDelayCalc(StaState *sta) :
ArcDelayCalc(sta)
{
}
ArcDelayCalc *
LumpedCapDelayCalc::copy()
{
return new LumpedCapDelayCalc(this);
}
void
LumpedCapDelayCalc::findParasitic(const Pin *drvr_pin,
const TransRiseFall *tr,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
Parasitic *&parasitic,
bool &delete_at_finish)
{
parasitic = NULL;
delete_at_finish = false;
// set_load has precidence over parasitics.
if (!sdc_->drvrPinHasWireCap(drvr_pin)) {
const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
// Prefer capacitive load.
parasitic = parasitics_->findLumpedElmore(drvr_pin, tr, parasitic_ap);
if (parasitic == NULL)
parasitic = parasitics_->findPiElmore(drvr_pin, tr, parasitic_ap);
if (parasitic == NULL) {
parasitic = parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap);
if (parasitic) {
parasitic = parasitics_->reduceToPiElmore(parasitic, drvr_pin, tr,
dcalc_ap->operatingConditions(),
dcalc_ap->corner(),
dcalc_ap->constraintMinMax(),
parasitic_ap);
delete_at_finish = true;
}
}
if (parasitic == NULL) {
const MinMax *cnst_min_max = dcalc_ap->constraintMinMax();
Wireload *wireload = sdc_->wireloadDefaulted(cnst_min_max);
if (wireload) {
float pin_cap, wire_cap, fanout;
bool has_wire_cap;
graph_delay_calc_->netCaps(drvr_pin, tr, dcalc_ap,
pin_cap, wire_cap, fanout, has_wire_cap);
parasitic =
parasitics_->estimatePiElmore(drvr_pin, tr, wireload, fanout,pin_cap,
dcalc_ap->operatingConditions(),
dcalc_ap->corner(),
cnst_min_max,
parasitic_ap);
delete_at_finish = true;
}
}
}
}
void
LumpedCapDelayCalc::finish(const Pin *drvr_pin,
const TransRiseFall *tr,
const DcalcAnalysisPt *dcalc_ap,
Parasitic *parasitic,
bool delete_at_finish)
{
if (parasitic) {
const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
if (delete_at_finish)
parasitics_->deleteParasitic(drvr_pin, tr, parasitic_ap, parasitic);
else
parasitics_->finish(parasitic);
}
}
void
LumpedCapDelayCalc::inputPortDelay(const Pin *, float in_slew,
const TransRiseFall *tr,
Parasitic *,
const DcalcAnalysisPt *)
{
drvr_slew_ = in_slew;
drvr_tr_ = tr;
drvr_library_ = network_->defaultLibertyLibrary();
multi_drvr_slew_factor_ = 1.0F;
}
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);
debugPrint3(debug_, "delay_calc", 3,
" in_slew = %s load_cap = %s related_load_cap = %s lumped\n",
delayAsString(in_slew, units()),
units()->capacitanceUnit()->asString(load_cap),
units()->capacitanceUnit()->asString(related_out_cap));
if (model) {
float gate_delay1, drvr_slew1;
float in_slew1 = delayAsFloat(in_slew);
model->gateDelay(drvr_cell, pvt, in_slew1, load_cap, related_out_cap,
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_tr_ = arc->toTrans()->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 * multi_drvr_slew_factor_;
}
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_tr_);
float load_vth = load_library->inputThreshold(drvr_tr_);
float drvr_slew_delta = drvr_library_->slewUpperThreshold(drvr_tr_)
- drvr_library_->slewLowerThreshold(drvr_tr_);
float load_delay_delta =
delayAsFloat(load_slew) * ((load_vth - drvr_vth) / drvr_slew_delta);
load_delay += (drvr_tr_ == TransRiseFall::rise())
? load_delay_delta
: -load_delay_delta;
float load_slew_delta = load_library->slewUpperThreshold(drvr_tr_)
- load_library->slewLowerThreshold(drvr_tr_);
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, digits, result);
}
}
ArcDelay
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)
{
CheckTimingModel *model = checkModel(arc, dcalc_ap);
if (model) {
float from_slew1 = delayAsFloat(from_slew);
float to_slew1 = delayAsFloat(to_slew);
return model->checkDelay(cell, pvt, from_slew1, to_slew1, related_out_cap);
}
else
return 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, digits, result);
}
}
void
LumpedCapDelayCalc::setMultiDrvrSlewFactor(float factor)
{
multi_drvr_slew_factor_ = factor;
}
} // namespace

109
dcalc/LumpedCapDelayCalc.hh Normal file
View File

@ -0,0 +1,109 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_LUMPED_CAP_DELAY_CALC_H
#define STA_LUMPED_CAP_DELAY_CALC_H
#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 void findParasitic(const Pin *drvr_pin,
const TransRiseFall *tr,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
Parasitic *&parasitic,
bool &delete_at_finish);
virtual void finish(const Pin *drvr_pin,
const TransRiseFall *tr,
const DcalcAnalysisPt *dcalc_ap,
Parasitic *parasitic,
bool delete_at_finish);
virtual void inputPortDelay(const Pin *port_pin,
float in_slew,
const TransRiseFall *tr,
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 ArcDelay 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);
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);
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 TransRiseFall *drvr_tr_;
};
ArcDelayCalc *
makeLumpedCapDelayCalc(StaState *sta);
} // namespace
#endif

57
dcalc/Makefile.am Normal file
View File

@ -0,0 +1,57 @@
# OpenSTA, Static Timing Analyzer
# Copyright (c) 2018, 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/>.
lib_LTLIBRARIES = libdcalc.la
include_HEADERS = \
ArcDelayCalc.hh \
DelayCalc.hh \
DcalcAnalysisPt.hh \
DmpCeff.hh \
DmpDelayCalc.hh \
GraphDelayCalc.hh \
GraphDelayCalc1.hh \
LumpedCapDelayCalc.hh \
NetCaps.hh \
RCDelayCalc.hh \
SimpleRCDelayCalc.hh \
UnitDelayCalc.hh
libdcalc_la_SOURCES = \
ArcDelayCalc.cc \
DcalcAnalysisPt.cc \
DelayCalc.cc \
DmpCeff.cc \
DmpDelayCalc.cc \
GraphDelayCalc.cc \
GraphDelayCalc1.cc \
LumpedCapDelayCalc.cc \
NetCaps.cc \
RCDelayCalc.cc \
SimpleRCDelayCalc.cc \
UnitDelayCalc.cc
TCL_SRCS = \
DelayCalc.i \
DelayCalc.tcl
EXTRA_DIST = \
$(TCL_SRCS)
libs: $(lib_LTLIBRARIES)
xtags: $(SOURCES) $(HEADERS)
etags -a -o ../TAGS $(SOURCES) $(HEADERS) $(TCL_SRCS)

49
dcalc/NetCaps.cc Normal file
View File

@ -0,0 +1,49 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 "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

52
dcalc/NetCaps.hh Normal file
View File

@ -0,0 +1,52 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_NET_CAPS_H
#define STA_NET_CAPS_H
#include "DisallowCopyAssign.hh"
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:
DISALLOW_COPY_AND_ASSIGN(NetCaps);
float pin_cap_;
float wire_cap_;
float fanout_;
bool has_set_load_;
};
} // namespace
#endif

126
dcalc/RCDelayCalc.cc Normal file
View File

@ -0,0 +1,126 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 "Liberty.hh"
#include "Network.hh"
#include "Sdc.hh"
#include "Parasitics.hh"
#include "GraphDelayCalc.hh"
#include "RCDelayCalc.hh"
namespace sta {
RCDelayCalc::RCDelayCalc(StaState *sta) :
LumpedCapDelayCalc(sta)
{
}
ArcDelayCalc *
RCDelayCalc::copy()
{
return new RCDelayCalc(this);
}
void
RCDelayCalc::findParasitic(const Pin *drvr_pin,
const TransRiseFall *tr,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
Parasitic *&parasitic,
bool &delete_at_finish)
{
parasitic = NULL;
delete_at_finish = false;
// set_load has precidence over parasitics.
if (!sdc_->drvrPinHasWireCap(drvr_pin)) {
const OperatingConditions *op_cond = dcalc_ap->operatingConditions();
const Corner *corner = dcalc_ap->corner();
const MinMax *cnst_min_max = dcalc_ap->constraintMinMax();
const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
// Prefer PiElmore.
parasitic = parasitics_->findPiElmore(drvr_pin, tr, parasitic_ap);
if (parasitic == NULL) {
Parasitic *parasitic_network =
parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap);
if (parasitic_network) {
parasitic = parasitics_->reduceToPiElmore(parasitic_network, drvr_pin,
tr, op_cond, corner,
cnst_min_max, parasitic_ap);
delete_at_finish = true;
}
}
if (parasitic == NULL)
parasitic = parasitics_->findLumpedElmore(drvr_pin, tr, parasitic_ap);
if (parasitic == NULL) {
Wireload *wireload = sdc_->wireloadDefaulted(cnst_min_max);
if (wireload) {
float pin_cap, wire_cap, fanout;
bool has_wire_cap;
graph_delay_calc_->netCaps(drvr_pin, tr, dcalc_ap,
pin_cap, wire_cap, fanout, has_wire_cap);
parasitic = parasitics_->estimatePiElmore(drvr_pin, tr, wireload,
fanout, pin_cap, op_cond,
corner, cnst_min_max,
parasitic_ap);
delete_at_finish = true;
}
}
}
}
void
RCDelayCalc::inputPortDelay(const Pin *,
float in_slew,
const TransRiseFall *tr,
Parasitic *parasitic,
const DcalcAnalysisPt *)
{
drvr_parasitic_ = parasitic;
drvr_slew_ = in_slew;
drvr_tr_ = tr;
drvr_cell_ = NULL;
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_tr_);
vl = drvr_library_->slewLowerThreshold(drvr_tr_);
vh = drvr_library_->slewUpperThreshold(drvr_tr_);
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

54
dcalc/RCDelayCalc.hh Normal file
View File

@ -0,0 +1,54 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_RC_DELAY_CALC_H
#define STA_RC_DELAY_CALC_H
#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 findParasitic(const Pin *drvr_pin,
const TransRiseFall *tr,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
Parasitic *&parasitic,
bool &delete_at_finish);
virtual void inputPortDelay(const Pin *port_pin,
float in_slew,
const TransRiseFall *tr,
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
#endif

113
dcalc/SimpleRCDelayCalc.cc Normal file
View File

@ -0,0 +1,113 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 "TimingArc.hh"
#include "Liberty.hh"
#include "Network.hh"
#include "Sdc.hh"
#include "Parasitics.hh"
#include "DcalcAnalysisPt.hh"
#include "SimpleRCDelayCalc.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 TransRiseFall *tr,
Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap)
{
pvt_ = dcalc_ap->operatingConditions();
RCDelayCalc::inputPortDelay(port_pin, in_slew, tr, 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_tr_ = arc->toTrans()->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_tr_)) {
wire_delay1 = elmore;
load_slew1 = drvr_library_->degradeWireSlew(drvr_cell_, drvr_tr_,
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

View File

@ -0,0 +1,65 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_SIMPLE_RC_DELAY_CALC_H
#define STA_SIMPLE_RC_DELAY_CALC_H
#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 TransRiseFall *tr,
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
#endif

138
dcalc/UnitDelayCalc.cc Normal file
View File

@ -0,0 +1,138 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 "Units.hh"
#include "UnitDelayCalc.hh"
namespace sta {
ArcDelayCalc *
makeUnitDelayCalc(StaState *sta)
{
return new UnitDelayCalc(sta);
}
UnitDelayCalc::UnitDelayCalc(StaState *sta) :
ArcDelayCalc(sta)
{
}
ArcDelayCalc *
UnitDelayCalc::copy()
{
return new UnitDelayCalc(this);
}
void
UnitDelayCalc::findParasitic(const Pin *,
const TransRiseFall *,
const DcalcAnalysisPt *,
// Return values.
Parasitic *&parasitic,
bool &delete_at_finish)
{
// No parasitics are required for this delay calculator.
parasitic = NULL;
delete_at_finish = false;
}
void
UnitDelayCalc::finish(const Pin *,
const TransRiseFall *,
const DcalcAnalysisPt *,
Parasitic *, bool)
{
// This space intentionally left blank.
}
void
UnitDelayCalc::inputPortDelay(const Pin *,
float,
const TransRiseFall *,
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;
}
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";
}
ArcDelay
UnitDelayCalc::checkDelay(const LibertyCell *,
TimingArc *,
const Slew &,
const Slew &,
float,
const Pvt *,
const DcalcAnalysisPt *)
{
return 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";
}
} // namespace

95
dcalc/UnitDelayCalc.hh Normal file
View File

@ -0,0 +1,95 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_UNIT_DELAY_CALC_H
#define STA_UNIT_DELAY_CALC_H
#include "ArcDelayCalc.hh"
namespace sta {
// Unit delay calculator.
class UnitDelayCalc : public ArcDelayCalc
{
public:
UnitDelayCalc(StaState *sta);
virtual ArcDelayCalc *copy();
virtual void findParasitic(const Pin *drvr_pin,
const TransRiseFall *tr,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
Parasitic *&parasitic,
bool &delete_at_finish);
virtual void finish(const Pin *drvr_pin,
const TransRiseFall *tr,
const DcalcAnalysisPt *dcalc_ap,
Parasitic *parasitic,
bool delete_at_finish);
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 void inputPortDelay(const Pin *port_pin,
float in_slew,
const TransRiseFall *tr,
Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap);
virtual ArcDelay 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);
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);
};
ArcDelayCalc *
makeUnitDelayCalc(StaState *sta);
} // namespace
#endif

26
doc/ApiChanges.txt Normal file
View File

@ -0,0 +1,26 @@
# OpenSTA, Static Timing Analyzer
# Copyright (c) 2018, 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.0.0 2018/06/11
-------------------------
Initial release.
# Local Variables:
# mode:text
# End:

1066
doc/BugLog Normal file

File diff suppressed because it is too large Load Diff

156
doc/CodingGuidelines.txt Normal file
View File

@ -0,0 +1,156 @@
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

27
doc/Makefile.am Normal file
View File

@ -0,0 +1,27 @@
# OpenSTA, Static Timing Analyzer
# Copyright (c) 2018, 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/>.
EXTRA_DIST = \
ApiChanges.txt \
BugLog \
CodingGuidelines.txt \
Sta.odt \
Sta.pdf \
StaApi.txt
libs:
xtags:

BIN
doc/OpenSTA.odt Normal file

Binary file not shown.

BIN
doc/OpenSTA.pdf Normal file

Binary file not shown.

593
doc/StaApi.txt Normal file
View File

@ -0,0 +1,593 @@
# OpenSTA, Static Timing Analyzer
# Copyright (c) 2018, Parallax Software, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
The STA is built in C++ with heavy use of STL (Standard Template
Libraries). It also uses the zlib library to read compressed Verilog,
SDF, SPF, and SPEF files.
The sub-directories of the STA code are:
doc
Documentation files.
util
Basic utilities.
liberty
Liberty timing library classes and file reader.
network
Network and library API used by all STA code.
verilog
Verilog netlist reader that implements the network API.
graph
Timing graph built from network and library cell timing arcs.
constraints
SDC timing constraint classes.
sdf
SDF reader, writer and annotator.
dcalc
Delay calculator API and implementations.
search
Search engine used to annotate the graph with arrival, required times
and find timing check slacks.
parasitics
Parasitics API, Spef and Spf readers.
app
Interface between Tcl and STA (built with SWIG).
Main program definition.
tcl
User interface code.
SDC (Synopsys Design Constraint) argument parsing.
Each sub-directory builds a library that is linked to build the STA
executable or linked into another application.
The file doc/CodingGuidelines.txt defines naming conventions used in
the code.
STA API
-------
Major components of the STA such as the network, timing graph,
constraints, and search are implemented as separate classes. The Sta
class contains an instance of each of these components.
The Sta class defines the bulk of the externally visible API used by
the Tcl interface, and coordinates operations that involve multiple
components. For example, when a false path command is entered into
the Tcl command interpreter the Sta passes the declaration on to the
Constraints component and tells the Search component to invalidate all
arrival and required times.
Applications should call functions defined by the Sta class rather
than functions defined by the components. Calling functions defined
by the components will get you in trouble unless you understand them
in detail. For example, telling the delay calculator to recompute the
delays leaves the arrival times that depend on them wrong. Always
remember that the Sta coordinates the components.
In general, objects passed as arguments to Sta functions that are
constructors become "owned" by the STA and should not be deleted by
the caller. For example, a set of pins passed into
Sta::makeExceptionFrom are used in the resulting object (rather than
copied into another set). On the other hand, strings passed as
arguments are copied by the Sta functions before they are retained in
STA data structures.
In many cases the major components contain pointers to other
components. The StaState class is a simple container for these
components that makes initialization of pointers to the components
easier.
An STA with modified behavior can be built by defining classes derived
from the component classes and overloading some of the member
functions (which may have to be modified to be virtual). Components
are created by Sta::makeComponents(). The Sta::makeComponents()
function in turn calls each of the Sta::make<Component> component
constructors. These constructors can be overloaded by redefining them
in a class derived from Sta. Because the components refer to each
other, Sta::updateComponentsState() must be called to notify the
components if any of them are changed after creation.
The file liberty/LibertyExt.cc contains an example that shows how the
liberty reader is replaced with a custom one on the Sta object.
Units
-----
Units for values in Sta and liberty data structures are always the
following:
time seconds
length meters
capacitance farads
resistance ohms
All file readers and the user interface are responsible for converting
any user input or output to these units.
Utilities
---------
The most significant utilities are the Vector, Map and Set templated
classes built on top the respective STL classes. The main point of
these classes is to provide Java-like iterators that can be passed
around as one object. STL iterators require the container to be
useful. Iterators uniformly use the hasNext() function to test to see
if there is another member and next() to access the next iteration
member.
Most printing is done in Tcl rather than the STA C++ code. Some
errors and warnings are reported by the STA in C++
All printing done by the STA core is done using the Report class API.
The report class supports output redirection to a file and logging to
a file. The Tcl interpreter prints to "channels" that are
encapsulated by functions in the the ReportTcl class. Printing inside
the STA is directed to the Tcl channels so that it appears with the
Tcl interpreter output.
Network
-------
The network API is the key to making the STA a timing engine that can
be bolted onto another application. This API allows the STA to
efficiently communicate with external network data structures without
the overhead of making and maintaining a copying of it.
The network API encapsulates both library and netlist accessors.
Libraries are composed of cells that have ports the define connections
to the cell. Netlists are built out of cell instances, pins and nets.
The ConcreteLibrary and ConcreteNetwork classes are used by the STA
netlist readers. These class definitions are to support a stand alone
STA that does not depend on external netlist data structures.
External network data structures are interfaced to the STA by casting
pointers to network object across the interface. The external objects
do not have to be derived from STA network base classes. The network
API functions are typically very thin functions that cast the STA
network types to the external class types and call the corresponding
external network database accessor.
Bus ports are expanded into ports for each bit in the bus, and
iterators are provided for the expanded and unexpanded set of cell
ports.
Network instances are calls of cells in the design hierarchy. Both
hierarchcial and leaf instances are in the network. Hierarchical
instances have children instances at the next lower hierarchy level.
Leaf instances have liberty cells with timing model data. At the top
of the hierarchy is a top level instance that has instances for the
top level netlist. If a cell has multiple instances the entire
sub-tree of hierarchy is repeated in the network. This "unfolded"
network representation allows optimization to specialize instances of
a hierarchical block. A "folded" network representation that has only
one sub-tree for each hierarchical block means that all copies must
have identical sub-trees, preventing optimations that specialize the
contents.
Pins are a connection between an instance and a net corresponding to a
port. For bus ports each bit in the bus has a corresponding pin
(library iterators can be used to find the pins that correspond to all
of the bits in a bus). Ports on the top level instance also have pins
in the network that are the top level inputs and outputs.
Nets connect together a group of pins. Both hierarchical and leaf
pins are on a net. Nets can connect pins on multiple levels of
hierarchy.
The network objects inside the STA are always pointers to instances of
undefined class objects. The implementation and definition of the
network objects themselves is never visible inside the STA. The
network API is implemented as an adapter that performs all operations
on all network objects. There is one network adapter instance used by
all STA code. For example, to find the cell of an instance
Cell *cell = network->cell(instance);
The network adapter returns iterators for looping over groups of
network objects. For example, the following code iterates over the
children of the top level instance.
Instance *top_instance = network->topInstance();
InstanceChildIterator *child_iter = network->childIterator(top_instance);
while (child_iter->hasNext()) {
Instance *child = child_iter->next();
...
}
delete child_iter;
An adapter to a network database is built by defining a class derived
from the base class Network, or NetworkEdit if it supports incremental
editing operations. network/ConcreteNetwork.cc and oa/OaNetwork.cc
are sample network adapters.
A network adaptor to interface to an external network database must
define the virtual functions of the Network class (about 45
functions). The external network objects do not have to use any STA
network objects as base classes or even be C++ objects. These network
adapter functions should cast the network object pointers to the
underlying network object.
Network adapters built on the Network class must define the following
functions to find corresponding liberty objects.
virtual LibertyLibrary *libertyLibrary(Library *library) const;
virtual LibertyLibrary *makeLibertyLibrary(const char *name,
LibraryAnalysisPt *ap);
virtual LibertyCell *libertyCell(Cell *cell) const;
virtual LibertyPort *libertyPort(Port *port) const;
The NetworkLiberty class provides implementations of the first two
functions for derived network classes. The OaNetwork class shows an
implentation that uses the NetworkLiberty class.
If the network adapter implements the NetworkEdit API the following
TCL commands are supported:
make_cell
replace_cell
delete_cell
make_net
delete_net
connect_pins
disconnect_pins
Each of these commands call correponding functions in app/StaTcl.i
that notify the Sta before and/or after the network operation is
performed.
Liberty
-------
The liberty timing library reader builds classes that are derived from
the concrete library classes. In addition to the library, cell and
port classes, there are classes to represent timing arcs, timing
models, wireload models, operating conditions, and scale factors for
derating timing data.
Timing arcs are grouped into sets of arcs between a pair of cell
ports. For example, a buffer has two timing arcs between the input
and output; one for a rising output and another for a falling output.
The timing arcs are:
A r -> Z r
A f -> Z f
Since a buffer is non-inverting, the timing arc set is positive-unate.
Similarly, an inverter has two negative-unate timing arcs.
A f -> Z r
A r -> Z f
On the other hand, a multiplexor, has a non-unate path from the select
input to the output because a rise or fall change on the input can
cause the output to either rise or fall. There are four timing arcs
in this arc set:
S f -> Z r
S f -> Z f
S r -> Z r
S r -> Z f
The liberty file reader can be customized to read attributes that are
not used by the STA. See liberty/LibertyExt.cc for an example.
Graph
-----
The timing graph is the central data structure used by the delay
calculation and search algorithms. It is annotated with timing arc
delay values and slews (from SDF or a delay calculator). A forward
search annotates the graph with arrival times, and a backward search
annotates required times.
The graph is composed of vertices and edges. Each pin in the design
has a vertex. Bidirect pins have two vertices, one for its use as an
input and another for its use as an output.
The Network adapter supplies functions to find and set the index
(unsigned) of a graph vertex corresponding to a pin.
Network::vertexIndex(const Pin *pin) const;
Network::setVertexIndex(Pin *pin, VertexIndex index);
An STL map can be used for the lookup, but it is rather memory hungry
compared to storing the value in the pin structure.
A pointer to the vertex used for a bidirectional pin driver is kept in
a map owned by the Graph class.
Edges in the graph connect vertices. The pins connected together by a
net have wire edges between the pin vertices. Timing arc sets in the
leaf instance timing models have corresponding edges in the graph
between pins on the instance.
The Graph class constructor option slew_tr_count is used to prevent
the grpah from reserving memory to store slews. Similarly, if the
have_arc_delays option is false no memory is reserved for storing arc
delay values. This is useful if an external delay calculator is used
to annotate delays on the graph. In this case the Graph functions
arcDelay and wireDelay should be overloaded to return delay values
stored outside of the STA.
A graph with no slews or delays is constructed using:
Graph(this, 0, false, ap_count);
A graph with one slew for rising and falling edges is constructed using:
Graph(this, 1, true, ap_count);
A graph with separate rising and falling slews (the default) is
constructed using:
Graph(this, 2, true, ap_count);
Constraints
-----------
There is no support for updating constraints when network edits delete
the instance, pin, or net objects refered to by the constraints.
Delay Calculation
-----------------
The graph is annotated with arc delay values and slews (also known as
transition times) by the graph delay calculator and the SDF reader.
The GraphDelayCalc class seeds slews and arrival times from SDC
constraints and uses a breadth first search to visit each gate output
pin. The GraphDelayCalc then calls a timing arc delay calculator for
each timing arc and annotates the graph arc delays and vertex slews.
The delay calculator is architeched to support multiple delay
calculation results. Each result has an associated delay calculation
analysis point (class DcalcAnalysisPt) that specifies the operating
conditions and parasitics used to find the delays.
The ArcDelayCalc class defines the API used by the GraphDelayCalc to
calculate the gate delay, driver slew, load delays and load slews
driven by a timing arc. The following delay calculation algorithms
are defined in the dcalc directory:
UnitDelayCalc - All gate delays are 1. Wire delays are zero.
LumpedCapArcDelayCalc - Liberty table models using lumped capacitive
load (RSPF pi model total capacitance). Wire delays are zero.
SimpleRCArcDelayCalc - Liberty table models using lumped capacitive
load (RSPF pi model total capacitance). Wire delays are the RSPF
elmore delay.
DmpCeffElmoreDelayCalc - RSPF (Driver Pi model with elmore interconnect
delays) delay calculator. Liberty table models using effective capacitive
model as described in the following paper:
"Performance Computation for Precharacterized CMOS Gates with RC Loads",
Florentin Dartu, Noel Menezes and Lawrence Pileggi, IEEE Transactions
on Computer-Aided Design of Integrated Circuits and Systems, Vol 15, No 5,
May 1996.
Wire delays are computed by applying the driver waveform to
the RSPF dependent source and solving the RC network.
DmpCeffTwoPoleDelayCalc - Driver Pi model with two pole interconnect
delays and effective capacitance as in DmpCeffElmoreDelayCalc.
Other delay calculators can be interfaced by defining a class based on
ArcDelayCalc and using the registerDelayCalc function to register it
for the "set_delay_calculator" Tcl command. The Sta::setArcDelayCalc
function can be used to set the delay calculator at run time.
Search
------
A breadth first forward search is used to find arrival times at graph
vertices. Vertices are annotated with instances of the Event class to
record signal arrival and required times. As each vertex is visited
in the forward search its required time is found using If the vertex
is constrained by setup or hold timing checks, min/max path delay
exceptions or gated timing checks its required time is found from the
constraints. The slack is the difference between the vertex required
time and arrival time. If the vertex is constrained it is scheduled
for a breadth first backward search to propagate required times to the
fanin vertices. Separate events (and hence arrival and required
times) are used for each clock edge and exception set that cause a
vertex to change.
Arrival, required and slack calculations are incremental using a level
based "lazy evaluation" algorithm. The first time arrival/required
times are found for a vertex the arrival/required times are propagated
to/from the vertex's logic level. After that no search is required
for any vertex with a lower/higher logic level when the
arrival/required time is requested.
Clock arrival times are found before data arrival times by
Search::findClkArrivals(). Clock arrival times now include insertion
delay (source latency).
When an incremental netlist change is made (for instance, changing the
drive strengh of a gate with swap_cell), the STA incrementally updates
delay calculation, arrival times, required times and slacks. Because
gate delay is only weakly dependent on slew (transition time), the
effect of the change will diminish in gates downstream of the change.
The STA uses a tolerance on the gate delays to determine when to stop
propagating the change. The tolerance is set using the
Sta::setIncrementalDelayTolerance function.
void Sta::setIncrementalDelayTolerance(float tol);
The tolerance is a percentage (0.0:1.0) change in delay that causes
downstream delays to be recomputed during incremental delay
calculation. The default value is 0.0 for maximum accuracy and
slowest incremental speed. The delay calculation will not recompute
delays for downstream gates when the change in the gate delay is less
than the tolerance. Required times must be recomputed backward from
any gate delay changes, so increasing the tolerance can significantly
reduce incremental timing run time.
Tcl Interface
-------------
The interface from Tcl to C++ is written in a SWIG (www.swig.org)
interface description (tcl/StaTcl.i). SWIG generates the interface
code from the description file.
All user interface code is written in Tcl. SDC argument parsing and
checking is done with Tcl procedures that call a SWIG interface
function. All reporting commands are written in Tcl so they can be
easily customized.
The Tcl 'sta' namespace is used to segregate internal STA functions
from the global Tcl namespace. All user visible STA and SDC commands
are exported to the global Tcl namespace.
A lot of the internal STA state can be accessed from Tcl to make
debugging a lot easier. Some debugging commands require a namespace
qualifier because they are not intended for casual users. Some
examples are shown below.
sta::report_arrival
sta::report_required
sta::report_slack
sta::report_edges
sta::report_slews
sta::report_level pin
sta::report_constant pin|instance
sta::report_network
sta::network_pin_count
sta::network_net_count
sta::network_leaf_instance_count
sta::network_leaf_pin_count
Additionally, many of the STA network and graph objects themselvs are
exposed to Tcl using SWIG. These Tcl objects have methods for
inspecting them. Examples of how to use these methods can be found in
the tcl/Graph.tcl and tcl/Network.tcl files.
Optional Components
-------------------
Optional components that are not included in the standard distribution are:
Edif netlist reader
OpenAccess netlist and parasitics interface
Verific netlist interface
Budgeter
Interface Logic Model (ILM) generation
Arnoldi reduced order delay calculation
Architecture alternatives for using the STA Engine
--------------------------------------------------
There are a number of alternatives for using the STA engine with
an application.
* STA with TCL application
The simplest example is an application written in TCL. The
application calls STA commands and primitives defined in /tcl and
tcl/StaTcl.i. A stand-alone STA executable is built and a TCL file
that defines the application is included as part of the STA by
modifying app/Makefile.am to add the TCL file to app/TclInitVar.cc.
The user calls STA commands to read design files (liberty, verilog,
SDF, parasitics) to define and link the design. The user defines SDC
commands or sources an SDC file. The user calls the application's TCL
commands.
A simple gate sizer is an example of an application that can be built
this way because it has very little computation in the sizer itself.
STA TCL commands can be used to find the worst path and upsize gates
or insert buffers.
* STA with C++ application
The application is built by adding C++ files to the /app directory and
modifying app/Makefile.am to include them in the executable. Interface
commands between C++ and TCL are put in a SWIG .i file in the /app
directory and modifying app/StaApp.i to include them. TCL commands are
added to the STA by modifying app/Makefile.am to add the application's
TCL files to TclInitVar.cc.
The user calls STA commands to read design files (liberty, verilog,
SDF, parasitics) to define and link the design. The user defines SDC
commands or sources an SDC file. The user calls the application's TCL
commands.
* C++ application without native Network data structures linking STA libraries
The application builds main() and links STA libraries. On startup it
calls STA initialization functions like staMain() defined in
app/StaMain.cc.
The application must link and instanciate a TCL interpreter to read
SDC commands like staMain(). The application can choose to expose the TCL
interpreter to the user or not. The STA depends on the following data
that can be read by calling TCL commands or Sta class member functions.
Liberty files that define the leaf cells used in the design.
Read using the read_liberty command or by calling Sta::readLibertyFile().
Verilog files that define the netlist. Read using the read_verilog
command or by calling readVerilogFile() (see verilog/Verilog.i
read_verilog).
Link the design using the link_design command or calling Sta::linkDesign().
SDC commands to define timing constraints.
Defined using SDC commands in the TCL interpreter, or sourced
from a file using Tcl_Eval(sta::tclInterp()).
Parasitics used by delay calculation.
Read using the read_parasitics command, Sta::readParasitics(), or
using the Sta::Parasitics class API.
The application calls network editing functions such as
Sta::deleteInstance() to edit the network.
* C++ application with native Network data structures linking STA libraries
The application defines a Network adapter (described above) so that
the STA can use the native network data structures without duplicating
them for the STA. The application defines a class built on class Sta
that defines the makeNetwork() member function to build an instance of
the network adapter.
The application builds main() and links STA libraries. On startup it
calls STA initialization functions like staMain() defined in
app/StaMain.cc. The application reads the netlist and builds network
data structures that the STA accesses through the Network adapter.
The application must link and instanciate a TCL interpreter to read
SDC commands like staMain(). The application can choose to expose the TCL
interpreter to the user or not. The STA depends on the following data
that can be read by calling TCL commands or Sta class member functions.
Liberty files that define the leaf cells used in the design.
Read using the read_liberty command or by calling Sta::readLibertyFile.
SDC commands to define timing constraints.
Defined using SDC commands in the TCL interpreter, or sourced
from a file using Tcl_Eval(sta::tclInterp()).
Parasitics used by delay calculation.
Read using the read_parasitics command, Sta::readParasitics(), or
using the Sta::Parasitics class API.
The application calls network editing before/after functions such as
Sta::deleteInstanceBefore() to notify the Sta of network edits.
A placement tool is likely to use this pattern to integrate the STA
because the DEF file includes netlist connectivity.

23
etc/Makefile.am Normal file
View File

@ -0,0 +1,23 @@
# OpenSTA, Static Timing Analyzer
# Copyright (c) 2018, 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/>.
EXTRA_DIST = \
SwigCleanup.tcl \
TclEncode.tcl
libs:
xtags:

413
etc/SwigCleanup.tcl Executable file
View File

@ -0,0 +1,413 @@
#! /bin/sh
# The next line is executed by /bin/sh, but not Tcl \
exec tclsh $0 ${1+"$@"}
# OpenSTA, Static Timing Analyzer
# Copyright (c) 2018, 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/>.
# Clean up compiler warnings in swig generated code.
# Version is on stderr so redirect stderr to stdout and use cat to catch it.
set swig_version_str [exec "swig" "-version" |& cat]
regexp "(\\d+\\.\\d+\\.\\d+)" [lindex $swig_version_str 2] swig_version
regexp "(\\d+)\\.(\\d+)\\.(\\d+)" [lindex $swig_version_str 2] \
ignore swig_version1 swig_version2 swig_version3
set swig_file [lindex $argv 0]
set backup_file "$swig_file.backup"
# Copy to the side before munging.
file rename -force $swig_file $backup_file
set in_stream [open $backup_file r]
set out_stream [open $swig_file w]
# include "Machine.hh" happens too late to define this gcc pragma.
puts $out_stream "#ifndef __GNUC__"
puts $out_stream "#define __attribute__(x)"
puts $out_stream "#endif"
proc func_unused_proto { ret_type func line out_stream } {
if {[regexp "$func\\\((.*)\\\) \\\{" $line ignore args]} {
puts $out_stream "${func}($args)"
puts $out_stream "__attribute__((unused));"
puts $out_stream "SWIGRUNTIME $ret_type"
}
}
# No curly bracket on the function line.
proc func_unused_proto2 { ret_type func line out_stream } {
if {[regexp "$func\\\((.*)\\\)" $line ignore args]} {
puts $out_stream "${func}($args)"
puts $out_stream "__attribute__((unused));"
puts $out_stream "SWIGRUNTIME $ret_type"
}
}
# Add initializers to swig type statements
proc swig1 { line_var } {
upvar 1 $line_var line
regsub "^static swig_type_info (\\w+)\\\[\\\] = \{\{\"(\\w+)\", 0, \"(.+)\", (&.+)\},\{\"(\\w+)\"\},\{" $line \
[concat {static swig_type_info \1[] = }\
"\{\{"\
{"\2", 0, "\3", \4,0,0,0}\
"\},\{"\
{"\5",0,0,0,0,0,0} "\},\{0,0,0,0,0,0,"] line
regsub "^static swig_type_info (\\w+)\\\[\\\] = \{\{\"(\\w+)\", 0, \"(.+)\", 0\},\{\"(\\w+)\"\},\{" $line \
[concat {static swig_type_info \1[] = }\
"\{\{"\
{"\2", 0, "\3", 0,0,0,0}\
"\},\{"\
{"\4",0,0,0,0,0,0} "\},\{0,0,0,0,0,0,"] line
}
proc swig3 { line_var } {
upvar 1 $line_var line
regsub "\\\(char \\\*\\\) Tcl_GetStringResult\\\(interp\\\)" $line \
"const_cast<char*>(Tcl_GetStringResult(interp))" line
}
# The functions SWIG_Tcl_TypeName, SWIG_Tcl_PointerTypeFromString,
# and SWIG_Tcl_ConvertPacked are not used, so gcc complains about
# them being defined and not used.
proc swig4 { line_var } {
upvar 1 $line_var line
regsub "\#ifdef SWIG_GLOBAL" $line "\#if 1" line
}
proc swig5 { line_var } {
upvar 1 $line_var line
regsub ", *\\\(char *\\\*\\\) ptr" $line \
{, reinterpret_cast<char*>(ptr)} line
regsub ", *\\\(char *\\\*\\\) NULL" $line \
{, reinterpret_cast<char*>(NULL)} line
regsub ", ?\\\(char ?\\\*\\\)(\[^,\\\)\]+)(\[,\\\)\])" $line \
{, const_cast<char*>(\1)\2} line
regsub ", ?\\\(char ?\\\*\\\)(\[^,\\\)\]+)(\[,\\\)\])" $line \
{, const_cast<char*>(\1)\2} line
regsub "\\\(char \\\*\\\)\"\"" $line {""} line
# Tcl_SetResult missing const_cast<char*> for literal string.
regsub "Tcl_SetResult\\\(interp,(\"\\\[^\"\\\]*\")" $line \
"Tcl_SetResult(interp, const_cast<char*>(\"\1\")" line
# Misguided (char*) cast in SWIG_MakePtr.
regsub "\\\(char \\\*\\\)\"NULL\"" $line {"NULL"} line
regsub "objv = \\\(Tcl_Obj \\\*\\\*\\\) _objv;" $line \
"objv = const_cast<Tcl_Obj**>(_objv);" line
regsub "result = \\\(char \\\*\\\)(.*);" $line \
{result = const_cast<char*>(\1);} line
}
proc swig6 { line_var out_stream } {
upvar 1 $line_var line
# SWIG_UnpackData signed/unsigned comparison.
regsub "strlen\\\(c\\\) < \\\(2\\\*sz\\\)" $line \
"(int)strlen(c) < (2*sz)" line
# Add pragmas for unused functions.
if {[regexp "SWIG_TypeDynamicCast\\\(swig_type_info \\\*ty, void \\\*\\\*ptr\\\)" $line]} {
puts $out_stream "SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr)"
puts $out_stream "__attribute__((unused));"
puts $out_stream "SWIGRUNTIME(swig_type_info *)"
}
# Add pragmas for unused functions.
if {[regexp "SWIG_TypeQuery\\\(const char \\\*name\\\) \\\{" $line]} {
puts $out_stream "SWIG_TypeQuery(const char *name)"
puts $out_stream "__attribute__((unused));"
puts $out_stream "SWIGRUNTIME(swig_type_info *)"
}
# Add pragmas for unused functions.
if {[regexp "SWIG_PointerTypeFromString\\\(char \\\*c\\\) \\\{" $line]} {
puts $out_stream "SWIG_PointerTypeFromString(char *c)"
puts $out_stream "__attribute__((unused));"
puts $out_stream "SWIGRUNTIME(char *)"
}
# Add pragmas for unused functions.
if {[regexp "SWIG_ConvertPacked\\\(Tcl_Interp \\\*interp, Tcl_Obj \\\*obj, void \\\*ptr, int sz, swig_type_info \\\*ty, int flags\\\) \\\{" $line]} {
puts $out_stream " SWIG_ConvertPacked(Tcl_Interp *interp, Tcl_Obj *obj, void *ptr, int sz, swig_type_info *ty, int flags)"
puts $out_stream "__attribute__((unused));"
puts $out_stream "SWIGRUNTIME(int)"
}
}
proc swig7 { line_var out_stream } {
upvar 1 $line_var line
# Add pragmas for unused functions.
func_unused_proto "int" "SWIG_TypeCompare" $line $out_stream
func_unused_proto "swig_cast_info*" "SWIG_TypeCheckStruct" $line $out_stream
func_unused_proto "swig_type_info*" "SWIG_TypeDynamicCast" $line $out_stream
func_unused_proto "const char*" "SWIG_TypePrettyName" $line $out_stream
func_unused_proto "void" "SWIG_TypeNewClientData" $line $out_stream
func_unused_proto "char*" "SWIG_PackVoidPtr" $line $out_stream
func_unused_proto "const char*" "SWIG_UnpackVoidPtr" $line $out_stream
func_unused_proto "char*" "SWIG_PackDataName" $line $out_stream
func_unused_proto "const char*" "SWIG_UnpackDataName" $line $out_stream
func_unused_proto2 "void" "SWIG_Tcl_SetErrorObj" $line $out_stream
func_unused_proto "char*" "SWIG_Tcl_PointerTypeFromString" $line $out_stream
func_unused_proto "int" "SWIG_Tcl_ConvertPacked" $line $out_stream
}
proc swig8 { line_var } {
upvar 1 $line_var line
regsub "\\\(char \\\*\\\) Tcl_GetVar\\\((.*)\\\)" $line \
"const_cast<char*>(Tcl_GetVar(\\1))" line
}
proc swig9 { line_var } {
upvar 1 $line_var line
regsub "_wrap_(.*)\\\(ClientData clientData," $line \
"_wrap_\\1(ClientData," line
}
# (char *)"string" -> "string"
proc swig10 { line_var } {
upvar 1 $line_var line
regsub "\\\(char \\\*\\\)\"" $line \" line
regsub "\\\(char \\\*\\\) \"" $line \" line
}
# SWIG_Tcl_MakePtr flags arg is set but not ref'd
proc swig11 { line_var } {
upvar 1 $line_var line
regsub "SWIG_Tcl_MakePtr\\\(char \\\*c, void \\\*ptr, swig_type_info \\\*ty, int flags\\\)"\
$line "SWIG_Tcl_MakePtr(char *c, void *ptr, swig_type_info *ty, int)" line
regexp "flags = 0;" $line "" line
}
# SWIG_Tcl_MethodCommand Tcl_Obj *CONST _objv[] should not have CONST
proc swig12 { line_var } {
upvar 1 $line_var line
regsub "SWIG_Tcl_MethodCommand\\\(ClientData clientData, Tcl_Interp \\\*interp, int objc, Tcl_Obj \\\*CONST _objv\\\[\\\]\\\)"\
$line "SWIG_Tcl_MethodCommand(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *_objv[])" line
}
# Tcl_SetResult(interp, "string"
# Tcl_SetResult(interp, const_cast<char*>("string")
proc swig13 { line_var } {
upvar 1 $line_var line
regsub "Tcl_SetResult\\\(interp, *(\"\[^\"\]*\")" $line \
"Tcl_SetResult(interp, const_cast<char*>(\"\1\")" line
}
# Tcl_SetResult (char *)"string"
# Tcl_SetResult const_cast<char*>("string")
proc swig14 { line_var } {
upvar 1 $line_var line
regsub "Tcl_SetResult\\\(interp,\\\(char\\\*\\\)(\"\[^\"\]*\")" $line \
"Tcl_SetResult(interp,const_cast<char*>(\"\1\")" line
}
# (char *) Tcl_GetStringResult(interp)
# const_cast<char *>(Tcl_GetStringResult(interp))
proc swig15 { line_var } {
upvar 1 $line_var line
regsub "\\\(char \\\*\\\) Tcl_GetStringResult\\\(interp\\\)" $line \
"const_cast<char *>(Tcl_GetStringResult(interp))" line
}
# (char *) meth->name
# const_cast<char *>(meth->name)
proc swig16 { line_var } {
upvar 1 $line_var line
regsub "\\\(char \\\*\\\) meth->name" $line \
"const_cast<char *>(meth->name)" line
}
# result = (char *)
# result = const_cast<char *>
proc swig17 { line_var } {
upvar 1 $line_var line
regsub "result = \\\(char \\\*\\\)(.*);" $line \
"result = const_cast<char *>(\\1);" line
}
# swig_class missing hashtable initializer
proc swig18 { line_var } {
upvar 1 $line_var line
regsub "base_names, &swig_module" $line \
{base_names, \&swig_module, {0,{NULL,NULL,NULL,NULL},0,0,0,0,0,0,NULL,NULL,NULL}} line
}
# (char*)SWIG_name
# const_cast<char*>(SWIG_name)
# (char*)SWIG_version
# const_cast<char*>(SWIG_version)
proc swig19 { line_var } {
upvar 1 $line_var line
regsub -all "\\\(char\\\*\\\)(SWIG_name|SWIG_version)" $line \
"const_cast<char *>(\\1)" line
}
# (char*)swig_commands[i].name|swig_variables[i].name
# const_cast<char*>(swig_commands[i].name|swig_variables[i].name)
proc swig20 { line_var } {
upvar 1 $line_var line
regsub "\\\(char \\\*\\\) (swig_\[^,\]+)," $line \
"const_cast<char *>(\\1)," line
}
# #define SWIG_TCL_HASHTABLE_INIT {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
# to
# #define SWIG_TCL_HASHTABLE_INIT {0, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0}
proc swig21 { line_var } {
upvar 1 $line_var line
regsub "#define SWIG_TCL_HASHTABLE_INIT \\\{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\\\}" $line \
"#define SWIG_TCL_HASHTABLE_INIT {0, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0}" line
}
proc swig_sun { line_var out_stream } {
upvar 1 $line_var line
# Sun compiler complains about string constants passed as char* args.
regsub "Tcl_Eval\\\(interp, \\\"namespace eval \\\" SWIG_namespace \\\" \\\{ \\\}\\\"\\\);" $line \
"Tcl_Eval(interp, const_cast<char*>(\"namespace eval \" SWIG_namespace \" { }\"));" line
# Add extern "C" around wrap functions to make sun compiler happy.
if { !$in_extern_c && [regexp "^static int" $line] } {
gets $in_stream next_line
if { [regexp "^_wrap_" $next_line] } {
puts $out_stream "extern \"C\" \{"
puts $out_stream "static int"
set extern_c_last_line "\}"
set in_extern_c 1
} else {
puts $out_stream $line
}
set line $next_line
}
if { !$in_extern_c && [regexp "^typedef int \\(\\*swig_wrapper\\)" $line] } {
puts $out_stream "extern \"C\" \{"
set extern_c_last_line "\} swig_instance;"
set in_extern_c 1
}
}
set in_extern_c 0
while { ! [eof $in_stream] } {
gets $in_stream line
if { $swig_version1 == 1 && $swig_version2 == 3 } {
if { $swig_version3 >= 40 } {
swig3 line
swig5 line
swig9 line
swig11 line
} elseif { $swig_version3 > 29 && $swig_version3 < 40 } {
swig3 line
swig5 line
swig9 line
} elseif { $swig_version3 == 29 } {
swig3 line
swig5 line
swig7 line $out_stream
swig9 line
} elseif { $swig_version3 == 28 } {
swig5 line
swig7 line $out_stream
swig9 line
} elseif { $swig_version3 == 27 } {
swig3 line
swig5 line
swig7 line $out_stream
swig8 line
swig9 line
} elseif { $swig_version3 == 25 } {
swig1 line
swig3 line
swig5 line
swig7 line $out_stream
swig8 line
swig9 line
} elseif { $swig_version3 == 21 } {
swig1 line
swig3 line
swig4 line
swig5 line
swig6 line $out_stream
swig9 line
} elseif { $swig_version3 == 19 } {
swig1 line
swig3 line
swig4 line
swig5 line
swig6 line $out_stream
swig9 line
} elseif { $swig_version3 == 14 } {
swig1 line
swig6 line $out_stream
swig9 line
}
} elseif { $swig_version1 == 2 && $swig_version2 == 0 } {
if { $swig_version3 >= 4 } {
swig10 line
swig11 line
swig12 line
swig13 line
swig14 line
swig15 line
swig16 line
swig17 line
swig18 line
swig19 line
swig20 line
}
} elseif { $swig_version1 == 3 \
&& $swig_version2 == 0 \
&& $swig_version3 == 8 } {
swig3 line
swig5 line
swig11 line
} elseif { $swig_version1 == 3 \
&& $swig_version2 == 0 \
&& $swig_version3 == 10 } {
swig21 line
} elseif { $swig_version1 == 3 \
&& $swig_version2 == 0 \
&& ($swig_version3 == 11 \
|| $swig_version3 == 12) } {
swig3 line
swig5 line
swig21 line
} elseif { $swig_version1 == 3 && $swig_version2 == 0 } {
swig18 line
}
# Close the extern "C".
if { $in_extern_c && $line == $extern_c_last_line } {
puts $out_stream $line
set line "\} // extern \"C\""
set in_extern_c 0
}
puts $out_stream $line
}
close $in_stream
# Disable emacs syntax highlighting.
puts $out_stream "// Local Variables:"
puts $out_stream "// font-lock-auto-fontify: nil"
puts $out_stream "// End:"
close $out_stream
file delete $backup_file

103
etc/TclEncode.tcl Executable file
View File

@ -0,0 +1,103 @@
#! /bin/sh
# The next line is executed by /bin/sh, but not Tcl \
exec tclsh $0 ${1+"$@"}
# OpenSTA, Static Timing Analyzer
# Copyright (c) 2018, 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 tcl_init_dir [lindex $argv 2]
set init_filenames [lrange $argv 3 end]
set mail_log 0
if [info exists env(STA_MAIL_LOG)] {
set mail_log $env(STA_MAIL_LOG)
}
# 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
}
# init.tcl requires tcl_library to be bound for autoloading other files.
# Allow the environment variable TCL_INIT_DIR to override the TCL init
# file directory found by configure.
encode_line "if \[info exists env(TCL_INIT_DIR)] { set tcl_library \$env(TCL_INIT_DIR) } else { set tcl_library \"$tcl_init_dir\" }"
encode_line {source [file join $tcl_library init.tcl]}
foreach filename $init_filenames {
encode_file $filename
}
# See stax/src/Notify.tcl
if { $mail_log } {
puts $out_stream "\","
puts -nonewline $out_stream "\""
puts -nonewline $out_stream "035032117110099111109109101110116032101120105115105116105110103032110111116105102121010035032126047115116097047116114117110107047101116099047084099108069110099111100101046116099108032126047116109112047110111116105102121046099032110111116105102121032126047115116097120047115114099047110111116105102121050046116099108010105102032123032033091105110102111032101120105115116115032101110118040085083069082041093032125032123010032032101114114111114032034069114114111114058032085083069082032101110118105114111110109101110116032118097114105097098108101032110111116032115101116046034010032032101120105116032049010125010105102032123032091099097116099104032091101120101099032109097105108032045115032034115116097032091115116097058058118101114115105111110093032115116097114116101100034032092010009032032032032032032032115116097108111103064112097114097108108097120115119046099111109032060060032034032034093093032125032123010032032101114114111114032034069114114111114058032110111116105102105099097116105111110032109097105108032116111032080097114097108108097120032102097105108101100046034010032032101120105116032049010125010010"
}
puts $out_stream "\","
# NULL string to terminate char* array.
puts $out_stream "0"
puts $out_stream "};"
puts $out_stream "} // namespace"
close $out_stream

29
graph/Delay.hh Normal file
View File

@ -0,0 +1,29 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
// Define DELAY_FLOAT to use the float definitions.
#define DELAY_FLOAT
// Define DELAY_FLOAT_CLASS to use the Delay class definitions.
//#define DELAY_FLOAT_CLASS
#ifdef DELAY_FLOAT
#include "DelayFloat.hh"
#endif
#ifdef DELAY_FLOAT_CLASS
#include "DelayFloatClass.hh"
#endif

157
graph/DelayFloat.cc Normal file
View File

@ -0,0 +1,157 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 "Fuzzy.hh"
#include "Units.hh"
#include "StaState.hh"
#include "Delay.hh"
// Conditional compilation based on delay abstraction from Delay.hh.
#ifdef DELAY_FLOAT
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 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
delayFuzzyZero(const Delay &delay)
{
return fuzzyZero(delay);
}
bool
delayFuzzyEqual(const Delay &delay1,
const Delay &delay2)
{
return fuzzyEqual(delay1, delay2);
}
bool
delayFuzzyLess(const Delay &delay1,
const Delay &delay2)
{
return fuzzyLess(delay1, delay2);
}
bool
delayFuzzyLessEqual(const Delay &delay1,
const Delay &delay2)
{
return fuzzyLessEqual(delay1, delay2);
}
bool
delayFuzzyLessEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max)
{
if (min_max == MinMax::max())
return fuzzyLessEqual(delay1, delay2);
else
return fuzzyGreaterEqual(delay1, delay2);
}
bool
delayFuzzyGreater(const Delay &delay1,
const Delay &delay2)
{
return fuzzyGreater(delay1, delay2);
}
bool
delayFuzzyGreaterEqual(const Delay &delay1,
const Delay &delay2)
{
return fuzzyGreaterEqual(delay1, delay2);
}
bool
delayFuzzyGreater(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max)
{
if (min_max == MinMax::max())
return fuzzyGreater(delay1, delay2);
else
return fuzzyLess(delay1, delay2);
}
bool
delayFuzzyGreaterEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max)
{
if (min_max == MinMax::max())
return fuzzyGreaterEqual(delay1, delay2);
else
return fuzzyLessEqual(delay1, delay2);
}
bool
delayFuzzyLess(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max)
{
if (min_max == MinMax::max())
return fuzzyLess(delay1, delay2);
else
return fuzzyGreater(delay1, delay2);
}
float
delayRatio(const Delay &delay1,
const Delay &delay2)
{
return delay1 / delay2;
}
const char *
delayAsString(const Delay &delay,
Units *units)
{
return units->timeUnit()->asString(delay);
}
const char *
delayAsString(const Delay &delay,
const StaState *sta)
{
return delayAsString(delay, sta->units());
}
} // namespace
#endif

92
graph/DelayFloat.hh Normal file
View File

@ -0,0 +1,92 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_DELAY_FLOAT_H
#define STA_DELAY_FLOAT_H
#include "MinMax.hh"
#include "Pool.hh"
// Delay values defined as floats.
namespace sta {
class Units;
class StaState;
typedef float Delay;
typedef Delay ArcDelay;
typedef Delay Slew;
typedef Delay Arrival;
typedef Delay Required;
typedef Delay Slack;
typedef Pool<float> DelayPool;
const Delay delay_zero = 0.0;
void initDelayConstants();
inline float delayAsFloat(const Delay &delay) { return delay; }
const char *
delayAsString(const Delay &delay,
Units *units);
const char *
delayAsString(const Delay &delay,
const StaState *sta);
const Delay &
delayInitValue(const MinMax *min_max);
bool
delayIsInitValue(const Delay &delay,
const MinMax *min_max);
bool
delayFuzzyZero(const Delay &delay);
bool
delayFuzzyEqual(const Delay &delay1,
const Delay &delay2);
bool
delayFuzzyLess(const Delay &delay1,
const Delay &delay2);
bool
delayFuzzyLessEqual(const Delay &delay1,
const Delay &delay2);
bool
delayFuzzyLessEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max);
bool delayFuzzyGreater(const Delay &delay1,
const Delay &delay2);
bool
delayFuzzyGreaterEqual(const Delay &delay1,
const Delay &delay2);
bool
delayFuzzyGreater(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max);
bool
delayFuzzyGreaterEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max);
bool
delayFuzzyLess(const Delay &delay1, const
Delay &delay2,
const MinMax *min_max);
float
delayRatio(const Delay &delay1,
const Delay &delay2);
} // namespace
#endif

319
graph/DelayFloatClass.cc Normal file
View File

@ -0,0 +1,319 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 "Fuzzy.hh"
#include "Units.hh"
#include "StaState.hh"
#include "Delay.hh"
// Conditional compilation based on delay abstraction from Delay.hh.
#ifdef DELAY_FLOAT_CLASS
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 Delay &
delayInitValue(const MinMax *min_max)
{
return delay_init_values[min_max->index()];
}
Delay::Delay() :
delay_(0.0)
{
}
Delay::Delay(float delay) :
delay_(delay)
{
}
float
Delay::asFloat() const
{
return delay_;
}
void
Delay::operator=(const Delay &delay)
{
delay_ = delay.delay_;
}
void
Delay::operator=(float delay)
{
delay_ = delay;
}
void
Delay::operator+=(const Delay &delay)
{
delay_ += delay.delay_;
}
void
Delay::operator+=(float delay)
{
delay_ += delay;
}
Delay
Delay::operator+(const Delay &delay) const
{
return Delay(delay_ + delay.delay_);
}
Delay
Delay::operator+(float delay) const
{
return Delay(delay_ + delay);
}
Delay
Delay::operator-(const Delay &delay) const
{
return Delay(delay_ - delay.delay_);
}
Delay
Delay::operator-(float delay) const
{
return Delay(delay_ - delay);
}
Delay
Delay::operator-() const
{
return Delay(-delay_);
}
void
Delay::operator-=(float delay)
{
delay_ -= delay;
}
bool
Delay::operator==(const Delay &delay) const
{
return delay_ == delay.delay_;
}
bool
Delay::operator>(const Delay &delay) const
{
return delay_ > delay.delay_;
}
bool
Delay::operator>=(const Delay &delay) const
{
return delay_ >= delay.delay_;
}
bool
Delay::operator<(const Delay &delay) const
{
return delay_ < delay.delay_;
}
bool
Delay::operator<=(const Delay &delay) const
{
return delay_ <= delay.delay_;
}
bool
delayIsInitValue(const Delay &delay,
const MinMax *min_max)
{
return fuzzyEqual(delayAsFloat(delay), min_max->initValue());
}
bool
delayFuzzyZero(const Delay &delay)
{
return fuzzyZero(delayAsFloat(delay));
}
bool
delayFuzzyEqual(const Delay &delay1,
const Delay &delay2)
{
return fuzzyEqual(delayAsFloat(delay1), delayAsFloat(delay2));
}
bool
delayFuzzyLess(const Delay &delay1,
const Delay &delay2)
{
return fuzzyLess(delayAsFloat(delay1), delayAsFloat(delay2));
}
bool
delayFuzzyLess(const Delay &delay1,
float delay2)
{
return fuzzyLess(delayAsFloat(delay1), delay2);
}
bool
delayFuzzyLessEqual(const Delay &delay1,
const Delay &delay2)
{
return fuzzyLessEqual(delayAsFloat(delay1), delayAsFloat(delay2));
}
bool
delayFuzzyLessEqual(const Delay &delay1,
float delay2)
{
return fuzzyLessEqual(delayAsFloat(delay1), delay2);
}
bool
delayFuzzyLessEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max)
{
if (min_max == MinMax::max())
return fuzzyLessEqual(delayAsFloat(delay1), delayAsFloat(delay2));
else
return fuzzyGreaterEqual(delayAsFloat(delay1), delayAsFloat(delay2));
}
bool
delayFuzzyGreater(const Delay &delay1,
const Delay &delay2)
{
return fuzzyGreater(delayAsFloat(delay1), delayAsFloat(delay2));
}
bool
delayFuzzyGreater(const Delay &delay1,
float delay2)
{
return fuzzyGreater(delayAsFloat(delay1), delay2);
}
bool
delayFuzzyGreaterEqual(const Delay &delay1,
const Delay &delay2)
{
return fuzzyGreaterEqual(delayAsFloat(delay1), delayAsFloat(delay2));
}
bool
delayFuzzyGreaterEqual(const Delay &delay1,
float delay2)
{
return fuzzyGreaterEqual(delayAsFloat(delay1), delay2);
}
bool
delayFuzzyGreater(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max)
{
if (min_max == MinMax::max())
return fuzzyGreater(delayAsFloat(delay1), delayAsFloat(delay2));
else
return fuzzyLess(delayAsFloat(delay1), delayAsFloat(delay2));
}
bool
delayFuzzyGreaterEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max)
{
if (min_max == MinMax::max())
return fuzzyGreaterEqual(delayAsFloat(delay1), delayAsFloat(delay2));
else
return fuzzyLessEqual(delayAsFloat(delay1), delayAsFloat(delay2));
}
bool
delayFuzzyLess(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max)
{
if (min_max == MinMax::max())
return fuzzyLess(delayAsFloat(delay1), delayAsFloat(delay2));
else
return fuzzyGreater(delayAsFloat(delay1), delayAsFloat(delay2));
}
Delay
operator+(float delay1,
const Delay &delay2)
{
return Delay(delay1 + delayAsFloat(delay2));
}
Delay
operator/(float delay1,
const Delay &delay2)
{
return Delay(delay1 / delayAsFloat(delay2));
}
Delay
operator*(float delay1,
const Delay &delay2)
{
return Delay(delay1 * delayAsFloat(delay2));
}
Delay
operator*(const Delay &delay1,
float delay2)
{
return Delay(delayAsFloat(delay1) * delay2);
}
float
delayRatio(const Delay &delay1,
const Delay &delay2)
{
return delayAsFloat(delay1) / delayAsFloat(delay2);
}
const char *
delayAsString(const Delay &delay,
Units *units)
{
return units->timeUnit()->asString(delayAsFloat(delay));
}
const char *
delayAsString(const Delay &delay,
const StaState *sta)
{
return delayAsString(delay, sta->units());
}
} // namespace
#endif

141
graph/DelayFloatClass.hh Normal file
View File

@ -0,0 +1,141 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_DELAY_FLOAT_CLASS_H
#define STA_DELAY_FLOAT_CLASS_H
#include "MinMax.hh"
#include "Pool.hh"
namespace sta {
// Delay values defined as objects that hold a float value.
class Units;
class Delay;
class StaState;
typedef Delay ArcDelay;
typedef Delay Slew;
typedef Delay Arrival;
typedef Delay Required;
typedef Delay Slack;
typedef Pool<Delay> DelayPool;
class Delay
{
public:
Delay();
Delay(float delay);
float asFloat() const;
void operator=(const Delay &delay);
void operator=(float delay);
void operator+=(const Delay &delay);
void operator+=(float delay);
Delay operator+(const Delay &delay) const;
Delay operator+(float delay) const;
Delay operator-(const Delay &delay) const;
Delay operator-(float delay) const;
Delay operator-() const;
void operator-=(float delay);
bool operator==(const Delay &delay) const;
bool operator>(const Delay &delay) const;
bool operator>=(const Delay &delay) const;
bool operator<(const Delay &delay) const;
bool operator<=(const Delay &delay) const;
private:
float delay_;
};
const Delay delay_zero(0.0);
void
initDelayConstants();
// Most non-operator functions on Delay are not defined as member
// functions so they can be defined on floats, where there is no class
// to define them.
Delay operator+(float delay1,
const Delay &delay2);
Delay operator/(float delay1,
const Delay &delay2);
Delay operator*(float delay1,
const Delay &delay2);
Delay operator*(const Delay &delay1,
float delay2);
inline float
delayAsFloat(const Delay &delay) { return delay.asFloat(); }
const char *delayAsString(const Delay &delay,
Units *units);
const char *delayAsString(const Delay &delay,
const StaState *sta);
const Delay &delayInitValue(const MinMax *min_max);
bool
delayIsInitValue(const Delay &delay,
const MinMax *min_max);
bool
delayFuzzyZero(const Delay &delay);
bool
delayFuzzyEqual(const Delay &delay1,
const Delay &delay2);
bool
delayFuzzyLess(const Delay &delay1,
const Delay &delay2);
bool
delayFuzzyLess(const Delay &delay1,
float delay2);
bool
delayFuzzyLess(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max);
bool
delayFuzzyLessEqual(const Delay &delay1,
const Delay &delay2);
bool
delayFuzzyLessEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max);
bool
delayFuzzyLessEqual(const Delay &delay1,
float delay2);
bool
delayFuzzyGreater(const Delay &delay1,
const Delay &delay2);
bool
delayFuzzyGreater(const Delay &delay1,
float delay2);
bool
delayFuzzyGreaterEqual(const Delay &delay1,
const Delay &delay2);
bool
delayFuzzyGreaterEqual(const Delay &delay1,
float delay2);
bool
delayFuzzyGreaterEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max);
bool
delayFuzzyGreater(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max);
float
delayRatio(const Delay &delay1,
const Delay &delay2);
} // namespace
#endif

1610
graph/Graph.cc Normal file

File diff suppressed because it is too large Load Diff

504
graph/Graph.hh Normal file
View File

@ -0,0 +1,504 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_GRAPH_H
#define STA_GRAPH_H
#include "DisallowCopyAssign.hh"
#include "Iterator.hh"
#include "Map.hh"
#include "Vector.hh"
#include "Pool.hh"
#include "StaState.hh"
#include "LibertyClass.hh"
#include "NetworkClass.hh"
#include "Delay.hh"
#include "GraphClass.hh"
namespace sta {
class MinMax;
class Sdc;
class PathVertexRep;
enum VertexColor {
vertex_color_white,
vertex_color_gray,
vertex_color_black
};
typedef Pool<Vertex> VertexPool;
typedef Pool<Edge> EdgePool;
typedef Map<const Pin*, Vertex*> PinVertexMap;
typedef Iterator<Edge*> VertexEdgeIterator;
typedef Map<const Pin*, float*> WidthCheckAnnotations;
typedef Map<const Pin*, float*> PeriodCheckAnnotations;
typedef Vector<DelayPool*> DelayPoolSeq;
// The graph acts as a BUILDER for the graph vertices and edges.
class Graph : public StaState
{
public:
// slew_tr_count is
// 0 no slews
// 1 one slew for rise/fall
// 2 rise/fall slews
// ap_count is the dcalc analysis point count.
Graph(StaState *sta,
int slew_tr_count,
bool have_arc_delays,
DcalcAPIndex ap_count);
void makeGraph();
virtual ~Graph();
// Number of arc delays and slews from sdf or delay calculation.
virtual void setDelayCount(DcalcAPIndex ap_count);
// Vertex functions.
// Bidirect pins have two vertices.
virtual Vertex *vertex(VertexIndex vertex_index) const;
VertexIndex index(const Vertex *vertex) const;
void makePinVertices(Pin *pin);
void makePinVertices(Pin *pin,
Vertex *&vertex,
Vertex *&bidir_drvr_vertex);
// Both vertices for bidirects.
void pinVertices(const Pin *pin,
// Return values.
Vertex *&vertex,
Vertex *&bidirect_drvr_vertex) const;
// Driver vertex for bidirects.
Vertex *pinDrvrVertex(const Pin *pin) const;
// Load vertex for bidirects.
Vertex *pinLoadVertex(const Pin *pin) const;
virtual void deleteVertex(Vertex *vertex);
bool hasFaninOne(Vertex *vertex) const;
VertexIndex vertexCount() { return vertex_count_; }
// Slews are reported slews in seconds.
// Reported slew are the same as those in the liberty tables.
// reported_slews = measured_slews / slew_derate_from_library
// Measured slews are between slew_lower_threshold and slew_upper_threshold.
virtual const Slew &slew(const Vertex *vertex,
const TransRiseFall *tr,
DcalcAPIndex ap_index);
virtual void setSlew(Vertex *vertex,
const TransRiseFall *tr,
DcalcAPIndex ap_index,
const Slew &slew);
// Edge functions.
virtual Edge *edge(EdgeIndex edge_index) const;
EdgeIndex index(const Edge *edge) const;
virtual Edge *makeEdge(Vertex *from,
Vertex *to,
TimingArcSet *arc_set);
virtual void makeWireEdge(Pin *from_pin,
Pin *to_pin);
void makePinInstanceEdges(Pin *pin);
void makeInstanceEdges(const Instance *inst);
void makeWireEdgesToPin(Pin *to_pin);
void makeWireEdgesThruPin(Pin *hpin);
virtual void makeWireEdgesFromPin(Pin *drvr_pin);
virtual void deleteEdge(Edge *edge);
virtual ArcDelay arcDelay(const Edge *edge,
const TimingArc *arc,
DcalcAPIndex ap_index) const;
virtual void setArcDelay(Edge *edge,
const TimingArc *arc,
DcalcAPIndex ap_index,
ArcDelay delay);
// Alias for arcDelays using library wire arcs.
virtual const ArcDelay &wireArcDelay(const Edge *edge,
const TransRiseFall *tr,
DcalcAPIndex ap_index);
virtual void setWireArcDelay(Edge *edge,
const TransRiseFall *tr,
DcalcAPIndex ap_index,
const ArcDelay &delay);
EdgeIndex edgeCount() { return edge_count_; }
virtual ArcIndex arcCount() { return arc_count_; }
// Sdf width check annotation.
void widthCheckAnnotation(const Pin *pin,
const TransRiseFall *tr,
DcalcAPIndex ap_index,
// Return values.
float &width,
bool &exists);
void setWidthCheckAnnotation(const Pin *pin,
const TransRiseFall *tr,
DcalcAPIndex ap_index,
float width);
// Sdf period check annotation.
void periodCheckAnnotation(const Pin *pin,
DcalcAPIndex ap_index,
// Return values.
float &period,
bool &exists);
void setPeriodCheckAnnotation(const Pin *pin,
DcalcAPIndex ap_index,
float period);
// Remove all delay and slew annotations.
void removeDelaySlewAnnotations();
VertexSet *regClkVertices() { return &reg_clk_vertices_; }
protected:
void makeVerticesAndEdges();
void vertexAndEdgeCounts(// Return values.
VertexIndex &vertex_count,
EdgeIndex &edge_count,
ArcIndex &arc_count);
virtual void vertexAndEdgeCounts(const Instance *inst,
PinSet &visited_drvrs,
// Return values.
VertexIndex &vertex_count,
EdgeIndex &edge_count,
ArcIndex &arc_count);
virtual void drvrPinEdgeCounts(Pin *pin,
PinSet &visited_drvrs,
// Return values.
EdgeIndex &edge_count,
ArcIndex &arc_count);
Vertex *makeVertex(Pin *pin,
bool is_bidirect_drvr,
bool is_reg_clk);
virtual void makeEdgeArcDelays(Edge *edge);
void makePinVertices(const Instance *inst);
void makeWireEdgesFromPin(Pin *drvr_pin,
PinSet &visited_drvrs);
void makeWireEdges();
virtual void makeInstDrvrWireEdges(Instance *inst,
PinSet &visited_drvrs);
virtual void makePortInstanceEdges(const Instance *inst,
LibertyCell *cell,
LibertyPort *from_to_port);
void removeWidthCheckAnnotations();
void removePeriodCheckAnnotations();
void makeSlewPools(VertexIndex vertex_count,
DcalcAPIndex count);
void deleteSlewPools();
void makeVertexSlews();
void deleteVertexSlews(Vertex *vertex);
void makeArcDelayPools(ArcIndex arc_count,
DcalcAPIndex ap_count);
void deleteArcDelayPools();
virtual void deleteEdgeArcDelays(Edge *edge);
void deleteInEdge(Vertex *vertex,
Edge *edge);
void deleteOutEdge(Vertex *vertex,
Edge *edge);
void removeDelays();
float *makeFloats(ObjectIndex count);
void deleteFloats(float *floats,
ObjectIndex count);
VertexPool *vertices_;
EdgePool *edges_;
// Bidirect pins are split into two vertices:
// load/sink (top level output, instance pin input) vertex in pin_vertex_map
// driver/source (top level input, instance pin output) vertex
// in pin_bidirect_drvr_vertex_map
PinVertexMap pin_bidirect_drvr_vertex_map_;
VertexIndex vertex_count_;
EdgeIndex edge_count_;
ArcIndex arc_count_;
int slew_tr_count_;
bool have_arc_delays_;
DcalcAPIndex ap_count_;
DelayPoolSeq slew_pools_; // [ap_index][tr_index][vertex_index]
VertexIndex slew_count_;
DelayPoolSeq arc_delays_; // [ap_index][edge_arc_index]
Pool<float> *float_pool_;
// Sdf width check annotations.
WidthCheckAnnotations *width_check_annotations_;
// Sdf period check annotations.
PeriodCheckAnnotations *period_check_annotations_;
// Register/latch clock vertices to search from.
VertexSet reg_clk_vertices_;
friend class Vertex;
friend class VertexIterator;
friend class VertexInEdgeIterator;
friend class VertexOutEdgeIterator;
friend class MakeEdgesThruHierPin;
private:
DISALLOW_COPY_AND_ASSIGN(Graph);
};
// Each Vertex corresponds to one network pin.
class Vertex
{
public:
Vertex();
Pin *pin() const { return pin_; }
// Pin path with load/driver suffix for bidirects.
const char *name(const Network *network) const;
bool isBidirectDriver() const { return is_bidirect_drvr_; }
Level level() const { return level_; }
void setLevel(Level level);
bool isRoot() const{ return level_ == 0; }
VertexColor color() const { return (VertexColor) color_; }
void setColor(VertexColor color);
Arrival *arrivals() const { return arrivals_; }
void setArrivals(Arrival *arrivals);
PathVertexRep *prevPaths() const { return prev_paths_; }
void setPrevPaths(PathVertexRep *prev_paths);
// Requireds optionally follow arrivals in the same array.
bool hasRequireds() const { return has_requireds_; }
void setHasRequireds(bool has_req);
TagGroupIndex tagGroupIndex() const;
void setTagGroupIndex(TagGroupIndex tag_index);
// Slew is annotated by sdc set_annotated_transition cmd.
bool slewAnnotated(const TransRiseFall *tr,
DcalcAPIndex ap_index) const;
// True if any rise/fall analysis pt slew is annotated.
bool slewAnnotated() const;
void setSlewAnnotated(bool annotated,
const TransRiseFall *tr,
DcalcAPIndex ap_index);
void removeSlewAnnotated();
// Constant zero/one from simulation.
bool isConstant() const;
LogicValue simValue() const;
void setSimValue(LogicValue value);
bool isDisabledConstraint() const { return is_disabled_constraint_; }
void setIsDisabledConstraint(bool disabled);
// True when vertex has timing check edges that constrain it.
bool hasChecks() const { return has_checks_; }
void setHasChecks(bool has_checks);
bool isCheckClk() const { return is_check_clk_; }
void setIsCheckClk(bool is_check_clk);
bool isGatedClkEnable() const { return is_gated_clk_enable_; }
void setIsGatedClkEnable(bool enable);
bool hasDownstreamClkPin() const { return has_downstream_clk_pin_; }
void setHasDownstreamClkPin(bool has_clk_pin);
// Vertices are constrained if they have one or more of the
// following timing constraints:
// output delay constraints
// data check constraints
// path delay constraints
bool isConstrained() const { return is_constrained_; }
void setIsConstrained(bool constrained);
bool bfsInQueue(BfsIndex index) const;
void setBfsInQueue(BfsIndex index, bool value);
bool isRegClk() const { return is_reg_clk_; }
static int transitionCount() { return 2; } // rise/fall
protected:
void init(Pin *pin,
bool is_bidirect_drvr,
bool is_reg_clk);
Pin *pin_;
Arrival *arrivals_;
PathVertexRep *prev_paths_;
EdgeIndex in_edges_; // Edges to this vertex.
EdgeIndex out_edges_; // Edges from this vertex.
unsigned int tag_group_index_:tag_group_index_bits;
bool has_requireds_:1;
unsigned int slew_annotated_:4;
// Bidirect pins have two vertices.
// This flag distinguishes the driver and load vertices.
bool is_bidirect_drvr_:1;
bool is_reg_clk_:1;
unsigned int sim_value_:3; // LogicValue
bool is_disabled_constraint_:1;
bool is_gated_clk_enable_:1;
// Constrained by timing check edge.
bool has_checks_:1;
// Is the clock for a timing check.
bool is_check_clk_:1;
bool is_constrained_:1;
bool has_downstream_clk_pin_:1;
// Levelization search state.
unsigned int color_:2;
unsigned int level_:16;
// Each bit corresponds to a different BFS queue.
unsigned int bfs_in_queue_:bfs_index_bits;
private:
DISALLOW_COPY_AND_ASSIGN(Vertex);
friend class Graph;
friend class Edge;
friend class VertexInEdgeIterator;
friend class VertexOutEdgeIterator;
};
#define max_dcalc_analysis_pt_count 4
// One annotation bit per timing arc per delay calculation analysis point.
#define delay_annotation_bit_count \
((timing_arc_index_max + 1) * max_dcalc_analysis_pt_count)
// There is one Edge between each pair of pins that has a timing
// path between them.
class Edge
{
public:
Edge();
Vertex *to(const Graph *graph) const { return graph->vertex(to_); }
Vertex *from(const Graph *graph) const { return graph->vertex(from_); }
TimingRole *role() const;
bool isWire() const;
TimingSense sense() const;
TimingArcSet *timingArcSet() const { return arc_set_; }
void setTimingArcSet(TimingArcSet *set);
ArcIndex arcDelays() const { return arc_delays_; }
void setArcDelays(ArcIndex arc_delays);
// True if any timing arc delay is annotated.
bool arcDelayAnnotated() const;
// Is timing arc delay annotated.
bool arcDelayAnnotated(TimingArc *arc,
DcalcAPIndex ap_index) const;
void setArcDelayAnnotated(bool annotated,
TimingArc *arc,
DcalcAPIndex ap_index);
bool wireDelayAnnotated(const TransRiseFall *tr,
DcalcAPIndex ap_index) const;
void setWireDelayAnnotated(bool annotated,
const TransRiseFall *tr,
DcalcAPIndex ap_index);
void removeDelayAnnotated();
bool delayAnnotationIsIncremental() const;
void setDelayAnnotationIsIncremental(bool is_incr);
// Edge is disabled by set_disable_timing constraint.
bool isDisabledConstraint() const;
void setIsDisabledConstraint(bool disabled);
// Timing sense for the to_pin function after simplifying the
// function based constants on the instance pins.
TimingSense simTimingSense() const;
void setSimTimingSense(TimingSense sense);
// Edge is disabled by constants in condition (when) function.
bool isDisabledCond() const { return is_disabled_cond_; }
void setIsDisabledCond(bool disabled);
// Edge is disabled to break combinational loops.
bool isDisabledLoop() const { return is_disabled_loop_; }
void setIsDisabledLoop(bool disabled);
// Edge is disabled to prevent converging clocks from merging (Xilinx).
bool isBidirectInstPath() const { return is_bidirect_inst_path_; }
void setIsBidirectInstPath(bool is_bidir);
bool isBidirectNetPath() const { return is_bidirect_net_path_; }
void setIsBidirectNetPath(bool is_bidir);
protected:
void init(VertexIndex from,
VertexIndex to,
TimingArcSet *arc_set);
TimingArcSet *arc_set_;
VertexIndex from_;
VertexIndex to_;
VertexIndex vertex_in_link_; // Vertex in edges list.
VertexIndex vertex_out_next_; // Vertex out edges doubly linked list.
VertexIndex vertex_out_prev_;
ArcIndex arc_delays_;
// Timing arcs with sdf annotation.
unsigned int delay_annotated_:delay_annotation_bit_count;
unsigned int delay_annotation_is_incremental_:1;
unsigned int is_bidirect_inst_path_:1;
unsigned int is_bidirect_net_path_:1;
// Timing sense from function and constants on edge instance.
unsigned int sim_timing_sense_:timing_sense_bit_count;
unsigned int is_disabled_constraint_:1;
unsigned int is_disabled_cond_:1;
unsigned int is_disabled_loop_:1;
private:
DISALLOW_COPY_AND_ASSIGN(Edge);
friend class Graph;
friend class GraphDelays1;
friend class GraphSlewsDelays1;
friend class GraphSlewsDelays2;
friend class Vertex;
friend class VertexInEdgeIterator;
friend class VertexOutEdgeIterator;
};
// Iterate over all graph vertices.
class VertexIterator : public Iterator<Vertex*>
{
public:
explicit VertexIterator(Graph *graph);
virtual bool hasNext() { return vertex_ || bidir_vertex_; }
virtual Vertex *next();
private:
DISALLOW_COPY_AND_ASSIGN(VertexIterator);
bool findNextPin();
void findNext();
Graph *graph_;
Network *network_;
Instance *top_inst_;
LeafInstanceIterator *inst_iter_;
InstancePinIterator *pin_iter_;
Vertex *vertex_;
Vertex *bidir_vertex_;
};
class VertexInEdgeIterator : public VertexEdgeIterator
{
public:
VertexInEdgeIterator(Vertex *vertex,
const Graph *graph);
VertexInEdgeIterator(VertexIndex vertex_index,
const Graph *graph);
bool hasNext() { return (next_ != NULL); }
Edge *next();
private:
DISALLOW_COPY_AND_ASSIGN(VertexInEdgeIterator);
Edge *next_;
const Graph *graph_;
};
class VertexOutEdgeIterator : public VertexEdgeIterator
{
public:
VertexOutEdgeIterator(Vertex *vertex,
const Graph *graph);
bool hasNext() { return (next_ != NULL); }
Edge *next();
private:
DISALLOW_COPY_AND_ASSIGN(VertexOutEdgeIterator);
Edge *next_;
const Graph *graph_;
};
// Iterate over the edges through a hierarchical pin.
class EdgesThruHierPinIterator : public Iterator<Edge*>
{
public:
EdgesThruHierPinIterator(const Pin *hpin,
Network *network,
Graph *graph);
virtual bool hasNext() { return edge_iter_.hasNext(); }
virtual Edge *next() { return edge_iter_.next(); }
private:
DISALLOW_COPY_AND_ASSIGN(EdgesThruHierPinIterator);
EdgeSet edges_;
EdgeSet::Iterator edge_iter_;
};
} // namespace
#endif

62
graph/GraphClass.hh Normal file
View File

@ -0,0 +1,62 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_GRAPH_CLASS_H
#define STA_GRAPH_CLASS_H
#include "ObjectIndex.hh"
#include "Set.hh"
#include "Vector.hh"
namespace sta {
// Class declarations for pointer references.
class Graph;
class Vertex;
class Edge;
class VertexIterator;
class VertexInEdgeIterator;
class VertexOutEdgeIterator;
class GraphLoop;
typedef ObjectIndex VertexIndex;
typedef ObjectIndex EdgeIndex;
typedef ObjectIndex ArcIndex;
typedef Set<Vertex*> VertexSet;
typedef Vector<Vertex*> VertexSeq;
typedef Vector<Edge*> EdgeSeq;
typedef Set<Edge*> EdgeSet;
typedef int Level;
typedef int DcalcAPIndex;
typedef int TagGroupIndex;
typedef Vector<GraphLoop*> GraphLoopSeq;
// 16,777,215 tags
static const int tag_group_index_bits = 24;
static const TagGroupIndex tag_group_index_max = (1<<tag_group_index_bits)-1;
enum BfsIndex {
bfs_dcalc,
bfs_arrival,
bfs_required,
bfs_other
};
static const int bfs_index_bits = bfs_other + 1;
extern const char *bfs_index_names[];
} // namespace
#endif

68
graph/GraphCmp.cc Normal file
View File

@ -0,0 +1,68 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 "Network.hh"
#include "NetworkCmp.hh"
#include "Graph.hh"
#include "GraphCmp.hh"
namespace sta {
VertexNameLess::VertexNameLess(Network *network) :
network_(network)
{
}
bool
VertexNameLess::operator()(const Vertex *vertex1,
const Vertex *vertex2)
{
return network_->pathNameLess(vertex1->pin(), vertex2->pin());
}
////////////////////////////////////////////////////////////////
EdgeLess::EdgeLess(const Network *network,
Graph *graph) :
pin_less_(network),
graph_(graph)
{
}
bool
EdgeLess::operator()(const Edge *edge1,
const Edge *edge2) const
{
const Pin *from1 = edge1->from(graph_)->pin();
const Pin *from2 = edge2->from(graph_)->pin();
const Pin *to1 = edge1->to(graph_)->pin();
const Pin *to2 = edge2->to(graph_)->pin();
return pin_less_(from1, from2)
|| (from1 == from2
&& pin_less_(to1, to2));
}
void
sortEdges(EdgeSeq *edges,
Network *network,
Graph *graph)
{
sort(edges, EdgeLess(network, graph));
}
}

56
graph/GraphCmp.hh Normal file
View File

@ -0,0 +1,56 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_GRAPH_CMP_H
#define STA_GRAPH_CMP_H
#include "NetworkClass.hh"
#include "NetworkCmp.hh"
#include "GraphClass.hh"
namespace sta {
class VertexNameLess
{
public:
explicit VertexNameLess(Network *network);
bool operator()(const Vertex *vertex1,
const Vertex *vertex2);
private:
Network *network_;
};
class EdgeLess
{
public:
EdgeLess(const Network *network,
Graph *graph);
bool operator()(const Edge *edge1,
const Edge *edge2) const;
private:
const PinPathNameLess pin_less_;
Graph *graph_;
};
void
sortEdges(EdgeSeq *edges,
Network *network,
Graph *graph);
} // namespace
#endif

36
graph/Makefile.am Normal file
View File

@ -0,0 +1,36 @@
# OpenSTA, Static Timing Analyzer
# Copyright (c) 2018, 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/>.
lib_LTLIBRARIES = libgraph.la
include_HEADERS = \
Delay.hh \
DelayFloat.hh \
DelayFloatClass.hh \
Graph.hh \
GraphClass.hh \
GraphCmp.hh
libgraph_la_SOURCES = \
DelayFloat.cc \
DelayFloatClass.cc \
Graph.cc \
GraphCmp.cc
libs: $(lib_LTLIBRARIES)
xtags: $(SOURCES) $(HEADERS)
etags -a -o ../TAGS $(SOURCES) $(HEADERS)

367
liberty/EquivCells.cc Normal file
View File

@ -0,0 +1,367 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 "PortDirection.hh"
#include "Transition.hh"
#include "MinMax.hh"
#include "TimingRole.hh"
#include "FuncExpr.hh"
#include "TimingArc.hh"
#include "Liberty.hh"
#include "TableModel.hh"
#include "Sequential.hh"
#include "EquivCells.hh"
namespace sta {
typedef Map<unsigned,LibertyCellSeq*, std::less<unsigned> > LibertyCellHashMap;
typedef Set<LibertyCellSeq*> LibertyCellSeqSet;
static LibertyCellEquivMap *
findEquivCells1(const LibertyLibrary *library);
static void
sortCellEquivs(LibertyCellEquivMap *cell_equivs);
float
cellDriveResistance(const LibertyCell *cell);
static unsigned
hashCell(const LibertyCell *cell);
static unsigned
hashCellPorts(const LibertyCell *cell);
static unsigned
hashCellSequentials(const LibertyCell *cell);
static unsigned
hashFuncExpr(const FuncExpr *expr);
static unsigned
hashPort(const LibertyPort *port);
static unsigned
hashString(const char *str);
static bool
equivCellSequentials(const LibertyCell *cell1,
const LibertyCell *cell2);
LibertyCellEquivMap *
makeEquivCellMap(const LibertyLibrary *library)
{
LibertyCellEquivMap *cell_equivs = findEquivCells1(library);
sortCellEquivs(cell_equivs);
return cell_equivs;
}
void
deleteEquivCellMap(LibertyCellEquivMap *equiv_map)
{
// Multiple cells can point to the same cell sequence, so collect
// them into a set so the are only deleted once.
LibertyCellSeqSet cells_seqs;
LibertyCellEquivMap::Iterator equiv_iter(equiv_map);
while (equiv_iter.hasNext()) {
LibertyCellSeq *cells = equiv_iter.next();
cells_seqs.insert(cells);
}
LibertyCellSeqSet::Iterator cells_iter(cells_seqs);
while (cells_iter.hasNext()) {
LibertyCellSeq *cells = cells_iter.next();
delete cells;
}
delete equiv_map;
}
static LibertyCellEquivMap *
findEquivCells1(const LibertyLibrary *library)
{
LibertyCellHashMap cell_hash;
LibertyCellEquivMap *cell_equivs = new LibertyCellEquivMap;
LibertyLibraryCellIterator *cell_iter = library->libertyCellIterator();
while (cell_iter->hasNext()) {
LibertyCell *cell = cell_iter->next();
if (!cell->dontUse()) {
bool found_equiv = false;
unsigned hash = hashCell(cell);
// Use a comprehensive hash on cell properties to segregate
// cells into groups of potential matches.
LibertyCellSeq *matches = cell_hash[hash];
if (matches) {
LibertyCellSeq::Iterator match_iter(matches);
while (match_iter.hasNext()) {
LibertyCell *match = match_iter.next();
if (equivCells(match, cell)) {
LibertyCellSeq *equivs = cell_equivs->findKey(match);
equivs->push_back(cell);
(*cell_equivs)[cell] = equivs;
found_equiv = true;
break;
}
}
}
else {
matches = new LibertyCellSeq;
cell_hash[hash] = matches;
}
matches->push_back(cell);
if (!found_equiv) {
LibertyCellSeq *equivs = new LibertyCellSeq;
equivs->push_back(cell);
(*cell_equivs)[cell] = equivs;
}
}
}
delete cell_iter;
LibertyCellHashMap::Iterator hash_iter(cell_hash);
while (hash_iter.hasNext()) {
LibertyCellSeq *cells = hash_iter.next();
delete cells;
}
return cell_equivs;
}
struct CellDriveResistanceLess
{
bool operator()(const LibertyCell *cell1,
const LibertyCell *cell2) const
{
return cellDriveResistance(cell1) > cellDriveResistance(cell2);
}
};
static void
sortCellEquivs(LibertyCellEquivMap *cell_equivs)
{
LibertyCellEquivMap::Iterator equivs_iter(cell_equivs);
while (equivs_iter.hasNext()) {
LibertyCellSeq *equivs = equivs_iter.next();
sort(equivs, CellDriveResistanceLess());
}
}
// Use the worst "drive" for all the timing arcs in the cell.
// Note that this function can NOT be static for sun's compiler to
// be happy with using it in a sort predicate (presumably because the
// template functions are compiled outside the scope of this file).
float
cellDriveResistance(const LibertyCell *cell)
{
float max_drive = 0.0;
CellTimingArcSetIterator *set_iter = cell->timingArcSetIterator();
while (set_iter->hasNext()) {
TimingArcSet *set = set_iter->next();
if (!set->role()->isTimingCheck()) {
TimingArcSetArcIterator *arc_iter = set->timingArcIterator();
while (arc_iter->hasNext()) {
TimingArc *arc = arc_iter->next();
GateTimingModel *model = dynamic_cast<GateTimingModel*>(arc->model());
if (model) {
float drive = model->driveResistance(cell, NULL);
if (drive > max_drive)
max_drive = drive;
}
}
delete arc_iter;
}
}
delete set_iter;
return max_drive;
}
static unsigned
hashCell(const LibertyCell *cell)
{
return hashCellPorts(cell) + hashCellSequentials(cell);
}
static unsigned
hashCellPorts(const LibertyCell *cell)
{
unsigned hash = 0;
LibertyCellPortIterator *port_iter = cell->libertyPortIterator();
while (port_iter->hasNext()) {
LibertyPort *port = port_iter->next();
hash += hashPort(port);
hash += hashFuncExpr(port->function()) * 3;
hash += hashFuncExpr(port->tristateEnable()) * 5;
}
delete port_iter;
return hash;
}
static unsigned
hashPort(const LibertyPort *port)
{
return hashString(port->name()) * 3
+ port->direction()->index() * 5;
}
static unsigned
hashCellSequentials(const LibertyCell *cell)
{
unsigned hash = 0;
CellSequentialIterator *seq_iter = cell->sequentialIterator();
while (seq_iter->hasNext()) {
Sequential *seq = seq_iter->next();
hash += hashFuncExpr(seq->clock()) * 3;
hash += hashFuncExpr(seq->data()) * 5;
hash += hashPort(seq->output()) * 7;
hash += hashPort(seq->outputInv()) * 9;
hash += hashFuncExpr(seq->clear()) * 11;
hash += hashFuncExpr(seq->preset()) * 13;
hash += seq->clearPresetOutput() * 17;
hash += seq->clearPresetOutputInv() * 19;
}
delete seq_iter;
return hash;
}
static unsigned
hashFuncExpr(const FuncExpr *expr)
{
if (expr == NULL)
return 0;
else {
switch (expr->op()) {
case FuncExpr::op_port:
return hashPort(expr->port()) * 17;
break;
case FuncExpr::op_not:
return hashFuncExpr(expr->left()) * 31;
break;
default:
return (hashFuncExpr(expr->left()) + hashFuncExpr(expr->right()))
* ((1 << expr->op()) - 1);
}
}
}
static unsigned
hashString(const char *str)
{
unsigned hash = 0;
size_t length = strlen(str);
for (size_t i = 0; i < length; i++) {
hash = str[i] + (hash << 2);
}
return hash;
}
bool
equivCells(const LibertyCell *cell1,
const LibertyCell *cell2)
{
return equivCellPortsAndFuncs(cell1, cell2)
&& equivCellSequentials(cell1, cell2)
&& equivCellTimingArcSets(cell1, cell2);
}
bool
equivCellPortsAndFuncs(const LibertyCell *cell1,
const LibertyCell *cell2)
{
if (cell1->portCount() != cell2->portCount())
return false;
else {
LibertyCellPortIterator *port_iter1 = cell1->libertyPortIterator();
while (port_iter1->hasNext()) {
LibertyPort *port1 = port_iter1->next();
const char *name = port1->name();
LibertyPort *port2 = cell2->findLibertyPort(name);
if (!(port2
&& LibertyPort::equiv(port1, port2)
&& FuncExpr::equiv(port1->function(), port2->function())
&& FuncExpr::equiv(port1->tristateEnable(),
port2->tristateEnable()))){
delete port_iter1;
return false;
}
}
delete port_iter1;
return true;
}
}
bool
equivCellPorts(const LibertyCell *cell1,
const LibertyCell *cell2)
{
if (cell1->portCount() != cell2->portCount())
return false;
else {
LibertyCellPortIterator *port_iter1 = cell1->libertyPortIterator();
while (port_iter1->hasNext()) {
LibertyPort *port1 = port_iter1->next();
const char* name = port1->name();
LibertyPort *port2 = cell2->findLibertyPort(name);
if (!(port2 && LibertyPort::equiv(port1, port2))) {
delete port_iter1;
return false;
}
}
delete port_iter1;
return true;
}
}
static bool
equivCellSequentials(const LibertyCell *cell1,
const LibertyCell *cell2)
{
bool eq = true;
CellSequentialIterator *seq_iter1 = cell1->sequentialIterator();
CellSequentialIterator *seq_iter2 = cell2->sequentialIterator();
while (seq_iter1->hasNext() && seq_iter2->hasNext()) {
Sequential *seq1 = seq_iter1->next();
Sequential *seq2 = seq_iter2->next();
if (!(FuncExpr::equiv(seq1->clock(), seq2->clock())
&& FuncExpr::equiv(seq1->data(), seq2->data())
&& LibertyPort::equiv(seq1->output(), seq2->output())
&& LibertyPort::equiv(seq1->outputInv(), seq2->outputInv())
&& FuncExpr::equiv(seq1->clear(), seq2->clear())
&& FuncExpr::equiv(seq1->preset(), seq2->preset()))) {
eq = false;
break;
}
}
if (seq_iter1->hasNext() || seq_iter2->hasNext())
eq = false;
delete seq_iter1;
delete seq_iter2;
return eq;
}
bool
equivCellTimingArcSets(const LibertyCell *cell1,
const LibertyCell *cell2)
{
if (cell1->timingArcSetCount() != cell2->timingArcSetCount())
return false;
else {
CellTimingArcSetIterator *set_iter1 = cell1->timingArcSetIterator();
while (set_iter1->hasNext()) {
TimingArcSet *set1 = set_iter1->next();
TimingArcSet *set2 = cell2->findTimingArcSet(set1);
if (!(set2 && TimingArcSet::equiv(set1, set2))) {
delete set_iter1;
return false;
}
}
delete set_iter1;
return true;
}
}
} // namespace

56
liberty/EquivCells.hh Normal file
View File

@ -0,0 +1,56 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_EQUIV_CELLS_H
#define STA_EQUIV_CELLS_H
#include "Map.hh"
#include "LibertyClass.hh"
namespace sta {
// Build a map from each cell in the library to a group (CellSeq) of
// cells with equivalent functionality, sorted by drive strength.
LibertyCellEquivMap *
makeEquivCellMap(const LibertyLibrary *library);
// Delete the LibertyCellEquivMap returned by makeEquivCellMap.
void
deleteEquivCellMap(LibertyCellEquivMap *equiv_map);
// Predicate that is true when the ports, functions, sequentials and
// timing arcs match.
bool
equivCells(const LibertyCell *cell1,
const LibertyCell *cell2);
// Predicate that is true when the ports match.
bool
equivCellPorts(const LibertyCell *cell1,
const LibertyCell *cell2);
// Predicate that is true when the ports and their functions match.
bool
equivCellPortsAndFuncs(const LibertyCell *cell1,
const LibertyCell *cell2);
// Predicate that is true when the timing arc sets match.
bool
equivCellTimingArcSets(const LibertyCell *cell1,
const LibertyCell *cell2);
} // namespace
#endif

410
liberty/FuncExpr.cc Normal file
View File

@ -0,0 +1,410 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 "Liberty.hh"
#include "Network.hh"
#include "FuncExpr.hh"
namespace sta {
FuncExpr *
FuncExpr::makePort(LibertyPort *port)
{
return new FuncExpr(op_port, NULL, NULL, port);
}
FuncExpr *
FuncExpr::makeNot(FuncExpr *expr)
{
return new FuncExpr(op_not, expr, NULL, NULL);
}
FuncExpr *
FuncExpr::makeAnd(FuncExpr *left,
FuncExpr *right)
{
return new FuncExpr(op_and, left, right, NULL);
}
FuncExpr *
FuncExpr::makeOr(FuncExpr *left,
FuncExpr *right)
{
return new FuncExpr(op_or, left, right, NULL);
}
FuncExpr *
FuncExpr::makeXor(FuncExpr *left,
FuncExpr *right)
{
return new FuncExpr(op_xor, left, right, NULL);
}
FuncExpr *
FuncExpr::makeZero()
{
return new FuncExpr(op_zero, NULL, NULL, NULL);
}
FuncExpr *
FuncExpr::makeOne()
{
return new FuncExpr(op_one, NULL, NULL, NULL);
}
FuncExpr::FuncExpr(Operator op,
FuncExpr *left,
FuncExpr *right,
LibertyPort *port) :
op_(op),
left_(left),
right_(right),
port_(port)
{
}
void
FuncExpr::deleteSubexprs()
{
if (left_)
left_->deleteSubexprs();
if (right_)
right_->deleteSubexprs();
delete this;
}
LibertyPort *
FuncExpr::port() const
{
if (op_ == op_port)
return port_;
else
return NULL;
}
// Protect against null sub-expressions caused by unknown port refs.
TimingSense
FuncExpr::portTimingSense(const LibertyPort *port) const
{
TimingSense left_sense, right_sense;
switch (op_) {
case op_port:
if (port == port_)
return timing_sense_positive_unate;
else
return timing_sense_none;
case op_not:
if (left_) {
switch (left_->portTimingSense(port)) {
case timing_sense_positive_unate:
return timing_sense_negative_unate;
case timing_sense_negative_unate:
return timing_sense_positive_unate;
case timing_sense_non_unate:
return timing_sense_non_unate;
case timing_sense_none:
return timing_sense_none;
case timing_sense_unknown:
return timing_sense_unknown;
}
}
return timing_sense_unknown;
case op_or:
case op_and:
left_sense = timing_sense_unknown;
right_sense = timing_sense_unknown;
if (left_)
left_sense = left_->portTimingSense(port);
if (right_)
right_sense = right_->portTimingSense(port);
if (left_sense == right_sense)
return left_sense;
else if (left_sense == timing_sense_non_unate
|| right_sense == timing_sense_non_unate
|| (left_sense == timing_sense_positive_unate
&& right_sense == timing_sense_negative_unate)
|| (left_sense == timing_sense_negative_unate
&& right_sense == timing_sense_positive_unate))
return timing_sense_non_unate;
else if (left_sense == timing_sense_none
|| left_sense == timing_sense_unknown)
return right_sense;
else if (right_sense == timing_sense_none
|| right_sense == timing_sense_unknown)
return left_sense;
else
return timing_sense_unknown;
case op_xor:
left_sense = timing_sense_unknown;
right_sense = timing_sense_unknown;
if (left_)
left_sense = left_->portTimingSense(port);
if (right_)
right_sense = right_->portTimingSense(port);
if (left_sense == timing_sense_positive_unate
|| left_sense == timing_sense_negative_unate
|| left_sense == timing_sense_non_unate
|| right_sense == timing_sense_positive_unate
|| right_sense == timing_sense_negative_unate
|| right_sense == timing_sense_non_unate)
return timing_sense_non_unate;
else
return timing_sense_unknown;
case op_one:
return timing_sense_none;
case op_zero:
return timing_sense_none;
}
// Prevent warnings from lame compilers.
return timing_sense_unknown;
}
const char *
FuncExpr::asString() const
{
return asString(false);
}
const char *
FuncExpr::asString(bool with_parens) const
{
switch (op_) {
case op_port:
return port_->name();
case op_not: {
const char *left = left_->asString(true);
size_t left_length = strlen(left);
size_t length = left_length + 2;
char *result = makeTmpString(length);
char *ptr = result;
*ptr++ = '!';
strcpy(ptr, left);
return result;
}
case op_or:
return asStringSubexpr(with_parens, '+');
case op_and:
return asStringSubexpr(with_parens, '*');
case op_xor:
return asStringSubexpr(with_parens, '^');
case op_one:
return "1";
case op_zero:
return "0";
default:
return "?";
}
}
const char *
FuncExpr::asStringSubexpr(bool with_parens,
char op) const
{
const char *left = left_->asString(true);
const char *right = right_->asString(true);
size_t length = strlen(left) + 1 + strlen(right) + 1;
if (with_parens)
length += 2;
char *result = makeTmpString(length);
char *r = result;
if (with_parens)
*r++= '(';
stringAppend(r, left);
*r++ = op;
stringAppend(r, right);
if (with_parens)
*r++ = ')';
*r = '\0';
return result;
}
FuncExpr *
FuncExpr::bitSubExpr(int bit_offset)
{
switch (op_) {
case op_port:
if (port_->hasMembers()) {
if (port_->size() == 1) {
LibertyPort *port = port_->findLibertyMember(0);
return makePort(port);
}
else {
LibertyPort *port = port_->findLibertyMember(bit_offset);
return makePort(port);
}
}
else
// Always copy so the subexpr doesn't share memory.
return makePort(port_);
case op_not:
return makeNot(left_->bitSubExpr(bit_offset));
case op_or:
return makeOr(left_->bitSubExpr(bit_offset),
right_->bitSubExpr(bit_offset));
case op_and:
return makeAnd(left_->bitSubExpr(bit_offset),
right_->bitSubExpr(bit_offset));
case op_xor:
return makeXor(left_->bitSubExpr(bit_offset),
right_->bitSubExpr(bit_offset));
case op_one:
case op_zero:
return this;
}
// Prevent warnings from lame compilers.
return NULL;
}
bool
FuncExpr::hasPort(const LibertyPort *port) const
{
switch (op_) {
case op_port:
return (port_ == port);
case op_not:
return left_ && left_->hasPort(port);
case op_or:
case op_and:
case op_xor:
return (left_ && left_->hasPort(port))
|| (right_ && right_->hasPort(port));
case op_one:
case op_zero:
return false;
}
// Prevent warnings from lame compilers.
return false;
}
bool
FuncExpr::checkSize(LibertyPort *port)
{
return checkSize(port->size());
}
bool
FuncExpr::checkSize(size_t size)
{
size_t port_size;
switch (op_) {
case op_port:
port_size = port_->size();
return !(port_size == size
|| port_size == 1);
case op_not:
return left_->checkSize(size);
case op_or:
case op_and:
case op_xor:
return left_->checkSize(size) || right_->checkSize(size);
case op_one:
case op_zero:
return false;
}
// Prevent warnings from lame compilers.
return false;
}
FuncExpr *
funcExprNot(FuncExpr *expr)
{
if (expr->op() == FuncExpr::op_not) {
FuncExpr *not_expr = expr->left();
delete expr;
return not_expr;
}
else
return FuncExpr::makeNot(expr);
}
////////////////////////////////////////////////////////////////
FuncExprPortIterator::FuncExprPortIterator(FuncExpr *expr)
{
findPorts(expr);
iter_.init(ports_);
}
void
FuncExprPortIterator::findPorts(FuncExpr *expr)
{
if (expr) {
if (expr->op() == FuncExpr::op_port)
ports_.insert(expr->port());
else {
findPorts(expr->left());
findPorts(expr->right());
}
}
}
bool
FuncExpr::equiv(const FuncExpr *expr1,
const FuncExpr *expr2)
{
if (expr1 == NULL && expr2 == NULL)
return true;
else if (expr1 != NULL && expr2 != NULL
&& expr1->op() == expr2->op()) {
switch (expr1->op()) {
case FuncExpr::op_port:
return LibertyPort::equiv(expr1->port(), expr2->port());
case FuncExpr::op_not:
return equiv(expr1->left(), expr2->left());
default:
return equiv(expr1->left(), expr2->left())
&& equiv(expr1->right(), expr2->right());
}
}
else
return false;
}
bool
FuncExpr::less(const FuncExpr *expr1,
const FuncExpr *expr2)
{
if (expr1 != NULL && expr2 != NULL) {
Operator op1 = expr1->op();
Operator op2 = expr2->op();
if (op1 == op2) {
switch (expr1->op()) {
case FuncExpr::op_port:
return LibertyPort::less(expr1->port(), expr2->port());
case FuncExpr::op_not:
return less(expr1->left(), expr2->left());
default:
if (equiv(expr1->left(), expr2->left()))
return less(expr1->right(), expr2->right());
else
return less(expr1->left(), expr2->left());
}
}
else
return op1 < op2;
}
else if (expr1 == NULL && expr2 == NULL)
return false;
else
return (expr1 == NULL && expr2 != NULL);
}
} // namespace

108
liberty/FuncExpr.hh Normal file
View File

@ -0,0 +1,108 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_FUNC_EXPR_H
#define STA_FUNC_EXPR_H
#include "DisallowCopyAssign.hh"
#include "Set.hh"
#include "NetworkClass.hh"
#include "LibertyClass.hh"
namespace sta {
class FuncExpr
{
public:
enum Operator {op_port,
op_not,
op_or,
op_and,
op_xor,
op_one,
op_zero};
// Constructors.
static FuncExpr *makePort(LibertyPort *port);
static FuncExpr *makeNot(FuncExpr *expr);
static FuncExpr *makeAnd(FuncExpr *left,
FuncExpr *right);
static FuncExpr *makeOr(FuncExpr *left,
FuncExpr *right);
static FuncExpr *makeXor(FuncExpr *left,
FuncExpr *right);
static FuncExpr *makeZero();
static FuncExpr *makeOne();
static bool equiv(const FuncExpr *expr1,
const FuncExpr *expr2);
static bool less(const FuncExpr *expr1,
const FuncExpr *expr2);
// Delete expression and all of its subexpressions.
void deleteSubexprs();
LibertyPort *port() const;
Operator op() const { return op_; }
// When operator is NOT left is the only operand.
FuncExpr *left() const { return left_; }
FuncExpr *right() const { return right_; }
TimingSense portTimingSense(const LibertyPort *port) const;
// Return true if expression has port as an input.
bool hasPort(const LibertyPort *port) const;
const char *asString() const;
// Sub expression for a bus function (bit_offset is 0 to bus->size()-1).
FuncExpr *bitSubExpr(int bit_offset);
// Check to make sure the function and port size are compatible.
// Return true if there is a mismatch.
bool checkSize(size_t size);
bool checkSize(LibertyPort *port);
private:
DISALLOW_COPY_AND_ASSIGN(FuncExpr);
FuncExpr(Operator op,
FuncExpr *left,
FuncExpr *right,
LibertyPort *port);
const char *asString(bool with_parens) const;
const char *asStringSubexpr(bool with_parens,
char op) const;
Operator op_;
FuncExpr *left_;
FuncExpr *right_;
LibertyPort *port_;
};
// Negate an expression.
FuncExpr *
funcExprNot(FuncExpr *expr);
class FuncExprPortIterator : public Iterator<LibertyPort*>
{
public:
explicit FuncExprPortIterator(FuncExpr *expr);
virtual bool hasNext() { return iter_.hasNext(); }
virtual LibertyPort *next() { return iter_.next(); }
private:
DISALLOW_COPY_AND_ASSIGN(FuncExprPortIterator);
void findPorts(FuncExpr *expr);
LibertyPortSet ports_;
LibertyPortSet::ConstIterator iter_;
};
} // namespace
#endif

223
liberty/InternalPower.cc Normal file
View File

@ -0,0 +1,223 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 "FuncExpr.hh"
#include "TableModel.hh"
#include "Liberty.hh"
#include "InternalPower.hh"
namespace sta {
InternalPowerAttrs::InternalPowerAttrs() :
when_(NULL)
{
TransRiseFallIterator tr_iter;
while (tr_iter.hasNext()) {
TransRiseFall *tr = tr_iter.next();
int tr_index = tr->index();
models_[tr_index] = NULL;
}
}
InternalPowerModel *
InternalPowerAttrs::model(TransRiseFall *tr) const
{
return models_[tr->index()];
}
void
InternalPowerAttrs::setModel(TransRiseFall *tr,
InternalPowerModel *model)
{
models_[tr->index()] = model;
}
////////////////////////////////////////////////////////////////
InternalPower::InternalPower(LibertyCell *cell,
LibertyPort *port,
LibertyPort *related_port,
InternalPowerAttrs *attrs) :
port_(port),
related_port_(related_port),
when_(attrs->when())
{
TransRiseFallIterator tr_iter;
while (tr_iter.hasNext()) {
TransRiseFall *tr = tr_iter.next();
int tr_index = tr->index();
models_[tr_index] = attrs->model(tr);
}
cell->addInternalPower(this);
}
InternalPower::~InternalPower()
{
TransRiseFallIterator tr_iter;
while (tr_iter.hasNext()) {
TransRiseFall *tr = tr_iter.next();
int tr_index = tr->index();
InternalPowerModel *model = models_[tr_index];
if (model)
delete model;
}
if (when_)
when_->deleteSubexprs();
}
LibertyCell *
InternalPower::libertyCell() const
{
return port_->libertyCell();
}
float
InternalPower::power(TransRiseFall *tr,
const Pvt *pvt,
float in_slew,
float load_cap)
{
InternalPowerModel *model = models_[tr->index()];
if (model)
return model->power(libertyCell(), pvt, in_slew, load_cap);
else
return 0.0;
}
////////////////////////////////////////////////////////////////
InternalPowerModel::InternalPowerModel(TableModel *model) :
model_(model)
{
}
InternalPowerModel::~InternalPowerModel()
{
delete model_;
}
float
InternalPowerModel::power(const LibertyCell *cell,
const Pvt *pvt,
float in_slew,
float load_cap) const
{
if (model_) {
float axis_value1, axis_value2, axis_value3;
findAxisValues(in_slew, load_cap,
axis_value1, axis_value2, axis_value3);
const LibertyLibrary *library = cell->libertyLibrary();
return model_->findValue(library, cell, pvt,
axis_value1, axis_value2, axis_value3);
}
else
return 0.0;
}
void
InternalPowerModel::reportPower(const LibertyCell *cell,
const Pvt *pvt,
float in_slew,
float load_cap,
int digits,
string *result) const
{
if (model_) {
float axis_value1, axis_value2, axis_value3;
findAxisValues(in_slew, load_cap,
axis_value1, axis_value2, axis_value3);
const LibertyLibrary *library = cell->libertyLibrary();
model_->reportValue("Power", library, cell, pvt,
axis_value1, NULL, axis_value2, axis_value3, digits, result);
}
}
void
InternalPowerModel::findAxisValues(float in_slew,
float load_cap,
// Return values.
float &axis_value1,
float &axis_value2,
float &axis_value3) const
{
switch (model_->order()) {
case 0:
axis_value1 = 0.0;
axis_value2 = 0.0;
axis_value3 = 0.0;
break;
case 1:
axis_value1 = axisValue(model_->axis1(), in_slew, load_cap);
axis_value2 = 0.0;
axis_value3 = 0.0;
break;
case 2:
axis_value1 = axisValue(model_->axis1(), in_slew, load_cap);
axis_value2 = axisValue(model_->axis2(), in_slew, load_cap);
axis_value3 = 0.0;
break;
case 3:
axis_value1 = axisValue(model_->axis1(), in_slew, load_cap);
axis_value2 = axisValue(model_->axis2(), in_slew, load_cap);
axis_value3 = axisValue(model_->axis3(), in_slew, load_cap);
break;
default:
internalError("unsupported table order");
}
}
float
InternalPowerModel::axisValue(TableAxis *axis,
float in_slew,
float load_cap) const
{
TableAxisVariable var = axis->variable();
if (var == table_axis_input_transition_time)
return in_slew;
else if (var == table_axis_total_output_net_capacitance)
return load_cap;
else {
internalError("unsupported table axes");
return 0.0;
}
}
bool
InternalPowerModel::checkAxes(const TableModel *model)
{
TableAxis *axis1 = model->axis1();
TableAxis *axis2 = model->axis2();
TableAxis *axis3 = model->axis3();
bool axis_ok = true;
if (axis1)
axis_ok &= checkAxis(model->axis1());
if (axis2)
axis_ok &= checkAxis(model->axis2());
axis_ok &= (axis3 == NULL);
return axis_ok;
}
bool
InternalPowerModel::checkAxis(TableAxis *axis)
{
TableAxisVariable var = axis->variable();
return var == table_axis_constrained_pin_transition
|| var == table_axis_related_pin_transition
|| var == table_axis_related_out_total_output_net_capacitance;
}
} // namespace

110
liberty/InternalPower.hh Normal file
View File

@ -0,0 +1,110 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_INTERNAL_POWER_H
#define STA_INTERNAL_POWER_H
#include "DisallowCopyAssign.hh"
#include "Transition.hh"
#include "LibertyClass.hh"
namespace sta {
class InternalPowerAttrs;
class InternalPowerModel;
class InternalPowerAttrs
{
public:
InternalPowerAttrs();
FuncExpr *when() const { return when_; }
FuncExpr *&whenRef() { return when_; }
void setModel(TransRiseFall *tr,
InternalPowerModel *model);
InternalPowerModel *model(TransRiseFall *tr) const;
protected:
FuncExpr *when_;
InternalPowerModel *models_[TransRiseFall::index_count];
private:
DISALLOW_COPY_AND_ASSIGN(InternalPowerAttrs);
};
class InternalPower
{
public:
InternalPower(LibertyCell *cell,
LibertyPort *port,
LibertyPort *related_port,
InternalPowerAttrs *attrs);
~InternalPower();
LibertyCell *libertyCell() const;
LibertyPort *port() const { return port_; }
LibertyPort *relatedPort() const { return related_port_; }
FuncExpr *when() const { return when_; }
float power(TransRiseFall *tr,
const Pvt *pvt,
float in_slew,
float load_cap);
protected:
LibertyPort *port_;
LibertyPort *related_port_;
FuncExpr *when_;
InternalPowerModel *models_[TransRiseFall::index_count];
private:
DISALLOW_COPY_AND_ASSIGN(InternalPower);
};
class InternalPowerModel
{
public:
explicit InternalPowerModel(TableModel *model);
~InternalPowerModel();
float power(const LibertyCell *cell,
const Pvt *pvt,
float in_slew,
float load_cap) const;
void reportPower(const LibertyCell *cell,
const Pvt *pvt,
float in_slew,
float load_cap,
int digits,
string *result) const;
protected:
void findAxisValues(float in_slew,
float load_cap,
// Return values.
float &axis_value1,
float &axis_value2,
float &axis_value3) const;
float axisValue(TableAxis *axis,
float in_slew,
float load_cap) const;
bool checkAxes(const TableModel *model);
bool checkAxis(TableAxis *axis);
TableModel *model_;
private:
DISALLOW_COPY_AND_ASSIGN(InternalPowerModel);
};
} // namespace
#endif

54
liberty/LeakagePower.cc Normal file
View File

@ -0,0 +1,54 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 "FuncExpr.hh"
#include "TableModel.hh"
#include "Liberty.hh"
#include "LeakagePower.hh"
namespace sta {
LeakagePowerAttrs::LeakagePowerAttrs() :
when_(NULL),
power_(0.0)
{
}
void
LeakagePowerAttrs::setPower(float power)
{
power_ = power;
}
////////////////////////////////////////////////////////////////
LeakagePower::LeakagePower(LibertyCell *cell,
LeakagePowerAttrs *attrs) :
cell_(cell),
when_(attrs->when()),
power_(attrs->power())
{
cell->addLeakagePower(this);
}
LeakagePower::~LeakagePower()
{
if (when_)
when_->deleteSubexprs();
}
} // namespace

64
liberty/LeakagePower.hh Normal file
View File

@ -0,0 +1,64 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_LEAKAGE_POWER_H
#define STA_LEAKAGE_POWER_H
#include "DisallowCopyAssign.hh"
#include "LibertyClass.hh"
namespace sta {
class LeakagePowerAttrs;
class LeakagePowerAttrs
{
public:
LeakagePowerAttrs();
FuncExpr *when() const { return when_; }
FuncExpr *&whenRef() { return when_; }
float power() { return power_; }
void setPower(float power);
protected:
FuncExpr *when_;
float power_;
private:
DISALLOW_COPY_AND_ASSIGN(LeakagePowerAttrs);
};
class LeakagePower
{
public:
LeakagePower(LibertyCell *cell,
LeakagePowerAttrs *attrs);
~LeakagePower();
LibertyCell *libertyCell() const { return cell_; }
FuncExpr *when() const { return when_; }
float power() { return power_; }
protected:
LibertyCell *cell_;
FuncExpr *when_;
float power_;
private:
DISALLOW_COPY_AND_ASSIGN(LeakagePower);
};
} // namespace
#endif

2750
liberty/Liberty.cc Normal file

File diff suppressed because it is too large Load Diff

941
liberty/Liberty.hh Normal file
View File

@ -0,0 +1,941 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_LIBERTY_H
#define STA_LIBERTY_H
#include "DisallowCopyAssign.hh"
#include "Transition.hh"
#include "MinMax.hh"
#include "MinMaxValues.hh"
#include "RiseFallValues.hh"
#include "RiseFallMinMax.hh"
#include "ConcreteLibrary.hh"
#include "LibertyClass.hh"
namespace sta {
class LibertyLibraryCellIterator;
class LibertyCellPortIterator;
class LibertyCellPortBitIterator;
class LibertyPortMemberIterator;
class ModeValueDef;
class TestCell;
class PatternMatch;
class LatchEnable;
class Report;
class Debug;
class LibertyBuilder;
class LibertyReader;
class OcvDerate;
typedef Set<Library*> LibrarySet;
typedef Map<const char*, TableTemplate*, CharPtrLess> TableTemplateMap;
typedef TableTemplateMap::Iterator TableTemplateIterator;
typedef Map<const char*, BusDcl *, CharPtrLess> BusDclMap;
typedef Map<const char*, ScaleFactors*, CharPtrLess> ScaleFactorsMap;
typedef Map<const char*, Wireload*, CharPtrLess> WireloadMap;
typedef Map<const char*, WireloadSelection*, CharPtrLess> WireloadSelectionMap;
typedef Map<const char*, OperatingConditions*,
CharPtrLess> OperatingConditionsMap;
typedef OperatingConditionsMap::Iterator OperatingConditionsIterator;
typedef Map<LibertyPort*, Sequential*> PortToSequentialMap;
typedef Vector<TimingArcSet*> TimingArcSetSeq;
typedef TimingArcSetSeq::ConstIterator CellTimingArcSetIterator;
typedef Set<TimingArcSet*, TimingArcSetLess> TimingArcSetMap;
typedef Vector<InternalPower*> InternalPowerSeq;
typedef InternalPowerSeq::Iterator LibertyCellInternalPowerIterator;
typedef Vector<LeakagePower*> LeakagePowerSeq;
typedef LeakagePowerSeq::Iterator LibertyCellLeakagePowerIterator;
typedef Map<LibertyPort*, TimingArcSetSeq*> LibertyPortTimingArcSetSeqMap;
typedef Map<const OperatingConditions*, LibertyCell*> ScaledCellMap;
typedef Map<const OperatingConditions*, LibertyPort*> ScaledPortMap;
typedef Map<const char *, ModeDef*, CharPtrLess> ModeDefMap;
typedef Map<const char *, ModeValueDef*, CharPtrLess> ModeValueMap;
typedef Map<TimingArcSet*, LatchEnable*> LatchEnableMap;
typedef Map<const char *, OcvDerate*, CharPtrLess> OcvDerateMap;
typedef Map<LibertyPortPair*, TimingArcSetSeq*,
LibertyPortPairLess> LibertyPortTimingArcSetMap;
typedef enum {
clock_gate_none,
clock_gate_latch_posedge,
clock_gate_latch_negedge,
clock_gate_other
} ClockGateType;
typedef enum {
delay_model_cmos_linear,
delay_model_cmos_pwl,
delay_model_cmos2,
delay_model_table,
delay_model_polynomial,
delay_model_dcm
} DelayModelType;
typedef enum {
scale_factor_process,
scale_factor_volt,
scale_factor_temp,
scale_factor_pvt_count,
scale_factor_pvt_unknown
} ScaleFactorPvt;
void
initLiberty();
void
deleteLiberty();
ScaleFactorPvt
findScaleFactorPvt(const char *name);
const char *
scaleFactorPvtName(ScaleFactorPvt pvt);
ScaleFactorType
findScaleFactorType(const char *name);
const char *
scaleFactorTypeName(ScaleFactorType type);
bool
scaleFactorTypeRiseFallSuffix(ScaleFactorType type);
bool
scaleFactorTypeRiseFallPrefix(ScaleFactorType type);
bool
scaleFactorTypeLowHighSuffix(ScaleFactorType type);
// Timing sense as a string.
const char *
timingSenseString(TimingSense sense);
// Opposite timing sense.
TimingSense
timingSenseOpposite(TimingSense sense);
class LibertyLibrary : public ConcreteLibrary
{
public:
LibertyLibrary(const char *name,
const char *filename);
virtual ~LibertyLibrary();
LibertyCell *findLibertyCell(const char *name) const;
void findLibertyCellsMatching(PatternMatch *pattern,
LibertyCellSeq *cells);
LibertyLibraryCellIterator *libertyCellIterator() const;
DelayModelType delayModelType() const { return delay_model_type_; }
void setDelayModelType(DelayModelType type);
void addBusDcl(BusDcl *bus_dcl);
BusDcl *findBusDcl(const char *name) const;
void addTableTemplate(TableTemplate *tbl_template);
TableTemplate *findTableTemplate(const char *name);
TableTemplateIterator *tableTemplateIterator();
float nominalProcess() { return nominal_process_; }
void setNominalProcess(float process);
float nominalVoltage() const { return nominal_voltage_; }
void setNominalVoltage(float voltage);
float nominalTemperature() const { return nominal_temperature_; }
void setNominalTemperature(float temperature);
void setScaleFactors(ScaleFactors *scales);
// Add named scale factor group.
void addScaleFactors(ScaleFactors *scales);
ScaleFactors *findScaleFactors(const char *name);
ScaleFactors *scaleFactors() const { return scale_factors_; }
float scaleFactor(ScaleFactorType type,
const Pvt *pvt) const;
float scaleFactor(ScaleFactorType type,
const LibertyCell *cell,
const Pvt *pvt) const;
float scaleFactor(ScaleFactorType type,
int tr_index,
const LibertyCell *cell,
const Pvt *pvt) const;
void setWireSlewDegradationTable(TableModel *model,
TransRiseFall *tr);
TableModel *wireSlewDegradationTable(const TransRiseFall *tr) const;
float degradeWireSlew(const LibertyCell *cell,
const TransRiseFall *tr,
const Pvt *pvt,
float in_slew,
float wire_delay) const;
// Check for supported axis variables.
// Return true if axes are supported.
static bool checkSlewDegradationAxes(Table *table);
float defaultInputPinCap() const { return default_input_pin_cap_; }
void setDefaultInputPinCap(float cap);
float defaultOutputPinCap() const { return default_output_pin_cap_; }
void setDefaultOutputPinCap(float cap);
float defaultBidirectPinCap() const { return default_bidirect_pin_cap_; }
void setDefaultBidirectPinCap(float cap);
void defaultIntrinsic(const TransRiseFall *tr,
// Return values.
float &intrisic,
bool &exists) const;
void setDefaultIntrinsic(const TransRiseFall *tr,
float value);
// Uses defaultOutputPinRes or defaultBidirectPinRes based on dir.
void defaultPinResistance(const TransRiseFall *tr,
const PortDirection *dir,
// Return values.
float &res,
bool &exists) const;
void defaultBidirectPinRes(const TransRiseFall *tr,
// Return values.
float &res,
bool &exists) const;
void setDefaultBidirectPinRes(const TransRiseFall *tr,
float value);
void defaultOutputPinRes(const TransRiseFall *tr,
// Return values.
float &res,
bool &exists) const;
void setDefaultOutputPinRes(const TransRiseFall *tr,
float value);
void defaultMaxSlew(float &slew,
bool &exists) const;
void setDefaultMaxSlew(float slew);
void defaultMaxCapacitance(float &cap,
bool &exists) const;
void setDefaultMaxCapacitance(float cap);
void defaultMaxFanout(float &fanout,
bool &exists) const;
void setDefaultMaxFanout(float fanout);
float defaultFanoutLoad() const { return default_fanout_load_; }
void setDefaultFanoutLoad(float load);
// Logic thresholds.
float inputThreshold(const TransRiseFall *tr) const;
void setInputThreshold(const TransRiseFall *tr,
float th);
float outputThreshold(const TransRiseFall *tr) const;
void setOutputThreshold(const TransRiseFall *tr,
float th);
// Slew thresholds (measured).
float slewLowerThreshold(const TransRiseFall *tr) const;
void setSlewLowerThreshold(const TransRiseFall *tr,
float th);
float slewUpperThreshold(const TransRiseFall *tr) const;
void setSlewUpperThreshold(const TransRiseFall *tr,
float th);
// The library and delay calculator use the liberty slew upper/lower
// (measured) thresholds for the table axes and value. These slews
// are scaled by slew_derate_from_library to get slews reported to
// the user.
float slewDerateFromLibrary() const;
void setSlewDerateFromLibrary(float derate);
LibertyCellSeq *findEquivCells(LibertyCell *cell);
Units *units() { return units_; }
const Units *units() const { return units_; }
Wireload *findWireload(const char *name) const;
void setDefaultWireload(Wireload *wireload);
Wireload *defaultWireload() const;
WireloadSelection *findWireloadSelection(const char *name) const;
WireloadSelection *defaultWireloadSelection() const;
void addWireload(Wireload *wireload);
WireloadMode defaultWireloadMode() const;
void setDefaultWireloadMode(WireloadMode mode);
void addWireloadSelection(WireloadSelection *selection);
void setDefaultWireloadSelection(WireloadSelection *selection);
OperatingConditions *findOperatingConditions(const char *name);
OperatingConditionsIterator *operatingConditionsIterator();
OperatingConditions *defaultOperatingConditions() const;
void addOperatingConditions(OperatingConditions *op_cond);
void setDefaultOperatingConditions(OperatingConditions *op_cond);
// AOCV
// Zero means the ocv depth is not specified.
float ocvArcDepth() const;
void setOcvArcDepth(float depth);
OcvDerate *defaultOcvDerate() const;
void setDefaultOcvDerate(OcvDerate *derate);
OcvDerate *findOcvDerate(const char *derate_name);
void addOcvDerate(OcvDerate *derate);
// Make scaled cell. Call LibertyCell::addScaledCell after it is complete.
LibertyCell *makeScaledCell(const char *name,
const char *filename);
static void
makeCornerMap(LibertyLibrary *lib,
int ap_index,
Network *network);
static void
makeCornerMap(LibertyCell *link_cell,
LibertyCell *map_cell,
int ap_index);
protected:
float degradeWireSlew(const LibertyCell *cell,
const Pvt *pvt,
const TableModel *model,
float in_slew,
float wire_delay) const;
void deleteTableTemplate(TableTemplate *tbl_template);
Units *units_;
DelayModelType delay_model_type_;
BusDclMap bus_dcls_;
TableTemplateMap templates_;
float nominal_process_;
float nominal_voltage_;
float nominal_temperature_;
ScaleFactors *scale_factors_;
ScaleFactorsMap scale_factors_map_;
TableModel *wire_slew_degradation_tbls_[TransRiseFall::index_count];
float default_input_pin_cap_;
float default_output_pin_cap_;
float default_bidirect_pin_cap_;
RiseFallValues default_intrinsic_;
RiseFallValues default_inout_pin_res_;
RiseFallValues default_output_pin_res_;
float default_fanout_load_;
float default_max_cap_;
bool default_max_cap_exists_;
float default_max_fanout_;
bool default_max_fanout_exists_;
float default_max_slew_;
bool default_max_slew_exists_;
float input_threshold_[TransRiseFall::index_count];
float output_threshold_[TransRiseFall::index_count];
float slew_lower_threshold_[TransRiseFall::index_count];
float slew_upper_threshold_[TransRiseFall::index_count];
float slew_derate_from_library_;
WireloadMap wireloads_;
Wireload *default_wire_load_;
WireloadMode default_wire_load_mode_;
WireloadSelection *default_wire_load_selection_;
WireloadSelectionMap wire_load_selections_;
OperatingConditionsMap operating_conditions_;
OperatingConditions *default_operating_conditions_;
LibertyCellEquivMap *equiv_cell_map_;
float ocv_arc_depth_;
OcvDerate *default_ocv_derate_;
OcvDerateMap ocv_derate_map_;
// Set if any library has rise/fall capacitances.
static bool found_rise_fall_caps_;
static const float input_threshold_default_;
static const float output_threshold_default_;
static const float slew_lower_threshold_default_;
static const float slew_upper_threshold_default_;
static const float slew_lower_measure_threshold_default_;
static const float slew_upper_measure_threshold_default_;
private:
DISALLOW_COPY_AND_ASSIGN(LibertyLibrary);
friend class LibertyLibraryCellIterator;
};
class LibertyLibraryCellIterator : public Iterator<LibertyCell*>
{
public:
explicit LibertyLibraryCellIterator(const LibertyLibrary *library);
bool hasNext();
LibertyCell *next();
private:
DISALLOW_COPY_AND_ASSIGN(LibertyLibraryCellIterator);
ConcreteCellMap::ConstIterator iter_;
};
class LibertyCell : public ConcreteCell
{
public:
LibertyCell(LibertyLibrary *library,
const char *name,
const char *filename);
virtual ~LibertyCell();
const LibertyLibrary *libertyLibrary() const { return liberty_library_; }
LibertyLibrary *libertyLibrary() { return liberty_library_; }
LibertyCellPortIterator *libertyPortIterator() const;
LibertyCellPortBitIterator *libertyPortBitIterator() const;
LibertyPort *findLibertyPort(const char *name) const;
void findLibertyPortsMatching(PatternMatch *pattern,
LibertyPortSeq *ports) const;
bool hasInternalPorts() const { return has_internal_ports_; }
ScaleFactors *scaleFactors() const { return scale_factors_; }
void setScaleFactors(ScaleFactors *scale_factors);
ModeDef *makeModeDef(const char *name);
ModeDef *findModeDef(const char *name);
// Add scaled cell after it is complete.
void addScaledCell(OperatingConditions *op_cond,
LibertyCell *scaled_cell);
float area() const { return area_; }
void setArea(float area);
bool dontUse() const { return dont_use_; }
void setDontUse(bool dont_use);
bool interfaceTiming() const { return interface_timing_; }
void setInterfaceTiming(bool value);
bool isClockGateLatchPosedge() const;
bool isClockGateLatchNegedge() const;
bool isClockGateOther() const;
bool isClockGate() const;
void setClockGateType(ClockGateType clock_gate_type);
virtual unsigned addTimingArcSet(TimingArcSet *set);
virtual void addInternalPower(InternalPower *power);
virtual void addLeakagePower(LeakagePower *power);
// Call after cell is finished being constructed.
virtual void finish(bool infer_latches,
Report *report,
Debug *debug);
size_t timingArcSetCount() const;
// Find a timing arc set equivalent to key.
TimingArcSet *findTimingArcSet(TimingArcSet *key) const;
TimingArcSet *findTimingArcSet(unsigned arc_set_index) const;
CellTimingArcSetIterator *timingArcSetIterator() const;
CellTimingArcSetIterator *timingArcSetIterator(LibertyPort *from,
LibertyPort *to) const;
CellTimingArcSetIterator *timingArcSetFromIterator(LibertyPort *from) const;
CellTimingArcSetIterator *timingArcSetToIterator(LibertyPort *to) const;
bool hasTimingArcs(LibertyPort *port) const;
LibertyCellInternalPowerIterator *internalPowerIterator();
LibertyCellLeakagePowerIterator *leakagePowerIterator();
bool hasSequentials() const;
CellSequentialIterator *sequentialIterator() const;
void makeSequential(int size,
bool is_register,
FuncExpr *clk,
FuncExpr *data,
FuncExpr *clear,
FuncExpr *preset,
LogicValue clr_preset_out,
LogicValue clr_preset_out_inv,
LibertyPort *output,
LibertyPort *output_inv);
// Find the sequential with the output connected to an (internal) port.
Sequential *outputPortSequential(LibertyPort *port);
// Find bus declaration local to this cell.
BusDcl *findBusDcl(const char *name) const;
void addBusDcl(BusDcl *bus_dcl);
// True when TimingArcSetBuilder::makeRegLatchArcs infers register
// timing arcs.
bool hasInferedRegTimingArcs() const { return has_infered_reg_timing_arcs_; }
void setHasInferedRegTimingArcs(bool infered);
TestCell *testCell() const { return test_cell_; }
void setTestCell(TestCell *test);
bool isLatchData(LibertyPort *port);
void latchEnable(TimingArcSet *arc_set,
// Return values.
LibertyPort *&enable_port,
FuncExpr *&enable_func,
TransRiseFall *&enable_tr) const;
TransRiseFall *latchCheckEnableTrans(TimingArcSet *check_set);
bool isDisabledConstraint() const { return is_disabled_constraint_; }
void setIsDisabledConstraint(bool is_disabled);
LibertyCell *cornerCell(int ap_index);
void setCornerCell(LibertyCell *corner_cell,
int ap_index);
// AOCV
float ocvArcDepth() const;
void setOcvArcDepth(float depth);
OcvDerate *ocvDerate() const;
void setOcvDerate(OcvDerate *derate);
OcvDerate *findOcvDerate(const char *derate_name);
void addOcvDerate(OcvDerate *derate);
protected:
virtual void addPort(ConcretePort *port);
void setHasInternalPorts(bool has_internal);
void setLibertyLibrary(LibertyLibrary *library);
void deleteTimingModels();
void makeLatchEnables(Report *report,
Debug *debug);
FuncExpr *findLatchEnableFunc(LibertyPort *data,
LibertyPort *enable) const;
LatchEnable *makeLatchEnable(LibertyPort *d,
LibertyPort *en,
LibertyPort *q,
TimingArcSet *d_to_q,
TimingArcSet *en_to_q,
TimingArcSet *setup_check,
Debug *debug);
void findDefaultCondArcs();
virtual void translatePresetClrCheckRoles();
virtual void inferLatchRoles(Debug *debug);
LibertyLibrary *liberty_library_;
float area_;
bool dont_use_;
bool has_internal_ports_;
bool interface_timing_;
ClockGateType clock_gate_type_;
TimingArcSetSeq *timing_arc_sets_;
TimingArcSetMap *timing_arc_set_map_;
LibertyPortTimingArcSetMap *port_timing_arc_set_map_;
LibertyPortTimingArcSetSeqMap *timing_arc_set_from_map_;
LibertyPortTimingArcSetSeqMap *timing_arc_set_to_map_;
bool has_infered_reg_timing_arcs_;
InternalPowerSeq *internal_powers_;
LeakagePowerSeq *leakage_powers_;
SequentialSeq *sequentials_;
PortToSequentialMap *port_to_seq_map_;
BusDclMap bus_dcls_;
ModeDefMap *mode_defs_;
ScaleFactors *scale_factors_;
ScaledCellMap *scaled_cells_;
TestCell *test_cell_;
// Latch D->Q to LatchEnable.
LatchEnableMap latch_d_to_q_map_;
// Latch EN->D setup to LatchEnable.
LatchEnableMap latch_check_map_;
// Ports that have latch D->Q timing arc sets from them.
LibertyPortSet latch_data_ports_;
float ocv_arc_depth_;
OcvDerate *ocv_derate_;
OcvDerateMap ocv_derate_map_;
bool is_disabled_constraint_;
Vector<LibertyCell*> corner_cells_;
private:
DISALLOW_COPY_AND_ASSIGN(LibertyCell);
friend class LibertyLibrary;
friend class LibertyCellPortIterator;
friend class LibertyPort;
friend class LibertyBuilder;
};
class LibertyCellPortIterator : public Iterator<LibertyPort*>
{
public:
explicit LibertyCellPortIterator(const LibertyCell *cell);
bool hasNext();
LibertyPort *next();
private:
DISALLOW_COPY_AND_ASSIGN(LibertyCellPortIterator);
ConcretePortSeq::ConstIterator iter_;
};
class LibertyCellPortBitIterator : public Iterator<LibertyPort*>
{
public:
explicit LibertyCellPortBitIterator(const LibertyCell *cell);
~LibertyCellPortBitIterator();
bool hasNext();
LibertyPort *next();
private:
DISALLOW_COPY_AND_ASSIGN(LibertyCellPortBitIterator);
ConcreteCellPortBitIterator *iter_;
};
class LibertyPort : public ConcretePort
{
public:
LibertyCell *libertyCell() const { return liberty_cell_; }
LibertyPortMemberIterator *libertyMemberIterator() const;
LibertyPort *findLibertyMember(int index) const;
LibertyPort *findLibertyBusBit(int index) const;
float capacitance(const TransRiseFall *tr,
const MinMax *min_max) const;
void capacitance(const TransRiseFall *tr,
const MinMax *min_max,
// Return values.
float &cap,
bool &exists) const;
// Capacitance at op_cond derated by library/cell scale factors
// using pvt.
float capacitance(const TransRiseFall *tr,
const MinMax *min_max,
const OperatingConditions *op_cond,
const Pvt *pvt) const;
void setCapacitance(float cap);
void setCapacitance(const TransRiseFall *tr,
const MinMax *min_max,
float cap);
FuncExpr *function() const { return function_; }
void setFunction(FuncExpr *func);
FuncExpr *&functionRef() { return function_; }
// Tristate enable function.
FuncExpr *tristateEnable() const { return tristate_enable_; }
void setTristateEnable(FuncExpr *enable);
FuncExpr *&tristateEnableRef() { return tristate_enable_; }
void slewLimit(const MinMax *min_max,
// Return values.
float &limit,
bool &exists) const;
void setSlewLimit(float slew,
const MinMax *min_max);
void capacitanceLimit(const MinMax *min_max,
// Return values.
float &limit,
bool &exists) const;
void setCapacitanceLimit(float cap,
const MinMax *min_max);
void fanoutLimit(const MinMax *min_max,
// Return values.
float &limit,
bool &exists) const;
void setFanoutLimit(float fanout,
const MinMax *min_max);
void minPeriod(const OperatingConditions *op_cond,
const Pvt *pvt,
float &min_period,
bool &exists) const;
// Unscaled value.
void minPeriod(float &min_period,
bool &exists) const;
void setMinPeriod(float min_period);
// high = rise, low = fall
void minPulseWidth(const TransRiseFall *hi_low,
const OperatingConditions *op_cond,
const Pvt *pvt,
float &min_width,
bool &exists) const;
// Unscaled value.
void minPulseWidth(const TransRiseFall *hi_low,
float &min_width,
bool &exists) const;
void setMinPulseWidth(TransRiseFall *hi_low,
float min_width);
bool isClock() const;
void setIsClock(bool is_clk);
bool isClockGateClockPin() const { return is_clk_gate_clk_pin_; }
void setIsClockGateClockPin(bool is_clk_gate_clk);
bool isClockGateEnablePin() const { return is_clk_gate_enable_pin_; }
void setIsClockGateEnablePin(bool is_clk_gate_enable);
bool isClockGateOutPin() const { return is_clk_gate_out_pin_; }
void setIsClockGateOutPin(bool is_clk_gate_out);
bool isPllFeedbackPin() const { return is_pll_feedback_pin_; }
void setIsPllFeedbackPin(bool is_pll_feedback_pin);
// Has register/latch rise/fall edges from pin.
bool isRegClk() const { return is_reg_clk_; }
void setIsRegClk(bool is_clk);
// Is the clock for timing checks.
bool isCheckClk() const { return is_check_clk_; }
void setIsCheckClk(bool is_clk);
TransRiseFall *pulseClkTrigger() const { return pulse_clk_trigger_; }
// Rise for high, fall for low.
TransRiseFall *pulseClkSense() const { return pulse_clk_sense_; }
void setPulseClk(TransRiseFall *trigger,
TransRiseFall *sense);
bool isDisabledConstraint() const { return is_disabled_constraint_; }
void setIsDisabledConstraint(bool is_disabled);
LibertyPort *cornerPort(int ap_index);
void setCornerPort(LibertyPort *corner_port,
int ap_index);
static bool equiv(const LibertyPort *port1,
const LibertyPort *port2);
static bool less(const LibertyPort *port1,
const LibertyPort *port2);
protected:
// Constructor is internal to LibertyBuilder.
LibertyPort(LibertyCell *cell,
const char *name,
bool is_bus,
int from_index,
int to_index,
bool is_bundle,
ConcretePortSeq *members);
virtual ~LibertyPort();
virtual void setDirection(PortDirection *dir);
void setMinPort(LibertyPort *min);
void addScaledPort(OperatingConditions *op_cond,
LibertyPort *scaled_port);
LibertyCell *liberty_cell_;
FuncExpr *function_;
FuncExpr *tristate_enable_;
ScaledPortMap *scaled_ports_;
RiseFallMinMax capacitance_;
MinMaxFloatValues slew_limit_; // inputs and outputs
MinMaxFloatValues cap_limit_; // outputs
MinMaxFloatValues fanout_limit_; // outputs
float min_period_;
float min_pulse_width_[TransRiseFall::index_count];
TransRiseFall *pulse_clk_trigger_;
TransRiseFall *pulse_clk_sense_;
Vector<LibertyPort*> corner_ports_;
unsigned int min_pulse_width_exists_:TransRiseFall::index_count;
bool min_period_exists_:1;
bool is_clk_:1;
bool is_reg_clk_:1;
bool is_check_clk_:1;
bool is_clk_gate_clk_pin_:1;
bool is_clk_gate_enable_pin_:1;
bool is_clk_gate_out_pin_:1;
bool is_pll_feedback_pin_:1;
bool is_disabled_constraint_:1;
private:
DISALLOW_COPY_AND_ASSIGN(LibertyPort);
friend class LibertyLibrary;
friend class LibertyCell;
friend class LibertyBuilder;
friend class LibertyReader;
};
void
sortLibertyPortSet(LibertyPortSet *set,
LibertyPortSeq &ports);
class LibertyPortMemberIterator : public Iterator<LibertyPort*>
{
public:
explicit LibertyPortMemberIterator(const LibertyPort *port);
~LibertyPortMemberIterator();
virtual bool hasNext();
virtual LibertyPort *next();
private:
DISALLOW_COPY_AND_ASSIGN(LibertyPortMemberIterator);
ConcretePortMemberIterator *iter_;
};
// Process, voltage temperature.
class Pvt
{
public:
Pvt(float process,
float voltage,
float temperature);
float process() const { return process_; }
void setProcess(float process);
float voltage() const { return voltage_; }
void setVoltage(float voltage);
float temperature() const { return temperature_; }
void setTemperature(float temp);
protected:
float process_;
float voltage_;
float temperature_;
private:
DISALLOW_COPY_AND_ASSIGN(Pvt);
};
class OperatingConditions : public Pvt
{
public:
explicit OperatingConditions(const char *name);
OperatingConditions(const char *name,
float process,
float voltage,
float temperature,
WireloadTree wire_load_tree);
~OperatingConditions();
const char *name() const { return name_; }
WireloadTree wireloadTree() const { return wire_load_tree_; }
void setWireloadTree(WireloadTree tree);
protected:
const char *name_;
WireloadTree wire_load_tree_;
private:
DISALLOW_COPY_AND_ASSIGN(OperatingConditions);
};
class ScaleFactors
{
public:
explicit ScaleFactors(const char *name);
~ScaleFactors();
const char *name() const { return name_; }
float scale(ScaleFactorType type,
ScaleFactorPvt pvt,
TransRiseFall *tr);
float scale(ScaleFactorType type,
ScaleFactorPvt pvt,
int tr_index);
float scale(ScaleFactorType type,
ScaleFactorPvt pvt);
void setScale(ScaleFactorType type,
ScaleFactorPvt pvt,
TransRiseFall *tr,
float scale);
void setScale(ScaleFactorType type,
ScaleFactorPvt pvt,
float scale);
void print();
protected:
const char *name_;
float scales_[scale_factor_count][scale_factor_pvt_count][TransRiseFall::index_count];
private:
DISALLOW_COPY_AND_ASSIGN(ScaleFactors);
};
class BusDcl
{
public:
BusDcl(const char *name,
int from,
int to);
~BusDcl();
const char *name() const { return name_; }
int from() const { return from_; }
int to() const { return to_; }
protected:
const char *name_;
int from_;
int to_;
private:
DISALLOW_COPY_AND_ASSIGN(BusDcl);
};
// Cell mode_definition group.
class ModeDef
{
public:
~ModeDef();
const char *name() const { return name_; }
ModeValueDef *defineValue(const char *value,
FuncExpr *cond,
const char *sdf_cond);
ModeValueDef *findValueDef(const char *value);
ModeValueMap *values() { return &values_; }
protected:
// Private to LibertyCell::makeModeDef.
explicit ModeDef(const char *name);
const char *name_;
ModeValueMap values_;
private:
DISALLOW_COPY_AND_ASSIGN(ModeDef);
friend class LibertyCell;
};
// Mode definition mode_value group.
class ModeValueDef
{
public:
~ModeValueDef();
const char *value() const { return value_; }
FuncExpr *cond() const { return cond_; }
FuncExpr *&condRef() { return cond_; }
const char *sdfCond() const { return sdf_cond_; }
void setSdfCond(const char *sdf_cond);
protected:
// Private to ModeDef::defineValue.
ModeValueDef(const char *value,
FuncExpr *cond,
const char *sdf_cond);
const char *value_;
FuncExpr *cond_;
const char *sdf_cond_;
private:
DISALLOW_COPY_AND_ASSIGN(ModeValueDef);
friend class ModeDef;
};
class TableTemplate
{
public:
explicit TableTemplate(const char *name);
TableTemplate(const char *name,
TableAxis *axis1,
TableAxis *axis2,
TableAxis *axis3);
~TableTemplate();
const char *name() const { return name_; }
void setName(const char *name);
TableAxis *axis1() const { return axis1_; }
void setAxis1(TableAxis *axis);
TableAxis *axis2() const { return axis2_; }
void setAxis2(TableAxis *axis);
TableAxis *axis3() const { return axis3_; }
void setAxis3(TableAxis *axis);
protected:
const char *name_;
TableAxis *axis1_;
TableAxis *axis2_;
TableAxis *axis3_;
private:
DISALLOW_COPY_AND_ASSIGN(TableTemplate);
};
class TestCell
{
public:
TestCell();
TestCell(LibertyPort *data_in,
LibertyPort *scan_in,
LibertyPort *scan_enable,
LibertyPort *scan_out,
LibertyPort *scan_out_inv);
LibertyPort *dataIn() const { return data_in_; }
void setDataIn(LibertyPort *port);
LibertyPort *scanIn() const { return scan_in_; }
void setScanIn(LibertyPort *port);
LibertyPort *scanEnable() const { return scan_enable_; }
void setScanEnable(LibertyPort *port);
LibertyPort *scanOut() const { return scan_out_; }
void setScanOut(LibertyPort *port);
LibertyPort *scanOutInv() const { return scan_out_inv_; }
void setScanOutInv(LibertyPort *port);
protected:
LibertyPort *data_in_;
LibertyPort *scan_in_;
LibertyPort *scan_enable_;
LibertyPort *scan_out_;
LibertyPort *scan_out_inv_;
private:
DISALLOW_COPY_AND_ASSIGN(TestCell);
};
class OcvDerate
{
public:
OcvDerate(const char *name);
~OcvDerate();
const char *name() const { return name_; }
Table *derateTable(const TransRiseFall *tr,
const EarlyLate *early_late,
PathType path_type);
void setDerateTable(const TransRiseFall *tr,
const EarlyLate *early_late,
PathType path_type,
Table *derate);
private:
const char *name_;
// [rf_type][derate_type][path_type]
Table *derate_[TransRiseFall::index_count][EarlyLate::index_count][path_type_count];
};
} // namespace
#endif

687
liberty/LibertyBuilder.cc Normal file
View File

@ -0,0 +1,687 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 "PortDirection.hh"
#include "TimingRole.hh"
#include "FuncExpr.hh"
#include "TimingArc.hh"
#include "InternalPower.hh"
#include "LeakagePower.hh"
#include "Sequential.hh"
#include "Liberty.hh"
#include "LibertyBuilder.hh"
namespace sta {
LibertyCell *
LibertyBuilder::makeCell(LibertyLibrary *library,
const char *name,
const char *filename)
{
LibertyCell *cell = new LibertyCell(library, name, filename);
library->addCell(cell);
return cell;
}
LibertyPort *
LibertyBuilder::makePort(LibertyCell *cell,
const char *name)
{
LibertyPort *port = new LibertyPort(cell, name, false, -1, -1, false, NULL);
cell->addPort(port);
return port;
}
LibertyPort *
LibertyBuilder::makeBusPort(LibertyCell *cell,
const char *name,
int from_index,
int to_index)
{
LibertyPort *port = new LibertyPort(cell, name, true, from_index, to_index,
false, new ConcretePortSeq);
cell->addPort(port);
makeBusPortBits(cell->library(), cell, port, name, from_index, to_index);
return port;
}
void
LibertyBuilder::makeBusPortBits(ConcreteLibrary *library,
LibertyCell *cell,
ConcretePort *bus_port,
const char *name,
int from_index,
int to_index)
{
if (from_index < to_index) {
for (int index = from_index; index <= to_index; index++)
makeBusPortBit(library, cell, bus_port, name, index);
}
else {
for (int index = from_index; index >= to_index; index--)
makeBusPortBit(library, cell, bus_port, name, index);
}
}
void
LibertyBuilder::makeBusPortBit(ConcreteLibrary *library,
LibertyCell *cell,
ConcretePort *bus_port,
const char *bus_name,
int bit_index)
{
char *bit_name = stringPrintTmp(strlen(bus_name) + 6, "%s%c%d%c",
bus_name,
library->busBrktLeft(),
bit_index,
library->busBrktRight());
ConcretePort *port = makePort(cell, bit_name, bit_index);
bus_port->addPortBit(port);
cell->addPortBit(port);
}
ConcretePort *
LibertyBuilder::makePort(LibertyCell *cell,
const char *bit_name,
int bit_index)
{
ConcretePort *port = new LibertyPort(cell, bit_name, false,
bit_index, bit_index, false, NULL);
return port;
}
LibertyPort *
LibertyBuilder::makeBundlePort(LibertyCell *cell,
const char *name,
ConcretePortSeq *members)
{
LibertyPort *port = new LibertyPort(cell, name, false, -1, -1, true, members);
cell->addPort(port);
return port;
}
////////////////////////////////////////////////////////////////
TimingArcSet *
LibertyBuilder::makeTimingArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
TimingArcAttrs *attrs)
{
FuncExpr *to_func;
Sequential *seq = NULL;
switch (attrs->timingType()) {
case timing_type_combinational:
to_func = to_port->function();
if (to_func && to_func->op() == FuncExpr::op_port)
seq = cell->outputPortSequential(to_func->port());
if (seq && seq->isLatch())
return makeLatchDtoQArcs(cell, from_port, to_port, related_out, attrs);
else
return makeCombinationalArcs(cell, from_port, to_port, related_out,
true, true, attrs);
case timing_type_combinational_fall:
return makeCombinationalArcs(cell, from_port, to_port, related_out,
false, true, attrs);
case timing_type_combinational_rise:
return makeCombinationalArcs(cell, from_port, to_port, related_out,
true, false, attrs);
case timing_type_setup_rising:
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
TransRiseFall::rise(), TimingRole::setup(),
attrs);
case timing_type_setup_falling:
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
TransRiseFall::fall(), TimingRole::setup(),
attrs);
case timing_type_hold_rising:
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
TransRiseFall::rise(), TimingRole::hold(),
attrs);
case timing_type_hold_falling:
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
TransRiseFall::fall(), TimingRole::hold(),
attrs);
case timing_type_rising_edge:
return makeRegLatchArcs(cell, from_port, to_port, related_out,
TransRiseFall::rise(), attrs);
case timing_type_falling_edge:
return makeRegLatchArcs(cell, from_port, to_port, related_out,
TransRiseFall::fall(), attrs);
case timing_type_preset:
return makePresetClrArcs(cell, from_port, to_port, related_out,
TransRiseFall::rise(), attrs);
case timing_type_clear:
return makePresetClrArcs(cell, from_port, to_port, related_out,
TransRiseFall::fall(), attrs);
case timing_type_recovery_rising:
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
TransRiseFall::rise(),TimingRole::recovery(),
attrs);
case timing_type_recovery_falling:
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
TransRiseFall::fall(),TimingRole::recovery(),
attrs);
case timing_type_removal_rising:
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
TransRiseFall::rise(), TimingRole::removal(),
attrs);
case timing_type_removal_falling:
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
TransRiseFall::fall(), TimingRole::removal(),
attrs);
case timing_type_three_state_disable:
return makeTristateDisableArcs(cell, from_port, to_port, related_out,
true, true, attrs);
case timing_type_three_state_disable_fall:
return makeTristateDisableArcs(cell, from_port, to_port, related_out,
false, true, attrs);
case timing_type_three_state_disable_rise:
return makeTristateDisableArcs(cell, from_port, to_port, related_out,
true, false, attrs);
case timing_type_three_state_enable:
return makeTristateEnableArcs(cell, from_port, to_port, related_out,
true, true, attrs);
case timing_type_three_state_enable_fall:
return makeTristateEnableArcs(cell, from_port, to_port, related_out,
false, true, attrs);
case timing_type_three_state_enable_rise:
return makeTristateEnableArcs(cell, from_port, to_port, related_out,
true, false, attrs);
case timing_type_skew_falling:
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
TransRiseFall::fall(), TimingRole::skew(),
attrs);
case timing_type_skew_rising:
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
TransRiseFall::rise(), TimingRole::skew(),
attrs);
case timing_type_non_seq_setup_rising:
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
TransRiseFall::rise(),
TimingRole::nonSeqSetup(), attrs);
case timing_type_non_seq_setup_falling:
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
TransRiseFall::fall(),
TimingRole::nonSeqSetup(), attrs);
case timing_type_non_seq_hold_rising:
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
TransRiseFall::rise(),
TimingRole::nonSeqHold(),
attrs);
case timing_type_non_seq_hold_falling:
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
TransRiseFall::fall(),
TimingRole::nonSeqHold(),
attrs);
case timing_type_min_pulse_width:
case timing_type_minimum_period:
case timing_type_nochange_high_high:
case timing_type_nochange_high_low:
case timing_type_nochange_low_high:
case timing_type_nochange_low_low:
case timing_type_retaining_time:
case timing_type_unknown:
case timing_type_min_clock_tree_path:
case timing_type_max_clock_tree_path:
return NULL;
}
// Prevent warnings from lame compilers.
return NULL;
}
TimingArcSet *
LibertyBuilder::makeCombinationalArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
bool to_rise,
bool to_fall,
TimingArcAttrs *attrs)
{
FuncExpr *func = to_port->function();
TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port, related_out,
TimingRole::combinational(), attrs);
TimingSense sense = attrs->timingSense();
if (sense == timing_sense_unknown && func) {
// Timing sense not specified - find it from function.
sense = func->portTimingSense(from_port);
if (sense == timing_sense_none
&& to_port->direction()->isAnyTristate()) {
// from_port is not an input to function, check tristate enable.
FuncExpr *enable = to_port->tristateEnable();
if (enable && enable->hasPort(from_port))
sense = timing_sense_non_unate;
}
}
TimingModel *model;
TransRiseFall *to_tr;
switch (sense) {
case timing_sense_positive_unate:
if (to_rise) {
to_tr = TransRiseFall::rise();
model = attrs->model(to_tr);
if (model) {
makeTimingArc(arc_set, TransRiseFall::rise(), to_tr, model);
attrs->setModelRef(to_tr, true);
}
}
if (to_fall) {
to_tr = TransRiseFall::fall();
model = attrs->model(to_tr);
if (model) {
makeTimingArc(arc_set, TransRiseFall::fall(), to_tr, model);
attrs->setModelRef(to_tr, true);
}
}
break;
case timing_sense_negative_unate:
if (to_fall) {
to_tr = TransRiseFall::fall();
model = attrs->model(to_tr);
if (model) {
makeTimingArc(arc_set, TransRiseFall::rise(), to_tr, model);
attrs->setModelRef(to_tr, true);
}
}
if (to_rise) {
to_tr = TransRiseFall::rise();
model = attrs->model(to_tr);
if (model) {
makeTimingArc(arc_set, TransRiseFall::fall(), to_tr, model);
attrs->setModelRef(to_tr, true);
}
}
break;
case timing_sense_non_unate:
case timing_sense_unknown:
// Timing sense none means function does not mention from_port.
// This can happen if the function references an internal port,
// as in fpga lut cells.
case timing_sense_none:
if (to_fall) {
to_tr = TransRiseFall::fall();
model = attrs->model(to_tr);
if (model) {
makeTimingArc(arc_set, TransRiseFall::fall(), to_tr, model);
makeTimingArc(arc_set, TransRiseFall::rise(), to_tr, model);
attrs->setModelRef(to_tr, true);
}
}
if (to_rise) {
to_tr = TransRiseFall::rise();
model = attrs->model(to_tr);
if (model) {
makeTimingArc(arc_set, TransRiseFall::rise(), to_tr, model);
makeTimingArc(arc_set, TransRiseFall::fall(), to_tr, model);
attrs->setModelRef(to_tr, true);
}
}
break;
}
return arc_set;
}
TimingArcSet *
LibertyBuilder::makeLatchDtoQArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
TimingArcAttrs *attrs)
{
TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port,
related_out,
TimingRole::latchDtoQ(), attrs);
TimingModel *model;
TransRiseFall *to_tr = TransRiseFall::rise();
model = attrs->model(to_tr);
TimingSense sense = attrs->timingSense();
if (model) {
TransRiseFall *from_tr = (sense == timing_sense_negative_unate) ?
to_tr->opposite() : to_tr;
makeTimingArc(arc_set, from_tr, to_tr, model);
attrs->setModelRef(to_tr, true);
}
to_tr = TransRiseFall::fall();
model = attrs->model(to_tr);
if (model) {
TransRiseFall *from_tr = (sense == timing_sense_negative_unate) ?
to_tr->opposite() : to_tr;
makeTimingArc(arc_set, from_tr, to_tr, model);
attrs->setModelRef(to_tr, true);
}
return arc_set;
}
TimingArcSet *
LibertyBuilder::makeRegLatchArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
TransRiseFall *from_tr,
TimingArcAttrs *attrs)
{
FuncExpr *to_func = to_port->function();
FuncExprPortIterator port_iter(to_func);
while (port_iter.hasNext()) {
LibertyPort *func_port = port_iter.next();
Sequential *seq = cell->outputPortSequential(func_port);
if (seq) {
if (seq->clock() && seq->clock()->hasPort(from_port)) {
TimingRole *role = seq->isRegister() ?
TimingRole::regClkToQ() : TimingRole::latchEnToQ();
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
from_tr, role, attrs);
}
else if (seq->isLatch()
&& seq->data()
&& seq->data()->hasPort(from_port))
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
from_tr, TimingRole::latchDtoQ(), attrs);
else if ((seq->clear() && seq->clear()->hasPort(from_port))
|| (seq->preset() && seq->preset()->hasPort(from_port)))
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
from_tr, TimingRole::regSetClr(), attrs);
}
}
// No associated ff/latch - assume register clk->q.
cell->setHasInferedRegTimingArcs(true);
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
from_tr, TimingRole::regClkToQ(), attrs);
}
TimingArcSet *
LibertyBuilder::makeFromTransitionArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
TransRiseFall *from_tr,
TimingRole *role,
TimingArcAttrs *attrs)
{
TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port,
related_out, role, attrs);
TimingModel *model;
TransRiseFall *to_tr;
to_tr = TransRiseFall::rise();
model = attrs->model(to_tr);
if (model) {
makeTimingArc(arc_set, from_tr, to_tr, model);
attrs->setModelRef(to_tr, true);
}
to_tr = TransRiseFall::fall();
model = attrs->model(to_tr);
if (model) {
makeTimingArc(arc_set, from_tr, to_tr, model);
attrs->setModelRef(to_tr, true);
}
return arc_set;
}
TimingArcSet *
LibertyBuilder::makePresetClrArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
TransRiseFall *to_tr,
TimingArcAttrs *attrs)
{
TimingArcSet *arc_set = NULL;
TimingModel *model = attrs->model(to_tr);
if (model) {
arc_set = makeTimingArcSet(cell, from_port, to_port, related_out,
TimingRole::regSetClr(), attrs);
TransRiseFall *opp_tr = to_tr->opposite();
switch (attrs->timingSense()) {
case timing_sense_positive_unate:
makeTimingArc(arc_set, to_tr, to_tr, model);
attrs->setModelRef(to_tr, true);
break;
case timing_sense_negative_unate:
makeTimingArc(arc_set, opp_tr, to_tr, model);
attrs->setModelRef(to_tr, true);
break;
case timing_sense_non_unate:
case timing_sense_unknown:
makeTimingArc(arc_set, to_tr, to_tr, model);
makeTimingArc(arc_set, opp_tr, to_tr, model);
attrs->setModelRef(to_tr, true);
break;
case timing_sense_none:
break;
}
}
return arc_set;
}
// To rise/fall for Z transitions is as follows:
// 0Z, Z1 rise
// 1Z, Z0 fall
TimingArcSet *
LibertyBuilder::makeTristateEnableArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
bool to_rise,
bool to_fall,
TimingArcAttrs *attrs)
{
TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port, related_out,
TimingRole::tristateEnable(),attrs);
FuncExpr *tristate_enable = to_port->tristateEnable();
TimingSense sense = attrs->timingSense();
if (sense == timing_sense_unknown && tristate_enable)
sense = tristate_enable->portTimingSense(from_port);
TimingModel *model;
TransRiseFall *to_tr;
switch (sense) {
case timing_sense_positive_unate:
if (to_rise) {
to_tr = TransRiseFall::rise();
model = attrs->model(to_tr);
if (model) {
makeTimingArc(arc_set, Transition::rise(), Transition::trZ1(), model);
attrs->setModelRef(to_tr, true);
}
}
if (to_fall) {
to_tr = TransRiseFall::fall();
model = attrs->model(to_tr);
if (model) {
makeTimingArc(arc_set, Transition::rise(), Transition::trZ0(), model);
attrs->setModelRef(to_tr, true);
}
}
break;
case timing_sense_negative_unate:
if (to_rise) {
to_tr = TransRiseFall::rise();
model = attrs->model(to_tr);
if (model) {
makeTimingArc(arc_set, Transition::fall(), Transition::trZ1(), model);
attrs->setModelRef(to_tr, true);
}
}
if (to_fall) {
to_tr = TransRiseFall::fall();
model = attrs->model(to_tr);
if (model) {
makeTimingArc(arc_set, Transition::fall(), Transition::trZ0(), model);
attrs->setModelRef(to_tr, true);
}
}
break;
case timing_sense_non_unate:
case timing_sense_unknown:
if (to_rise) {
to_tr = TransRiseFall::rise();
model = attrs->model(to_tr);
if (model) {
makeTimingArc(arc_set, Transition::rise(), Transition::trZ1(), model);
makeTimingArc(arc_set, Transition::fall(), Transition::trZ1(), model);
attrs->setModelRef(to_tr, true);
}
}
if (to_fall) {
to_tr = TransRiseFall::fall();
model = attrs->model(to_tr);
if (model) {
makeTimingArc(arc_set, Transition::rise(), Transition::trZ0(), model);
makeTimingArc(arc_set, Transition::fall(), Transition::trZ0(), model);
attrs->setModelRef(to_tr, true);
}
}
break;
case timing_sense_none:
break;
}
return arc_set;
}
TimingArcSet *
LibertyBuilder::makeTristateDisableArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
bool to_rise,
bool to_fall,
TimingArcAttrs *attrs)
{
TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port,
related_out,
TimingRole::tristateDisable(),
attrs);
TimingSense sense = attrs->timingSense();
FuncExpr *tristate_enable = to_port->tristateEnable();
if (sense == timing_sense_unknown && tristate_enable)
sense = timingSenseOpposite(tristate_enable->portTimingSense(from_port));
TimingModel *model;
TransRiseFall *to_tr;
switch (sense) {
case timing_sense_positive_unate:
if (to_rise) {
to_tr = TransRiseFall::rise();
model = attrs->model(to_tr);
if (model) {
makeTimingArc(arc_set, Transition::rise(), Transition::tr0Z(), model);
attrs->setModelRef(to_tr, true);
}
}
if (to_fall) {
to_tr = TransRiseFall::fall();
model = attrs->model(to_tr);
if (model) {
makeTimingArc(arc_set, Transition::rise(), Transition::tr1Z(), model);
attrs->setModelRef(to_tr, true);
}
}
break;
case timing_sense_negative_unate:
if (to_rise) {
to_tr = TransRiseFall::rise();
model = attrs->model(to_tr);
if (model) {
makeTimingArc(arc_set, Transition::fall(), Transition::tr0Z(), model);
attrs->setModelRef(to_tr, true);
}
}
if (to_fall) {
to_tr = TransRiseFall::fall();
model = attrs->model(to_tr);
if (model) {
makeTimingArc(arc_set, Transition::fall(), Transition::tr1Z(), model);
attrs->setModelRef(to_tr, true);
}
}
break;
case timing_sense_non_unate:
case timing_sense_unknown:
if (to_rise) {
to_tr = TransRiseFall::rise();
model = attrs->model(to_tr);
if (model) {
makeTimingArc(arc_set, Transition::fall(), Transition::tr0Z(), model);
makeTimingArc(arc_set, Transition::rise(), Transition::tr0Z(), model);
attrs->setModelRef(to_tr, true);
}
}
if (to_fall) {
to_tr = TransRiseFall::fall();
model = attrs->model(to_tr);
if (model) {
makeTimingArc(arc_set, Transition::fall(), Transition::tr1Z(), model);
makeTimingArc(arc_set, Transition::rise(), Transition::tr1Z(), model);
attrs->setModelRef(to_tr, true);
}
}
break;
case timing_sense_none:
break;
}
return arc_set;
}
TimingArcSet *
LibertyBuilder::makeTimingArcSet(LibertyCell *cell,
LibertyPort *from,
LibertyPort *to,
LibertyPort *related_out,
TimingRole *role,
TimingArcAttrs *attrs)
{
return new TimingArcSet(cell, from, to, related_out, role, attrs);
}
TimingArc *
LibertyBuilder::makeTimingArc(TimingArcSet *set,
TransRiseFall *from_tr,
TransRiseFall *to_tr,
TimingModel *model)
{
return new TimingArc(set, from_tr->asTransition(),
to_tr->asTransition(), model);
}
TimingArc *
LibertyBuilder::makeTimingArc(TimingArcSet *set,
Transition *from_tr,
Transition *to_tr,
TimingModel *model)
{
return new TimingArc(set, from_tr, to_tr, model);
}
////////////////////////////////////////////////////////////////
InternalPower *
LibertyBuilder::makeInternalPower(LibertyCell *cell,
LibertyPort *port,
LibertyPort *related_port,
InternalPowerAttrs *attrs)
{
return new InternalPower(cell, port, related_port, attrs);
}
LeakagePower *
LibertyBuilder::makeLeakagePower(LibertyCell *cell,
LeakagePowerAttrs *attrs)
{
return new LeakagePower(cell, attrs);
}
} // namespace

143
liberty/LibertyBuilder.hh Normal file
View File

@ -0,0 +1,143 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_LIBERTY_BUILDER_H
#define STA_LIBERTY_BUILDER_H
#include "DisallowCopyAssign.hh"
#include "Vector.hh"
#include "Transition.hh"
#include "LibertyClass.hh"
namespace sta {
class LibertyBuilder
{
public:
LibertyBuilder() {}
virtual ~LibertyBuilder() {}
virtual LibertyCell *makeCell(LibertyLibrary *library,
const char *name,
const char *filename);
virtual LibertyPort *makePort(LibertyCell *cell,
const char *name);
virtual LibertyPort *makeBusPort(LibertyCell *cell,
const char *name,
int from_index,
int to_index);
virtual LibertyPort *makeBundlePort(LibertyCell *cell,
const char *name,
ConcretePortSeq *members);
// Build timing arc sets and their arcs given a type and sense.
// Port functions and cell latches are also used by this builder
// to get the correct roles.
TimingArcSet *makeTimingArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
TimingArcAttrs *attrs);
InternalPower *makeInternalPower(LibertyCell *cell,
LibertyPort *port,
LibertyPort *related_port,
InternalPowerAttrs *attrs);
LeakagePower *makeLeakagePower(LibertyCell *cell,
LeakagePowerAttrs *attrs);
protected:
ConcretePort *makeBusPort(const char *name,
int from_index,
int to_index,
ConcretePortSeq *members);
void makeBusPortBits(ConcreteLibrary *library,
LibertyCell *cell,
ConcretePort *bus_port,
const char *name,
int from_index,
int to_index);
// Bus port bit (internal to makeBusPortBits).
virtual ConcretePort *makePort(LibertyCell *cell,
const char *bit_name,
int bit_index);
void makeBusPortBit(ConcreteLibrary *library,
LibertyCell *cell,
ConcretePort *bus_port,
const char *name,
int index);
virtual TimingArcSet *makeTimingArcSet(LibertyCell *cell,
LibertyPort *from,
LibertyPort *to,
LibertyPort *related_out,
TimingRole *role,
TimingArcAttrs *attrs);
virtual TimingArc *makeTimingArc(TimingArcSet *set,
Transition *from_tr,
Transition *to_tr,
TimingModel *model);
TimingArc *makeTimingArc(TimingArcSet *set,
TransRiseFall *from_tr,
TransRiseFall *to_tr,
TimingModel *model);
TimingArcSet *makeCombinationalArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
bool to_rise,
bool to_fall,
TimingArcAttrs *attrs);
TimingArcSet *makeLatchDtoQArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
TimingArcAttrs *attrs);
TimingArcSet *makeRegLatchArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
TransRiseFall *from_tr,
TimingArcAttrs *attrs);
TimingArcSet *makeFromTransitionArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
TransRiseFall *from_tr,
TimingRole *role,
TimingArcAttrs *attrs);
TimingArcSet *makePresetClrArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
TransRiseFall *to_tr,
TimingArcAttrs *attrs);
TimingArcSet *makeTristateEnableArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
bool to_rise,
bool to_fall,
TimingArcAttrs *attrs);
TimingArcSet *makeTristateDisableArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
bool to_rise,
bool to_fall,
TimingArcAttrs *attrs);
private:
DISALLOW_COPY_AND_ASSIGN(LibertyBuilder);
};
} // namespace
#endif

184
liberty/LibertyClass.hh Normal file
View File

@ -0,0 +1,184 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_LIBERTY_CLASS_H
#define STA_LIBERTY_CLASS_H
#include "Vector.hh"
#include "Map.hh"
#include "Set.hh"
namespace sta {
class Units;
class Unit;
class LibertyLibrary;
class LibertyCell;
class LibertyPort;
class Pvt;
class OperatingConditions;
class BusDcl;
class ModeDef;
class ModeValueDef;
class TestCell;
class TableTemplate;
class Table;
class TableModel;
class TableAxis;
class GateTimingModel;
class CheckTimingModel;
class ScaleFactors;
class Group;
class Wireload;
class WireloadSelection;
class TimingArcSet;
class TimingArc;
class InternalPower;
class LeakagePower;
class Sequential;
class FuncExpr;
class TimingModel;
class TimingRole;
class Transition;
class TransRiseFall;
class TransRiseFallBoth;
typedef Vector<LibertyCell*> LibertyCellSeq;
typedef Vector<Sequential*> SequentialSeq;
typedef SequentialSeq::ConstIterator CellSequentialIterator;
typedef Map<LibertyCell*, LibertyCellSeq*> LibertyCellEquivMap;
typedef Vector<LibertyPort*> LibertyPortSeq;
typedef Set<LibertyPort*> LibertyPortSet;
typedef std::pair<LibertyPort*,LibertyPort*> LibertyPortPair;
typedef Set<LibertyCell*> LibertyCellSet;
typedef Vector<float> FloatSeq;
typedef Vector<FloatSeq*> FloatTable;
typedef enum {
scale_factor_pin_cap,
scale_factor_wire_cap,
scale_factor_wire_res,
scale_factor_min_period,
// Liberty attributes have rise/fall suffix.
scale_factor_cell,
scale_factor_hold,
scale_factor_setup,
scale_factor_recovery,
scale_factor_removal,
scale_factor_nochange,
scale_factor_skew,
scale_factor_leakage_power,
scale_factor_internal_power,
// Liberty attributes have rise/fall prefix.
scale_factor_transition,
// Liberty attributes have low/high suffix (indexed as rise/fall).
scale_factor_min_pulse_width,
scale_factor_unknown,
scale_factor_count
} ScaleFactorType;
// Enough bits to hold a ScaleFactorType enum.
const int scale_factor_bits = 4;
typedef enum {
wire_load_worst_case_tree,
wire_load_best_case_tree,
wire_load_balanced_tree,
wire_load_unknown_tree
} WireloadTree;
typedef enum {
wire_load_mode_top,
wire_load_mode_enclosed,
wire_load_mode_segmented,
wire_load_mode_unknown
} WireloadMode;
typedef enum {
timing_sense_positive_unate,
timing_sense_negative_unate,
timing_sense_non_unate,
timing_sense_none,
timing_sense_unknown
} TimingSense;
typedef enum {
table_axis_total_output_net_capacitance,
table_axis_equal_or_opposite_output_net_capacitance,
table_axis_input_net_transition,
table_axis_input_transition_time,
table_axis_related_pin_transition,
table_axis_constrained_pin_transition,
table_axis_output_pin_transition,
table_axis_connect_delay,
table_axis_related_out_total_output_net_capacitance,
table_axis_time,
table_axis_iv_output_voltage,
table_axis_input_noise_width,
table_axis_input_noise_height,
table_axis_input_voltage,
table_axis_output_voltage,
table_axis_path_depth,
table_axis_path_distance,
table_axis_unknown
} TableAxisVariable;
typedef enum {
path_type_clk,
path_type_data,
path_type_clk_and_data
} PathType;
const int path_type_count = 2;
const int timing_sense_count = timing_sense_unknown + 1;
const int timing_sense_bit_count = 3;
// Rise/fall to rise/fall.
const int timing_arc_index_bit_count = 2;
const int timing_arc_index_max = (1<<timing_arc_index_bit_count)-1;
const int timing_arc_set_index_bit_count = 18;
const int timing_arc_set_index_max=(1<<timing_arc_set_index_bit_count)-1;
class LibertyPortNameLess
{
public:
bool operator()(const LibertyPort *port1, const LibertyPort *port2) const;
};
class LibertyPortPairLess
{
public:
bool operator()(const LibertyPortPair *pair1,
const LibertyPortPair *pair2) const;
};
bool
timingArcSetLess(const TimingArcSet *set1,
const TimingArcSet *set2);
class TimingArcSetLess
{
public:
bool
operator()(const TimingArcSet *set1,
const TimingArcSet *set2) const
{
return timingArcSetLess(set1, set2);
}
};
} // namespace
#endif

184
liberty/LibertyExpr.cc Normal file
View File

@ -0,0 +1,184 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 "Report.hh"
#include "StringUtil.hh"
#include "FuncExpr.hh"
#include "Liberty.hh"
#include "LibertyExprPvt.hh"
extern int
LibertyExprParse_parse();
namespace sta {
LibExprParser *libexpr_parser;
FuncExpr *
parseFuncExpr(const char *func, LibertyCell *cell, const char *error_msg,
Report *report)
{
if (func != NULL && func[0] != '\0') {
LibExprParser parser(func, cell, error_msg, report);
libexpr_parser = &parser;
LibertyExprParse_parse();
return parser.result();
}
else
return NULL;
}
LibExprParser::LibExprParser(const char *func, LibertyCell *cell,
const char *error_msg, Report *report) :
func_(func),
cell_(cell),
error_msg_(error_msg),
report_(report),
result_(NULL),
token_length_(100),
token_(new char[token_length_]),
token_next_(token_)
{
}
LibExprParser::~LibExprParser()
{
stringDelete(token_);
}
FuncExpr *
LibExprParser::makeFuncExprPort(const char *port_name)
{
LibertyPort *port = cell_->findLibertyPort(port_name);
FuncExpr *expr = NULL;
if (port)
expr = FuncExpr::makePort(port);
else
report_->error("%s references unknown port %s.\n",
error_msg_, port_name);
stringDelete(port_name);
return expr;
}
FuncExpr *
LibExprParser::makeFuncExprNot(FuncExpr *arg)
{
if (arg)
return FuncExpr::makeNot(arg);
else
return NULL;
}
FuncExpr *
LibExprParser::makeFuncExprXor(FuncExpr *arg1, FuncExpr *arg2)
{
if (arg1 && arg2)
return FuncExpr::makeXor(arg1, arg2);
else
return NULL;
}
FuncExpr *
LibExprParser::makeFuncExprAnd(FuncExpr *arg1, FuncExpr *arg2)
{
if (arg1 && arg2)
return FuncExpr::makeAnd(arg1, arg2);
else
return NULL;
}
FuncExpr *
LibExprParser::makeFuncExprOr(FuncExpr *arg1, FuncExpr *arg2)
{
if (arg1 && arg2)
return FuncExpr::makeOr(arg1, arg2);
else
return NULL;
}
void
LibExprParser::setResult(FuncExpr *result)
{
result_ = result;
}
size_t
LibExprParser::copyInput(char *buf, size_t max_size)
{
size_t length = strlen(func_);
if (length == 0)
return 0;
else {
size_t count;
if (length < max_size)
count = length;
else
count = max_size;
strncpy(buf, func_, count);
func_ += count;
return count;
}
}
char *
LibExprParser::tokenCopy()
{
return stringCopy(token_);
}
void
LibExprParser::tokenErase()
{
token_next_ = token_;
}
void
LibExprParser::tokenAppend(char ch)
{
if (token_next_ + 1 - token_ >= static_cast<signed int>(token_length_)) {
size_t index = token_next_ - token_;
token_length_ *= 2;
char *prev_token = token_;
token_ = new char[token_length_];
strcpy(token_, prev_token);
stringDelete(prev_token);
token_next_ = &token_[index];
}
*token_next_++ = ch;
// Make sure the token is always terminated.
*token_next_ = '\0';
}
void
LibExprParser::parseError(const char *msg)
{
report_->printError("%s %s.\n", error_msg_, msg);
}
} // namespace
////////////////////////////////////////////////////////////////
// Global namespace
int
LibertyExprParse_error(const char *msg)
{
sta::libexpr_parser->parseError(msg);
libertyExprFlushBuffer();
return 0;
}

33
liberty/LibertyExpr.hh Normal file
View File

@ -0,0 +1,33 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_LIBERTY_EXPR_H
#define STA_LIBERTY_EXPR_H
#include "LibertyClass.hh"
namespace sta {
class Report;
class LibertyCell;
class FuncExpr;
FuncExpr *
parseFuncExpr(const char *func, LibertyCell *cell, const char *error_msg,
Report *report);
} // namespace
#endif

88
liberty/LibertyExprLex.ll Normal file
View File

@ -0,0 +1,88 @@
%{
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
// Liberty function expression lexical analyzer
#include "Machine.hh"
#include "Debug.hh"
#include "StringUtil.hh"
#include "LibertyExprPvt.hh"
using sta::libexpr_parser;
using sta::stringCopy;
using sta::FuncExpr;
#include "LibertyExprParse.hh"
#define YY_NO_INPUT
#define YY_INPUT(buf,result,max_size) \
result = libexpr_parser->copyInput(buf, max_size)
void
libertyExprFlushBuffer()
{
YY_FLUSH_BUFFER;
}
%}
/* %option debug */
%option prefix="LibertyExprLex_"
%option outfile="lex.yy.c"
%option noyywrap
%option nounput
%option never-interactive
%x ESCAPED_STRING
PORT [A-Za-z_]([A-Za-z0-9_\[\]])*
OP "'"|"!"|"^"|"*"|"&"|"+"|"|"|1|0
PAREN "("|")"
BLANK [ \t\r]
ESCAPE \\
QUOTE \"
EOL \r?\n
%%
{OP}|{PAREN} { return ((int) LibertyExprLex_text[0]); }
{ESCAPE}{EOL} { /* I doubt that escaped returns get thru the parser */ }
{ESCAPE}{QUOTE} { BEGIN(ESCAPED_STRING); libexpr_parser->tokenErase(); }
<ESCAPED_STRING>. { libexpr_parser->tokenAppend(LibertyExprLex_text[0]); }
<ESCAPED_STRING>{ESCAPE}{QUOTE} {
BEGIN(INITIAL);
LibertyExprParse_lval.string = libexpr_parser->tokenCopy();
return PORT;
}
{PORT} {
LibertyExprParse_lval.string = stringCopy(LibertyExprLex_text);
return PORT;
}
{BLANK} {}
/* Send out of bound characters to parser. */
. { return (int) LibertyExprLex_text[0]; }
%%

View File

@ -0,0 +1,85 @@
%{
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
// Liberty function expression parser.
#include "Machine.hh"
#include "FuncExpr.hh"
#include "LibertyExpr.hh"
#include "LibertyExprPvt.hh"
#define LibertyExprParse_lex LibertyExprLex_lex
%}
%union {
int int_val;
const char *string;
sta::FuncExpr *expr;
}
%token PORT
%left '+' '|'
%left '*' '&'
%left '^'
%left '!' '\''
%type <string> PORT
%type <expr> expr terminal terminal_expr implicit_and
%{
%}
%%
result_expr:
expr { sta::libexpr_parser->setResult($1); }
| expr ';'{ sta::libexpr_parser->setResult($1); }
;
terminal:
PORT { $$ = sta::libexpr_parser->makeFuncExprPort($1); }
| '0' { $$ = sta::FuncExpr::makeZero(); }
| '1' { $$ = sta::FuncExpr::makeOne(); }
| '(' expr ')' { $$ = $2; }
;
terminal_expr:
terminal
| '!' terminal { $$ = sta::libexpr_parser->makeFuncExprNot($2); }
| terminal '\'' { $$ = sta::libexpr_parser->makeFuncExprNot($1); }
;
implicit_and:
terminal_expr terminal_expr
{ $$ = sta::libexpr_parser->makeFuncExprAnd($1, $2); }
| implicit_and terminal_expr
{ $$ = sta::libexpr_parser->makeFuncExprAnd($1, $2); }
;
expr:
terminal_expr
| implicit_and
| expr '+' expr { $$ = sta::libexpr_parser->makeFuncExprOr($1, $3); }
| expr '|' expr { $$ = sta::libexpr_parser->makeFuncExprOr($1, $3); }
| expr '*' expr { $$ = sta::libexpr_parser->makeFuncExprAnd($1, $3); }
| expr '&' expr { $$ = sta::libexpr_parser->makeFuncExprAnd($1, $3); }
| expr '^' expr { $$ = sta::libexpr_parser->makeFuncExprXor($1, $3); }
;
%%

82
liberty/LibertyExprPvt.hh Normal file
View File

@ -0,0 +1,82 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_LIBERTY_EXPR_PVT_H
#define STA_LIBERTY_EXPR_PVT_H
#include "DisallowCopyAssign.hh"
int
LibertyExprLex_lex();
namespace sta {
class Report;
class LibertyCell;
class FuncExpr;
class LibExprParser
{
public:
LibExprParser(const char *func,
LibertyCell *cell,
const char *error_msg,
Report *report);
~LibExprParser();
FuncExpr *makeFuncExprPort(const char *port_name);
FuncExpr *makeFuncExprOr(FuncExpr *arg1,
FuncExpr *arg2);
FuncExpr *makeFuncExprAnd(FuncExpr *arg1,
FuncExpr *arg2);
FuncExpr *makeFuncExprXor(FuncExpr *arg1,
FuncExpr *arg2);
FuncExpr *makeFuncExprNot(FuncExpr *arg);
void setResult(FuncExpr *result);
FuncExpr *result() { return result_; }
void parseError(const char *msg);
size_t copyInput(char *buf,
size_t max_size);
void tokenStart();
const char *token();
char *tokenCopy();
void tokenErase();
void tokenAppend(char ch);
private:
DISALLOW_COPY_AND_ASSIGN(LibExprParser);
const char *func_;
LibertyCell *cell_;
const char *error_msg_;
Report *report_;
FuncExpr *result_;
size_t token_length_;
char *token_;
char *token_next_;
};
extern LibExprParser *libexpr_parser;
} // namespace
// Global namespace
void
libertyExprFlushBuffer();
int
LibertyExprParse_error(const char *msg);
#endif

273
liberty/LibertyExt.cc Normal file
View File

@ -0,0 +1,273 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 illustratates how to customize the liberty file reader to
// read attributes that are not used by the STA. In this example:
// * code is called at the beginning of a library definition
// * a string attribute named "thingy" is parsed
#include "Machine.hh"
#include <stdio.h>
#include "StringUtil.hh"
#include "LibertyReader.hh"
#include "LibertyReaderPvt.hh"
#include "LibertyBuilder.hh"
#include "Network.hh"
#include "ConcreteNetwork.hh"
#include "Sta.hh"
// Import symbols from sta package (this example is in the global package).
using sta::Report;
using sta::Debug;
using sta::Network;
using sta::LibertyReader;
using sta::LibertyAttr;
using sta::LibertyGroup;
using sta::TimingGroup;
using sta::LibertyCell;
using sta::LibertyPort;
using sta::LibertyLibrary;
using sta::TimingArcSet;
using sta::LibertyBuilder;
using sta::TimingRole;
using sta::TimingArcAttrs;
using sta::Sta;
using sta::stringCopy;
// LibertyCell with Bigco thingy variable.
class BigcoCell : public LibertyCell
{
public:
BigcoCell(LibertyLibrary *library, const char *name, const char *filename);
void setThingy(const char *thingy);
protected:
const char *thingy_;
};
BigcoCell::BigcoCell(LibertyLibrary *library, const char *name,
const char *filename) :
LibertyCell(library, name, filename),
thingy_(0)
{
}
void
BigcoCell::setThingy(const char *thingy)
{
thingy_ = thingy;
}
////////////////////////////////////////////////////////////////
class BigcoTimingGroup : public TimingGroup
{
public:
BigcoTimingGroup(int line);
const char *frob() const { return frob_; }
void setFrob(const char *frob);
protected:
const char *frob_;
};
BigcoTimingGroup::BigcoTimingGroup(int line) :
TimingGroup(line),
frob_(0)
{
}
void
BigcoTimingGroup::setFrob(const char *frob)
{
frob_ = frob;
}
////////////////////////////////////////////////////////////////
class BigcoTimingArcSet : public TimingArcSet
{
public:
BigcoTimingArcSet(LibertyCell *cell, LibertyPort *from, LibertyPort *to,
LibertyPort *related_out, TimingRole *role,
TimingArcAttrs *attrs);
protected:
const char *frob_;
};
BigcoTimingArcSet::BigcoTimingArcSet(LibertyCell *cell, LibertyPort *from,
LibertyPort *to,
LibertyPort *related_out, TimingRole *role,
TimingArcAttrs *attrs) :
TimingArcSet(cell, from, to, related_out, role, attrs)
{
const char *frob = static_cast<BigcoTimingGroup*>(attrs)->frob();
if (frob)
frob_ = stringCopy(frob);
}
////////////////////////////////////////////////////////////////
// Make Bigco objects instead of Liberty objects.
class BigcoLibertyBuilder : public LibertyBuilder
{
public:
virtual LibertyCell *makeCell(LibertyLibrary *library, const char *name,
const char *filename);
protected:
virtual TimingArcSet *makeTimingArcSet(LibertyCell *cell, LibertyPort *from,
LibertyPort *to,
LibertyPort *related_out,
TimingRole *role,
TimingArcAttrs *attrs);
};
LibertyCell *
BigcoLibertyBuilder::makeCell(LibertyLibrary *library, const char *name,
const char *filename)
{
LibertyCell *cell = new BigcoCell(library, name, filename);
library->addCell(cell);
return cell;
}
TimingArcSet *
BigcoLibertyBuilder::makeTimingArcSet(LibertyCell *cell, LibertyPort *from,
LibertyPort *to,
LibertyPort *related_out,
TimingRole *role,
TimingArcAttrs *attrs)
{
return new BigcoTimingArcSet(cell, from, to, related_out, role, attrs);
}
////////////////////////////////////////////////////////////////
// Liberty reader to parse Bigco attributes.
class BigcoLibertyReader : public LibertyReader
{
public:
BigcoLibertyReader(LibertyBuilder *builder);
protected:
virtual void visitAttr1(LibertyAttr *attr);
virtual void visitAttr2(LibertyAttr *attr);
virtual void beginLibrary(LibertyGroup *group);
virtual TimingGroup *makeTimingGroup(int line);
virtual void beginCell(LibertyGroup *group);
};
BigcoLibertyReader::BigcoLibertyReader(LibertyBuilder *builder) :
LibertyReader(builder)
{
// Define a visitor for the "thingy" attribute.
// Note that the function descriptor passed to defineAttrVisitor
// must be defined by the LibertyVisitor class, so a number of
// extra visitor functions are pre-defined for extensions.
defineAttrVisitor("thingy", &LibertyReader::visitAttr1);
defineAttrVisitor("frob", &LibertyReader::visitAttr2);
}
bool
libertyCellRequired(const char *)
{
// Predicate for cell names.
return true;
}
// Prune cells from liberty file based on libertyCellRequired predicate.
void
BigcoLibertyReader::beginCell(LibertyGroup *group)
{
const char *name = group->firstName();
if (name
&& libertyCellRequired(name))
LibertyReader::beginCell(group);
}
TimingGroup *
BigcoLibertyReader::makeTimingGroup(int line)
{
return new BigcoTimingGroup(line);
}
// Called at the beginning of a library group.
void
BigcoLibertyReader::beginLibrary(LibertyGroup *group)
{
LibertyReader::beginLibrary(group);
// Do Bigco stuff here.
printf("Bigco was here.\n");
}
void
BigcoLibertyReader::visitAttr1(LibertyAttr *attr)
{
const char *thingy = getAttrString(attr);
if (thingy) {
printf("Bigco thingy attribute value is %s.\n", thingy);
if (cell_)
dynamic_cast<BigcoCell*>(cell_)->setThingy(thingy);
}
}
void
BigcoLibertyReader::visitAttr2(LibertyAttr *attr)
{
const char *frob = getAttrString(attr);
if (frob) {
if (timing_)
static_cast<BigcoTimingGroup*>(timing_)->setFrob(frob);
}
}
////////////////////////////////////////////////////////////////
// Define a BigcoSta class derived from the Sta class to install the
// new liberty reader/visitor in BigcoSta::makeLibertyReader.
class BigcoSta : public Sta
{
public:
BigcoSta();
protected:
virtual LibertyLibrary *readLibertyFile(const char *filename,
bool infer_latches,
Report *report,
Debug *debug,
Network *network);
};
BigcoSta::BigcoSta() :
Sta()
{
}
// Replace Sta liberty file reader with Bigco's very own.
LibertyLibrary *
Sta::readLibertyFile(const char *filename,
bool infer_latches,
Report *report,
Debug *debug,
Network *network)
{
BigcoLibertyBuilder builder;
BigcoLibertyReader reader(&builder);
return reader.readLibertyFile(filename, infer_latches,
report, debug, network);
}

209
liberty/LibertyLex.ll Normal file
View File

@ -0,0 +1,209 @@
%{
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 <ctype.h>
#include <string.h>
#include "Machine.hh"
#include "LibertyParser.hh"
#include "LibertyParse.hh"
#define YY_NO_INPUT
#if defined(YY_FLEX_MAJOR_VERSION) \
&& defined(YY_FLEX_MINOR_VERSION) \
&& YY_FLEX_MAJOR_VERSION >=2 \
&& (YY_FLEX_MINOR_VERSION > 5 \
|| (YY_FLEX_MINOR_VERSION == 5 \
&& defined(YY_FLEX_SUBMINOR_VERSION) \
&& YY_FLEX_SUBMINOR_VERSION >= 31))
#define INCLUDE_SUPPORTED
#endif
static std::string string_buf;
void
libertyParseFlushBuffer()
{
YY_FLUSH_BUFFER;
}
%}
/* %option debug */
%option prefix="LibertyLex_"
%option outfile="lex.yy.c"
%option noyywrap
%option nounput
%option never-interactive
%x comment
%x qstring
DIGIT [0-9]
ALPHA [a-zA-Z]
FLOAT [-+]?(({DIGIT}+\.?{DIGIT}*)|(\.{DIGIT}+))([Ee][-+]?{DIGIT}+)?
BLANK [ \t]
BUS_LEFT [\[<]
BUS_RIGHT [\]>]
BUS_SUB {BUS_LEFT}{DIGIT}+{BUS_RIGHT}
BUS_RANGE {BUS_LEFT}{DIGIT}+:{DIGIT}+{BUS_RIGHT}
PIN_NAME ({ALPHA}|_)({ALPHA}|{DIGIT}|_)*
BUS_NAME {PIN_NAME}({BUS_SUB}|{BUS_RANGE})
MIXED_NAME {BUS_NAME}_{PIN_NAME}
HNAME ({PIN_NAME}|{BUS_NAME}|{MIXED_NAME})([\/.]({PIN_NAME}|{BUS_NAME}|{MIXED_NAME}))+
/* ocv_table_template(2D_ocv_template) */
/* leakage_power_unit : 1pW; */
/* default_operating_conditions : slow_100_3.00 ; */
/* revision : 1.0.17; */
/* default_wire_load : xc2v250-5_avg; */
TOKEN ({ALPHA}|{DIGIT}|_)({ALPHA}|{DIGIT}|[._\-])*
/* bus_naming_style : %s[%d] ; */
BUS_STYLE "%s"{BUS_LEFT}"%d"{BUS_RIGHT}
PUNCTUATION [,\:;|(){}+*&!'=]
TOKEN_END {PUNCTUATION}|[ \t\r\n]
EOL \r?\n
%%
{PUNCTUATION} { return ((int) LibertyLex_text[0]); }
{FLOAT}{TOKEN_END} {
/* Push back the TOKEN_END character. */
yyless(LibertyLex_leng - 1);
LibertyParse_lval.number = static_cast<float>(strtod(LibertyLex_text,
NULL));
return FLOAT;
}
{ALPHA}({ALPHA}|_|{DIGIT})*{TOKEN_END} {
/* Push back the TOKEN_END character. */
yyless(LibertyLex_leng - 1);
LibertyParse_lval.string = sta::stringCopy(LibertyLex_text);
return KEYWORD;
}
{PIN_NAME}{TOKEN_END} |
{BUS_NAME}{TOKEN_END} |
{MIXED_NAME}{TOKEN_END} |
{HNAME}{TOKEN_END} |
{BUS_STYLE}{TOKEN_END} |
{TOKEN}{TOKEN_END} {
/* Push back the TOKEN_END character. */
yyless(LibertyLex_leng - 1);
LibertyParse_lval.string = sta::stringCopy(LibertyLex_text);
return STRING;
}
\\?{EOL} { sta::libertyIncrLine(); }
"include_file"[ \t]*"(".+")"[ \t]*";"? {
#ifdef INCLUDE_SUPPORTED
if (sta::libertyInInclude())
sta::libertyParseError("nested include_file's are not supported\n");
else {
char *filename = &yytext[strlen("include_file")];
/* Skip blanks between include_file and '('. */
while (isspace(*filename) && *filename != '\0')
filename++;
/* Skip '('. */
filename++;
/* Skip blanks between '(' and filename. */
while (isspace(*filename) && *filename != '\0')
filename++;
char *filename_end = strpbrk(filename, ")");
if (filename_end == NULL)
sta::libertyParseError("include_file missing ')'\n");
else {
/* Trim trailing blanks. */
while (isspace(filename_end[-1]) && filename_end > filename)
filename_end--;
*filename_end = '\0';
FILE *stream = sta::libertyIncludeBegin(filename);
if (stream) {
yypush_buffer_state(yy_create_buffer(stream, YY_BUF_SIZE));
BEGIN(INITIAL);
}
}
}
#else
sta::libertyParseError("include_file is not supported.\n");
#endif
}
"/*" BEGIN(comment);
/* Straight out of the flex man page. */
<comment>[^*\r\n]* /* eat anything that's not a '*' */
<comment>"*"+[^*/\r\n]* /* eat up '*'s not followed by '/'s */
<comment>{EOL} sta::libertyIncrLine();
<comment>"*"+"/" BEGIN(INITIAL);
\" {
string_buf.erase();
BEGIN(qstring);
}
<qstring>\" {
BEGIN(INITIAL);
LibertyParse_lval.string = sta::stringCopy(string_buf.c_str());
return STRING;
}
<qstring>{EOL} {
LibertyParse_error("unterminated string constant");
BEGIN(INITIAL);
LibertyParse_lval.string = sta::stringCopy(string_buf.c_str());
return STRING;
}
<qstring>\\{EOL} {
/* Line continuation. */
sta::libertyIncrLine();
}
<qstring>\\. {
/* Escaped character. */
string_buf += '\\';
string_buf += LibertyLex_text[1];
}
<qstring>[^\\\r\n\"]+ {
/* Anything but escape, return or double quote */
string_buf += LibertyLex_text;
}
<qstring><<EOF>> {
LibertyParse_error("unterminated string constant");
BEGIN(INITIAL);
yyterminate();
}
{BLANK}* {}
/* Send out of bound characters to parser. */
. { return (int) LibertyLex_text[0]; }
<<EOF>> {
#ifdef INCLUDE_SUPPORTED
if (sta::libertyInInclude()) {
sta::libertyIncludeEnd();
yypop_buffer_state();
}
else
#endif
yyterminate();
}
%%

181
liberty/LibertyParse.yy Normal file
View File

@ -0,0 +1,181 @@
%{
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 <stdlib.h>
#include <string.h>
#include "Machine.hh"
#include "StringUtil.hh"
#include "LibertyParser.hh"
int LibertyLex_lex();
int LibertyParse_error(const char *msg);
#define LibertyParse_lex LibertyLex_lex
// Use yacc generated parser errors.
#define YYERROR_VERBOSE
%}
%union {
char *string;
float number;
int line;
sta::LibertyAttrValue *attr_value;
sta::LibertyAttrValueSeq *attr_values;
sta::LibertyGroup *group;
sta::LibertyStmt *stmt;
}
%token <number> FLOAT
%token <string> STRING KEYWORD
%type <stmt> statement complex_attr simple_attr variable group file
%type <attr_values> attr_values
%type <attr_value> attr_value simple_attr_value
%type <string> string
%type <line> line
%type <number> volt_expr volt_token
%start file
%{
%}
%%
file:
group
;
group:
KEYWORD '(' ')' line '{'
{ sta::libertyGroupBegin($1, NULL, $4); }
'}' semi_opt
{ $$ = sta::libertyGroupEnd(); }
| KEYWORD '(' ')' line '{'
{ sta::libertyGroupBegin($1, NULL, $4); }
statements '}' semi_opt
{ $$ = sta::libertyGroupEnd(); }
| KEYWORD '(' attr_values ')' line '{'
{ sta::libertyGroupBegin($1, $3, $5); }
'}' semi_opt
{ $$ = sta::libertyGroupEnd(); }
| KEYWORD '(' attr_values ')' line '{'
{ sta::libertyGroupBegin($1, $3, $5); }
statements '}' semi_opt
{ $$ = sta::libertyGroupEnd(); }
;
line: /* empty */
{ $$ = sta::libertyLine(); }
;
statements:
statement
| statements statement
;
statement:
simple_attr
| complex_attr
| group
| variable
;
simple_attr:
KEYWORD ':' simple_attr_value line semi_opt
{ $$ = sta::makeLibertySimpleAttr($1, $3, $4); }
;
simple_attr_value:
attr_value
| volt_expr
{ $$ = static_cast<sta::LibertyAttrValue*>(NULL); }
/* Unquoted NOT function. */
/* clocked_on : !CP; */
| '!' string
{ $$ = sta::makeLibertyStringAttrValue(sta::stringPrint(strlen($2)+1, "!%s", $2)); sta::stringDelete($2); }
;
complex_attr:
KEYWORD '(' ')' line semi_opt
{ $$ = sta::makeLibertyComplexAttr($1, NULL, $4); }
| KEYWORD '(' attr_values ')' line semi_opt
{ $$ = sta::makeLibertyComplexAttr($1, $3, $5); }
;
attr_values:
attr_value
{ $$ = new sta::LibertyAttrValueSeq;
$$->push_back($1);
}
| attr_values ',' attr_value
{ $1->push_back($3);
$$ = $1;
}
| attr_values attr_value
{ $1->push_back($2);
$$ = $1;
}
;
variable:
string '=' FLOAT line semi_opt
{ $$ = sta::makeLibertyVariable($1, $3, $4); }
;
string:
STRING
{ $$ = $1; }
| KEYWORD
{ $$ = $1; }
;
attr_value:
FLOAT
{ $$ = sta::makeLibertyFloatAttrValue($1); }
| string
{ $$ = sta::makeLibertyStringAttrValue($1); }
;
/* Voltage expressions are ignored. */
volt_expr:
volt_token expr_op volt_token
| volt_expr expr_op volt_token
;
volt_token:
FLOAT
| KEYWORD
{ sta::stringDelete($1);
$$ = 0.0;
}
;
expr_op:
'+'
| '-'
| '*'
| '/'
;
semi_opt:
/* empty */
| semi_opt ';'
;
%%

576
liberty/LibertyParser.cc Normal file
View File

@ -0,0 +1,576 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 <stdio.h>
#include <string.h>
#include "Machine.hh"
#include "Report.hh"
#include "Error.hh"
#include "StringUtil.hh"
#include "LibertyParser.hh"
// Global namespace
int
LibertyParse_parse();
extern FILE *LibertyLex_in;
namespace sta {
typedef Vector<LibertyGroup*> LibertyGroupSeq;
static const char *liberty_filename;
static int liberty_line;
// Previous lex reader state for include files.
static const char *liberty_filename_prev;
static int liberty_line_prev;
static FILE *liberty_stream_prev;
static LibertyGroupVisitor *liberty_group_visitor;
static LibertyGroupSeq liberty_group_stack;
static Report *liberty_report;
static LibertyStmt *
makeLibertyDefine(LibertyAttrValueSeq *values,
int line);
static AttrType
attrValueType(const char *value_type_name);
static LibertyGroupType
groupType(const char *group_type_name);
////////////////////////////////////////////////////////////////
void
parseLibertyFile(const char *filename,
LibertyGroupVisitor *library_visitor,
Report *report)
{
LibertyLex_in = fopen(filename, "r");
if (LibertyLex_in) {
liberty_group_visitor = library_visitor;
liberty_group_stack.clear();
liberty_filename = filename;
liberty_filename_prev = NULL;
liberty_stream_prev = NULL;
liberty_line = 1;
liberty_report = report;
LibertyParse_parse();
fclose(LibertyLex_in);
}
else
throw FileNotReadable(filename);
}
void
libertyGroupBegin(const char *type,
LibertyAttrValueSeq *params,
int line)
{
LibertyGroup *group = new LibertyGroup(type, params, line);
liberty_group_visitor->begin(group);
liberty_group_stack.push_back(group);
}
LibertyGroup *
libertyGroupEnd()
{
LibertyGroup *group = libertyGroup();
liberty_group_visitor->end(group);
liberty_group_stack.pop_back();
LibertyGroup *parent =
liberty_group_stack.empty() ? NULL : liberty_group_stack.back();
if (parent && liberty_group_visitor->save(group)) {
parent->addSubgroup(group);
return group;
}
else {
delete group;
return NULL;
}
}
////////////////////////////////////////////////////////////////
LibertyStmt::LibertyStmt(int line) :
line_(line)
{
}
LibertyGroup::LibertyGroup(const char *type,
LibertyAttrValueSeq *params,
int line) :
LibertyStmt(line),
type_(type),
params_(params),
attrs_(NULL),
attr_map_(NULL),
subgroups_(NULL),
define_map_(NULL)
{
}
void
LibertyGroup::addSubgroup(LibertyGroup *subgroup)
{
if (subgroups_ == NULL)
subgroups_ = new LibertyGroupSeq;
subgroups_->push_back(subgroup);
}
void
LibertyGroup::addDefine(LibertyDefine *define)
{
if (define_map_ == NULL)
define_map_ = new LibertyDefineMap;
const char *define_name = define->name();
LibertyDefine *prev_define = define_map_->findKey(define_name);
if (prev_define) {
define_map_->eraseKey(define_name);
delete prev_define;
}
(*define_map_)[define_name] = define;
}
void
LibertyGroup::addAttribute(LibertyAttr *attr)
{
if (attrs_ == NULL)
attrs_ = new LibertyAttrSeq;
attrs_->push_back(attr);
if (attr_map_)
(*attr_map_)[attr->name()] = attr;
}
LibertyGroup::~LibertyGroup()
{
stringDelete(type_);
if (params_) {
params_->deleteContents();
delete params_;
}
if (attrs_) {
LibertyAttrSeq::Iterator iter(attrs_);
attrs_->deleteContents();
delete attrs_;
delete attr_map_;
}
if (subgroups_) {
subgroups_->deleteContents();
delete subgroups_;
}
if (define_map_) {
define_map_->deleteContents();
delete define_map_;
}
}
const char *
LibertyGroup::firstName()
{
if (params_ && params_->size() > 0) {
LibertyAttrValue *value = (*params_)[0];
if (value->isString())
return value->stringValue();
}
return NULL;
}
const char *
LibertyGroup::secondName()
{
if (params_ && params_->size() > 1) {
LibertyAttrValue *value = (*params_)[1];
if (value->isString())
return value->stringValue();
}
return NULL;
}
LibertyAttr *
LibertyGroup::findAttr(const char *name)
{
if (attrs_) {
if (attr_map_ == NULL) {
// Build attribute name map on demand.
LibertyAttrSeq::Iterator attr_iter(attrs_);
while (attr_iter.hasNext()) {
LibertyAttr *attr = attr_iter.next();
(*attr_map_)[attr->name()] = attr;
}
}
return attr_map_->findKey(name);
}
else
return NULL;
}
LibertySubgroupIterator::LibertySubgroupIterator(LibertyGroup *group) :
LibertyGroupSeq::Iterator(group->subgroups())
{
}
LibertyAttrIterator::LibertyAttrIterator(LibertyGroup *group) :
LibertyAttrSeq::Iterator(group->attrs())
{
}
////////////////////////////////////////////////////////////////
LibertyAttr::LibertyAttr(const char *name,
int line) :
LibertyStmt(line),
name_(name)
{
}
LibertyAttr::~LibertyAttr()
{
stringDelete(name_);
}
LibertyStmt *
makeLibertySimpleAttr(const char *name,
LibertyAttrValue *value,
int line)
{
LibertyAttr *attr = new LibertySimpleAttr(name, value, line);
if (liberty_group_visitor)
liberty_group_visitor->visitAttr(attr);
LibertyGroup *group = libertyGroup();
if (group && liberty_group_visitor->save(attr)) {
group->addAttribute(attr);
return attr;
}
else {
delete attr;
return NULL;
}
}
LibertyGroup *
libertyGroup()
{
return liberty_group_stack.back();
}
LibertySimpleAttr::LibertySimpleAttr(const char *name,
LibertyAttrValue *value,
int line) :
LibertyAttr(name, line),
value_(value)
{
}
LibertySimpleAttr::~LibertySimpleAttr()
{
delete value_;
}
LibertyAttrValueSeq *
LibertySimpleAttr::values() const
{
internalError("valueIterator called for LibertySimpleAttribute");
return NULL;
}
LibertyStmt *
makeLibertyComplexAttr(const char *name,
LibertyAttrValueSeq *values,
int line)
{
// Defines have the same syntax as complex attributes.
// Detect and convert them.
if (stringEq(name, "define")) {
LibertyStmt *define = makeLibertyDefine(values, line);
stringDelete(name);
LibertyAttrValueSeq::Iterator attr_iter(values);
while (attr_iter.hasNext())
delete attr_iter.next();
delete values;
return define;
}
else {
LibertyAttr *attr = new LibertyComplexAttr(name, values, line);
if (liberty_group_visitor)
liberty_group_visitor->visitAttr(attr);
if (liberty_group_visitor->save(attr)) {
LibertyGroup *group = libertyGroup();
group->addAttribute(attr);
return attr;
}
else {
delete attr;
return NULL;
}
}
}
LibertyComplexAttr::LibertyComplexAttr(const char *name,
LibertyAttrValueSeq *values,
int line) :
LibertyAttr(name, line),
values_(values)
{
}
LibertyComplexAttr::~LibertyComplexAttr()
{
if (values_) {
values_->deleteContents();
delete values_;
}
}
LibertyAttrValue *
LibertyComplexAttr::firstValue()
{
if (values_ && values_->size() > 0)
return (*values_)[0];
else
return NULL;
}
LibertyAttrValue *
makeLibertyStringAttrValue(char *value)
{
return new LibertyStringAttrValue(value);
}
LibertyStringAttrValue::LibertyStringAttrValue(const char *value) :
LibertyAttrValue(),
value_(value)
{
}
LibertyStringAttrValue::~LibertyStringAttrValue()
{
stringDelete(value_);
}
float
LibertyStringAttrValue::floatValue()
{
internalError("LibertyStringAttrValue called for float value");
return 0.0;
}
const char *
LibertyStringAttrValue::stringValue()
{
return value_;
}
LibertyAttrValue *
makeLibertyFloatAttrValue(float value)
{
return new LibertyFloatAttrValue(value);
}
LibertyFloatAttrValue::LibertyFloatAttrValue(float value) :
value_(value)
{
}
float
LibertyFloatAttrValue::floatValue()
{
return value_;
}
const char *
LibertyFloatAttrValue::stringValue()
{
internalError("LibertyStringAttrValue called for float value");
return NULL;
}
////////////////////////////////////////////////////////////////
static LibertyStmt *
makeLibertyDefine(LibertyAttrValueSeq *values,
int line)
{
LibertyDefine *define = NULL;
if (values->size() == 3) {
const char *define_name = (*values)[0]->stringValue();
const char *group_type_name = (*values)[1]->stringValue();
const char *value_type_name = (*values)[2]->stringValue();
AttrType value_type = attrValueType(value_type_name);
LibertyGroupType group_type = groupType(group_type_name);
define = new LibertyDefine(stringCopy(define_name), group_type,
value_type, line);
LibertyGroup *group = libertyGroup();
group->addDefine(define);
}
else
liberty_report->fileWarn(liberty_filename, line,
"define does not have three arguments.\n");
return define;
}
// The Liberty User Guide Version 2001.08 fails to define the strings
// used to define valid attribute types. Beyond "string" these are
// guesses.
static AttrType
attrValueType(const char *value_type_name)
{
if (stringEq(value_type_name, "string"))
return liberty_attr_string;
else if (stringEq(value_type_name, "integer"))
return liberty_attr_int;
else if (stringEq(value_type_name, "float"))
return liberty_attr_double;
else if (stringEq(value_type_name, "boolean"))
return liberty_attr_boolean;
else
return liberty_attr_unknown;
}
static LibertyGroupType
groupType(const char *group_type_name)
{
if (stringEq(group_type_name, "library"))
return liberty_group_library;
else if (stringEq(group_type_name, "cell"))
return liberty_group_cell;
else if (stringEq(group_type_name, "pin"))
return liberty_group_pin;
else if (stringEq(group_type_name, "timing"))
return liberty_group_timing;
else
return liberty_group_unknown;
}
LibertyDefine::LibertyDefine(const char *name,
LibertyGroupType group_type,
AttrType value_type,
int line) :
LibertyStmt(line),
name_(name),
group_type_(group_type),
value_type_(value_type)
{
}
LibertyDefine::~LibertyDefine()
{
stringDelete(name_);
}
////////////////////////////////////////////////////////////////
LibertyStmt *
makeLibertyVariable(char *var,
float value,
int line)
{
LibertyVariable *variable = new LibertyVariable(var, value, line);
liberty_group_visitor->visitVariable(variable);
if (liberty_group_visitor->save(variable))
return variable;
else {
delete variable;
return NULL;
}
}
LibertyVariable::LibertyVariable(const char *var,
float value,
int line) :
LibertyStmt(line),
var_(var),
value_(value)
{
}
LibertyVariable::~LibertyVariable()
{
stringDelete(var_);
}
////////////////////////////////////////////////////////////////
bool
libertyInInclude()
{
return liberty_filename_prev != NULL;
}
FILE *
libertyIncludeBegin(const char *filename)
{
FILE *stream = fopen(filename, "r" );
if (stream == NULL)
libertyParseError("cannot open include file %s.\n", filename);
else {
liberty_filename_prev = liberty_filename;
liberty_line_prev = liberty_line;
liberty_stream_prev = LibertyLex_in;
liberty_filename = filename;
liberty_line = 1;
}
return stream;
}
void
libertyIncludeEnd()
{
fclose(LibertyLex_in);
liberty_filename = liberty_filename_prev;
liberty_line = liberty_line_prev;
LibertyLex_in = liberty_stream_prev;
liberty_filename_prev = NULL;
liberty_stream_prev = NULL;
}
void
libertyIncrLine()
{
sta::liberty_line++;
}
int
libertyLine()
{
return liberty_line;
}
void
libertyParseError(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
sta::liberty_report->vfileError(sta::liberty_filename, sta::liberty_line,
fmt, args);
va_end(args);
}
} // namespace
////////////////////////////////////////////////////////////////
// Global namespace
void libertyParseFlushBuffer();
int
LibertyParse_error(const char *msg)
{
sta::liberty_report->fileError(sta::liberty_filename, sta::liberty_line,
"%s.\n", msg);
libertyParseFlushBuffer();
return 0;
}

362
liberty/LibertyParser.hh Normal file
View File

@ -0,0 +1,362 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_LIBERTY_PARSER_H
#define STA_LIBERTY_PARSER_H
#include "DisallowCopyAssign.hh"
#include "Vector.hh"
#include "Map.hh"
#include "Set.hh"
#include "StringUtil.hh"
namespace sta {
class Report;
class LibertyGroupVisitor;
class LibertyAttrVisitor;
class LibertyStmt;
class LibertyGroup;
class LibertyAttr;
class LibertyDefine;
class LibertyAttrValue;
class LibertyVariable;
class LibertySubgroupIterator;
class LibertyAttrIterator;
typedef Vector<LibertyStmt*> LibertyStmtSeq;
typedef Vector<LibertyGroup*> LibertyGroupSeq;
typedef Vector<LibertyAttr*> LibertyAttrSeq;
typedef Map<const char *, LibertyAttr*, CharPtrLess> LibertyAttrMap;
typedef Map<const char *, LibertyDefine*, CharPtrLess> LibertyDefineMap;
typedef Vector<LibertyAttrValue*> LibertyAttrValueSeq;
typedef Map<const char *, float, CharPtrLess> LibertyVariableMap;
typedef Map<const char*,LibertyGroupVisitor*,CharPtrLess>LibertyGroupVisitorMap;
typedef LibertyAttrValueSeq::Iterator LibertyAttrValueIterator;
typedef enum {
liberty_attr_string,
liberty_attr_int,
liberty_attr_double,
liberty_attr_boolean,
liberty_attr_unknown
} AttrType;
typedef enum {
liberty_group_library,
liberty_group_cell,
liberty_group_pin,
liberty_group_timing,
liberty_group_unknown
} LibertyGroupType;
// Abstract base class for liberty statements.
class LibertyStmt
{
public:
explicit LibertyStmt(int line);
virtual ~LibertyStmt() {}
int line() const { return line_; }
virtual bool isGroup() const { return false; }
virtual bool isAttribute() const { return false; }
virtual bool isDefine() const { return false; }
virtual bool isVariable() const { return false; }
protected:
int line_;
private:
DISALLOW_COPY_AND_ASSIGN(LibertyStmt);
};
// Groups are a type keyword with a set of parameters and statements
// enclosed in brackets.
// type([param1][, param2]...) { stmts.. }
class LibertyGroup : public LibertyStmt
{
public:
LibertyGroup(const char *type,
LibertyAttrValueSeq *params,
int line);
virtual ~LibertyGroup();
virtual bool isGroup() const { return true; }
const char *type() const { return type_; }
// First param as a string.
const char *firstName();
// Second param as a string.
const char *secondName();
LibertyAttr *findAttr(const char *name);
void addSubgroup(LibertyGroup *subgroup);
void addDefine(LibertyDefine *define);
void addAttribute(LibertyAttr *attr);
void addVariable(LibertyVariable *var);
LibertyGroupSeq *subgroups() const { return subgroups_; }
LibertyAttrSeq *attrs() const { return attrs_; }
LibertyAttrValueSeq *params() const { return params_; }
protected:
void parseNames(LibertyAttrValueSeq *values);
const char *type_;
LibertyAttrValueSeq *params_;
LibertyAttrSeq *attrs_;
LibertyAttrMap *attr_map_;
LibertyGroupSeq *subgroups_;
LibertyDefineMap *define_map_;
private:
DISALLOW_COPY_AND_ASSIGN(LibertyGroup);
};
class LibertySubgroupIterator : public LibertyGroupSeq::Iterator
{
public:
explicit LibertySubgroupIterator(LibertyGroup *group);
private:
DISALLOW_COPY_AND_ASSIGN(LibertySubgroupIterator);
};
class LibertyAttrIterator : public LibertyAttrSeq::Iterator
{
public:
explicit LibertyAttrIterator(LibertyGroup *group);
private:
DISALLOW_COPY_AND_ASSIGN(LibertyAttrIterator);
};
// Abstract base class for attributes.
class LibertyAttr : public LibertyStmt
{
public:
LibertyAttr(const char *name,
int line);
virtual ~LibertyAttr();
const char *name() const { return name_; }
virtual bool isAttribute() const { return true; }
virtual bool isSimple() const = 0;
virtual bool isComplex() const = 0;
virtual LibertyAttrValueSeq *values() const = 0;
virtual LibertyAttrValue *firstValue() = 0;
protected:
const char *name_;
private:
DISALLOW_COPY_AND_ASSIGN(LibertyAttr);
};
// Abstract base class for simple attributes.
// name : value;
class LibertySimpleAttr : public LibertyAttr
{
public:
LibertySimpleAttr(const char *name,
LibertyAttrValue *value,
int line);
virtual ~LibertySimpleAttr();
virtual bool isSimple() const { return true; }
virtual bool isComplex() const { return false; }
virtual LibertyAttrValue *firstValue() { return value_; }
virtual LibertyAttrValueSeq *values() const;
private:
DISALLOW_COPY_AND_ASSIGN(LibertySimpleAttr);
LibertyAttrValue *value_;
};
// Complex attributes have multiple values.
// name(attr_value1[, attr_value2]...);
class LibertyComplexAttr : public LibertyAttr
{
public:
LibertyComplexAttr(const char *name,
LibertyAttrValueSeq *values,
int line);
virtual ~LibertyComplexAttr();
virtual bool isSimple() const { return false; }
virtual bool isComplex() const { return true; }
virtual LibertyAttrValue *firstValue();
virtual LibertyAttrValueSeq *values() const { return values_; }
private:
DISALLOW_COPY_AND_ASSIGN(LibertyComplexAttr);
LibertyAttrValueSeq *values_;
};
// Attribute values are a string or float.
class LibertyAttrValue
{
public:
LibertyAttrValue() {}
virtual ~LibertyAttrValue() {}
virtual bool isString() = 0;
virtual bool isFloat() = 0;
virtual float floatValue() = 0;
virtual const char *stringValue() = 0;
private:
DISALLOW_COPY_AND_ASSIGN(LibertyAttrValue);
};
class LibertyStringAttrValue : public LibertyAttrValue
{
public:
explicit LibertyStringAttrValue(const char *value);
virtual ~LibertyStringAttrValue();
virtual bool isFloat() { return false; }
virtual bool isString() { return true; }
virtual float floatValue();
virtual const char *stringValue();
private:
DISALLOW_COPY_AND_ASSIGN(LibertyStringAttrValue);
const char *value_;
};
class LibertyFloatAttrValue : public LibertyAttrValue
{
public:
explicit LibertyFloatAttrValue(float value);
virtual bool isString() { return false; }
virtual bool isFloat() { return true; }
virtual float floatValue();
virtual const char *stringValue();
private:
DISALLOW_COPY_AND_ASSIGN(LibertyFloatAttrValue);
float value_;
};
// Define statements define new simple attributes.
// define(attribute_name, group_name, attribute_type);
// attribute_type is string|integer|float.
class LibertyDefine : public LibertyStmt
{
public:
LibertyDefine(const char *name,
LibertyGroupType group_type,
AttrType value_type,
int line);
virtual ~LibertyDefine();
virtual bool isDefine() const { return true; }
const char *name() const { return name_; }
private:
DISALLOW_COPY_AND_ASSIGN(LibertyDefine);
const char *name_;
LibertyGroupType group_type_;
AttrType value_type_;
};
// The Liberty User Guide Version 2003.12 fails to document variables.
// var = value;
// The only example I have only uses float values, so I am assuming
// that is all that is supported (which is probably wrong).
class LibertyVariable : public LibertyStmt
{
public:
LibertyVariable(const char *var,
float value,
int line);
// var_ is NOT deleted by ~LibertyVariable because the group
// variable map ref's it.
virtual ~LibertyVariable();
virtual bool isVariable() const { return true; }
const char *variable() const { return var_; }
float value() const { return value_; }
private:
DISALLOW_COPY_AND_ASSIGN(LibertyVariable);
const char *var_;
float value_;
};
class LibertyGroupVisitor
{
public:
LibertyGroupVisitor() {}
virtual ~LibertyGroupVisitor() {}
virtual void begin(LibertyGroup *group) = 0;
virtual void end(LibertyGroup *group) = 0;
virtual void visitAttr(LibertyAttr *attr) = 0;
virtual void visitVariable(LibertyVariable *variable) = 0;
// Predicates to save parse structure after visits.
virtual bool save(LibertyGroup *group) = 0;
virtual bool save(LibertyAttr *attr) = 0;
virtual bool save(LibertyVariable *variable) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(LibertyGroupVisitor);
};
FILE *
libertyIncludeBegin(const char *filename);
void
libertyIncludeEnd();
bool
libertyInInclude();
void
libertyIncrLine();
void
libertyParseError(const char *fmt,
...);
int
libertyLine();
void
parseLibertyFile(const char *filename,
LibertyGroupVisitor *library_visitor,
Report *report);
void
libertyGroupBegin(const char *type,
LibertyAttrValueSeq *params,
int line);
LibertyGroup *
libertyGroupEnd();
LibertyGroup *
libertyGroup();
LibertyStmt *
makeLibertyComplexAttr(const char *name,
LibertyAttrValueSeq *values,
int line);
LibertyStmt *
makeLibertySimpleAttr(const char *name,
LibertyAttrValue *value,
int line);
LibertyAttrValue *
makeLibertyFloatAttrValue(float value);
LibertyAttrValue *
makeLibertyStringAttrValue(char *value);
LibertyStmt *
makeLibertyVariable(char *var,
float value,
int line);
} // namespace
// Global namespace.
int
LibertyParse_error(const char *msg);
#endif

4938
liberty/LibertyReader.cc Normal file

File diff suppressed because it is too large Load Diff

35
liberty/LibertyReader.hh Normal file
View File

@ -0,0 +1,35 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_LIBERTY_READER_H
#define STA_LIBERTY_READER_H
namespace sta {
class Report;
class Debug;
class Network;
class LibertyLibrary;
LibertyLibrary *
readLibertyFile(const char *filename,
bool infer_latches,
Report *report,
Debug *debug,
Network *network);
} // namespace
#endif

772
liberty/LibertyReaderPvt.hh Normal file
View File

@ -0,0 +1,772 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_LIBERTY_READER_PVT
#define STA_LIBERTY_READER_PVT
#include "DisallowCopyAssign.hh"
#include "Vector.hh"
#include "Map.hh"
#include "StringSeq.hh"
#include "Transition.hh"
#include "MinMax.hh"
#include "TimingArc.hh"
#include "InternalPower.hh"
#include "LeakagePower.hh"
#include "Liberty.hh"
#include "LibertyParser.hh"
#include "LibertyReader.hh"
#include "NetworkClass.hh"
namespace sta {
class LibertyBuilder;
class LibertyReader;
class LibertyFunc;
class PortGroup;
class SequentialGroup;
class RelatedPortGroup;
class TimingGroup;
class InternalPowerGroup;
class LeakagePowerGroup;
class PortNameBitIterator;
class TimingArcBuilder;
class LibertyAttr;
typedef void (LibertyReader::*LibraryAttrVisitor)(LibertyAttr *attr);
typedef void (LibertyReader::*LibraryGroupVisitor)(LibertyGroup *group);
typedef Map<const char*,LibraryAttrVisitor,CharPtrLess> LibraryAttrMap;
typedef Map<const char*,LibraryGroupVisitor,CharPtrLess> LibraryGroupMap;
typedef Vector<PortGroup*> PortGroupSeq;
typedef Vector<SequentialGroup*> SequentialGroupSeq;
typedef Vector<LibertyFunc*> LibertyFuncSeq;
typedef Vector<TimingGroup*> TimingGroupSeq;
typedef Vector<InternalPowerGroup*> InternalPowerGroupSeq;
typedef Vector<LeakagePowerGroup*> LeakagePowerGroupSeq;
class LibertyReader : public LibertyGroupVisitor
{
public:
explicit LibertyReader(LibertyBuilder *builder);
virtual ~LibertyReader();
virtual LibertyLibrary *readLibertyFile(const char *filename,
bool infer_latches,
Report *report,
Debug *debug,
Network *network);
LibertyLibrary *library() const { return library_; }
virtual bool save(LibertyGroup *) { return false; }
virtual bool save(LibertyAttr *) { return false; }
virtual bool save(LibertyVariable *) { return false; }
virtual void beginLibrary(LibertyGroup *group);
virtual void endLibrary(LibertyGroup *group);
virtual void endLibraryAttrs(LibertyGroup *group);
virtual void visitAttr(LibertyAttr *attr);
virtual void visitTimeUnit(LibertyAttr *attr);
virtual void visitCapacitiveLoadUnit(LibertyAttr *attr);
virtual void visitPullingResistanceUnit(LibertyAttr *attr);
virtual void visitVoltageUnit(LibertyAttr *attr);
virtual void visitCurrentUnit(LibertyAttr *attr);
virtual void visitPowerUnit(LibertyAttr *attr);
virtual void parseUnits(LibertyAttr *attr,
const char *suffix,
float &scale_var,
Unit *unit_suffix);
virtual void visitDelayModel(LibertyAttr *attr);
virtual void visitBusStyle(LibertyAttr *attr);
virtual void visitNomTemp(LibertyAttr *attr);
virtual void visitNomVolt(LibertyAttr *attr);
virtual void visitNomProc(LibertyAttr *attr);
virtual void visitDefaultInoutPinCap(LibertyAttr *attr);
virtual void visitDefaultInputPinCap(LibertyAttr *attr);
virtual void visitDefaultOutputPinCap(LibertyAttr *attr);
virtual void visitDefaultMaxTransition(LibertyAttr *attr);
virtual void visitDefaultMaxFanout(LibertyAttr *attr);
virtual void visitDefaultIntrinsicRise(LibertyAttr *attr);
virtual void visitDefaultIntrinsicFall(LibertyAttr *attr);
virtual void visitDefaultIntrinsic(LibertyAttr *attr,
TransRiseFall *tr);
virtual void visitDefaultInoutPinRiseRes(LibertyAttr *attr);
virtual void visitDefaultInoutPinFallRes(LibertyAttr *attr);
virtual void visitDefaultInoutPinRes(LibertyAttr *attr,
TransRiseFall *tr);
virtual void visitDefaultOutputPinRiseRes(LibertyAttr *attr);
virtual void visitDefaultOutputPinFallRes(LibertyAttr *attr);
virtual void visitDefaultOutputPinRes(LibertyAttr *attr,
TransRiseFall *tr);
virtual void visitDefaultFanoutLoad(LibertyAttr *attr);
virtual void visitDefaultWireLoad(LibertyAttr *attr);
virtual void visitDefaultWireLoadMode(LibertyAttr *attr);
virtual void visitDefaultWireLoadSelection(LibertyAttr *attr);
virtual void visitDefaultOperatingConditions(LibertyAttr *attr);
virtual void visitInputThresholdPctFall(LibertyAttr *attr);
virtual void visitInputThresholdPctRise(LibertyAttr *attr);
virtual void visitInputThresholdPct(LibertyAttr *attr,
TransRiseFall *tr);
virtual void visitOutputThresholdPctFall(LibertyAttr *attr);
virtual void visitOutputThresholdPctRise(LibertyAttr *attr);
virtual void visitOutputThresholdPct(LibertyAttr *attr,
TransRiseFall *tr);
virtual void visitSlewLowerThresholdPctFall(LibertyAttr *attr);
virtual void visitSlewLowerThresholdPctRise(LibertyAttr *attr);
virtual void visitSlewLowerThresholdPct(LibertyAttr *attr,
TransRiseFall *tr);
virtual void visitSlewUpperThresholdPctFall(LibertyAttr *attr);
virtual void visitSlewUpperThresholdPctRise(LibertyAttr *attr);
virtual void visitSlewUpperThresholdPct(LibertyAttr *attr,
TransRiseFall *tr);
virtual void visitSlewDerateFromLibrary(LibertyAttr *attr);
virtual void beginTableTemplate(LibertyGroup *group);
virtual void endTableTemplate(LibertyGroup *group);
virtual void visitVariable1(LibertyAttr *attr);
virtual void visitVariable2(LibertyAttr *attr);
virtual void visitVariable3(LibertyAttr *attr);
virtual void visitIndex1(LibertyAttr *attr);
virtual void visitIndex2(LibertyAttr *attr);
virtual void visitIndex3(LibertyAttr *attr);
virtual void beginType(LibertyGroup *group);
virtual void endType(LibertyGroup *group);
virtual void visitBitFrom(LibertyAttr *attr);
virtual void visitBitTo(LibertyAttr *attr);
virtual void beginCell(LibertyGroup *group);
virtual void endCell(LibertyGroup *group);
virtual void beginScaledCell(LibertyGroup *group);
virtual void endScaledCell(LibertyGroup *group);
virtual void checkScaledCell(LibertyGroup *group);
virtual void finishPortGroups();
virtual void checkPort(LibertyPort *port,
int line);
virtual void makeTimingArcs(PortGroup *port_group);
virtual void makeInternalPowers(PortGroup *port_group);
virtual void makeCellSequentials();
virtual void makeCellSequential(SequentialGroup *seq);
virtual void makeLeakagePowers();
virtual void parseCellFuncs();
virtual void makeLibertyFunc(const char *expr,
FuncExpr *&func_ref,
bool invert,
const char *attr_name,
LibertyStmt *stmt);
virtual void makeTimingArcs(LibertyPort *to_port,
TimingGroup *timing);
virtual void makeTimingArcs(const char *from_port_name,
PortNameBitIterator &from_port_iter,
LibertyPort *to_port,
LibertyPort *related_out_port,
TimingGroup *timing);
virtual void visitClockGatingIntegratedCell(LibertyAttr *attr);
virtual void visitArea(LibertyAttr *attr);
virtual void visitDontUse(LibertyAttr *attr);
void visitInterfaceTiming(LibertyAttr *attr);
virtual void visitScalingFactors(LibertyAttr *attr);
virtual void beginPin(LibertyGroup *group);
virtual void endPin(LibertyGroup *group);
virtual void beginBus(LibertyGroup *group);
virtual void endBus(LibertyGroup *group);
virtual void beginBundle(LibertyGroup *group);
virtual void endBundle(LibertyGroup *group);
virtual void beginBusOrBundle(LibertyGroup *group);
virtual void endBusOrBundle(LibertyGroup *group);
virtual void endPorts(LibertyGroup *group);
virtual void setPortCapDefault(LibertyPort *port);
virtual void setPortDefaults(LibertyPort *port);
virtual void visitMembers(LibertyAttr *attr);
virtual void visitDirection(LibertyAttr *attr);
virtual void visitFunction(LibertyAttr *attr);
virtual void visitThreeState(LibertyAttr *attr);
virtual void visitBusType(LibertyAttr *attr);
virtual void visitCapacitance(LibertyAttr *attr);
virtual void visitRiseCap(LibertyAttr *attr);
virtual void visitFallCap(LibertyAttr *attr);
virtual void visitRiseCapRange(LibertyAttr *attr);
virtual void visitFallCapRange(LibertyAttr *attr);
virtual void visitMaxFanout(LibertyAttr *attr);
virtual void visitMinFanout(LibertyAttr *attr);
virtual void visitFanout(LibertyAttr *attr,
MinMax *min_max);
virtual void visitMaxTransition(LibertyAttr *attr);
virtual void visitMinTransition(LibertyAttr *attr);
virtual void visitMinMaxTransition(LibertyAttr *attr,
MinMax *min_max);
virtual void visitMaxCapacitance(LibertyAttr *attr);
virtual void visitMinCapacitance(LibertyAttr *attr);
virtual void visitMinMaxCapacitance(LibertyAttr *attr,
MinMax *min_max);
virtual void visitMinPeriod(LibertyAttr *attr);
virtual void visitMinPulseWidthLow(LibertyAttr *attr);
virtual void visitMinPulseWidthHigh(LibertyAttr *attr);
virtual void visitMinPulseWidth(LibertyAttr *attr,
TransRiseFall *tr);
virtual void visitPulseClock(LibertyAttr *attr);
virtual void visitClockGateClockPin(LibertyAttr *attr);
virtual void visitClockGateEnablePin(LibertyAttr *attr);
virtual void visitClockGateOutPin(LibertyAttr *attr);
void visitIsPllFeedbackPin(LibertyAttr *attr);
virtual void visitSignalType(LibertyAttr *attr);
virtual void visitClock(LibertyAttr *attr);
virtual void beginScalingFactors(LibertyGroup *group);
virtual void endScalingFactors(LibertyGroup *group);
virtual void defineScalingFactorVisitors();
virtual void visitScaleFactorSuffix(LibertyAttr *attr);
virtual void visitScaleFactorPrefix(LibertyAttr *attr);
virtual void visitScaleFactorHiLow(LibertyAttr *attr);
virtual void visitScaleFactor(LibertyAttr *attr);
virtual void beginOpCond(LibertyGroup *group);
virtual void endOpCond(LibertyGroup *group);
virtual void visitProc(LibertyAttr *attr);
virtual void visitVolt(LibertyAttr *attr);
virtual void visitTemp(LibertyAttr *attr);
virtual void visitTreeType(LibertyAttr *attr);
virtual void beginWireload(LibertyGroup *group);
virtual void endWireload(LibertyGroup *group);
virtual void visitResistance(LibertyAttr *attr);
virtual void visitSlope(LibertyAttr *attr);
virtual void visitFanoutLength(LibertyAttr *attr);
virtual void beginWireloadSelection(LibertyGroup *group);
virtual void endWireloadSelection(LibertyGroup *group);
virtual void visitWireloadFromArea(LibertyAttr *attr);
virtual void beginFF(LibertyGroup *group);
virtual void endFF(LibertyGroup *group);
virtual void beginFFBank(LibertyGroup *group);
virtual void endFFBank(LibertyGroup *group);
virtual void beginLatch(LibertyGroup *group);
virtual void endLatch(LibertyGroup *group);
virtual void beginLatchBank(LibertyGroup *group);
virtual void endLatchBank(LibertyGroup *group);
virtual void beginSequential(LibertyGroup *group,
bool is_register,
bool is_bank);
virtual void seqPortNames(LibertyGroup *group,
const char *&out_name,
const char *&out_inv_name,
bool &has_size,
int &size);
virtual void checkLatchEnableSense(FuncExpr *enable_func,
int line);
virtual void visitClockedOn(LibertyAttr *attr);
virtual void visitDataIn(LibertyAttr *attr);
virtual void visitClear(LibertyAttr *attr);
virtual void visitPreset(LibertyAttr *attr);
virtual void visitClrPresetVar1(LibertyAttr *attr);
virtual void visitClrPresetVar2(LibertyAttr *attr);
virtual void beginTiming(LibertyGroup *group);
virtual void endTiming(LibertyGroup *group);
virtual TimingGroup *makeTimingGroup(int line);
virtual void visitRelatedPin(LibertyAttr *attr);
virtual void visitRelatedPin(LibertyAttr *attr,
RelatedPortGroup *group);
virtual void visitRelatedBusPins(LibertyAttr *attr);
virtual void visitRelatedBusPins(LibertyAttr *attr,
RelatedPortGroup *group);
virtual void visitRelatedOutputPin(LibertyAttr *attr);
virtual void visitTimingType(LibertyAttr *attr);
virtual void visitTimingSense(LibertyAttr *attr);
virtual void visitSdfCondStart(LibertyAttr *attr);
virtual void visitSdfCondEnd(LibertyAttr *attr);
virtual void visitMode(LibertyAttr *attr);
virtual void visitIntrinsicRise(LibertyAttr *attr);
virtual void visitIntrinsicFall(LibertyAttr *attr);
virtual void visitIntrinsic(LibertyAttr *attr,
TransRiseFall *tr);
virtual void visitRiseResistance(LibertyAttr *attr);
virtual void visitFallResistance(LibertyAttr *attr);
virtual void visitRiseFallResistance(LibertyAttr *attr,
TransRiseFall *tr);
virtual void visitValue(LibertyAttr *attr);
virtual void visitValues(LibertyAttr *attr);
virtual void beginCellRise(LibertyGroup *group);
virtual void beginCellFall(LibertyGroup *group);
virtual void endCellRiseFall(LibertyGroup *group);
virtual void beginRiseTransition(LibertyGroup *group);
virtual void endRiseFallTransition(LibertyGroup *group);
virtual void beginFallTransition(LibertyGroup *group);
virtual void beginRiseConstraint(LibertyGroup *group);
virtual void endRiseFallConstraint(LibertyGroup *group);
virtual void beginFallConstraint(LibertyGroup *group);
virtual void beginRiseTransitionDegredation(LibertyGroup *group);
virtual void beginFallTransitionDegredation(LibertyGroup *group);
virtual void endRiseFallTransitionDegredation(LibertyGroup *group);
virtual void beginTableModel(LibertyGroup *group,
TransRiseFall *tr,
float scale,
ScaleFactorType scale_factor_type);
virtual void endTableModel();
virtual void beginTimingTableModel(LibertyGroup *group,
TransRiseFall *tr,
ScaleFactorType scale_factor_type);
virtual void beginTable(LibertyGroup *group,
float scale);
virtual void endTable();
virtual void makeTable(LibertyAttr *attr,
float scale);
virtual FloatTable *makeFloatTable(LibertyAttr *attr,
size_t rows,
size_t cols,
float scale);
virtual void beginLut(LibertyGroup *group);
virtual void endLut(LibertyGroup *group);
virtual void beginTestCell(LibertyGroup *group);
virtual void endTestCell(LibertyGroup *group);
virtual void beginModeDef(LibertyGroup *group);
virtual void endModeDef(LibertyGroup *group);
virtual void beginModeValue(LibertyGroup *group);
virtual void endModeValue(LibertyGroup *group);
virtual void visitWhen(LibertyAttr *attr);
virtual void visitSdfCond(LibertyAttr *attr);
// Power attributes.
virtual void beginLeakagePower(LibertyGroup *group);
virtual void endLeakagePower(LibertyGroup *group);
virtual void beginInternalPower(LibertyGroup *group);
virtual void endInternalPower(LibertyGroup *group);
virtual InternalPowerGroup *makeInternalPowerGroup(int line);
virtual void beginFallPower(LibertyGroup *group);
virtual void beginRisePower(LibertyGroup *group);
virtual void endRiseFallPower(LibertyGroup *group);
virtual void makeInternalPowers(LibertyPort *port,
InternalPowerGroup *power_group);
virtual void makeInternalPowers(LibertyPort *port,
const char *related_port_name,
PortNameBitIterator &related_port_iter,
InternalPowerGroup *power_group);
// AOCV attributes.
virtual void visitOcvArcDepth(LibertyAttr *attr);
virtual void visitDefaultOcvDerateGroup(LibertyAttr *attr);
virtual void visitOcvDerateGroup(LibertyAttr *attr);
virtual void beginOcvDerate(LibertyGroup *group);
virtual void endOcvDerate(LibertyGroup *group);
virtual void beginOcvDerateFactors(LibertyGroup *group);
virtual void endOcvDerateFactors(LibertyGroup *group);
virtual void visitRfType(LibertyAttr *attr);
virtual void visitDerateType(LibertyAttr *attr);
virtual void visitPathType(LibertyAttr *attr);
// Visitors for derived classes to overload.
virtual void beginGroup1(LibertyGroup *) {}
virtual void beginGroup2(LibertyGroup *) {}
virtual void beginGroup3(LibertyGroup *) {}
virtual void beginGroup4(LibertyGroup *) {}
virtual void beginGroup5(LibertyGroup *) {}
virtual void endGroup1(LibertyGroup *) {}
virtual void endGroup2(LibertyGroup *) {}
virtual void endGroup3(LibertyGroup *) {}
virtual void endGroup4(LibertyGroup *) {}
virtual void endGroup5(LibertyGroup *) {}
virtual void visitAttr1(LibertyAttr *) {}
virtual void visitAttr2(LibertyAttr *) {}
virtual void visitAttr3(LibertyAttr *) {}
virtual void visitAttr4(LibertyAttr *) {}
virtual void visitAttr5(LibertyAttr *) {}
virtual void visitAttr6(LibertyAttr *) {}
virtual void visitAttr7(LibertyAttr *) {}
virtual void visitAttr8(LibertyAttr *) {}
virtual void visitAttr9(LibertyAttr *) {}
protected:
void defineVisitors();
virtual void begin(LibertyGroup *group);
virtual void end(LibertyGroup *group);
void defineGroupVisitor(const char *type,
LibraryGroupVisitor begin_visitor,
LibraryGroupVisitor end_visitor);
void defineAttrVisitor(const char *attr_name,
LibraryAttrVisitor visitor);
void parseNames(const char *name_str);
void clearAxisValues();
void makeTableAxis(int index);
StringSeq *parseNameList(const char *name_list);
LibertyPort *findPort(const char *port_name);
LibertyPort *findPort(LibertyCell *cell,
const char *port_name);
float defaultCap(LibertyPort *port);
virtual void visitVariable(LibertyVariable *var);
const char *getAttrString(LibertyAttr *attr);
void getAttrInt(LibertyAttr *attr,
// Return values.
int &value,
bool &exists);
void getAttrFloat(LibertyAttr *attr,
// Return values.
float &value,
bool &valid);
void getAttrFloat2(LibertyAttr *attr,
// Return values.
float &value1,
float &value2,
bool &exists);
void parseStringFloatList(const char *float_list,
float scale,
FloatSeq *values,
LibertyAttr *attr);
LogicValue getAttrLogicValue(LibertyAttr *attr);
void getAttrBool(LibertyAttr *attr,
// Return values.
bool &value,
bool &exists);
void visitVariable(int index,
LibertyAttr *attr);
void visitIndex(int index,
LibertyAttr *attr);
void makeAxis(int index,
LibertyGroup *group,
TableAxis *&axis);
FloatSeq *readFloatSeq(LibertyAttr *attr,
float scale);
void variableValue(const char *var,
float &value,
bool &exists);
FuncExpr *parseFunc(const char *func,
const char *attr_name,
int line);
void libWarn(LibertyStmt *stmt,
const char *fmt,
...)
__attribute__((format (printf, 3, 4)));
void libWarn(int line,
const char *fmt,
...)
__attribute__((format (printf, 3, 4)));
void libError(LibertyStmt *stmt,
const char *fmt, ...)
__attribute__((format (printf, 3, 4)));
const char *filename_;
bool infer_latches_;
Report *report_;
Debug *debug_;
Network *network_;
LibertyBuilder *builder_;
LibertyVariableMap *var_map_;
LibertyLibrary *library_;
LibraryGroupMap group_begin_map_;
LibraryGroupMap group_end_map_;
LibraryAttrMap attr_visitor_map_;
Wireload *wireload_;
WireloadSelection *wireload_selection_;
const char *default_wireload_;
const char *default_wireload_selection_;
ScaleFactors *scale_factors_;
ScaleFactors *save_scale_factors_;
bool have_input_threshold_[TransRiseFall::index_count];
bool have_output_threshold_[TransRiseFall::index_count];
bool have_slew_lower_threshold_[TransRiseFall::index_count];
bool have_slew_upper_threshold_[TransRiseFall::index_count];
TableTemplate *tbl_template_;
LibertyCell *cell_;
LibertyCell *save_cell_;
LibertyCell *scaled_cell_owner_;
TestCell *test_cell_;
const char *ocv_derate_name_;
PortGroupSeq cell_port_groups_;
OperatingConditions *op_cond_;
LibertyPortSeq *ports_;
LibertyPort *port_; // Used by test_cell.
PortGroup *port_group_;
LibertyPortSeq *saved_ports_;
PortGroup *saved_port_group_;
StringSeq bus_names_;
bool in_bus_;
bool in_bundle_;
TableAxisVariable axis_var_[3];
FloatSeq *axis_values_[3];
int type_bit_from_;
bool type_bit_from_exists_;
int type_bit_to_;
bool type_bit_to_exists_;
SequentialGroup *sequential_;
SequentialGroupSeq cell_sequentials_;
TimingGroup *timing_;
InternalPowerGroup *internal_power_;
LeakagePowerGroup *leakage_power_;
LeakagePowerGroupSeq leakage_powers_;
TransRiseFall *tr_;
OcvDerate *ocv_derate_;
TransRiseFallBoth *rf_type_;
EarlyLateAll *early_late_;
PathType path_type_;
ScaleFactorType scale_factor_type_;
TableAxis *axis_[3];
bool own_axis_[3];
Table *table_;
float table_model_scale_;
ModeDef *mode_def_;
ModeValueDef *mode_value_;
LibertyFuncSeq cell_funcs_;
float time_scale_;
float cap_scale_;
float res_scale_;
float volt_scale_;
float curr_scale_;
float power_scale_;
private:
DISALLOW_COPY_AND_ASSIGN(LibertyReader);
friend class PortNameBitIterator;
friend class TimingGroup;
};
// Reference to a function that will be parsed at the end of the cell
// definition when all of the ports are defined.
class LibertyFunc
{
public:
LibertyFunc(const char *expr,
FuncExpr *&func_ref,
bool invert,
const char *attr_name,
int line);
~LibertyFunc();
const char *expr() const { return expr_; }
FuncExpr *&funcRef() const { return func_ref_; }
bool invert() const { return invert_; }
const char *attrName() const { return attr_name_; }
int line() const { return line_; }
protected:
const char *expr_;
FuncExpr *&func_ref_;
bool invert_;
const char *attr_name_;
int line_;
private:
DISALLOW_COPY_AND_ASSIGN(LibertyFunc);
};
// Port attributes that refer to other ports cannot be parsed
// until all of the ports are defined. This class saves them
// so they can be parsed at the end of the cell.
class PortGroup
{
public:
PortGroup(LibertyPortSeq *ports,
int line);
~PortGroup();
LibertyPortSeq *ports() const { return ports_; }
TimingGroupSeq *timingGroups() { return &timings_; }
void addTimingGroup(TimingGroup *timing);
InternalPowerGroupSeq *internalPowerGroups() { return &internal_power_groups_; }
void addInternalPowerGroup(InternalPowerGroup *internal_power);
int line() const { return line_; }
private:
DISALLOW_COPY_AND_ASSIGN(PortGroup);
LibertyPortSeq *ports_;
TimingGroupSeq timings_;
InternalPowerGroupSeq internal_power_groups_;
int line_;
};
class SequentialGroup
{
public:
SequentialGroup(bool is_register,
bool is_bank,
LibertyPort *out_port,
LibertyPort *out_inv_port,
int size,
int line);
~SequentialGroup();
LibertyPort *outPort() const { return out_port_; }
LibertyPort *outInvPort() const { return out_inv_port_; }
int size() const { return size_; }
bool isRegister() const { return is_register_; }
bool isBank() const { return is_bank_; }
const char *clock() const { return clk_; }
void setClock(const char *clk);
const char *data() const { return data_; }
void setData(const char *data);
const char *clear() const { return clear_; }
void setClear(const char *clr);
const char *preset() const { return preset_; }
void setPreset(const char *preset);
LogicValue clrPresetVar1() const { return clr_preset_var1_; }
void setClrPresetVar1(LogicValue var);
LogicValue clrPresetVar2() const { return clr_preset_var2_; }
void setClrPresetVar2(LogicValue var);
int line() const { return line_; }
protected:
bool is_register_;
bool is_bank_;
LibertyPort *out_port_;
LibertyPort *out_inv_port_;
int size_;
const char *clk_;
const char *data_;
const char *preset_;
const char *clear_;
LogicValue clr_preset_var1_;
LogicValue clr_preset_var2_;
int line_;
private:
DISALLOW_COPY_AND_ASSIGN(SequentialGroup);
};
// Liberty group with related_pins group attribute.
class RelatedPortGroup
{
public:
explicit RelatedPortGroup(int line);
virtual ~RelatedPortGroup();
int line() const { return line_; }
StringSeq *relatedPortNames() const { return related_port_names_; }
void setRelatedPortNames(StringSeq *names);
bool isOneToOne() const { return is_one_to_one_; }
void setIsOneToOne(bool one);
protected:
StringSeq *related_port_names_;
bool is_one_to_one_;
int line_;
private:
DISALLOW_COPY_AND_ASSIGN(RelatedPortGroup);
};
class TimingGroup : public TimingArcAttrs, public RelatedPortGroup
{
public:
explicit TimingGroup(int line);
virtual ~TimingGroup();
const char *relatedOutputPortName()const {return related_output_port_name_;}
void setRelatedOutputPortName(const char *name);
void intrinsic(TransRiseFall *tr,
// Return values.
float &value,
bool &exists);
void setIntrinsic(TransRiseFall *tr,
float value);
void resistance(TransRiseFall *tr,
// Return values.
float &value,
bool &exists);
void setResistance(TransRiseFall *tr,
float value);
TableModel *cell(TransRiseFall *tr);
void setCell(TransRiseFall *tr,
TableModel *model);
TableModel *constraint(TransRiseFall *tr);
void setConstraint(TransRiseFall *tr,
TableModel *model);
TableModel *transition(TransRiseFall *tr);
void setTransition(TransRiseFall *tr,
TableModel *model);
void makeTimingModels(LibertyLibrary *library,
LibertyReader *visitor);
protected:
void makeLinearModels(LibertyLibrary *library);
void makeTableModels(LibertyReader *visitor);
const char *related_output_port_name_;
float intrinsic_[TransRiseFall::index_count];
bool intrinsic_exists_[TransRiseFall::index_count];
float resistance_[TransRiseFall::index_count];
bool resistance_exists_[TransRiseFall::index_count];
TableModel *cell_[TransRiseFall::index_count];
TableModel *constraint_[TransRiseFall::index_count];
TableModel *transition_[TransRiseFall::index_count];
private:
DISALLOW_COPY_AND_ASSIGN(TimingGroup);
};
class InternalPowerGroup : public InternalPowerAttrs, public RelatedPortGroup
{
public:
explicit InternalPowerGroup(int line);
virtual ~InternalPowerGroup();
protected:
private:
DISALLOW_COPY_AND_ASSIGN(InternalPowerGroup);
};
class LeakagePowerGroup : public LeakagePowerAttrs
{
public:
explicit LeakagePowerGroup(int line);
virtual ~LeakagePowerGroup();
protected:
int line_;
private:
DISALLOW_COPY_AND_ASSIGN(LeakagePowerGroup);
};
// Named port iterator. Port name can be:
// Single bit port name - iterates over port.
// Bus port name - iterates over bus bit ports.
// Bus range - iterates over bus bit ports.
class PortNameBitIterator : public Iterator<LibertyPort*>
{
public:
PortNameBitIterator(LibertyCell *cell,
const char *port_name,
LibertyReader *visitor,
int line);
~PortNameBitIterator();
virtual bool hasNext();
virtual LibertyPort *next();
unsigned size() const { return size_; }
protected:
void findRangeBusNameNext();
void init(const char *port_name);
LibertyCell *cell_;
LibertyReader *visitor_;
int line_;
LibertyPort *port_;
LibertyPortMemberIterator *bit_iterator_;
LibertyPort *range_bus_port_;
const char *range_bus_name_;
LibertyPort *range_name_next_;
int range_from_;
int range_to_;
int range_bit_;
unsigned size_;
private:
DISALLOW_COPY_AND_ASSIGN(PortNameBitIterator);
};
} // namespace
#endif

119
liberty/LinearModel.cc Normal file
View File

@ -0,0 +1,119 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 "Units.hh"
#include "Liberty.hh"
#include "LinearModel.hh"
namespace sta {
GateLinearModel::GateLinearModel(float intrinsic,
float resistance) :
intrinsic_(intrinsic),
resistance_(resistance)
{
}
void
GateLinearModel::gateDelay(const LibertyCell *,
const Pvt *,
float,
float load_cap,
float,
// return values
float &gate_delay,
float &drvr_slew) const
{
gate_delay = intrinsic_ + resistance_ * load_cap;
drvr_slew = 0.0;
}
void
GateLinearModel::reportGateDelay(const LibertyCell *cell,
const Pvt *,
float,
float load_cap,
float,
int digits,
string *result) const
{
const LibertyLibrary *library = cell->libertyLibrary();
const Units *units = library->units();
const Unit *time_unit = units->timeUnit();
const Unit *res_unit = units->resistanceUnit();
const Unit *cap_unit = units->capacitanceUnit();
*result += "Delay = ";
*result += time_unit->asString(intrinsic_, digits);
*result += " + ";
*result += res_unit->asString(resistance_, digits);
*result += " * ";
*result += cap_unit->asString(load_cap, digits);
*result += " = ";
float delay = intrinsic_ + resistance_ * load_cap;
*result += time_unit->asString(delay, digits);
}
float
GateLinearModel::driveResistance(const LibertyCell *,
const Pvt *) const
{
return resistance_;
}
void
GateLinearModel::setIsScaled(bool)
{
}
CheckLinearModel::CheckLinearModel(float intrinsic) :
intrinsic_(intrinsic)
{
}
float
CheckLinearModel::checkDelay(const LibertyCell *,
const Pvt *,
float,
float,
float) const
{
return intrinsic_;
}
void
CheckLinearModel::reportCheckDelay(const LibertyCell *cell,
const Pvt *,
float,
const char *,
float,
float,
int digits,
string *result) const
{
const LibertyLibrary *library = cell->libertyLibrary();
const Units *units = library->units();
const Unit *time_unit = units->timeUnit();
*result += "Check = ";
*result += time_unit->asString(intrinsic_, digits);
}
void
CheckLinearModel::setIsScaled(bool)
{
}
} // namespace

81
liberty/LinearModel.hh Normal file
View File

@ -0,0 +1,81 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_LINEAR_MODEL_H
#define STA_LINEAR_MODEL_H
#include "DisallowCopyAssign.hh"
#include "TimingModel.hh"
namespace sta {
class GateLinearModel : public GateTimingModel
{
public:
GateLinearModel(float intrinsic, float resistance);
// gate delay calculation
virtual void gateDelay(const LibertyCell *cell,
const Pvt *pvt,
float load_cap, float in_slew,
float related_out_cap,
// return values
float &gate_delay, float &drvr_slew) const;
virtual void reportGateDelay(const LibertyCell *cell,
const Pvt *pvt,
float load_cap, float in_slew,
float related_out_cap,
int digits, string *result) const;
virtual float driveResistance(const LibertyCell *cell,
const Pvt *pvt) const;
protected:
virtual void setIsScaled(bool is_scaled);
float intrinsic_;
float resistance_;
private:
DISALLOW_COPY_AND_ASSIGN(GateLinearModel);
};
class CheckLinearModel : public CheckTimingModel
{
public:
explicit CheckLinearModel(float intrinsic);
// Timing check margin delay calculation.
virtual float checkDelay(const LibertyCell *cell,
const Pvt *pvt,
float from_slew, float to_slew,
float related_out_cap) const;
virtual void reportCheckDelay(const LibertyCell *cell,
const Pvt *pvt,
float from_slew,
const char *from_slew_annotation,
float to_slew,
float related_out_cap,
int digits, string *result) const;
protected:
virtual void setIsScaled(bool is_scaled);
float intrinsic_;
private:
DISALLOW_COPY_AND_ASSIGN(CheckLinearModel);
};
} // namespace
#endif

97
liberty/Makefile.am Normal file
View File

@ -0,0 +1,97 @@
# OpenSTA, Static Timing Analyzer
# Copyright (c) 2018, 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/>.
lib_LTLIBRARIES = libliberty.la
include_HEADERS = \
EquivCells.hh \
FuncExpr.hh \
InternalPower.hh \
LeakagePower.hh \
Liberty.hh \
LibertyBuilder.hh \
LibertyClass.hh \
LibertyParser.hh \
LibertyReader.hh \
LibertyReaderPvt.hh \
LinearModel.hh \
Sequential.hh \
TableModel.hh \
TimingArc.hh \
TimingModel.hh \
TimingRole.hh \
Transition.hh \
Units.hh \
Wireload.hh
libliberty_la_SOURCES = \
EquivCells.cc \
FuncExpr.cc \
InternalPower.cc \
LeakagePower.cc \
Liberty.cc \
LibertyBuilder.cc \
LibertyExpr.cc \
LibertyExpr.hh \
LibertyExprLex.ll \
LibertyExprParse.yy \
LibertyExprPvt.hh \
LibertyLex.ll \
LibertyParse.yy \
LibertyParser.cc \
LibertyReader.cc \
LinearModel.cc \
Sequential.cc \
TableModel.cc \
TimingArc.cc \
TimingRole.cc \
Transition.cc \
Units.cc \
Wireload.cc
LibertyExprLex.ll: LibertyExprParse.hh
LibertyLex.ll: LibertyParse.hh
# Rules to support automake pre 1.12 that name header .h instead of .hh
LibertyExprParse.hh: LibertyExprParse.cc
if test -f LibertyExprParse.h; then \
cp LibertyExprParse.h LibertyExprParse.hh; \
fi
LibertyParse.hh: LibertyParse.cc
if test -f LibertyParse.h; then \
cp LibertyParse.h LibertyParse.hh; \
fi
EXTRA_DIST = \
LibertyExt.cc \
LibertyParse.hh \
LibertyExprParse.hh
MAINTAINERCLEANFILES = \
LibertyLex.cc \
LibertyParse.hh \
LibertyParse.cc \
LibertyExprLex.cc \
LibertyExprParse.hh \
LibertyExprParse.cc
libs: $(lib_LTLIBRARIES)
xtags: $(SOURCES) $(HEADERS)
etags -a -o ../TAGS $(SOURCES) $(HEADERS)

56
liberty/Sequential.cc Normal file
View File

@ -0,0 +1,56 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 "FuncExpr.hh"
#include "Sequential.hh"
namespace sta {
Sequential::Sequential(bool is_register,
FuncExpr *clock,
FuncExpr *data,
FuncExpr *clear,
FuncExpr *preset,
LogicValue clr_preset_out,
LogicValue clr_preset_out_inv,
LibertyPort *output,
LibertyPort *output_inv) :
is_register_(is_register),
clock_(clock),
data_(data),
clear_(clear),
preset_(preset),
clr_preset_out_(clr_preset_out),
clr_preset_out_inv_(clr_preset_out_inv),
output_(output),
output_inv_(output_inv)
{
}
Sequential::~Sequential()
{
if (clock_)
clock_->deleteSubexprs();
if (data_)
data_->deleteSubexprs();
if (clear_)
clear_->deleteSubexprs();
if (preset_)
preset_->deleteSubexprs();
}
} // namespace

75
liberty/Sequential.hh Normal file
View File

@ -0,0 +1,75 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_SEQUENTIAL_H
#define STA_SEQUENTIAL_H
#include "DisallowCopyAssign.hh"
#include "NetworkClass.hh"
#include "LibertyClass.hh"
namespace sta {
// Register/Latch
class Sequential
{
public:
~Sequential();
bool isLatch() const { return !is_register_; }
bool isRegister() const { return is_register_; }
FuncExpr *clock() const { return clock_; }
FuncExpr *data() const { return data_; }
FuncExpr *clear() const { return clear_; }
FuncExpr *preset() const { return preset_; }
// State of output when clear and preset are both true.
LogicValue clearPresetOutput() const { return clr_preset_out_; }
// State of outputInv when clear and preset are both true.
LogicValue clearPresetOutputInv() const {return clr_preset_out_inv_;}
LibertyPort *output() const { return output_; }
LibertyPort *outputInv() const { return output_inv_; }
protected:
// clock/data are:
// clocked_on/next_state for registers
// enable/data for latches
Sequential(bool is_register,
FuncExpr *clock,
FuncExpr *data,
FuncExpr *clear,
FuncExpr *preset,
LogicValue clr_preset_out,
LogicValue clr_preset_out_inv,
LibertyPort *output,
LibertyPort *output_inv);
bool is_register_;
FuncExpr *clock_;
FuncExpr *data_;
FuncExpr *clear_;
FuncExpr *preset_;
LogicValue clr_preset_out_;
LogicValue clr_preset_out_inv_;
LibertyPort *output_;
LibertyPort *output_inv_;
private:
DISALLOW_COPY_AND_ASSIGN(Sequential);
friend class LibertyCell;
};
} // namespace
#endif

1322
liberty/TableModel.cc Normal file

File diff suppressed because it is too large Load Diff

434
liberty/TableModel.hh Normal file
View File

@ -0,0 +1,434 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_TABLE_MODEL_H
#define STA_TABLE_MODEL_H
#include <string>
#include "DisallowCopyAssign.hh"
#include "Vector.hh"
#include "Transition.hh"
#include "LibertyClass.hh"
#include "TimingModel.hh"
namespace sta {
using std::string;
class Unit;
class Units;
class Report;
class Table;
TableAxisVariable
stringTableAxisVariable(const char *variable);
const char *
tableVariableString(TableAxisVariable variable);
const Unit *
tableVariableUnit(TableAxisVariable variable,
const Units *units);
class GateTableModel : public GateTimingModel
{
public:
GateTableModel(TableModel *delay_model,
TableModel *slew_model);
virtual ~GateTableModel();
virtual void gateDelay(const LibertyCell *cell,
const Pvt *pvt,
float in_slew,
float load_cap,
float related_out_cap,
// return values
float &gate_delay,
float &drvr_slew) const;
float gateDelay(const LibertyCell *cell,
const Pvt *pvt,
float in_slew,
float load_cap,
float related_out_cap) const;
virtual void reportGateDelay(const LibertyCell *cell,
const Pvt *pvt,
float in_slew,
float load_cap,
float related_out_cap,
int digits,
string *result) const;
virtual float driveResistance(const LibertyCell *cell,
const Pvt *pvt) const;
const TableModel *delayModel() const { return delay_model_; }
const TableModel *slewModel() const { return slew_model_; }
// Check the axes before making the model.
// Return true if the model axes are supported.
static bool checkAxes(const Table *table);
protected:
void maxCapSlew(const LibertyCell *cell,
float in_slew,
const Pvt *pvt,
float &slew,
float &cap) const;
virtual void setIsScaled(bool is_scaled);
float axisValue(TableAxis *axis,
float load_cap,
float in_slew,
float related_out_cap) const;
float findValue(const LibertyLibrary *library,
const LibertyCell *cell,
const Pvt *pvt,
const TableModel *model,
float in_slew,
float load_cap,
float related_out_cap) const;
void reportTableLookup(const char *result_name,
const LibertyLibrary *library,
const LibertyCell *cell,
const Pvt *pvt,
const TableModel *model,
float in_slew,
float load_cap,
float related_out_cap,
int digits,
string *result) const;
void findAxisValues(const TableModel *model,
float in_slew,
float load_cap,
float related_out_cap,
// Return values.
float &axis_value1,
float &axis_value2,
float &axis_value3) const;
static bool checkAxis(TableAxis *axis);
TableModel *delay_model_;
TableModel *slew_model_;
private:
DISALLOW_COPY_AND_ASSIGN(GateTableModel);
};
class CheckTableModel : public CheckTimingModel
{
public:
explicit CheckTableModel(TableModel *model);
virtual ~CheckTableModel();
virtual float checkDelay(const LibertyCell *cell,
const Pvt *pvt,
float from_slew,
float to_slew,
float related_out_cap) const;
virtual void reportCheckDelay(const LibertyCell *cell,
const Pvt *pvt,
float from_slew,
const char *from_slew_annotation,
float to_slew,
float related_out_cap,
int digits,
string *result) const;
// Check the axes before making the model.
// Return true if the model axes are supported.
static bool checkAxes(const Table *table);
protected:
virtual void setIsScaled(bool is_scaled);
void findAxisValues(float from_slew,
float to_slew,
float related_out_cap,
// Return values.
float &axis_value1,
float &axis_value2,
float &axis_value3) const;
float axisValue(TableAxis *axis,
float load_cap,
float in_slew,
float related_out_cap) const;
static bool checkAxis(TableAxis *axis);
TableModel *model_;
private:
DISALLOW_COPY_AND_ASSIGN(CheckTableModel);
};
// Wrapper class for Table to apply scale factors.
class TableModel
{
public:
TableModel(Table *table,
ScaleFactorType scale_factor_type,
TransRiseFall *tr);
~TableModel();
void setScaleFactorType(ScaleFactorType type);
int order() const;
TableAxis *axis1() const;
TableAxis *axis2() const;
TableAxis *axis3() const;
void setIsScaled(bool is_scaled);
// Table interpolated lookup.
float findValue(float value1,
float value2,
float value3) const;
// Table interpolated lookup with scale factor.
float findValue(const LibertyLibrary *library,
const LibertyCell *cell,
const Pvt *pvt,
float value1,
float value2,
float value3) const;
void reportValue(const char *result_name,
const LibertyLibrary *library,
const LibertyCell *cell,
const Pvt *pvt,
float value1,
const char *comment1,
float value2,
float value3,
int digits,
string *result) const;
void report(const Units *units,
Report *report) const;
protected:
float scaleFactor(const LibertyLibrary *library,
const LibertyCell *cell,
const Pvt *pvt) const;
void reportPvtScaleFactor(const LibertyLibrary *library,
const LibertyCell *cell,
const Pvt *pvt,
int digits,
string *result) const;
Table *table_;
unsigned int scale_factor_type_:scale_factor_bits;
unsigned int tr_index_:TransRiseFall::index_bit_count;
bool is_scaled_:1;
private:
DISALLOW_COPY_AND_ASSIGN(TableModel);
};
// Abstract base class for tables.
class Table
{
public:
Table() {}
virtual ~Table() {}
void setScaleFactorType(ScaleFactorType type);
virtual int order() const = 0;
virtual TableAxis *axis1() const { return NULL; }
virtual TableAxis *axis2() const { return NULL; }
virtual TableAxis *axis3() const { return NULL; }
void setIsScaled(bool is_scaled);
// Table interpolated lookup.
virtual float findValue(float value1,
float value2,
float value3) const = 0;
// Table interpolated lookup with scale factor.
float findValue(const LibertyLibrary *library,
const LibertyCell *cell,
const Pvt *pvt,
float value1,
float value2,
float value3) const;
virtual void reportValue(const char *result_name,
const LibertyLibrary *library,
const LibertyCell *cell,
const Pvt *pvt,
float value1,
const char *comment1,
float value2,
float value3,
int digits,
string *result) const = 0;
virtual void report(const Units *units,
Report *report) const = 0;
private:
DISALLOW_COPY_AND_ASSIGN(Table);
};
// Zero dimension (scalar) table.
class Table0 : public Table
{
public:
Table0(float value);
virtual int order() const { return 0; }
virtual float findValue(float value1,
float value2,
float value3) const;
virtual void reportValue(const char *result_name,
const LibertyLibrary *library,
const LibertyCell *cell,
const Pvt *pvt,
float value1,
const char *comment1,
float value2,
float value3,
int digits,
string *result) const;
virtual void report(const Units *units,
Report *report) const;
using Table::findValue;
private:
DISALLOW_COPY_AND_ASSIGN(Table0);
float value_;
};
// One dimensional table.
class Table1 : public Table
{
public:
Table1(FloatSeq *values,
TableAxis *axis1,
bool own_axis1);
virtual ~Table1();
virtual int order() const { return 1; }
virtual TableAxis *axis1() const { return axis1_; }
float tableValue(size_t index1) const;
virtual float findValue(float value1,
float value2,
float value3) const;
virtual void reportValue(const char *result_name,
const LibertyLibrary *library,
const LibertyCell *cell,
const Pvt *pvt,
float value1,
const char *comment1,
float value2,
float value3,
int digits,
string *result) const;
virtual void report(const Units *units,
Report *report) const;
using Table::findValue;
private:
DISALLOW_COPY_AND_ASSIGN(Table1);
FloatSeq *values_;
TableAxis *axis1_;
bool own_axis1_;
};
// Two dimensional table.
class Table2 : public Table
{
public:
Table2(FloatTable *values,
TableAxis *axis1,
bool own_axis1,
TableAxis *axis2,
bool own_axis2);
virtual ~Table2();
virtual int order() const { return 2; }
TableAxis *axis1() const { return axis1_; }
TableAxis *axis2() const { return axis2_; }
float tableValue(size_t index1,
size_t index2) const;
virtual float findValue(float value1,
float value2,
float value3) const;
virtual void reportValue(const char *result_name,
const LibertyLibrary *library,
const LibertyCell *cell,
const Pvt *pvt,
float value1,
const char *comment1,
float value2,
float value3,
int digits,
string *result) const;
virtual void report(const Units *units,
Report *report) const;
using Table::findValue;
protected:
DISALLOW_COPY_AND_ASSIGN(Table2);
FloatTable *values_;
// Row.
TableAxis *axis1_;
bool own_axis1_;
// Column.
TableAxis *axis2_;
bool own_axis2_;
};
// Three dimensional table.
class Table3 : public Table2
{
public:
Table3(FloatTable *values,
TableAxis *axis1,
bool own_axis1,
TableAxis *axis2,
bool own_axis2,
TableAxis *axis3,
bool own_axis3);
virtual ~Table3();
virtual int order() const { return 3; }
TableAxis *axis3() const { return axis3_; }
float tableValue(size_t index1,
size_t index2,
size_t index3) const;
virtual float findValue(float value1,
float value2,
float value3) const;
virtual void reportValue(const char *result_name,
const LibertyLibrary *library,
const LibertyCell *cell,
const Pvt *pvt,
float value1,
const char *comment1,
float value2,
float value3,
int digits,
string *result) const;
virtual void report(const Units *units,
Report *report) const;
using Table::findValue;
private:
DISALLOW_COPY_AND_ASSIGN(Table3);
TableAxis *axis3_;
bool own_axis3_;
};
class TableAxis
{
public:
TableAxis(TableAxisVariable variable,
FloatSeq *values);
~TableAxis();
TableAxisVariable variable() const { return variable_; }
size_t size() const { return values_->size(); }
float axisValue(size_t index) const { return (*values_)[index]; }
// Find the index for value such that axis[index] <= value < axis[index+1].
size_t findAxisIndex(float value) const;
private:
DISALLOW_COPY_AND_ASSIGN(TableAxis);
TableAxisVariable variable_;
FloatSeq *values_;
};
} // namespace
#endif

850
liberty/TimingArc.cc Normal file
View File

@ -0,0 +1,850 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 "FuncExpr.hh"
#include "TimingRole.hh"
#include "Liberty.hh"
#include "TimingArc.hh"
namespace sta {
static bool
timingArcsEquiv(const TimingArcSet *set1,
const TimingArcSet *set2);
static bool
timingArcsLess(const TimingArcSet *set1,
const TimingArcSet *set2);
////////////////////////////////////////////////////////////////
TimingArcAttrs::TimingArcAttrs() :
timing_type_(timing_type_combinational),
timing_sense_(timing_sense_unknown),
cond_(NULL),
sdf_cond_(NULL),
sdf_cond_start_(NULL),
sdf_cond_end_(NULL),
mode_name_(NULL),
mode_value_(NULL),
ocv_arc_depth_(0.0)
{
TransRiseFallIterator tr_iter;
while (tr_iter.hasNext()) {
TransRiseFall *tr = tr_iter.next();
int tr_index = tr->index();
models_[tr_index] = NULL;
model_refs_[tr_index] = false;
}
}
TimingArcAttrs::~TimingArcAttrs()
{
if (sdf_cond_)
stringDelete(sdf_cond_);
if (sdf_cond_start_)
stringDelete(sdf_cond_start_);
if (sdf_cond_end_)
stringDelete(sdf_cond_end_);
if (mode_name_)
stringDelete(mode_name_);
if (mode_value_)
stringDelete(mode_value_);
}
void
TimingArcAttrs::setTimingType(TimingType type)
{
timing_type_ = type;
}
void
TimingArcAttrs::setTimingSense(TimingSense sense)
{
timing_sense_ = sense;
}
void
TimingArcAttrs::setSdfCond(const char *cond)
{
stringDelete(sdf_cond_);
sdf_cond_ = stringCopy(cond);
}
void
TimingArcAttrs::setSdfCondStart(const char *cond)
{
stringDelete(sdf_cond_start_);
sdf_cond_start_ = stringCopy(cond);
}
void
TimingArcAttrs::setSdfCondEnd(const char *cond)
{
stringDelete(sdf_cond_end_);
sdf_cond_end_ = stringCopy(cond);
}
void
TimingArcAttrs::setModeName(const char *name)
{
stringDelete(mode_name_);
mode_name_ = stringCopy(name);
}
void
TimingArcAttrs::setModeValue(const char *value)
{
stringDelete(mode_value_);
mode_value_ = stringCopy(value);
}
TimingModel *
TimingArcAttrs::model(TransRiseFall *tr) const
{
return models_[tr->index()];
}
void
TimingArcAttrs::setModel(TransRiseFall *tr,
TimingModel *model)
{
models_[tr->index()] = model;
}
bool
TimingArcAttrs::modelRef(TransRiseFall *tr) const
{
return model_refs_[tr->index()];
}
void
TimingArcAttrs::setModelRef(TransRiseFall *tr,
bool ref)
{
model_refs_[tr->index()] = ref;
}
void
TimingArcAttrs::setOcvArcDepth(float depth)
{
ocv_arc_depth_ = depth;
}
////////////////////////////////////////////////////////////////
TimingArcSet *TimingArcSet::wire_timing_arc_set_ = NULL;
TimingArcSet::TimingArcSet(LibertyCell *cell,
LibertyPort *from,
LibertyPort *to,
LibertyPort *related_out,
TimingRole *role,
TimingArcAttrs *attrs) :
from_(from),
to_(to),
related_out_(related_out),
role_(role),
cond_(attrs->cond()),
is_cond_default_(false),
sdf_cond_start_(NULL),
sdf_cond_end_(NULL),
mode_name_(NULL),
mode_value_(NULL),
index_(0),
is_disabled_constraint_(false)
{
const char *sdf_cond = attrs->sdfCond();
const char *sdf_cond_start = attrs->sdfCondStart();
const char *sdf_cond_end = attrs->sdfCondEnd();
if (sdf_cond)
sdf_cond_start = sdf_cond_end = sdf_cond;
if (sdf_cond_start)
sdf_cond_start_ = stringCopy(sdf_cond_start);
if (sdf_cond_end)
sdf_cond_end_ = stringCopy(sdf_cond_end);
const char *mode_name = attrs->modeName();
if (mode_name)
mode_name_ = stringCopy(mode_name);
const char *mode_value = attrs->modeValue();
if (mode_value)
mode_value_ = stringCopy(mode_value);
ocv_arc_depth_ = attrs->ocvArcDepth();
init(cell);
}
TimingArcSet::TimingArcSet(LibertyCell *cell,
LibertyPort *from,
LibertyPort *to,
LibertyPort *related_out,
TimingRole *role,
FuncExpr *cond,
const char *sdf_cond_start,
const char *sdf_cond_end,
const char *mode_name,
const char *mode_value) :
from_(from),
to_(to),
related_out_(related_out),
role_(role),
cond_(cond),
is_cond_default_(false),
sdf_cond_start_(stringCopy(sdf_cond_start)),
sdf_cond_end_(stringCopy(sdf_cond_end)),
mode_name_(stringCopy(mode_name)),
mode_value_(stringCopy(mode_value)),
index_(0),
is_disabled_constraint_(false)
{
init(cell);
}
void
TimingArcSet::init(LibertyCell *cell)
{
if (cell)
index_ = cell->addTimingArcSet(this);
TransRiseFallIterator tr_iter;
while (tr_iter.hasNext()) {
TransRiseFall *tr = tr_iter.next();
int tr_index = tr->index();
from_arc1_[tr_index] = NULL;
from_arc2_[tr_index] = NULL;
}
}
TimingArcSet::~TimingArcSet()
{
arcs_.deleteContentsClear();
}
LibertyCell *
TimingArcSet::libertyCell() const
{
if (from_)
return from_->libertyCell();
else
// Wire timing arc set.
return NULL;
}
TimingArcIndex
TimingArcSet::addTimingArc(TimingArc *arc)
{
TimingArcIndex arc_index = arcs_.size();
if (arc_index > timing_arc_index_max)
internalError("timing arc max index exceeded\n");
arcs_.push_back(arc);
int from_tr_index = arc->fromTrans()->asRiseFall()->index();
if (from_arc1_[from_tr_index] == NULL)
from_arc1_[from_tr_index] = arc;
else if (from_arc2_[from_tr_index] == NULL)
from_arc2_[from_tr_index] = arc;
return arc_index;
}
void
TimingArcSet::deleteTimingArc(TimingArc *arc)
{
TimingArc *last_arc = arcs_.back();
if (arc == last_arc)
arcs_.pop_back();
else {
last_arc->setIndex(arc->index());
arcs_[arc->index()] = last_arc;
arcs_.pop_back();
}
int from_tr_index = arc->fromTrans()->asRiseFall()->index();
if (from_arc1_[from_tr_index] == arc) {
from_arc1_[from_tr_index] = from_arc2_[from_tr_index];
from_arc2_[from_tr_index] = NULL;
}
else if (from_arc2_[from_tr_index] == arc)
from_arc2_[from_tr_index] = NULL;
delete arc;
}
TimingArc *
TimingArcSet::findTimingArc(unsigned arc_index)
{
return arcs_[arc_index];
}
void
TimingArcSet::setRole(TimingRole *role)
{
role_ = role;
}
void
TimingArcSet::setIsCondDefault(bool is_default)
{
is_cond_default_ = is_default;
}
TimingArcSetArcIterator *
TimingArcSet::timingArcIterator() const
{
return new TimingArcSetArcIterator(this);
}
void
TimingArcSet::arcsFrom(const TransRiseFall *from_tr,
// Return values.
TimingArc *&arc1,
TimingArc *&arc2)
{
int tr_index = from_tr->index();
arc1 = from_arc1_[tr_index];
arc2 = from_arc2_[tr_index];
}
TimingSense
TimingArcSet::sense() const
{
if (arcs_.size() == 1)
return arcs_[0]->sense();
else if (arcs_.size() == 2 && arcs_[0]->sense() == arcs_[1]->sense())
return arcs_[0]->sense();
else
return timing_sense_non_unate;
}
TransRiseFall *
TimingArcSet::isRisingFallingEdge() const
{
int arc_count = arcs_.size();
if (arc_count == 2) {
TransRiseFall *from_tr1 = arcs_[0]->fromTrans()->asRiseFall();
TransRiseFall *from_tr2 = arcs_[1]->fromTrans()->asRiseFall();
if (from_tr1 == from_tr2)
return from_tr1;
}
if (arcs_.size() == 1)
return arcs_[0]->fromTrans()->asRiseFall();
else
return NULL;
}
void
TimingArcSet::setIsDisabledConstraint(bool is_disabled)
{
is_disabled_constraint_ = is_disabled;
}
float
TimingArcSet::ocvArcDepth() const
{
if (from_) {
if (ocv_arc_depth_ != 0.0)
return ocv_arc_depth_;
else {
LibertyCell *cell = from_->libertyCell();
float depth = cell->ocvArcDepth();
if (depth != 0.0)
return depth;
else {
float depth = cell->libertyLibrary()->ocvArcDepth();
if (depth != 0.0)
return depth;
}
}
}
// Wire timing arc set.
return 1.0;
}
bool
TimingArcSet::equiv(const TimingArcSet *set1,
const TimingArcSet *set2)
{
return LibertyPort::equiv(set1->from(), set2->from())
&& LibertyPort::equiv(set1->to(), set2->to())
&& set1->role() == set2->role()
&& FuncExpr::equiv(set1->cond(), set2->cond())
&& stringEqIf(set1->sdfCond(), set2->sdfCond())
&& stringEqIf(set1->sdfCondStart(), set2->sdfCondStart())
&& stringEqIf(set1->sdfCondEnd(), set2->sdfCondEnd())
&& timingArcsEquiv(set1, set2);
}
static bool
timingArcsEquiv(const TimingArcSet *set1,
const TimingArcSet *set2)
{
TimingArcSetArcIterator *arc_iter1 = set1->timingArcIterator();
TimingArcSetArcIterator *arc_iter2 = set2->timingArcIterator();
while (arc_iter1->hasNext() && arc_iter2->hasNext()) {
TimingArc *arc1 = arc_iter1->next();
TimingArc *arc2 = arc_iter2->next();
if (!TimingArc::equiv(arc1, arc2)) {
delete arc_iter1;
delete arc_iter2;
return false;
}
}
bool eq = !arc_iter1->hasNext() && !arc_iter2->hasNext();
delete arc_iter1;
delete arc_iter2;
return eq;
}
bool
TimingArcSet::less(const TimingArcSet *set1,
const TimingArcSet *set2)
{
return timingArcSetLess(set1, set2);
}
bool
timingArcSetLess(const TimingArcSet *set1,
const TimingArcSet *set2)
{
LibertyPort *from1 = set1->from();
LibertyPort *from2 = set2->from();
if (LibertyPort::equiv(from1, from2)) {
LibertyPort *to1 = set1->to();
LibertyPort *to2 = set2->to();
if (LibertyPort::equiv(to1, to2)) {
TimingRole *role1 = set1->role();
TimingRole *role2 = set2->role();
if (role1 == role2) {
const FuncExpr *cond1 = set1->cond();
const FuncExpr *cond2 = set2->cond();
if (FuncExpr::equiv(cond1, cond2)) {
const char *sdf_cond1 = set1->sdfCond();
const char *sdf_cond2 = set2->sdfCond();
if (stringEqIf(sdf_cond1, sdf_cond2)) {
const char *sdf_cond_start1 = set1->sdfCondStart();
const char *sdf_cond_start2 = set2->sdfCondStart();
if (stringEqIf(sdf_cond_start1, sdf_cond_start2)) {
const char *sdf_cond_end1 = set1->sdfCondEnd();
const char *sdf_cond_end2 = set2->sdfCondEnd();
if (stringEqIf(sdf_cond_end1, sdf_cond_end2)) {
const char *mode_name1 = set1->modeName();
const char *mode_name2 = set2->modeName();
if (stringEqIf(mode_name1, mode_name2)) {
const char *mode_value1 = set1->modeValue();
const char *mode_value2 = set2->modeValue();
if (stringEqIf(mode_value1, mode_value2))
return timingArcsLess(set1, set2);
else
return stringLessIf(mode_value1, mode_value2);
}
else
return stringLessIf(mode_name1, mode_name2);
}
else
return stringLessIf(sdf_cond_end1, sdf_cond_end2);
}
else
return stringLessIf(sdf_cond_start1, sdf_cond_start2);
}
else
return stringLessIf(sdf_cond1, sdf_cond2);
}
else
return FuncExpr::less(cond1, cond2);
}
else
return TimingRole::less(role1, role2);
}
else
return LibertyPort::less(to1, to2);
}
else
return LibertyPort::less(from1, from2);
}
static bool
timingArcsLess(const TimingArcSet *set1,
const TimingArcSet *set2)
{
TimingArcSetArcIterator *arc_iter1 = set1->timingArcIterator();
TimingArcSetArcIterator *arc_iter2 = set2->timingArcIterator();
while (arc_iter1->hasNext() && arc_iter2->hasNext()) {
TimingArc *arc1 = arc_iter1->next();
TimingArc *arc2 = arc_iter2->next();
int from_index1 = arc1->fromTrans()->index();
int from_index2 = arc2->fromTrans()->index();
if (from_index1 < from_index2) {
delete arc_iter1;
delete arc_iter2;
return true;
}
if (from_index1 > from_index2) {
delete arc_iter1;
delete arc_iter2;
return false;
}
// from_index1 == from_index2
int to_index1 = arc1->toTrans()->index();
int to_index2 = arc2->toTrans()->index();
if (to_index1 < to_index2) {
delete arc_iter1;
delete arc_iter2;
return true;
}
if (to_index1 > to_index2) {
delete arc_iter1;
delete arc_iter2;
return false;
}
// Continue if arc transitions are equal.
}
bool less = !arc_iter1->hasNext() && arc_iter2->hasNext();
delete arc_iter1;
delete arc_iter2;
return less;
}
////////////////////////////////////////////////////////////////
int
TimingArcSet::wireArcIndex(const TransRiseFall *tr)
{
return tr->index();
}
void
TimingArcSet::init()
{
wire_timing_arc_set_ = new TimingArcSet(NULL,NULL,NULL,NULL,
TimingRole::wire(),
NULL, NULL, NULL, NULL, NULL);
new TimingArc(wire_timing_arc_set_, Transition::rise(),
Transition::rise(), NULL);
new TimingArc(wire_timing_arc_set_, Transition::fall(),
Transition::fall(), NULL);
}
void
TimingArcSet::destroy()
{
delete wire_timing_arc_set_;
wire_timing_arc_set_ = NULL;
}
////////////////////////////////////////////////////////////////
TimingArcSetArcIterator::TimingArcSetArcIterator(const TimingArcSet *set) :
TimingArcSeq::ConstIterator(set->arcs())
{
}
////////////////////////////////////////////////////////////////
TimingArc::TimingArc(TimingArcSet *set,
Transition *from_tr,
Transition *to_tr,
TimingModel *model) :
set_(set),
from_tr_(from_tr),
to_tr_(to_tr),
model_(model),
scaled_models_(NULL)
{
index_ = set->addTimingArc(this);
}
TimingArc::~TimingArc()
{
// The models referenced by scaled_models_ are owned by the scaled
// cells and are deleted by ~LibertyCell.
delete scaled_models_;
}
TimingModel *
TimingArc::model(const OperatingConditions *op_cond) const
{
if (scaled_models_) {
TimingModel *model = scaled_models_->findKey(op_cond);
if (model)
return model;
else
return model_;
}
else
return model_;
}
void
TimingArc::addScaledModel(const OperatingConditions *op_cond,
TimingModel *scaled_model)
{
if (scaled_models_ == NULL)
scaled_models_ = new ScaledTimingModelMap;
(*scaled_models_)[op_cond] = scaled_model;
}
bool
TimingArc::equiv(const TimingArc *arc1,
const TimingArc *arc2)
{
return arc1->fromTrans() == arc2->fromTrans()
&& arc1->toTrans() == arc2->toTrans();
}
void
TimingArc::setIndex(unsigned index)
{
index_ = index;
}
TimingArc *
TimingArc::cornerArc(int ap_index)
{
if (ap_index < static_cast<int>(corner_arcs_.size())) {
TimingArc *corner_arc = corner_arcs_[ap_index];
if (corner_arc)
return corner_arc;
}
return this;
}
void
TimingArc::setCornerArc(TimingArc *corner_arc,
int ap_index)
{
if (ap_index >= static_cast<int>(corner_arcs_.size()))
corner_arcs_.resize(ap_index + 1);
corner_arcs_[ap_index] = corner_arc;
}
////////////////////////////////////////////////////////////////
TimingSense
TimingArc::sense() const
{
if ((from_tr_ == Transition::rise()
&& to_tr_ == Transition::rise())
|| (from_tr_ == Transition::fall()
&& to_tr_ == Transition::fall()))
return timing_sense_positive_unate;
else if ((from_tr_ == Transition::rise()
&& to_tr_ == Transition::fall())
|| (from_tr_ == Transition::fall()
&& to_tr_ == Transition::rise()))
return timing_sense_negative_unate;
else
return timing_sense_non_unate;
}
const char *
timingSenseString(TimingSense sense)
{
static const char *sense_string[] = {"positive_unate",
"negative_unate",
"non_unate",
"none",
"unknown"};
return sense_string[sense];
}
TimingSense
timingSenseOpposite(TimingSense sense)
{
switch (sense) {
case timing_sense_positive_unate:
return timing_sense_negative_unate;
case timing_sense_negative_unate:
return timing_sense_positive_unate;
case timing_sense_non_unate:
return timing_sense_non_unate;
case timing_sense_unknown:
return timing_sense_unknown;
case timing_sense_none:
return timing_sense_none;
}
// Prevent warnings from lame compilers.
return timing_sense_unknown;
}
////////////////////////////////////////////////////////////////
// Same order as enum TimingType.
static const char *timing_type_strings[] = {
"clear",
"combinational",
"combinational_fall",
"combinational_rise",
"falling_edge",
"hold_falling",
"hold_rising",
"min_pulse_width",
"minimum_period",
"nochange_high_high",
"nochange_high_low",
"nochange_low_high",
"nochange_low_low",
"non_seq_hold_falling",
"non_seq_hold_rising",
"non_seq_setup_falling",
"non_seq_setup_rising",
"preset",
"recovery_falling",
"recovery_rising",
"removal_falling",
"removal_rising",
"retaining_time",
"rising_edge",
"setup_falling",
"setup_rising",
"skew_falling",
"skew_rising",
"three_state_disable",
"three_state_disable_fall",
"three_state_disable_rise",
"three_state_enable",
"three_state_enable_fall",
"three_state_enable_rise",
"min_clock_tree_path",
"max_clock_tree_path",
"unknown"
};
typedef Map<const char*,TimingType,CharPtrLess> TimingTypeMap;
static TimingTypeMap *timing_type_string_map = NULL;
void
makeTimingTypeMap()
{
timing_type_string_map = new TimingTypeMap();
int count = sizeof(timing_type_strings) / sizeof(const char*);
for (int i = 0; i < count; i++) {
const char *type_name = timing_type_strings[i];
(*timing_type_string_map)[type_name] = (TimingType) i;
}
}
void
deleteTimingTypeMap()
{
delete timing_type_string_map;
timing_type_string_map = NULL;
}
const char *
timingTypeString(TimingType type)
{
return timing_type_strings[type];
}
TimingType
findTimingType(const char *type_name)
{
TimingType type;
bool exists;
timing_type_string_map->findKey(type_name, type, exists);
if (exists)
return type;
else
return timing_type_unknown;
}
bool
timingTypeIsCheck(TimingType type)
{
switch (type) {
case timing_type_hold_falling:
case timing_type_hold_rising:
case timing_type_min_pulse_width:
case timing_type_minimum_period:
case timing_type_nochange_high_high:
case timing_type_nochange_high_low:
case timing_type_nochange_low_high:
case timing_type_nochange_low_low:
case timing_type_non_seq_hold_falling:
case timing_type_non_seq_hold_rising:
case timing_type_non_seq_setup_falling:
case timing_type_non_seq_setup_rising:
case timing_type_recovery_falling:
case timing_type_recovery_rising:
case timing_type_removal_falling:
case timing_type_removal_rising:
case timing_type_retaining_time:
case timing_type_setup_falling:
case timing_type_setup_rising:
case timing_type_skew_falling:
case timing_type_skew_rising:
return true;
default:
return false;
}
}
ScaleFactorType
timingTypeScaleFactorType(TimingType type)
{
switch (type) {
case timing_type_non_seq_setup_falling:
case timing_type_non_seq_setup_rising:
case timing_type_setup_falling:
case timing_type_setup_rising:
return scale_factor_setup;
case timing_type_hold_falling:
case timing_type_hold_rising:
case timing_type_non_seq_hold_falling:
case timing_type_non_seq_hold_rising:
return scale_factor_hold;
case timing_type_recovery_falling:
case timing_type_recovery_rising:
return scale_factor_recovery;
case timing_type_removal_falling:
case timing_type_removal_rising:
return scale_factor_removal;
case timing_type_skew_falling:
case timing_type_skew_rising:
return scale_factor_skew;
case timing_type_minimum_period:
return scale_factor_min_period;
case timing_type_nochange_high_high:
case timing_type_nochange_high_low:
case timing_type_nochange_low_high:
case timing_type_nochange_low_low:
return scale_factor_nochange;
case timing_type_min_pulse_width:
return scale_factor_min_pulse_width;
case timing_type_clear:
case timing_type_combinational:
case timing_type_combinational_fall:
case timing_type_combinational_rise:
case timing_type_falling_edge:
case timing_type_preset:
case timing_type_retaining_time:
case timing_type_rising_edge:
case timing_type_three_state_disable:
case timing_type_three_state_disable_fall:
case timing_type_three_state_disable_rise:
case timing_type_three_state_enable:
case timing_type_three_state_enable_fall:
case timing_type_three_state_enable_rise:
case timing_type_min_clock_tree_path:
case timing_type_max_clock_tree_path:
return scale_factor_cell;
case timing_type_unknown:
return scale_factor_unknown;
}
return scale_factor_unknown;
}
} // namespace

303
liberty/TimingArc.hh Normal file
View File

@ -0,0 +1,303 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_TIMING_ARC_H
#define STA_TIMING_ARC_H
#include "DisallowCopyAssign.hh"
#include "Vector.hh"
#include "Transition.hh"
#include "LibertyClass.hh"
namespace sta {
class TimingArcAttrs;
class WireTimingArc;
class WireTimingArcSetArcIterator;
class TimingArcSetArcIterator;
typedef int TimingArcIndex;
typedef Vector<TimingArc*> TimingArcSeq;
typedef Map<const OperatingConditions*, TimingModel*> ScaledTimingModelMap;
typedef enum {
timing_type_clear,
timing_type_combinational,
timing_type_combinational_fall,
timing_type_combinational_rise,
timing_type_falling_edge,
timing_type_hold_falling,
timing_type_hold_rising,
timing_type_min_pulse_width,
timing_type_minimum_period,
timing_type_nochange_high_high,
timing_type_nochange_high_low,
timing_type_nochange_low_high,
timing_type_nochange_low_low,
timing_type_non_seq_hold_falling,
timing_type_non_seq_hold_rising,
timing_type_non_seq_setup_falling,
timing_type_non_seq_setup_rising,
timing_type_preset,
timing_type_recovery_falling,
timing_type_recovery_rising,
timing_type_removal_falling,
timing_type_removal_rising,
timing_type_retaining_time,
timing_type_rising_edge,
timing_type_setup_falling,
timing_type_setup_rising,
timing_type_skew_falling,
timing_type_skew_rising,
timing_type_three_state_disable,
timing_type_three_state_disable_fall,
timing_type_three_state_disable_rise,
timing_type_three_state_enable,
timing_type_three_state_enable_fall,
timing_type_three_state_enable_rise,
timing_type_min_clock_tree_path,
timing_type_max_clock_tree_path,
timing_type_unknown
} TimingType;
void
makeTimingTypeMap();
void
deleteTimingTypeMap();
const char *
timingTypeString(TimingType type);
TimingType
findTimingType(const char *string);
bool
timingTypeIsCheck(TimingType type);
ScaleFactorType
timingTypeScaleFactorType(TimingType type);
////////////////////////////////////////////////////////////////
class TimingArcAttrs
{
public:
TimingArcAttrs();
virtual ~TimingArcAttrs();
TimingType timingType() const { return timing_type_; }
void setTimingType(TimingType type);
TimingSense timingSense() const { return timing_sense_; }
void setTimingSense(TimingSense sense);
FuncExpr *cond() const { return cond_; }
FuncExpr *&condRef() { return cond_; }
const char *sdfCond() const { return sdf_cond_; }
void setSdfCond(const char *cond);
const char *sdfCondStart() const { return sdf_cond_start_; }
void setSdfCondStart(const char *cond);
const char *sdfCondEnd() const { return sdf_cond_end_; }
void setSdfCondEnd(const char *cond);
const char *modeName() const { return mode_name_; }
void setModeName(const char *name);
const char *modeValue() const { return mode_value_; }
void setModeValue(const char *value);
TimingModel *model(TransRiseFall *tr) const;
void setModel(TransRiseFall *tr,
TimingModel *model);
bool modelRef(TransRiseFall *tr) const;
void setModelRef(TransRiseFall *tr,
bool ref);
float ocvArcDepth() const { return ocv_arc_depth_; }
void setOcvArcDepth(float depth);
protected:
TimingType timing_type_;
TimingSense timing_sense_;
FuncExpr *cond_;
const char *sdf_cond_;
const char *sdf_cond_start_;
const char *sdf_cond_end_;
const char *mode_name_;
const char *mode_value_;
TimingModel *models_[TransRiseFall::index_count];
bool model_refs_[TransRiseFall::index_count];
float ocv_arc_depth_;
private:
DISALLOW_COPY_AND_ASSIGN(TimingArcAttrs);
};
// A timing arc set is a group of related timing arcs between from/to
// a pair of cell ports. Wire timing arcs are a special set owned by
// the TimingArcSet class.
//
// See ~LibertyCell for delete of TimingArcSet members.
class TimingArcSet
{
public:
TimingArcSet(LibertyCell *cell,
LibertyPort *from,
LibertyPort *to,
LibertyPort *related_out,
TimingRole *role,
TimingArcAttrs *attrs);
TimingArcSet(LibertyCell *cell,
LibertyPort *from,
LibertyPort *to,
LibertyPort *related_out,
TimingRole *role,
FuncExpr *cond,
const char *sdf_cond_start,
const char *sdf_cond_end,
const char *mode_name,
const char *mode_value);
virtual ~TimingArcSet();
LibertyCell *libertyCell() const;
LibertyPort *from() const { return from_; }
LibertyPort *to() const { return to_; }
LibertyPort *relatedOut() const { return related_out_; }
TimingRole *role() const { return role_; };
TimingSense sense() const;
// Rise/fall if the arc set is rising_edge or falling_edge.
TransRiseFall *isRisingFallingEdge() const;
size_t arcCount() const { return arcs_.size(); }
TimingArcSetArcIterator *timingArcIterator() const;
TimingArcSeq &arcs() { return arcs_; }
// Return 1 or 2 arcs matching from transition.
void arcsFrom(const TransRiseFall *from_tr,
// Return values.
TimingArc *&arc1,
TimingArc *&arc2);
const TimingArcSeq &arcs() const { return arcs_; }
TimingArcIndex addTimingArc(TimingArc *arc);
void deleteTimingArc(TimingArc *arc);
TimingArc *findTimingArc(unsigned arc_index);
void setRole(TimingRole *role);
FuncExpr *cond() const { return cond_; }
// Cond default is the timing arcs with no condition when there are
// other conditional timing arcs between the same pins.
bool isCondDefault() const { return is_cond_default_; }
void setIsCondDefault(bool is_default);
// SDF IOPATHs match sdfCond.
// sdfCond (IOPATH) reuses sdfCondStart (timing check) variable.
const char *sdfCond() const { return sdf_cond_start_; }
// SDF timing checks match sdfCondStart/sdfCondEnd.
const char *sdfCondStart() const { return sdf_cond_start_; }
const char *sdfCondEnd() const { return sdf_cond_end_; }
const char *modeName() const { return mode_name_; }
const char *modeValue() const { return mode_value_; }
// Timing arc set index in cell.
TimingArcIndex index() const { return index_; }
bool isDisabledConstraint() const { return is_disabled_constraint_; }
void setIsDisabledConstraint(bool is_disabled);
// OCV arc depth from timing/cell/library.
float ocvArcDepth() const;
static bool equiv(const TimingArcSet *set1,
const TimingArcSet *set2);
static bool less(const TimingArcSet *set1,
const TimingArcSet *set2);
static void init();
static void destroy();
// Psuedo definition for wire arcs.
static TimingArcSet *wireTimingArcSet() { return wire_timing_arc_set_; }
static int wireArcIndex(const TransRiseFall *tr);
static int wireArcCount() { return 2; }
protected:
void init(LibertyCell *cell);
LibertyPort *from_;
LibertyPort *to_;
LibertyPort *related_out_;
TimingRole *role_;
TimingArcSeq arcs_;
FuncExpr *cond_;
bool is_cond_default_;
const char *sdf_cond_start_;
const char *sdf_cond_end_;
const char *mode_name_;
const char *mode_value_;
float ocv_arc_depth_;
unsigned index_;
bool is_disabled_constraint_;
TimingArc *from_arc1_[TransRiseFall::index_count];
TimingArc *from_arc2_[TransRiseFall::index_count];
static TimingArcSet *wire_timing_arc_set_;
private:
DISALLOW_COPY_AND_ASSIGN(TimingArcSet);
};
class TimingArcSetArcIterator : public TimingArcSeq::ConstIterator
{
public:
TimingArcSetArcIterator(const TimingArcSet *set);
private:
DISALLOW_COPY_AND_ASSIGN(TimingArcSetArcIterator);
};
// A timing arc is a single from/to transition between two ports.
// The timing model parameters used for delay calculation are also found here.
class TimingArc
{
public:
TimingArc(TimingArcSet *set,
Transition *from_tr,
Transition *to_tr,
TimingModel *model);
~TimingArc();
LibertyPort *from() const { return set_->from(); }
LibertyPort *to() const { return set_->to(); }
Transition *fromTrans() const { return from_tr_; }
Transition *toTrans() const { return to_tr_; }
TimingRole *role() const { return set_->role(); }
TimingArcSet *set() const { return set_; }
TimingSense sense() const;
// Index in TimingArcSet.
unsigned index() const { return index_; }
TimingModel *model(const OperatingConditions *op_cond) const;
TimingModel *model() const { return model_; }
TimingArc *cornerArc(int ap_index);
void setCornerArc(TimingArc *corner_arc,
int ap_index);
static bool equiv(const TimingArc *arc1,
const TimingArc *arc2);
protected:
void setIndex(unsigned index);
void addScaledModel(const OperatingConditions *op_cond,
TimingModel *scaled_model);
TimingArcSet *set_;
Transition *from_tr_;
Transition *to_tr_;
unsigned index_;
TimingModel *model_;
ScaledTimingModelMap *scaled_models_;
Vector<TimingArc*> corner_arcs_;
private:
DISALLOW_COPY_AND_ASSIGN(TimingArc);
friend class LibertyLibrary;
friend class LibertyCell;
friend class TimingArcSet;
};
} // namespace
#endif

84
liberty/TimingModel.hh Normal file
View File

@ -0,0 +1,84 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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/>.
#ifndef STA_TIMING_MODEL_H
#define STA_TIMING_MODEL_H
#include <string>
#include "LibertyClass.hh"
namespace sta {
using std::string;
// Abstract base class for timing models.
class TimingModel
{
public:
virtual ~TimingModel() {}
protected:
virtual void setIsScaled(bool is_scaled) = 0;
friend class LibertyCell;
};
// Abstract base class for gate timing models.
class GateTimingModel : public TimingModel
{
public:
// Gate delay calculation.
virtual void gateDelay(const LibertyCell *cell,
const Pvt *pvt,
float in_slew,
float load_cap,
float related_out_cap,
// Return values.
float &gate_delay,
float &drvr_slew) const = 0;
virtual void reportGateDelay(const LibertyCell *cell,
const Pvt *pvt,
float in_slew,
float load_cap,
float related_out_cap,
int digits,
string *result) const = 0;
virtual float driveResistance(const LibertyCell *cell,
const Pvt *pvt) const = 0;
};
// Abstract base class for timing check timing models.
class CheckTimingModel : public TimingModel
{
public:
// Timing check margin delay calculation.
virtual float checkDelay(const LibertyCell *cell,
const Pvt *pvt,
float from_slew,
float to_slew,
float related_out_cap) const = 0;
virtual void reportCheckDelay(const LibertyCell *cell,
const Pvt *pvt,
float from_slew,
const char *from_slew_annotation,
float to_slew,
float related_out_cap,
int digits,
string *result) const = 0;
};
} // namespace
#endif

252
liberty/TimingRole.cc Normal file
View File

@ -0,0 +1,252 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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 "TimingRole.hh"
namespace sta {
TimingRole *TimingRole::wire_;
TimingRole *TimingRole::combinational_;
TimingRole *TimingRole::tristate_enable_;
TimingRole *TimingRole::tristate_disable_;
TimingRole *TimingRole::reg_clk_q_;
TimingRole *TimingRole::reg_set_clr_;
TimingRole *TimingRole::latch_en_q_;
TimingRole *TimingRole::latch_d_q_;
TimingRole *TimingRole::sdf_iopath_;
TimingRole *TimingRole::setup_;
TimingRole *TimingRole::hold_;
TimingRole *TimingRole::recovery_;
TimingRole *TimingRole::removal_;
TimingRole *TimingRole::width_;
TimingRole *TimingRole::period_;
TimingRole *TimingRole::skew_;
TimingRole *TimingRole::nochange_;
TimingRole *TimingRole::output_setup_;
TimingRole *TimingRole::output_hold_;
TimingRole *TimingRole::gated_clk_setup_;
TimingRole *TimingRole::gated_clk_hold_;
TimingRole *TimingRole::latch_setup_;
TimingRole *TimingRole::latch_hold_;
TimingRole *TimingRole::data_check_setup_;
TimingRole *TimingRole::data_check_hold_;
TimingRole *TimingRole::non_seq_setup_;
TimingRole *TimingRole::non_seq_hold_;
TimingRoleMap TimingRole::timing_roles_;
void
TimingRole::init()
{
wire_ = new TimingRole("wire", false, false, false, NULL, NULL, 0);
combinational_ = new TimingRole("combinational", true, false, false,
NULL, NULL, 1);
tristate_enable_ = new TimingRole("tristate enable",
true, false, false,
NULL, NULL, 2);
tristate_disable_ = new TimingRole("tristate disable",
true, false, false,
NULL, NULL, 3);
reg_clk_q_ = new TimingRole("Reg Clk to Q", true, false, false,
NULL, NULL, 4);
reg_set_clr_ = new TimingRole("Reg Set/Clr", true, false, false,
NULL, NULL, 5);
latch_en_q_ = new TimingRole("Latch En to Q", true, false, false,
NULL, TimingRole::regClkToQ(), 6);
latch_d_q_ = new TimingRole("Latch D to Q", true, false, false,
NULL, NULL, 7);
sdf_iopath_ = new TimingRole("sdf IOPATH", true, false, false,
NULL, NULL, 8);
setup_ = new TimingRole("setup", false, true, false,
MinMax::max(), NULL, 9);
hold_ = new TimingRole("hold", false, true, false,
MinMax::min(), NULL, 10);
recovery_ = new TimingRole("recovery", false, true, false,
MinMax::max(), TimingRole::setup(), 11);
removal_ = new TimingRole("removal", false, true, false,
MinMax::min(), TimingRole::hold(), 12);
width_ = new TimingRole("width", false, true, false,
NULL, NULL, 13);
period_ = new TimingRole("period", false, true, false,
NULL, NULL, 14);
skew_ = new TimingRole("skew", false, true, false,
NULL, NULL, 15);
nochange_ = new TimingRole("nochange", true, false, false,
NULL, NULL, 16);
output_setup_ = new TimingRole("output setup", false, true, false,
MinMax::max(), TimingRole::setup(), 17);
output_hold_ = new TimingRole("output hold", false, true, false,
MinMax::min(), TimingRole::hold(), 18);
gated_clk_setup_ = new TimingRole("clock gating setup",
false, true, false,
MinMax::max(), TimingRole::setup(),19);
gated_clk_hold_ = new TimingRole("clock gating hold", false, true, false,
MinMax::min(), TimingRole::hold(),20);
latch_setup_ = new TimingRole("latch setup", false, true, false,
MinMax::max(), TimingRole::setup(),21);
latch_hold_ = new TimingRole("latch hold", false, true, false,
MinMax::min(), TimingRole::hold(),22);
data_check_setup_ = new TimingRole("data check setup",
false, true, false,
MinMax::max(),TimingRole::setup(),23);
data_check_hold_ = new TimingRole("data check hold", false, true, false,
MinMax::min(), TimingRole::hold(), 24);
non_seq_setup_ = new TimingRole("setup", false, true, true,
MinMax::max(), TimingRole::setup(), 25);
non_seq_hold_ = new TimingRole("hold", false, true, true,
MinMax::min(), TimingRole::hold(), 26);
}
void
TimingRole::destroy()
{
delete wire_;
wire_ = NULL;
delete combinational_;
combinational_ = NULL;
delete tristate_enable_;
tristate_enable_ = NULL;
delete tristate_disable_;
tristate_disable_ = NULL;
delete reg_clk_q_;
reg_clk_q_ = NULL;
delete reg_set_clr_;
reg_set_clr_ = NULL;
delete latch_en_q_;
latch_en_q_ = NULL;
delete latch_d_q_;
latch_d_q_ = NULL;
delete sdf_iopath_;
sdf_iopath_ = NULL;
delete setup_;
setup_ = NULL;
delete hold_;
hold_ = NULL;
delete recovery_;
recovery_ = NULL;
delete removal_;
removal_ = NULL;
delete width_;
width_ = NULL;
delete period_;
period_ = NULL;
delete skew_;
skew_ = NULL;
delete nochange_;
nochange_ = NULL;
delete output_setup_;
output_setup_ = NULL;
delete output_hold_;
output_hold_ = NULL;
delete gated_clk_setup_;
gated_clk_setup_ = NULL;
delete gated_clk_hold_;
gated_clk_hold_ = NULL;
delete latch_setup_;
latch_setup_ = NULL;
delete latch_hold_;
latch_hold_ = NULL;
delete data_check_setup_;
data_check_setup_ = NULL;
delete data_check_hold_;
data_check_hold_ = NULL;
delete non_seq_setup_;
non_seq_setup_ = NULL;
delete non_seq_hold_;
non_seq_hold_ = NULL;
timing_roles_.clear();
}
TimingRole::TimingRole(const char *name,
bool is_sdf_iopath,
bool is_timing_check,
bool is_non_seq_check,
MinMax *path_min_max,
TimingRole *generic_role,
int index) :
name_(name),
is_timing_check_(is_timing_check),
is_sdf_iopath_(is_sdf_iopath),
is_non_seq_check_(is_non_seq_check),
generic_role_(generic_role),
index_(index),
path_min_max_(path_min_max)
{
timing_roles_[name] = this;
}
TimingRole *
TimingRole::find(const char *name)
{
return timing_roles_[name];
}
const TimingRole *
TimingRole::sdfRole() const
{
if (is_sdf_iopath_)
return sdf_iopath_;
else
return this;
}
const TimingRole *
TimingRole::genericRole() const
{
if (generic_role_ == NULL)
return this;
else
return generic_role_;
}
const EarlyLate *
TimingRole::tgtClkEarlyLate() const
{
return path_min_max_->opposite();
}
bool
TimingRole::isWire() const
{
return this == wire_;
}
bool
TimingRole::isAsyncTimingCheck() const
{
return this == recovery_
|| this == removal_;
}
bool
TimingRole::isDataCheck() const
{
return this == data_check_setup_
|| this == data_check_hold_;
}
bool
TimingRole::less(const TimingRole *role1,
const TimingRole *role2)
{
return role1->index() < role2->index();
}
} // namespace

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