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.
|
# Copyright (c) 2019, Parallax Software, Inc.
|
||||||
# All rights reserved.
|
|
||||||
#
|
#
|
||||||
# No part of this document may be copied, transmitted or
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# disclosed in any form or fashion without the express
|
# it under the terms of the GNU General Public License as published by
|
||||||
# written consent of Parallax Software, Inc.
|
# 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)
|
cmake_minimum_required (VERSION 3.9)
|
||||||
|
|
||||||
|
|
@ -205,7 +213,6 @@ set(STA_SOURCE
|
||||||
verilog/VerilogReader.cc
|
verilog/VerilogReader.cc
|
||||||
verilog/VerilogLex.cc
|
verilog/VerilogLex.cc
|
||||||
verilog/VerilogParse.cc
|
verilog/VerilogParse.cc
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(STA_HEADERS
|
set(STA_HEADERS
|
||||||
|
|
@ -707,3 +714,10 @@ install(TARGETS OpenSTA DESTINATION lib)
|
||||||
|
|
||||||
# include
|
# include
|
||||||
install(FILES ${STA_HEADERS} DESTINATION 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
|
See README.MD for installation instructions.
|
||||||
# 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.
|
|
||||||
|
|
|
||||||
70
README
70
README
|
|
@ -1,69 +1 @@
|
||||||
# OpenSTA, Static Timing Analyzer
|
See README.MD
|
||||||
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
|
|
||||||
|
|
|
||||||
293
README.md
293
README.md
|
|
@ -1,49 +1,19 @@
|
||||||
# OpenSTA, Static Timing Analyzer
|
# Parallax Static Timing Analyzer
|
||||||
Copyright (c) 2019, Parallax Software, Inc.
|
|
||||||
|
|
||||||
> This program is free software: you can redistribute it and/or modify
|
OpenSTA is a gate level static timing verifier. As a stand-alone
|
||||||
> it under the terms of the GNU General Public License as published by
|
executable it can be used to verify the timing of a design using
|
||||||
> the Free Software Foundation, either version 3 of the License, or
|
standard file formats.
|
||||||
> (at your option) any later version.
|
|
||||||
|
|
||||||
> This program is distributed in the hope that it will be useful,
|
* Verilog netlist
|
||||||
> but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* Liberty library
|
||||||
> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* SDC timing constraints
|
||||||
> GNU General Public License for more details.
|
* SDF delay annotation
|
||||||
|
* SPEF parasitics
|
||||||
|
|
||||||
> You should have received a copy of the GNU General Public License
|
OpenSTA uses a TCL command interpreter to read the design, specify
|
||||||
> along with this program. If not, see <https://www.gnu.org/licenses/>.
|
timing constraints and print timing reports.
|
||||||
|
|
||||||
Parallax Gate Level Static Timing Analyzer
|
##### Clocks
|
||||||
|
|
||||||
## 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
|
|
||||||
* Generated
|
* Generated
|
||||||
* Latency
|
* Latency
|
||||||
* Source latency (insertion delay)
|
* Source latency (insertion delay)
|
||||||
|
|
@ -52,18 +22,247 @@ See INSTALL for installation and build instructions. Alternatively, run using Do
|
||||||
* Gated clock checks
|
* Gated clock checks
|
||||||
* Multiple frequency clocks
|
* 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
|
* Integrated Dartu/Menezes/Pileggi RC effective capacitance algorithm
|
||||||
* External delay calculator API
|
* External delay calculator API
|
||||||
|
|
||||||
## Analysis
|
##### Analysis
|
||||||
* Report timing checks -from, -through, -to, multiple paths to endpoint
|
* Report timing checks -from, -through, -to, multiple paths to endpoint
|
||||||
* Report delay calculation
|
* Report delay calculation
|
||||||
* Check timing setup
|
* 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
|
* Query based incremental update of delays, arrival and required times
|
||||||
* Simulator to propagate constants from constraints and netlist tie high/low
|
* Simulator to propagate constants from constraints and netlist tie high/low
|
||||||
|
|
||||||
## Timing engine library
|
See doc/OpenSTA.pdf for complete documentiaton.
|
||||||
* Network adapter uses external netlist database without duplicating any data
|
|
||||||
|
## 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.
|
// Delete expression and all of its subexpressions.
|
||||||
void deleteSubexprs();
|
void deleteSubexprs();
|
||||||
|
// op == op_port
|
||||||
LibertyPort *port() const;
|
LibertyPort *port() const;
|
||||||
Operator op() const { return op_; }
|
Operator op() const { return op_; }
|
||||||
// When operator is NOT left is the only operand.
|
// When operator is NOT left is the only operand.
|
||||||
FuncExpr *left() const { return left_; }
|
FuncExpr *left() const { return left_; }
|
||||||
|
// NULL when op == op_not
|
||||||
FuncExpr *right() const { return right_; }
|
FuncExpr *right() const { return right_; }
|
||||||
TimingSense portTimingSense(const LibertyPort *port) const;
|
TimingSense portTimingSense(const LibertyPort *port) const;
|
||||||
// Return true if expression has port as an input.
|
// Return true if expression has port as an input.
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
#include "StringUtil.hh"
|
#include "StringUtil.hh"
|
||||||
#include "FuncExpr.hh"
|
#include "FuncExpr.hh"
|
||||||
#include "Units.hh"
|
#include "Units.hh"
|
||||||
|
#include "Sequential.hh"
|
||||||
#include "Liberty.hh"
|
#include "Liberty.hh"
|
||||||
#include "TimingArc.hh"
|
#include "TimingArc.hh"
|
||||||
#include "Network.hh"
|
#include "Network.hh"
|
||||||
|
|
@ -83,17 +84,18 @@ private:
|
||||||
void writeHeader();
|
void writeHeader();
|
||||||
void writeStageInstances();
|
void writeStageInstances();
|
||||||
void writeInputSource();
|
void writeInputSource();
|
||||||
|
void writeStepVoltSource(const Pin *pin,
|
||||||
|
const TransRiseFall *tr,
|
||||||
|
float slew,
|
||||||
|
float time,
|
||||||
|
int &volt_index);
|
||||||
void writeStageSubckts();
|
void writeStageSubckts();
|
||||||
void writeInputStage(Stage stage);
|
void writeInputStage(Stage stage);
|
||||||
void writeMeasureStmts();
|
void writeMeasureStmts();
|
||||||
void writeMeasureStmt(const Pin *pin);
|
void writeMeasureStmt(const Pin *pin);
|
||||||
void writeGateStage(Stage stage);
|
void writeGateStage(Stage stage);
|
||||||
void writeStageVoltageSources(LibertyCell *cell,
|
void writeStageVoltageSources(Stage stage,
|
||||||
StringVector *spice_port_names,
|
StringVector *spice_port_names);
|
||||||
const Instance *inst,
|
|
||||||
const char *inst_name,
|
|
||||||
LibertyPort *from_port,
|
|
||||||
LibertyPort *drvr_port);
|
|
||||||
void writeStageParasitics(Stage stage);
|
void writeStageParasitics(Stage stage);
|
||||||
void writeSubckts();
|
void writeSubckts();
|
||||||
void findPathCellnames(// Return values.
|
void findPathCellnames(// Return values.
|
||||||
|
|
@ -114,9 +116,36 @@ private:
|
||||||
Path *path);
|
Path *path);
|
||||||
void sensitizationValues(const Instance *inst,
|
void sensitizationValues(const Instance *inst,
|
||||||
FuncExpr *expr,
|
FuncExpr *expr,
|
||||||
LibertyPort *from_port,
|
LibertyPort *input_port,
|
||||||
// Return values.
|
// Return values.
|
||||||
LibertyPortLogicValues &port_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".
|
// Stage "accessors".
|
||||||
//
|
//
|
||||||
|
|
@ -144,7 +173,7 @@ private:
|
||||||
TimingArc *stageWireArc(Stage stage);
|
TimingArc *stageWireArc(Stage stage);
|
||||||
Edge *stageGateEdge(Stage stage);
|
Edge *stageGateEdge(Stage stage);
|
||||||
Edge *stageWireEdge(Stage stage);
|
Edge *stageWireEdge(Stage stage);
|
||||||
Pin *stageInputPin(Stage stage);
|
Pin *stageGateInputPin(Stage stage);
|
||||||
Pin *stageDrvrPin(Stage stage);
|
Pin *stageDrvrPin(Stage stage);
|
||||||
Pin *stageLoadPin(Stage stage);
|
Pin *stageLoadPin(Stage stage);
|
||||||
const char *stageGateInputPinName(Stage stage);
|
const char *stageGateInputPinName(Stage stage);
|
||||||
|
|
@ -167,8 +196,11 @@ private:
|
||||||
const char *net_name_;
|
const char *net_name_;
|
||||||
float power_voltage_;
|
float power_voltage_;
|
||||||
float gnd_voltage_;
|
float gnd_voltage_;
|
||||||
|
LibertyLibrary *default_library_;
|
||||||
// Resistance to use to simulate a short circuit between spice nodes.
|
// Resistance to use to simulate a short circuit between spice nodes.
|
||||||
float short_ckt_resistance_;
|
float short_ckt_resistance_;
|
||||||
|
// Input clock waveform cycles.
|
||||||
|
int clk_cycle_count_;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
@ -235,11 +267,12 @@ WritePathSpice::WritePathSpice(Path *path,
|
||||||
gnd_name_(gnd_name),
|
gnd_name_(gnd_name),
|
||||||
path_expanded_(sta),
|
path_expanded_(sta),
|
||||||
net_name_(NULL),
|
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_ = default_library_->supplyVoltage(power_name_);
|
||||||
power_voltage_ = lib->supplyVoltage(power_name_);
|
gnd_voltage_ = default_library_->supplyVoltage(gnd_name_);
|
||||||
gnd_voltage_ = lib->supplyVoltage(gnd_name_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WritePathSpice::~WritePathSpice()
|
WritePathSpice::~WritePathSpice()
|
||||||
|
|
@ -274,7 +307,7 @@ WritePathSpice::writeHeader()
|
||||||
auto min_max = path_->minMax(this);
|
auto min_max = path_->minMax(this);
|
||||||
auto pvt = sdc_->operatingConditions(min_max);
|
auto pvt = sdc_->operatingConditions(min_max);
|
||||||
if (pvt == NULL)
|
if (pvt == NULL)
|
||||||
pvt = network_->defaultLibertyLibrary()->defaultOperatingConditions();
|
pvt = default_library_->defaultOperatingConditions();
|
||||||
auto temp = pvt->temperature();
|
auto temp = pvt->temperature();
|
||||||
streamPrint(spice_stream_, ".temp %.1f\n", temp);
|
streamPrint(spice_stream_, ".temp %.1f\n", temp);
|
||||||
streamPrint(spice_stream_, ".include \"%s\"\n", model_filename_);
|
streamPrint(spice_stream_, ".include \"%s\"\n", model_filename_);
|
||||||
|
|
@ -291,13 +324,22 @@ WritePathSpice::maxTime()
|
||||||
{
|
{
|
||||||
auto input_stage = stageFirst();
|
auto input_stage = stageFirst();
|
||||||
auto input_path = stageDrvrPath(input_stage);
|
auto input_path = stageDrvrPath(input_stage);
|
||||||
auto input_slew = input_path->slew(this);
|
auto input_slew = findSlew(input_path);
|
||||||
auto end_slew = path_->slew(this);
|
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
|
auto max_time = delayAsFloat(input_slew
|
||||||
+ path_->arrival(this)
|
+ path_->arrival(this)
|
||||||
+ end_slew * 2) * 1.5;
|
+ end_slew * 2) * 1.5;
|
||||||
return max_time;
|
return max_time;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
WritePathSpice::writeStageInstances()
|
WritePathSpice::writeStageInstances()
|
||||||
|
|
@ -351,11 +393,36 @@ WritePathSpice::writeInputSource()
|
||||||
streamPrint(spice_stream_, "**************\n\n");
|
streamPrint(spice_stream_, "**************\n\n");
|
||||||
|
|
||||||
auto input_stage = stageFirst();
|
auto input_stage = stageFirst();
|
||||||
streamPrint(spice_stream_, "v1 %s 0 pwl(\n",
|
auto input_path = stageDrvrPath(input_stage);
|
||||||
stageDrvrPinName(input_stage));
|
if (input_path->isClock(this))
|
||||||
auto wire_arc = stageWireArc(input_stage);
|
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;
|
float volt0, volt1;
|
||||||
if (wire_arc->fromTrans()->asRiseFall() == TransRiseFall::rise()) {
|
if (tr == TransRiseFall::rise()) {
|
||||||
volt0 = gnd_voltage_;
|
volt0 = gnd_voltage_;
|
||||||
volt1 = power_voltage_;
|
volt1 = power_voltage_;
|
||||||
}
|
}
|
||||||
|
|
@ -363,20 +430,114 @@ WritePathSpice::writeInputSource()
|
||||||
volt0 = power_voltage_;
|
volt0 = power_voltage_;
|
||||||
volt1 = gnd_voltage_;
|
volt1 = gnd_voltage_;
|
||||||
}
|
}
|
||||||
auto input_path = stageDrvrPath(input_stage);
|
streamPrint(spice_stream_, "v%d %s 0 pwl(\n",
|
||||||
auto input_slew = delayAsFloat(input_path->slew(this));
|
volt_index,
|
||||||
if (input_slew == 0.0)
|
network_->pathName(pin));
|
||||||
input_slew = maxTime() / 1e+3;
|
|
||||||
// Arbitrary offset.
|
|
||||||
auto time0 = input_slew;
|
|
||||||
auto time1 = time0 + input_slew;
|
|
||||||
streamPrint(spice_stream_, "+%.3e %.3e\n", 0.0, volt0);
|
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", time0, volt0);
|
||||||
streamPrint(spice_stream_, "+%.3e %.3e\n", time1, volt1);
|
streamPrint(spice_stream_, "+%.3e %.3e\n", time1, volt1);
|
||||||
streamPrint(spice_stream_, "+%.3e %.3e\n", maxTime(), volt1);
|
|
||||||
streamPrint(spice_stream_, "+)\n\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void
|
void
|
||||||
WritePathSpice::writeMeasureStmts()
|
WritePathSpice::writeMeasureStmts()
|
||||||
{
|
{
|
||||||
|
|
@ -407,14 +568,13 @@ WritePathSpice::writeMeasureDelayStmt(Stage stage,
|
||||||
Path *from_path,
|
Path *from_path,
|
||||||
Path *to_path)
|
Path *to_path)
|
||||||
{
|
{
|
||||||
auto lib = network_->defaultLibertyLibrary();
|
|
||||||
auto from_pin_name = network_->pathName(from_path->pin(this));
|
auto from_pin_name = network_->pathName(from_path->pin(this));
|
||||||
auto from_tr = from_path->transition(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_pin_name = network_->pathName(to_path->pin(this));
|
||||||
auto to_tr = to_path->transition(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_,
|
streamPrint(spice_stream_,
|
||||||
".measure tran %s_%s_delay_%s\n",
|
".measure tran %s_%s_delay_%s\n",
|
||||||
stageName(stage).c_str(),
|
stageName(stage).c_str(),
|
||||||
|
|
@ -436,12 +596,11 @@ void
|
||||||
WritePathSpice::writeMeasureSlewStmt(Stage stage,
|
WritePathSpice::writeMeasureSlewStmt(Stage stage,
|
||||||
Path *path)
|
Path *path)
|
||||||
{
|
{
|
||||||
auto lib = network_->defaultLibertyLibrary();
|
|
||||||
auto pin_name = network_->pathName(path->pin(this));
|
auto pin_name = network_->pathName(path->pin(this));
|
||||||
auto tr = path->transition(this);
|
auto tr = path->transition(this);
|
||||||
auto spice_tr = spiceTrans(tr);
|
auto spice_tr = spiceTrans(tr);
|
||||||
auto lower = power_voltage_ * lib->slewLowerThreshold(tr);
|
auto lower = power_voltage_ * default_library_->slewLowerThreshold(tr);
|
||||||
auto upper = power_voltage_ * lib->slewUpperThreshold(tr);
|
auto upper = power_voltage_ * default_library_->slewUpperThreshold(tr);
|
||||||
float threshold1, threshold2;
|
float threshold1, threshold2;
|
||||||
if (tr == TransRiseFall::rise()) {
|
if (tr == TransRiseFall::rise()) {
|
||||||
threshold1 = lower;
|
threshold1 = lower;
|
||||||
|
|
@ -511,9 +670,8 @@ WritePathSpice::writeInputStage(Stage stage)
|
||||||
void
|
void
|
||||||
WritePathSpice::writeGateStage(Stage stage)
|
WritePathSpice::writeGateStage(Stage stage)
|
||||||
{
|
{
|
||||||
auto input_pin = stageInputPin(stage);
|
auto input_pin = stageGateInputPin(stage);
|
||||||
auto input_pin_name = stageGateInputPinName(stage);
|
auto input_pin_name = stageGateInputPinName(stage);
|
||||||
auto drvr_pin = stageDrvrPin(stage);
|
|
||||||
auto drvr_pin_name = stageDrvrPinName(stage);
|
auto drvr_pin_name = stageDrvrPinName(stage);
|
||||||
auto load_pin_name = stageLoadPinName(stage);
|
auto load_pin_name = stageLoadPinName(stage);
|
||||||
streamPrint(spice_stream_, ".subckt stage%d %s %s %s\n",
|
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);
|
streamPrint(spice_stream_, " %s\n", cell_name);
|
||||||
|
|
||||||
writeStageVoltageSources(cell, spice_port_names,
|
writeStageVoltageSources(stage, spice_port_names);
|
||||||
inst, inst_name,
|
|
||||||
network_->libertyPort(input_pin),
|
|
||||||
network_->libertyPort(drvr_pin));
|
|
||||||
writeStageParasitics(stage);
|
writeStageParasitics(stage);
|
||||||
streamPrint(spice_stream_, ".ends\n\n");
|
streamPrint(spice_stream_, ".ends\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Power/ground and input voltage sources.
|
// Power/ground and input voltage sources.
|
||||||
void
|
void
|
||||||
WritePathSpice::writeStageVoltageSources(LibertyCell *cell,
|
WritePathSpice::writeStageVoltageSources(Stage stage,
|
||||||
StringVector *spice_port_names,
|
StringVector *spice_port_names)
|
||||||
const Instance *inst,
|
|
||||||
const char *inst_name,
|
|
||||||
LibertyPort *from_port,
|
|
||||||
LibertyPort *drvr_port)
|
|
||||||
{
|
{
|
||||||
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 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;
|
LibertyPortLogicValues port_values;
|
||||||
sensitizationValues(inst, drvr_port->function(), from_port, port_values);
|
const Clock *clk = NULL;
|
||||||
int volt_source = 1;
|
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());
|
debugPrint1(debug_, "write_spice", 2, "subckt %s\n", cell->name());
|
||||||
StringVector::Iterator port_iter(spice_port_names);
|
StringVector::Iterator port_iter(spice_port_names);
|
||||||
while (port_iter.hasNext()) {
|
while (port_iter.hasNext()) {
|
||||||
|
|
@ -578,16 +761,15 @@ WritePathSpice::writeStageVoltageSources(LibertyCell *cell,
|
||||||
if (pg_port) {
|
if (pg_port) {
|
||||||
auto voltage = pgPortVoltage(pg_port);
|
auto voltage = pgPortVoltage(pg_port);
|
||||||
streamPrint(spice_stream_, "v%d %s/%s 0 %.3f\n",
|
streamPrint(spice_stream_, "v%d %s/%s 0 %.3f\n",
|
||||||
volt_source,
|
volt_index,
|
||||||
inst_name, subckt_port_name,
|
inst_name, subckt_port_name,
|
||||||
voltage);
|
voltage);
|
||||||
volt_source++;
|
volt_index++;
|
||||||
} else if (!(stringEq(subckt_port_name, from_port_name)
|
} else if (!(stringEq(subckt_port_name, input_port_name)
|
||||||
|| stringEq(subckt_port_name, drvr_port_name))) {
|
|| stringEq(subckt_port_name, drvr_port_name))) {
|
||||||
// Input voltage to sensitize path from gate input to output.
|
// Input voltage to sensitize path from gate input to output.
|
||||||
auto port = cell->findLibertyPort(subckt_port_name);
|
auto port = cell->findLibertyPort(subckt_port_name);
|
||||||
if (port) {
|
if (port) {
|
||||||
const char *pg_port_name = NULL;
|
|
||||||
const Pin *pin = network_->findPin(inst, port);
|
const Pin *pin = network_->findPin(inst, port);
|
||||||
// Look for tie high/low or propagated constant values.
|
// Look for tie high/low or propagated constant values.
|
||||||
LogicValue port_value = sim_->logicValue(pin);
|
LogicValue port_value = sim_->logicValue(pin);
|
||||||
|
|
@ -598,21 +780,63 @@ WritePathSpice::writeStageVoltageSources(LibertyCell *cell,
|
||||||
if (has_value)
|
if (has_value)
|
||||||
port_value = value;
|
port_value = value;
|
||||||
}
|
}
|
||||||
if (port_value == logic_zero)
|
switch (port_value) {
|
||||||
pg_port_name = port->relatedGroundPin();
|
case logic_zero:
|
||||||
else if (port_value == logic_one)
|
writeVoltageSource(cell, inst_name, subckt_port_name,
|
||||||
pg_port_name = port->relatedPowerPin();
|
port->relatedGroundPin(),
|
||||||
if (pg_port_name) {
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
auto pg_port = cell->findPgPort(pg_port_name);
|
||||||
if (pg_port) {
|
if (pg_port) {
|
||||||
auto voltage_name = pg_port->voltageName();
|
auto voltage_name = pg_port->voltageName();
|
||||||
if (voltage_name) {
|
if (voltage_name) {
|
||||||
float voltage = lib->supplyVoltage(voltage_name);
|
float voltage = cell->libertyLibrary()->supplyVoltage(voltage_name);
|
||||||
streamPrint(spice_stream_, "v%d %s/%s 0 %.3f\n",
|
streamPrint(spice_stream_, "v%d %s/%s 0 %.3f\n",
|
||||||
volt_source,
|
volt_index,
|
||||||
inst_name, subckt_port_name,
|
inst_name, subckt_port_name,
|
||||||
voltage);
|
voltage);
|
||||||
volt_source++;
|
volt_index++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
report_->error("port %s %s voltage %s not found,\n",
|
report_->error("port %s %s voltage %s not found,\n",
|
||||||
|
|
@ -625,16 +849,12 @@ WritePathSpice::writeStageVoltageSources(LibertyCell *cell,
|
||||||
subckt_port_name,
|
subckt_port_name,
|
||||||
pg_port_name);
|
pg_port_name);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the logic values for expression inputs to enable paths from_port.
|
// Find the logic values for expression inputs to enable paths input_port.
|
||||||
void
|
void
|
||||||
WritePathSpice::sensitizationValues(const Instance *inst,
|
WritePathSpice::sensitizationValues(const Instance *inst,
|
||||||
FuncExpr *expr,
|
FuncExpr *expr,
|
||||||
LibertyPort *from_port,
|
LibertyPort *input_port,
|
||||||
// Return values.
|
// Return values.
|
||||||
LibertyPortLogicValues &port_values)
|
LibertyPortLogicValues &port_values)
|
||||||
{
|
{
|
||||||
|
|
@ -644,63 +864,63 @@ WritePathSpice::sensitizationValues(const Instance *inst,
|
||||||
case FuncExpr::op_port:
|
case FuncExpr::op_port:
|
||||||
break;
|
break;
|
||||||
case FuncExpr::op_not:
|
case FuncExpr::op_not:
|
||||||
sensitizationValues(inst, expr->left(), from_port, port_values);
|
sensitizationValues(inst, left, input_port, port_values);
|
||||||
break;
|
break;
|
||||||
case FuncExpr::op_or:
|
case FuncExpr::op_or:
|
||||||
if (left->hasPort(from_port)
|
if (left->hasPort(input_port)
|
||||||
&& right->op() == FuncExpr::op_port)
|
&& right->op() == FuncExpr::op_port)
|
||||||
port_values[right->port()] = logic_zero;
|
port_values[right->port()] = logic_zero;
|
||||||
else if (left->hasPort(from_port)
|
else if (left->hasPort(input_port)
|
||||||
&& right->op() == FuncExpr::op_not
|
&& right->op() == FuncExpr::op_not
|
||||||
&& right->left()->op() == FuncExpr::op_port)
|
&& right->left()->op() == FuncExpr::op_port)
|
||||||
// from_port + !right_port
|
// input_port + !right_port
|
||||||
port_values[right->left()->port()] = logic_one;
|
port_values[right->left()->port()] = logic_one;
|
||||||
else if (right->hasPort(from_port)
|
else if (right->hasPort(input_port)
|
||||||
&& left->op() == FuncExpr::op_port)
|
&& left->op() == FuncExpr::op_port)
|
||||||
port_values[left->port()] = logic_zero;
|
port_values[left->port()] = logic_zero;
|
||||||
else if (right->hasPort(from_port)
|
else if (right->hasPort(input_port)
|
||||||
&& left->op() == FuncExpr::op_not
|
&& left->op() == FuncExpr::op_not
|
||||||
&& left->left()->op() == FuncExpr::op_port)
|
&& left->left()->op() == FuncExpr::op_port)
|
||||||
// from_port + !left_port
|
// input_port + !left_port
|
||||||
port_values[left->left()->port()] = logic_one;
|
port_values[left->left()->port()] = logic_one;
|
||||||
else {
|
else {
|
||||||
sensitizationValues(inst, expr->left(), from_port, port_values);
|
sensitizationValues(inst, left, input_port, port_values);
|
||||||
sensitizationValues(inst, expr->right(), from_port, port_values);
|
sensitizationValues(inst, right, input_port, port_values);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FuncExpr::op_and:
|
case FuncExpr::op_and:
|
||||||
if (left->hasPort(from_port)
|
if (left->hasPort(input_port)
|
||||||
&& right->op() == FuncExpr::op_port)
|
&& right->op() == FuncExpr::op_port)
|
||||||
port_values[right->port()] = logic_one;
|
port_values[right->port()] = logic_one;
|
||||||
else if (left->hasPort(from_port)
|
else if (left->hasPort(input_port)
|
||||||
&& right->op() == FuncExpr::op_not
|
&& right->op() == FuncExpr::op_not
|
||||||
&& right->left()->op() == FuncExpr::op_port)
|
&& right->left()->op() == FuncExpr::op_port)
|
||||||
// from_port * !right_port
|
// input_port * !right_port
|
||||||
port_values[right->left()->port()] = logic_zero;
|
port_values[right->left()->port()] = logic_zero;
|
||||||
else if (right->hasPort(from_port)
|
else if (right->hasPort(input_port)
|
||||||
&& left->op() == FuncExpr::op_port)
|
&& left->op() == FuncExpr::op_port)
|
||||||
port_values[left->port()] = logic_one;
|
port_values[left->port()] = logic_one;
|
||||||
else if (right->hasPort(from_port)
|
else if (right->hasPort(input_port)
|
||||||
&& left->op() == FuncExpr::op_not
|
&& left->op() == FuncExpr::op_not
|
||||||
&& left->left()->op() == FuncExpr::op_port)
|
&& left->left()->op() == FuncExpr::op_port)
|
||||||
// from_port * !left_port
|
// input_port * !left_port
|
||||||
port_values[left->left()->port()] = logic_zero;
|
port_values[left->left()->port()] = logic_zero;
|
||||||
else {
|
else {
|
||||||
sensitizationValues(inst, expr->left(), from_port, port_values);
|
sensitizationValues(inst, left, input_port, port_values);
|
||||||
sensitizationValues(inst, expr->right(), from_port, port_values);
|
sensitizationValues(inst, right, input_port, port_values);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FuncExpr::op_xor:
|
case FuncExpr::op_xor:
|
||||||
// Need to know timing arc sense to get this right.
|
// 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)
|
&& right->op() == FuncExpr::op_port)
|
||||||
port_values[right->port()] = logic_zero;
|
port_values[right->port()] = logic_zero;
|
||||||
else if (right->port() == from_port
|
else if (right->port() == input_port
|
||||||
&& left->op() == FuncExpr::op_port)
|
&& left->op() == FuncExpr::op_port)
|
||||||
port_values[left->port()] = logic_zero;
|
port_values[left->port()] = logic_zero;
|
||||||
else {
|
else {
|
||||||
sensitizationValues(inst, expr->left(), from_port, port_values);
|
sensitizationValues(inst, left, input_port, port_values);
|
||||||
sensitizationValues(inst, expr->right(), from_port, port_values);
|
sensitizationValues(inst, right, input_port, port_values);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FuncExpr::op_one:
|
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
|
class ParasiticNodeNameLess
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -1033,7 +1310,7 @@ WritePathSpice::stageWireArc(Stage stage)
|
||||||
Edge *
|
Edge *
|
||||||
WritePathSpice::stageGateEdge(Stage stage)
|
WritePathSpice::stageGateEdge(Stage stage)
|
||||||
{
|
{
|
||||||
auto path = stageGateInputPath(stage);
|
auto path = stageDrvrPath(stage);
|
||||||
auto arc = stageGateArc(stage);
|
auto arc = stageGateArc(stage);
|
||||||
return path->prevEdge(arc, this);
|
return path->prevEdge(arc, this);
|
||||||
}
|
}
|
||||||
|
|
@ -1047,7 +1324,7 @@ WritePathSpice::stageWireEdge(Stage stage)
|
||||||
}
|
}
|
||||||
|
|
||||||
Pin *
|
Pin *
|
||||||
WritePathSpice::stageInputPin(Stage stage)
|
WritePathSpice::stageGateInputPin(Stage stage)
|
||||||
{
|
{
|
||||||
auto path = stageGateInputPath(stage);
|
auto path = stageGateInputPath(stage);
|
||||||
return path->pin(this);
|
return path->pin(this);
|
||||||
|
|
@ -1070,7 +1347,7 @@ WritePathSpice::stageLoadPin(Stage stage)
|
||||||
const char *
|
const char *
|
||||||
WritePathSpice::stageGateInputPinName(Stage stage)
|
WritePathSpice::stageGateInputPinName(Stage stage)
|
||||||
{
|
{
|
||||||
auto pin = stageInputPin(stage);
|
auto pin = stageGateInputPin(stage);
|
||||||
return network_->pathName(pin);
|
return network_->pathName(pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue