write_path_spice register path support
This commit is contained in:
parent
b700eca86b
commit
f2a28bdcaf
|
|
@ -1,10 +1,18 @@
|
|||
# Parallax Static Timing Analyzer
|
||||
# OpenSTA, Static Timing Analyzer
|
||||
# Copyright (c) 2019, Parallax Software, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# No part of this document may be copied, transmitted or
|
||||
# disclosed in any form or fashion without the express
|
||||
# written consent of 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/>.
|
||||
|
||||
cmake_minimum_required (VERSION 3.9)
|
||||
|
||||
|
|
@ -205,7 +213,6 @@ set(STA_SOURCE
|
|||
verilog/VerilogReader.cc
|
||||
verilog/VerilogLex.cc
|
||||
verilog/VerilogParse.cc
|
||||
|
||||
)
|
||||
|
||||
set(STA_HEADERS
|
||||
|
|
@ -707,3 +714,10 @@ install(TARGETS OpenSTA DESTINATION lib)
|
|||
|
||||
# include
|
||||
install(FILES ${STA_HEADERS} DESTINATION include)
|
||||
|
||||
################################################################
|
||||
|
||||
add_custom_target(tags etags -o TAGS ${STA_SOURCE} ${STA_HEADERS} ${STA_TCL_FILES} ${SWIG_TCL_FILES}
|
||||
WORKING_DIRECTORY ${STA_HOME}
|
||||
DEPENDS ${STA_SOURCE} ${STA_HEADERS} ${STA_TCL_FILES} ${SWIG_TCL_FILES}
|
||||
)
|
||||
|
|
|
|||
205
INSTALL
205
INSTALL
|
|
@ -1,204 +1 @@
|
|||
# OpenSTA, Static Timing Analyzer
|
||||
# Copyright (c) 2019, Parallax Software, Inc.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Builds are supported with cmake. Builds with Autotools are supported
|
||||
for compatibility but are deprecated.
|
||||
|
||||
Building with Cmake
|
||||
-------------------
|
||||
|
||||
The build dependency versions are show below. Other versions may
|
||||
work, but these are the versions used for development.
|
||||
|
||||
from Ubuntu Xcode
|
||||
18.04.1 10.1
|
||||
clang 9.1.0 10.0.0
|
||||
gcc 3.3.2 7.3.0
|
||||
tcl 8.2 8.6 8.6.6
|
||||
swig 1.3.28 3.0.12 3.0.12
|
||||
bison 1.35 3.0.4 2.3
|
||||
flex 2.5.4 2.6.4 2.5.35
|
||||
|
||||
Building with cmake requires bison, flex and swig.
|
||||
|
||||
These packages are optional:
|
||||
|
||||
libz 1.1.4 1.2.5 1.2.8
|
||||
cudd 2.4.1 3.0.0
|
||||
|
||||
CUDD is a BDD package that is used to improve conditional timing arc
|
||||
handling. It is available here:
|
||||
|
||||
https://www.davidkebo.com/source/cudd_versions/cudd-3.0.0.tar.gz
|
||||
https://sourceforge.net/projects/cudd-mirror/
|
||||
|
||||
Note that the file hierarchy of the CUDD installation changed with
|
||||
version 3.0. This build only supports the 3.0 layout but only small
|
||||
changes to configure.ac are required to support older versions.
|
||||
|
||||
cd $HOME/cudd-3.0.0
|
||||
mkdir $HOME/cudd
|
||||
./configure --prefix $HOME/cudd
|
||||
make
|
||||
make install
|
||||
|
||||
And then pass the install directory to cmake before building OpenSTA.
|
||||
|
||||
cmake .. -DCUDD=$HOME/cudd
|
||||
|
||||
The Zlib library is an optional. If the configure script finds libz,
|
||||
OpenSTA can read Verilog, SDF, SPF, and SPEF files compressed with
|
||||
gzip.
|
||||
|
||||
Use the following commands to checkout the git repository build the
|
||||
OpenSTA library and excutable.
|
||||
|
||||
git clone https://xp-dev.com/git/opensta
|
||||
cd opensta
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
|
||||
The resulting executable is in app/sta.
|
||||
The library without a main() procedure is app/libSTA.a.
|
||||
|
||||
Optional cmake variables passed as -D<var>=<value> arguments to cmake
|
||||
are show below.
|
||||
|
||||
CMAKE_BUILD_TYPE DEBUG|RELEASE
|
||||
CMAKE_CXX_FLAGS - additional compiler flags
|
||||
TCL_LIB - path to tcl library
|
||||
TCL_HEADER - path to tcl.h
|
||||
ZLIB_ROOT - path to zlib
|
||||
CMAKE_INSTALL_PREFIX
|
||||
|
||||
If TCL_LIB is specified the cmake script will attempt to locate the
|
||||
header from its path.
|
||||
|
||||
The default install directory is /usr/local.
|
||||
To install in a different directory with cmake use:
|
||||
|
||||
cmake .. -DCMAKE_INSTALL_PREFIX=<prefix_path>
|
||||
|
||||
or use the DESTDIR variable with make.
|
||||
|
||||
make DESTDIR=<prefix_path> install
|
||||
|
||||
If you make changes to CMakeLists.txt you may need to clean out
|
||||
existing cmake cached variable values by deleting all of the
|
||||
files in the build directory.
|
||||
|
||||
Building from a tarfile
|
||||
-----------------------
|
||||
|
||||
Use the following commands to unpack the dist file and compile it.
|
||||
|
||||
tar zvfz opensta-<version>.tgz
|
||||
cd opensta-<version>
|
||||
./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
|
||||
|
||||
If the configure script fails to find any of the TCL, Zlib or CUDD
|
||||
files, use the --with-include, --with-lib, --with-tcl, --with-cudd
|
||||
options to add directories to search for the files.
|
||||
|
||||
The configure -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 with GNU Autotools
|
||||
---------------------------
|
||||
|
||||
Building with GNU Autotools the additional build dependencies
|
||||
shown below.
|
||||
|
||||
from Ubuntu Xcode
|
||||
18.04.1 10.1
|
||||
autoconf 2.53 2.69 2.69
|
||||
automake 1.6.3 1.15.1 1.16.1
|
||||
libtool 1.4.2 2.4.6 2.4.6
|
||||
|
||||
Use the following commands to checkout the git repository and compile
|
||||
it.
|
||||
|
||||
git clone https://xp-dev.com/git/opensta
|
||||
git checkout master|branch
|
||||
./bootstrap
|
||||
./configure [options...]
|
||||
make
|
||||
|
||||
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
|
||||
|
||||
cmake is supposedly more compatible with the windoz environment
|
||||
so you may have better luck wih it.
|
||||
|
||||
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
|
||||
----------------------
|
||||
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.
|
||||
See README.MD for installation instructions.
|
||||
|
|
|
|||
70
README
70
README
|
|
@ -1,69 +1 @@
|
|||
# OpenSTA, Static Timing Analyzer
|
||||
Copyright (c) 2019, Parallax Software, Inc.
|
||||
|
||||
> This program is free software: you can redistribute it and/or modify
|
||||
> it under the terms of the GNU General Public License as published by
|
||||
> the Free Software Foundation, either version 3 of the License, or
|
||||
> (at your option) any later version.
|
||||
|
||||
> This program is distributed in the hope that it will be useful,
|
||||
> but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
> GNU General Public License for more details.
|
||||
|
||||
> You should have received a copy of the GNU General Public License
|
||||
> along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Parallax Gate Level Static Timing Analyzer
|
||||
|
||||
## Install
|
||||
|
||||
See INSTALL for installation and build instructions. Alternatively, run using Docker as described in the next section
|
||||
|
||||
## Run using Docker
|
||||
1. Install Docker on [Windows](https://docs.docker.com/docker-for-windows/), [Mac](https://docs.docker.com/docker-for-mac/) or [Linux](https://docs.docker.com/install/).
|
||||
2. Navigate to the directory where you have the input files.
|
||||
3. Run OpenSTA as a binary using `docker run -it -v $(pwd):/data openroad/opensta`
|
||||
4. From the interactive terminal, use OpenSTA commands. You can read input files from `/data` directory inside the docker container (e.g. `read_liberty /data/liberty.lib`). You can use OpenSTA in non-interactive mode by passing a command file using `-f` flag as follows `docker run -it -v $(pwd):/data openroad/opensta -f /data/cmd_file`. Note that the path after `-f` is the path inside container, not on the guest machine.
|
||||
|
||||
## Standard file formats
|
||||
|
||||
* Verilog
|
||||
* Liberty
|
||||
* SDC
|
||||
* SDF
|
||||
* 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
|
||||
See README.MD
|
||||
|
|
|
|||
293
README.md
293
README.md
|
|
@ -1,49 +1,19 @@
|
|||
# OpenSTA, Static Timing Analyzer
|
||||
Copyright (c) 2019, Parallax Software, Inc.
|
||||
# Parallax Static Timing Analyzer
|
||||
|
||||
> 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.
|
||||
OpenSTA is a gate level static timing verifier. As a stand-alone
|
||||
executable it can be used to verify the timing of a design using
|
||||
standard file formats.
|
||||
|
||||
> 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.
|
||||
* Verilog netlist
|
||||
* Liberty library
|
||||
* SDC timing constraints
|
||||
* SDF delay annotation
|
||||
* SPEF parasitics
|
||||
|
||||
> You should have received a copy of the GNU General Public License
|
||||
> along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
OpenSTA uses a TCL command interpreter to read the design, specify
|
||||
timing constraints and print timing reports.
|
||||
|
||||
Parallax Gate Level Static Timing Analyzer
|
||||
|
||||
## Install
|
||||
|
||||
See INSTALL for installation and build instructions. Alternatively, run using Docker as described in the next section
|
||||
|
||||
## Run using Docker
|
||||
1. Install Docker on [Windows](https://docs.docker.com/docker-for-windows/), [Mac](https://docs.docker.com/docker-for-mac/) or [Linux](https://docs.docker.com/install/).
|
||||
2. Navigate to the directory where you have the input files.
|
||||
3. Run OpenSTA as a binary using `docker run -it -v $(pwd):/data openroad/opensta`
|
||||
4. From the interactive terminal, use OpenSTA commands. You can read input files from `/data` directory inside the docker container (e.g. `read_liberty /data/liberty.lib`). You can use OpenSTA in non-interactive mode by passing a command file using `-f` flag as follows `docker run -it -v $(pwd):/data openroad/opensta -f /data/cmd_file`. Note that the path after `-f` is the path inside container, not on the guest machine.
|
||||
|
||||
## 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
|
||||
##### Clocks
|
||||
* Generated
|
||||
* Latency
|
||||
* Source latency (insertion delay)
|
||||
|
|
@ -52,18 +22,247 @@ See INSTALL for installation and build instructions. Alternatively, run using Do
|
|||
* Gated clock checks
|
||||
* Multiple frequency clocks
|
||||
|
||||
## Delay calculation
|
||||
##### Exception paths
|
||||
* False path
|
||||
* Multicycle path
|
||||
* Min/Max path delay
|
||||
* Exception points
|
||||
* -from clock/pin/instance -through pin/net -to clock/pin/instance
|
||||
* Edge specific exception points
|
||||
* -rise_from/-fall_from, -rise_through/-fall_through, -rise_to/-fall_to
|
||||
|
||||
##### Delay calculation
|
||||
* Integrated Dartu/Menezes/Pileggi RC effective capacitance algorithm
|
||||
* External delay calculator API
|
||||
|
||||
## Analysis
|
||||
##### Analysis
|
||||
* Report timing checks -from, -through, -to, multiple paths to endpoint
|
||||
* Report delay calculation
|
||||
* Check timing setup
|
||||
|
||||
## Search Engine
|
||||
##### Timing Engine
|
||||
OpenSTA is architected to be easily bolted on to other tools as a
|
||||
timing engine. By using a network adapter, OpenSTA can access the host
|
||||
netlist data structures without duplicating them.
|
||||
|
||||
* Query based incremental update of delays, arrival and required times
|
||||
* Simulator to propagate constants from constraints and netlist tie high/low
|
||||
|
||||
## Timing engine library
|
||||
* Network adapter uses external netlist database without duplicating any data
|
||||
See doc/OpenSTA.pdf for complete documentiaton.
|
||||
|
||||
## Getting Started
|
||||
|
||||
OpenSTA can be run as a [Docker](https://www.docker.com/) container
|
||||
or built as local executable with CMake or Autotools.
|
||||
|
||||
### Run using Docker
|
||||
* Install Docker on [Windows](https://docs.docker.com/docker-for-windows/), [Mac](https://docs.docker.com/docker-for-mac/) or [Linux](https://docs.docker.com/install/).
|
||||
* Navigate to the directory where you have the input files.
|
||||
* Run OpenSTA as a binary using
|
||||
````
|
||||
docker run -it -v $(pwd):/data openroad/opensta
|
||||
````
|
||||
|
||||
4. From the interactive terminal, use OpenSTA commands. You can read input files from `/data` directory inside the docker container (e.g. `read_liberty /data/liberty.lib`). You can use OpenSTA in non-interactive mode by passing a command file using the `-f` flag as follows.
|
||||
```
|
||||
docker run -it -v $(pwd):/data openroad/opensta -f /data/cmd_file
|
||||
```
|
||||
Note that the path after `-f` is the path inside container, not on the guest machine.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
The build dependency versions are show below. Other versions may
|
||||
work, but these are the versions used for development.
|
||||
|
||||
```
|
||||
from Ubuntu Xcode
|
||||
18.04.1 10.1
|
||||
cmake 3.9
|
||||
clang 9.1.0 10.0.0
|
||||
gcc 3.3.2 7.3.0
|
||||
tcl 8.2 8.6 8.6.6
|
||||
swig 1.3.28 3.0.12 3.0.12
|
||||
bison 1.35 3.0.4 2.3
|
||||
flex 2.5.4 2.6.4 2.5.35
|
||||
```
|
||||
|
||||
These packages are optional:
|
||||
|
||||
```
|
||||
libz 1.1.4 1.2.5 1.2.8
|
||||
cudd 2.4.1 3.0.0
|
||||
```
|
||||
|
||||
CUDD is a binary decision diageram (BDD) package that is used to improve conditional timing arc handling. It is available [here](https://www.davidkebo.com/source/cudd_versions/cudd-3.0.0.tar.gz) or [here](https://sourceforge.net/projects/cudd-mirror/).
|
||||
|
||||
Note that the file hierarchy of the CUDD installation changed with version 3.0.
|
||||
Some changes to the CMake or configure scripts are required to support older
|
||||
versions.
|
||||
|
||||
You may use the `--prefix ` option to `configure` to install in a location other than
|
||||
the default (`/usr/local/lib`).
|
||||
```
|
||||
cd $HOME/cudd-3.0.0
|
||||
mkdir $HOME/cudd
|
||||
./configure --prefix $HOME/cudd
|
||||
make
|
||||
make install
|
||||
```
|
||||
|
||||
The Zlib library is an optional. If CMake or the configure script
|
||||
finds libz, OpenSTA can read Verilog, SDF, SPF, and SPEF files
|
||||
compressed with gzip.
|
||||
|
||||
### Installing with CMake
|
||||
|
||||
Use the following commands to checkout the git repository and build the
|
||||
OpenSTA library and excutable.
|
||||
|
||||
```
|
||||
git clone https://xp-dev.com/git/opensta
|
||||
cd opensta
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCUDD=$HOME/cudd
|
||||
make
|
||||
```
|
||||
The default build type is release to compile optimized code.
|
||||
The resulting executable is in `app/sta`.
|
||||
The library without a `main()` procedure is `app/libSTA.a`.
|
||||
|
||||
Optional CMake variables passed as -D<var>=<value> arguments to CMake are show below.
|
||||
|
||||
```
|
||||
CMAKE_BUILD_TYPE DEBUG|RELEASE
|
||||
CMAKE_CXX_FLAGS - additional compiler flags
|
||||
TCL_LIB - path to tcl library
|
||||
TCL_HEADER - path to tcl.h
|
||||
CUDD - path to cudd installation ($HOME/cudd if following install shown above)
|
||||
ZLIB_ROOT - path to zlib
|
||||
CMAKE_INSTALL_PREFIX
|
||||
```
|
||||
|
||||
If `TCL_LIB` is specified the CMake script will attempt to locate the
|
||||
header from the library path.
|
||||
|
||||
The default install directory is `/usr/local`.
|
||||
To install in a different directory with CMake use:
|
||||
|
||||
```
|
||||
cmake .. -DCMAKE_INSTALL_PREFIX=<prefix_path>
|
||||
```
|
||||
|
||||
Alternatively, you can use the `DESTDIR` variable with make.
|
||||
|
||||
```
|
||||
make DESTDIR=<prefix_path> install
|
||||
```
|
||||
|
||||
If you make changes to `CMakeLists.txt` you may need to clean out
|
||||
existing CMake cached variable values by deleting all of the
|
||||
files in the build directory.
|
||||
|
||||
### Installing from a tarfile
|
||||
|
||||
Installing from a tarfile has the advantage that Autotools, bison,
|
||||
flex and swig do not need to be installed.
|
||||
|
||||
Use the following commands to unpack the dist file and compile it.
|
||||
```
|
||||
tar zvfz opensta-<version>.tgz
|
||||
cd opensta-<version>
|
||||
./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
|
||||
```
|
||||
If the configure script fails to find any of the `TCL`, `Zlib` or `CUDD`
|
||||
files, use the `--with-include`, `--with-lib`, `--with-tcl`, `--with-cudd`
|
||||
options to add directories to search for the files.
|
||||
|
||||
The configure `--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.
|
||||
|
||||
### Installing with Autotools
|
||||
|
||||
Building with GNU Autotools the additional build dependencies shown
|
||||
below.
|
||||
```
|
||||
from Ubuntu Xcode
|
||||
18.04.1 10.1
|
||||
autoconf 2.53 2.69 2.69
|
||||
automake 1.6.3 1.15.1 1.16.1
|
||||
libtool 1.4.2 2.4.6 2.4.6
|
||||
```
|
||||
Use the following commands to checkout the git repository and compile
|
||||
it.
|
||||
```
|
||||
git clone https://xp-dev.com/git/opensta
|
||||
git checkout master|branch
|
||||
./bootstrap
|
||||
./configure [options...]
|
||||
make
|
||||
```
|
||||
Configure options are show above in the "Installing from tarkit" section.
|
||||
|
||||
### Installing 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 [pthreads](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
|
||||
```
|
||||
CMake is supposedly more compatible with the windoz environment
|
||||
so you may have better luck wih it.
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
## Authors
|
||||
|
||||
* James Cherry
|
||||
|
||||
* William Scott authored the arnoldi delay calculator at Blaze, Inc which was subsequently licensed to Nefelus, Inc that has graciously contributed it to OpenSTA.
|
||||
|
||||
## License
|
||||
|
||||
Copyright (c) 2019, Parallax Software, Inc.
|
||||
All rights reserved.
|
||||
|
||||
No part of this document may be copied, transmitted or
|
||||
disclosed in any form or fashion without the express
|
||||
written consent of Parallax Software, Inc.
|
||||
|
|
|
|||
|
|
@ -53,10 +53,12 @@ public:
|
|||
|
||||
// Delete expression and all of its subexpressions.
|
||||
void deleteSubexprs();
|
||||
// op == op_port
|
||||
LibertyPort *port() const;
|
||||
Operator op() const { return op_; }
|
||||
// When operator is NOT left is the only operand.
|
||||
FuncExpr *left() const { return left_; }
|
||||
// NULL when op == op_not
|
||||
FuncExpr *right() const { return right_; }
|
||||
TimingSense portTimingSense(const LibertyPort *port) const;
|
||||
// Return true if expression has port as an input.
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "StringUtil.hh"
|
||||
#include "FuncExpr.hh"
|
||||
#include "Units.hh"
|
||||
#include "Sequential.hh"
|
||||
#include "Liberty.hh"
|
||||
#include "TimingArc.hh"
|
||||
#include "Network.hh"
|
||||
|
|
@ -83,17 +84,18 @@ private:
|
|||
void writeHeader();
|
||||
void writeStageInstances();
|
||||
void writeInputSource();
|
||||
void writeStepVoltSource(const Pin *pin,
|
||||
const TransRiseFall *tr,
|
||||
float slew,
|
||||
float time,
|
||||
int &volt_index);
|
||||
void writeStageSubckts();
|
||||
void writeInputStage(Stage stage);
|
||||
void writeMeasureStmts();
|
||||
void writeMeasureStmt(const Pin *pin);
|
||||
void writeGateStage(Stage stage);
|
||||
void writeStageVoltageSources(LibertyCell *cell,
|
||||
StringVector *spice_port_names,
|
||||
const Instance *inst,
|
||||
const char *inst_name,
|
||||
LibertyPort *from_port,
|
||||
LibertyPort *drvr_port);
|
||||
void writeStageVoltageSources(Stage stage,
|
||||
StringVector *spice_port_names);
|
||||
void writeStageParasitics(Stage stage);
|
||||
void writeSubckts();
|
||||
void findPathCellnames(// Return values.
|
||||
|
|
@ -114,9 +116,36 @@ private:
|
|||
Path *path);
|
||||
void sensitizationValues(const Instance *inst,
|
||||
FuncExpr *expr,
|
||||
LibertyPort *from_port,
|
||||
LibertyPort *input_port,
|
||||
// Return values.
|
||||
LibertyPortLogicValues &port_values);
|
||||
void seqSensitizationValues(Sequential *seq,
|
||||
const TransRiseFall *tr,
|
||||
// Return values.
|
||||
LibertyPortLogicValues &port_values);
|
||||
void writeInputWaveform();
|
||||
void writeClkWaveform();
|
||||
void writeWaveformEdge(const TransRiseFall *tr,
|
||||
float time,
|
||||
float slew);
|
||||
void writeClkedStepSource(const Pin *pin,
|
||||
const TransRiseFall *tr,
|
||||
const Clock *clk,
|
||||
DcalcAPIndex dcalc_ap_index,
|
||||
int &volt_index);
|
||||
float clkWaveformTImeOffset(const Clock *clk);
|
||||
float findSlew(Path *path);
|
||||
float findSlew(Path *path,
|
||||
const TransRiseFall *tr);
|
||||
float findSlew(Vertex *vertex,
|
||||
const TransRiseFall *tr,
|
||||
DcalcAPIndex dcalc_ap_index);
|
||||
LibertyPort *onePort(FuncExpr *expr);
|
||||
void writeVoltageSource(LibertyCell *cell,
|
||||
const char *inst_name,
|
||||
const char *subckt_port_name,
|
||||
const char *pg_port_name,
|
||||
int &volt_index);
|
||||
|
||||
// Stage "accessors".
|
||||
//
|
||||
|
|
@ -144,7 +173,7 @@ private:
|
|||
TimingArc *stageWireArc(Stage stage);
|
||||
Edge *stageGateEdge(Stage stage);
|
||||
Edge *stageWireEdge(Stage stage);
|
||||
Pin *stageInputPin(Stage stage);
|
||||
Pin *stageGateInputPin(Stage stage);
|
||||
Pin *stageDrvrPin(Stage stage);
|
||||
Pin *stageLoadPin(Stage stage);
|
||||
const char *stageGateInputPinName(Stage stage);
|
||||
|
|
@ -167,8 +196,11 @@ private:
|
|||
const char *net_name_;
|
||||
float power_voltage_;
|
||||
float gnd_voltage_;
|
||||
LibertyLibrary *default_library_;
|
||||
// Resistance to use to simulate a short circuit between spice nodes.
|
||||
float short_ckt_resistance_;
|
||||
// Input clock waveform cycles.
|
||||
int clk_cycle_count_;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
|
@ -235,11 +267,12 @@ WritePathSpice::WritePathSpice(Path *path,
|
|||
gnd_name_(gnd_name),
|
||||
path_expanded_(sta),
|
||||
net_name_(NULL),
|
||||
short_ckt_resistance_(.0001)
|
||||
default_library_(network_->defaultLibertyLibrary()),
|
||||
short_ckt_resistance_(.0001),
|
||||
clk_cycle_count_(3)
|
||||
{
|
||||
auto lib = network_->defaultLibertyLibrary();
|
||||
power_voltage_ = lib->supplyVoltage(power_name_);
|
||||
gnd_voltage_ = lib->supplyVoltage(gnd_name_);
|
||||
power_voltage_ = default_library_->supplyVoltage(power_name_);
|
||||
gnd_voltage_ = default_library_->supplyVoltage(gnd_name_);
|
||||
}
|
||||
|
||||
WritePathSpice::~WritePathSpice()
|
||||
|
|
@ -274,7 +307,7 @@ WritePathSpice::writeHeader()
|
|||
auto min_max = path_->minMax(this);
|
||||
auto pvt = sdc_->operatingConditions(min_max);
|
||||
if (pvt == NULL)
|
||||
pvt = network_->defaultLibertyLibrary()->defaultOperatingConditions();
|
||||
pvt = default_library_->defaultOperatingConditions();
|
||||
auto temp = pvt->temperature();
|
||||
streamPrint(spice_stream_, ".temp %.1f\n", temp);
|
||||
streamPrint(spice_stream_, ".include \"%s\"\n", model_filename_);
|
||||
|
|
@ -291,12 +324,21 @@ WritePathSpice::maxTime()
|
|||
{
|
||||
auto input_stage = stageFirst();
|
||||
auto input_path = stageDrvrPath(input_stage);
|
||||
auto input_slew = input_path->slew(this);
|
||||
auto end_slew = path_->slew(this);
|
||||
auto max_time = delayAsFloat(input_slew
|
||||
+ path_->arrival(this)
|
||||
+ end_slew * 2) * 1.5;
|
||||
return max_time;
|
||||
auto input_slew = findSlew(input_path);
|
||||
if (input_path->isClock(this)) {
|
||||
auto clk = input_path->clock(this);
|
||||
auto period = clk->period();
|
||||
float first_edge_offset = period / 10;
|
||||
auto max_time = period * clk_cycle_count_ + first_edge_offset;
|
||||
return max_time;
|
||||
}
|
||||
else {
|
||||
auto end_slew = findSlew(path_);
|
||||
auto max_time = delayAsFloat(input_slew
|
||||
+ path_->arrival(this)
|
||||
+ end_slew * 2) * 1.5;
|
||||
return max_time;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -351,11 +393,36 @@ WritePathSpice::writeInputSource()
|
|||
streamPrint(spice_stream_, "**************\n\n");
|
||||
|
||||
auto input_stage = stageFirst();
|
||||
streamPrint(spice_stream_, "v1 %s 0 pwl(\n",
|
||||
stageDrvrPinName(input_stage));
|
||||
auto wire_arc = stageWireArc(input_stage);
|
||||
auto input_path = stageDrvrPath(input_stage);
|
||||
if (input_path->isClock(this))
|
||||
writeClkWaveform();
|
||||
else
|
||||
writeInputWaveform();
|
||||
streamPrint(spice_stream_, "\n");
|
||||
}
|
||||
|
||||
void
|
||||
WritePathSpice::writeInputWaveform()
|
||||
{
|
||||
auto input_stage = stageFirst();
|
||||
auto input_path = stageDrvrPath(input_stage);
|
||||
auto tr = input_path->transition(this);
|
||||
auto slew0 = findSlew(input_path, tr);
|
||||
// Arbitrary offset.
|
||||
auto time0 = slew0;
|
||||
int volt_index = 1;
|
||||
writeStepVoltSource(stageDrvrPin(input_stage), tr, slew0, time0, volt_index);
|
||||
}
|
||||
|
||||
void
|
||||
WritePathSpice::writeStepVoltSource(const Pin *pin,
|
||||
const TransRiseFall *tr,
|
||||
float slew,
|
||||
float time,
|
||||
int &volt_index)
|
||||
{
|
||||
float volt0, volt1;
|
||||
if (wire_arc->fromTrans()->asRiseFall() == TransRiseFall::rise()) {
|
||||
if (tr == TransRiseFall::rise()) {
|
||||
volt0 = gnd_voltage_;
|
||||
volt1 = power_voltage_;
|
||||
}
|
||||
|
|
@ -363,20 +430,114 @@ WritePathSpice::writeInputSource()
|
|||
volt0 = power_voltage_;
|
||||
volt1 = gnd_voltage_;
|
||||
}
|
||||
auto input_path = stageDrvrPath(input_stage);
|
||||
auto input_slew = delayAsFloat(input_path->slew(this));
|
||||
if (input_slew == 0.0)
|
||||
input_slew = maxTime() / 1e+3;
|
||||
// Arbitrary offset.
|
||||
auto time0 = input_slew;
|
||||
auto time1 = time0 + input_slew;
|
||||
streamPrint(spice_stream_, "v%d %s 0 pwl(\n",
|
||||
volt_index,
|
||||
network_->pathName(pin));
|
||||
streamPrint(spice_stream_, "+%.3e %.3e\n", 0.0, volt0);
|
||||
writeWaveformEdge(tr, time, slew);
|
||||
streamPrint(spice_stream_, "+%.3e %.3e\n", maxTime(), volt1);
|
||||
streamPrint(spice_stream_, "+)\n");
|
||||
volt_index++;
|
||||
}
|
||||
|
||||
void
|
||||
WritePathSpice::writeClkWaveform()
|
||||
{
|
||||
auto input_stage = stageFirst();
|
||||
auto input_path = stageDrvrPath(input_stage);
|
||||
auto clk_edge = input_path->clkEdge(this);
|
||||
auto clk = clk_edge->clock();
|
||||
auto period = clk->period();
|
||||
float time_offset = clkWaveformTImeOffset(clk);
|
||||
TransRiseFall *tr0, *tr1;
|
||||
float volt0;
|
||||
if (clk_edge->time() < period) {
|
||||
tr0 = TransRiseFall::rise();
|
||||
tr1 = TransRiseFall::fall();
|
||||
volt0 = gnd_voltage_;
|
||||
}
|
||||
else {
|
||||
tr0 = TransRiseFall::fall();
|
||||
tr1 = TransRiseFall::rise();
|
||||
volt0 = power_voltage_;
|
||||
}
|
||||
auto slew0 = findSlew(input_path, tr0);
|
||||
auto slew1 = findSlew(input_path, tr1);
|
||||
streamPrint(spice_stream_, "v1 %s 0 pwl(\n",
|
||||
stageDrvrPinName(input_stage));
|
||||
streamPrint(spice_stream_, "+%.3e %.3e\n", 0.0, volt0);
|
||||
for (int cycle = 0; cycle < clk_cycle_count_; cycle++) {
|
||||
auto time0 = time_offset + cycle * period;
|
||||
auto time1 = time0 + period / 2.0;
|
||||
writeWaveformEdge(tr0, time0, slew0);
|
||||
writeWaveformEdge(tr1, time1, slew1);
|
||||
}
|
||||
streamPrint(spice_stream_, "+%.3e %.3e\n", maxTime(), volt0);
|
||||
streamPrint(spice_stream_, "+)\n");
|
||||
}
|
||||
|
||||
float
|
||||
WritePathSpice::clkWaveformTImeOffset(const Clock *clk)
|
||||
{
|
||||
return clk->period() / 10;
|
||||
}
|
||||
|
||||
float
|
||||
WritePathSpice::findSlew(Path *path)
|
||||
{
|
||||
auto vertex = path->vertex(this);
|
||||
auto dcalc_ap_index = path->dcalcAnalysisPt(this)->index();
|
||||
auto tr = path->transition(this);
|
||||
return findSlew(vertex, tr, dcalc_ap_index);
|
||||
}
|
||||
|
||||
float
|
||||
WritePathSpice::findSlew(Path *path,
|
||||
const TransRiseFall *tr)
|
||||
{
|
||||
auto vertex = path->vertex(this);
|
||||
auto dcalc_ap_index = path->dcalcAnalysisPt(this)->index();
|
||||
return findSlew(vertex, tr, dcalc_ap_index);
|
||||
}
|
||||
|
||||
float
|
||||
WritePathSpice::findSlew(Vertex *vertex,
|
||||
const TransRiseFall *tr,
|
||||
DcalcAPIndex dcalc_ap_index)
|
||||
{
|
||||
auto slew = delayAsFloat(graph_->slew(vertex, tr, dcalc_ap_index));
|
||||
if (slew == 0.0)
|
||||
slew = units_->timeUnit()->scale();
|
||||
return slew;
|
||||
}
|
||||
|
||||
// Write PWL rise/fall edge that crosses threshold at time.
|
||||
void
|
||||
WritePathSpice::writeWaveformEdge(const TransRiseFall *tr,
|
||||
float time,
|
||||
float slew)
|
||||
{
|
||||
float volt0, volt1;
|
||||
if (tr == TransRiseFall::rise()) {
|
||||
volt0 = gnd_voltage_;
|
||||
volt1 = power_voltage_;
|
||||
}
|
||||
else {
|
||||
volt0 = power_voltage_;
|
||||
volt1 = gnd_voltage_;
|
||||
}
|
||||
auto threshold = default_library_->inputThreshold(tr);
|
||||
auto lower = default_library_->slewLowerThreshold(tr);
|
||||
auto upper = default_library_->slewUpperThreshold(tr);
|
||||
auto dt = slew / (upper - lower);
|
||||
auto time0 = time - dt * threshold;
|
||||
auto time1 = time0 + dt;
|
||||
streamPrint(spice_stream_, "+%.3e %.3e\n", time0, volt0);
|
||||
streamPrint(spice_stream_, "+%.3e %.3e\n", time1, volt1);
|
||||
streamPrint(spice_stream_, "+%.3e %.3e\n", maxTime(), volt1);
|
||||
streamPrint(spice_stream_, "+)\n\n");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
WritePathSpice::writeMeasureStmts()
|
||||
{
|
||||
|
|
@ -407,14 +568,13 @@ WritePathSpice::writeMeasureDelayStmt(Stage stage,
|
|||
Path *from_path,
|
||||
Path *to_path)
|
||||
{
|
||||
auto lib = network_->defaultLibertyLibrary();
|
||||
auto from_pin_name = network_->pathName(from_path->pin(this));
|
||||
auto from_tr = from_path->transition(this);
|
||||
auto from_threshold = power_voltage_ * lib->inputThreshold(from_tr);
|
||||
auto from_threshold = power_voltage_ * default_library_->inputThreshold(from_tr);
|
||||
|
||||
auto to_pin_name = network_->pathName(to_path->pin(this));
|
||||
auto to_tr = to_path->transition(this);
|
||||
auto to_threshold = power_voltage_ * lib->inputThreshold(to_tr);
|
||||
auto to_threshold = power_voltage_ * default_library_->inputThreshold(to_tr);
|
||||
streamPrint(spice_stream_,
|
||||
".measure tran %s_%s_delay_%s\n",
|
||||
stageName(stage).c_str(),
|
||||
|
|
@ -436,12 +596,11 @@ void
|
|||
WritePathSpice::writeMeasureSlewStmt(Stage stage,
|
||||
Path *path)
|
||||
{
|
||||
auto lib = network_->defaultLibertyLibrary();
|
||||
auto pin_name = network_->pathName(path->pin(this));
|
||||
auto tr = path->transition(this);
|
||||
auto spice_tr = spiceTrans(tr);
|
||||
auto lower = power_voltage_ * lib->slewLowerThreshold(tr);
|
||||
auto upper = power_voltage_ * lib->slewUpperThreshold(tr);
|
||||
auto lower = power_voltage_ * default_library_->slewLowerThreshold(tr);
|
||||
auto upper = power_voltage_ * default_library_->slewUpperThreshold(tr);
|
||||
float threshold1, threshold2;
|
||||
if (tr == TransRiseFall::rise()) {
|
||||
threshold1 = lower;
|
||||
|
|
@ -511,9 +670,8 @@ WritePathSpice::writeInputStage(Stage stage)
|
|||
void
|
||||
WritePathSpice::writeGateStage(Stage stage)
|
||||
{
|
||||
auto input_pin = stageInputPin(stage);
|
||||
auto input_pin = stageGateInputPin(stage);
|
||||
auto input_pin_name = stageGateInputPinName(stage);
|
||||
auto drvr_pin = stageDrvrPin(stage);
|
||||
auto drvr_pin_name = stageDrvrPinName(stage);
|
||||
auto load_pin_name = stageLoadPinName(stage);
|
||||
streamPrint(spice_stream_, ".subckt stage%d %s %s %s\n",
|
||||
|
|
@ -544,29 +702,54 @@ WritePathSpice::writeGateStage(Stage stage)
|
|||
}
|
||||
streamPrint(spice_stream_, " %s\n", cell_name);
|
||||
|
||||
writeStageVoltageSources(cell, spice_port_names,
|
||||
inst, inst_name,
|
||||
network_->libertyPort(input_pin),
|
||||
network_->libertyPort(drvr_pin));
|
||||
writeStageVoltageSources(stage, spice_port_names);
|
||||
writeStageParasitics(stage);
|
||||
streamPrint(spice_stream_, ".ends\n\n");
|
||||
}
|
||||
|
||||
// Power/ground and input voltage sources.
|
||||
void
|
||||
WritePathSpice::writeStageVoltageSources(LibertyCell *cell,
|
||||
StringVector *spice_port_names,
|
||||
const Instance *inst,
|
||||
const char *inst_name,
|
||||
LibertyPort *from_port,
|
||||
LibertyPort *drvr_port)
|
||||
WritePathSpice::writeStageVoltageSources(Stage stage,
|
||||
StringVector *spice_port_names)
|
||||
{
|
||||
auto from_port_name = from_port->name();
|
||||
auto input_pin = stageGateInputPin(stage);
|
||||
auto drvr_pin = stageDrvrPin(stage);
|
||||
auto input_port = network_->libertyPort(input_pin);
|
||||
auto drvr_port = network_->libertyPort(drvr_pin);
|
||||
auto input_port_name = input_port->name();
|
||||
auto drvr_port_name = drvr_port->name();
|
||||
auto lib = cell->libertyLibrary();
|
||||
auto inst = network_->instance(input_pin);
|
||||
auto inst_name = network_->pathName(inst);
|
||||
auto cell = network_->libertyCell(inst);
|
||||
auto gate_edge = stageGateEdge(stage);
|
||||
|
||||
LibertyPortLogicValues port_values;
|
||||
sensitizationValues(inst, drvr_port->function(), from_port, port_values);
|
||||
int volt_source = 1;
|
||||
const Clock *clk = NULL;
|
||||
DcalcAPIndex dcalc_ap_index = 0;
|
||||
if (gate_edge->role()->genericRole() == TimingRole::regClkToQ()) {
|
||||
auto drvr_expr = drvr_port->function();
|
||||
if (drvr_expr) {
|
||||
auto q_port = drvr_expr->port();
|
||||
if (q_port) {
|
||||
// Drvr (register/latch output) function should be a reference
|
||||
// to an internal port like IQ or IQN.
|
||||
auto seq = cell->outputPortSequential(q_port);
|
||||
if (seq) {
|
||||
auto drvr_path = stageDrvrPath(stage);
|
||||
auto drvr_tr = drvr_path->transition(this);
|
||||
seqSensitizationValues(seq, drvr_tr, port_values);
|
||||
clk = drvr_path->clock(this);
|
||||
dcalc_ap_index = drvr_path->dcalcAnalysisPt(this)->index();
|
||||
}
|
||||
else
|
||||
report_->error("no register/latch found for path from %s to %s,\n",
|
||||
input_port_name, drvr_port_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
sensitizationValues(inst, drvr_port->function(), input_port, port_values);
|
||||
int volt_index = 1;
|
||||
debugPrint1(debug_, "write_spice", 2, "subckt %s\n", cell->name());
|
||||
StringVector::Iterator port_iter(spice_port_names);
|
||||
while (port_iter.hasNext()) {
|
||||
|
|
@ -578,16 +761,15 @@ WritePathSpice::writeStageVoltageSources(LibertyCell *cell,
|
|||
if (pg_port) {
|
||||
auto voltage = pgPortVoltage(pg_port);
|
||||
streamPrint(spice_stream_, "v%d %s/%s 0 %.3f\n",
|
||||
volt_source,
|
||||
volt_index,
|
||||
inst_name, subckt_port_name,
|
||||
voltage);
|
||||
volt_source++;
|
||||
} else if (!(stringEq(subckt_port_name, from_port_name)
|
||||
volt_index++;
|
||||
} else if (!(stringEq(subckt_port_name, input_port_name)
|
||||
|| stringEq(subckt_port_name, drvr_port_name))) {
|
||||
// Input voltage to sensitize path from gate input to output.
|
||||
auto port = cell->findLibertyPort(subckt_port_name);
|
||||
if (port) {
|
||||
const char *pg_port_name = NULL;
|
||||
const Pin *pin = network_->findPin(inst, port);
|
||||
// Look for tie high/low or propagated constant values.
|
||||
LogicValue port_value = sim_->logicValue(pin);
|
||||
|
|
@ -598,43 +780,81 @@ WritePathSpice::writeStageVoltageSources(LibertyCell *cell,
|
|||
if (has_value)
|
||||
port_value = value;
|
||||
}
|
||||
if (port_value == logic_zero)
|
||||
pg_port_name = port->relatedGroundPin();
|
||||
else if (port_value == logic_one)
|
||||
pg_port_name = port->relatedPowerPin();
|
||||
if (pg_port_name) {
|
||||
auto pg_port = cell->findPgPort(pg_port_name);
|
||||
if (pg_port) {
|
||||
auto voltage_name = pg_port->voltageName();
|
||||
if (voltage_name) {
|
||||
float voltage = lib->supplyVoltage(voltage_name);
|
||||
streamPrint(spice_stream_, "v%d %s/%s 0 %.3f\n",
|
||||
volt_source,
|
||||
inst_name, subckt_port_name,
|
||||
voltage);
|
||||
volt_source++;
|
||||
}
|
||||
else
|
||||
report_->error("port %s %s voltage %s not found,\n",
|
||||
subckt_port_name,
|
||||
pg_port_name,
|
||||
voltage_name);
|
||||
}
|
||||
else
|
||||
report_->error("port %s %s not found,\n",
|
||||
subckt_port_name,
|
||||
pg_port_name);
|
||||
switch (port_value) {
|
||||
case logic_zero:
|
||||
writeVoltageSource(cell, inst_name, subckt_port_name,
|
||||
port->relatedGroundPin(),
|
||||
volt_index);
|
||||
break;
|
||||
case logic_one:
|
||||
writeVoltageSource(cell, inst_name, subckt_port_name,
|
||||
port->relatedPowerPin(),
|
||||
volt_index);
|
||||
break;
|
||||
case logic_rise:
|
||||
writeClkedStepSource(pin, TransRiseFall::rise(), clk,
|
||||
dcalc_ap_index, volt_index);
|
||||
break;
|
||||
case logic_fall:
|
||||
writeClkedStepSource(pin, TransRiseFall::fall(), clk,
|
||||
dcalc_ap_index, volt_index);
|
||||
break;
|
||||
case logic_unknown:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find the logic values for expression inputs to enable paths from_port.
|
||||
void
|
||||
WritePathSpice::writeClkedStepSource(const Pin *pin,
|
||||
const TransRiseFall *tr,
|
||||
const Clock *clk,
|
||||
DcalcAPIndex dcalc_ap_index,
|
||||
int &volt_index)
|
||||
{
|
||||
auto vertex = graph_->pinLoadVertex(pin);
|
||||
auto slew = findSlew(vertex, tr, dcalc_ap_index);
|
||||
auto time = clkWaveformTImeOffset(clk) + clk->period() / 2.0;
|
||||
writeStepVoltSource(pin, tr, slew, time, volt_index);
|
||||
}
|
||||
|
||||
void
|
||||
WritePathSpice::writeVoltageSource(LibertyCell *cell,
|
||||
const char *inst_name,
|
||||
const char *subckt_port_name,
|
||||
const char *pg_port_name,
|
||||
int &volt_index)
|
||||
{
|
||||
auto pg_port = cell->findPgPort(pg_port_name);
|
||||
if (pg_port) {
|
||||
auto voltage_name = pg_port->voltageName();
|
||||
if (voltage_name) {
|
||||
float voltage = cell->libertyLibrary()->supplyVoltage(voltage_name);
|
||||
streamPrint(spice_stream_, "v%d %s/%s 0 %.3f\n",
|
||||
volt_index,
|
||||
inst_name, subckt_port_name,
|
||||
voltage);
|
||||
volt_index++;
|
||||
}
|
||||
else
|
||||
report_->error("port %s %s voltage %s not found,\n",
|
||||
subckt_port_name,
|
||||
pg_port_name,
|
||||
voltage_name);
|
||||
}
|
||||
else
|
||||
report_->error("port %s %s not found,\n",
|
||||
subckt_port_name,
|
||||
pg_port_name);
|
||||
}
|
||||
|
||||
// Find the logic values for expression inputs to enable paths input_port.
|
||||
void
|
||||
WritePathSpice::sensitizationValues(const Instance *inst,
|
||||
FuncExpr *expr,
|
||||
LibertyPort *from_port,
|
||||
LibertyPort *input_port,
|
||||
// Return values.
|
||||
LibertyPortLogicValues &port_values)
|
||||
{
|
||||
|
|
@ -644,63 +864,63 @@ WritePathSpice::sensitizationValues(const Instance *inst,
|
|||
case FuncExpr::op_port:
|
||||
break;
|
||||
case FuncExpr::op_not:
|
||||
sensitizationValues(inst, expr->left(), from_port, port_values);
|
||||
sensitizationValues(inst, left, input_port, port_values);
|
||||
break;
|
||||
case FuncExpr::op_or:
|
||||
if (left->hasPort(from_port)
|
||||
if (left->hasPort(input_port)
|
||||
&& right->op() == FuncExpr::op_port)
|
||||
port_values[right->port()] = logic_zero;
|
||||
else if (left->hasPort(from_port)
|
||||
else if (left->hasPort(input_port)
|
||||
&& right->op() == FuncExpr::op_not
|
||||
&& right->left()->op() == FuncExpr::op_port)
|
||||
// from_port + !right_port
|
||||
// input_port + !right_port
|
||||
port_values[right->left()->port()] = logic_one;
|
||||
else if (right->hasPort(from_port)
|
||||
else if (right->hasPort(input_port)
|
||||
&& left->op() == FuncExpr::op_port)
|
||||
port_values[left->port()] = logic_zero;
|
||||
else if (right->hasPort(from_port)
|
||||
else if (right->hasPort(input_port)
|
||||
&& left->op() == FuncExpr::op_not
|
||||
&& left->left()->op() == FuncExpr::op_port)
|
||||
// from_port + !left_port
|
||||
// input_port + !left_port
|
||||
port_values[left->left()->port()] = logic_one;
|
||||
else {
|
||||
sensitizationValues(inst, expr->left(), from_port, port_values);
|
||||
sensitizationValues(inst, expr->right(), from_port, port_values);
|
||||
sensitizationValues(inst, left, input_port, port_values);
|
||||
sensitizationValues(inst, right, input_port, port_values);
|
||||
}
|
||||
break;
|
||||
case FuncExpr::op_and:
|
||||
if (left->hasPort(from_port)
|
||||
if (left->hasPort(input_port)
|
||||
&& right->op() == FuncExpr::op_port)
|
||||
port_values[right->port()] = logic_one;
|
||||
else if (left->hasPort(from_port)
|
||||
else if (left->hasPort(input_port)
|
||||
&& right->op() == FuncExpr::op_not
|
||||
&& right->left()->op() == FuncExpr::op_port)
|
||||
// from_port * !right_port
|
||||
// input_port * !right_port
|
||||
port_values[right->left()->port()] = logic_zero;
|
||||
else if (right->hasPort(from_port)
|
||||
else if (right->hasPort(input_port)
|
||||
&& left->op() == FuncExpr::op_port)
|
||||
port_values[left->port()] = logic_one;
|
||||
else if (right->hasPort(from_port)
|
||||
else if (right->hasPort(input_port)
|
||||
&& left->op() == FuncExpr::op_not
|
||||
&& left->left()->op() == FuncExpr::op_port)
|
||||
// from_port * !left_port
|
||||
// input_port * !left_port
|
||||
port_values[left->left()->port()] = logic_zero;
|
||||
else {
|
||||
sensitizationValues(inst, expr->left(), from_port, port_values);
|
||||
sensitizationValues(inst, expr->right(), from_port, port_values);
|
||||
sensitizationValues(inst, left, input_port, port_values);
|
||||
sensitizationValues(inst, right, input_port, port_values);
|
||||
}
|
||||
break;
|
||||
case FuncExpr::op_xor:
|
||||
// Need to know timing arc sense to get this right.
|
||||
if (left->port() == from_port
|
||||
if (left->port() == input_port
|
||||
&& right->op() == FuncExpr::op_port)
|
||||
port_values[right->port()] = logic_zero;
|
||||
else if (right->port() == from_port
|
||||
else if (right->port() == input_port
|
||||
&& left->op() == FuncExpr::op_port)
|
||||
port_values[left->port()] = logic_zero;
|
||||
else {
|
||||
sensitizationValues(inst, expr->left(), from_port, port_values);
|
||||
sensitizationValues(inst, expr->right(), from_port, port_values);
|
||||
sensitizationValues(inst, left, input_port, port_values);
|
||||
sensitizationValues(inst, right, input_port, port_values);
|
||||
}
|
||||
break;
|
||||
case FuncExpr::op_one:
|
||||
|
|
@ -709,6 +929,63 @@ WritePathSpice::sensitizationValues(const Instance *inst,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
WritePathSpice::seqSensitizationValues(Sequential *seq,
|
||||
const TransRiseFall *tr,
|
||||
// Return values.
|
||||
LibertyPortLogicValues &port_values)
|
||||
{
|
||||
auto data = seq->data();
|
||||
auto port = onePort(data);
|
||||
if (port) {
|
||||
auto sense = data->portTimingSense(port);
|
||||
switch (sense) {
|
||||
case timing_sense_positive_unate:
|
||||
if (tr == TransRiseFall::rise())
|
||||
port_values[port] = logic_rise;
|
||||
else
|
||||
port_values[port] = logic_fall;
|
||||
break;
|
||||
case timing_sense_negative_unate:
|
||||
if (tr == TransRiseFall::rise())
|
||||
port_values[port] = logic_fall;
|
||||
else
|
||||
port_values[port] = logic_rise;
|
||||
break;
|
||||
case timing_sense_non_unate:
|
||||
case timing_sense_none:
|
||||
case timing_sense_unknown:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pick a port, any port...
|
||||
LibertyPort *
|
||||
WritePathSpice::onePort(FuncExpr *expr)
|
||||
{
|
||||
auto left = expr->left();
|
||||
auto right = expr->right();
|
||||
LibertyPort *port;
|
||||
switch (expr->op()) {
|
||||
case FuncExpr::op_port:
|
||||
return expr->port();
|
||||
case FuncExpr::op_not:
|
||||
return onePort(left);
|
||||
case FuncExpr::op_or:
|
||||
case FuncExpr::op_and:
|
||||
case FuncExpr::op_xor:
|
||||
port = onePort(left);
|
||||
if (port == NULL)
|
||||
port = onePort(right);
|
||||
return port;
|
||||
case FuncExpr::op_one:
|
||||
case FuncExpr::op_zero:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
class ParasiticNodeNameLess
|
||||
{
|
||||
public:
|
||||
|
|
@ -1033,7 +1310,7 @@ WritePathSpice::stageWireArc(Stage stage)
|
|||
Edge *
|
||||
WritePathSpice::stageGateEdge(Stage stage)
|
||||
{
|
||||
auto path = stageGateInputPath(stage);
|
||||
auto path = stageDrvrPath(stage);
|
||||
auto arc = stageGateArc(stage);
|
||||
return path->prevEdge(arc, this);
|
||||
}
|
||||
|
|
@ -1047,7 +1324,7 @@ WritePathSpice::stageWireEdge(Stage stage)
|
|||
}
|
||||
|
||||
Pin *
|
||||
WritePathSpice::stageInputPin(Stage stage)
|
||||
WritePathSpice::stageGateInputPin(Stage stage)
|
||||
{
|
||||
auto path = stageGateInputPath(stage);
|
||||
return path->pin(this);
|
||||
|
|
@ -1070,7 +1347,7 @@ WritePathSpice::stageLoadPin(Stage stage)
|
|||
const char *
|
||||
WritePathSpice::stageGateInputPinName(Stage stage)
|
||||
{
|
||||
auto pin = stageInputPin(stage);
|
||||
auto pin = stageGateInputPin(stage);
|
||||
return network_->pathName(pin);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue