and then there was light...
This commit is contained in:
commit
1154fb89fd
|
|
@ -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
|
||||
|
|
@ -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/>.
|
||||
|
||||
|
|
@ -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:
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
@ -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"
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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 *¶sitic,
|
||||
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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
|
|
@ -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 *¶sitic,
|
||||
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 *¶sitic,
|
||||
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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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 ¶llel_delay,
|
||||
Slew ¶llel_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
|
||||
|
|
@ -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 *¶sitic,
|
||||
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
|
||||
|
|
@ -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 *¶sitic,
|
||||
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
|
||||
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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 *¶sitic,
|
||||
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
|
||||
|
|
@ -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 *¶sitic,
|
||||
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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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 *¶sitic,
|
||||
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
|
||||
|
|
@ -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 *¶sitic,
|
||||
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
|
||||
|
|
@ -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:
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
|
|
@ -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:
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -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.
|
||||
|
|
@ -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:
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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 ®_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
|
||||
|
|
@ -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
|
||||
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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]; }
|
||||
|
||||
%%
|
||||
|
|
@ -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); }
|
||||
;
|
||||
|
||||
%%
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
%%
|
||||
|
|
@ -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 ';'
|
||||
;
|
||||
|
||||
%%
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
Loading…
Reference in New Issue