Merge branch 'master' into master
This commit is contained in:
commit
2c928b7f51
|
|
@ -1,22 +1,14 @@
|
|||
# OpenSTA, Static Timing Analyzer
|
||||
# Parallax Static Timing Analyzer
|
||||
# Copyright (c) 2019, Parallax Software, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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/>.
|
||||
# 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.
|
||||
|
||||
cmake_minimum_required (VERSION 3.9)
|
||||
|
||||
project(STA VERSION 2.0.4)
|
||||
project(STA VERSION 2.0.5)
|
||||
|
||||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
|
@ -113,19 +105,12 @@ set(STA_SOURCE
|
|||
parasitics/EstimateParasitics.cc
|
||||
parasitics/NullParasitics.cc
|
||||
parasitics/Parasitics.cc
|
||||
parasitics/ReadParasitics.cc
|
||||
parasitics/ReduceParasitics.cc
|
||||
parasitics/SpefLex.cc
|
||||
parasitics/SpefNamespace.cc
|
||||
parasitics/SpefParse.cc
|
||||
parasitics/SpefReader.cc
|
||||
parasitics/SpefReaderPvt.hh
|
||||
parasitics/SpfLex.cc
|
||||
parasitics/SpfParse.cc
|
||||
parasitics/SpfReader.cc
|
||||
parasitics/SpfReaderPvt.hh
|
||||
parasitics/SpfSpefReader.cc
|
||||
parasitics/SpfSpefReader.cc
|
||||
|
||||
sdc/Clock.cc
|
||||
sdc/ClockGatingCheck.cc
|
||||
|
|
@ -288,11 +273,9 @@ set(STA_HEADERS
|
|||
parasitics/NullParasitics.hh
|
||||
parasitics/Parasitics.hh
|
||||
parasitics/ParasiticsClass.hh
|
||||
parasitics/ReadParasitics.hh
|
||||
parasitics/ReduceParasitics.hh
|
||||
parasitics/SpefNamespace.hh
|
||||
parasitics/SpefReader.hh
|
||||
parasitics/SpfReader.hh
|
||||
|
||||
sdc/Clock.hh
|
||||
sdc/ClockGatingCheck.hh
|
||||
|
|
@ -597,19 +580,6 @@ flex_target(SpefLex parasitics/SpefLex.ll ${STA_HOME}/parasitics/SpefLex.cc
|
|||
|
||||
add_flex_bison_dependency(SpefLex SpefParser)
|
||||
|
||||
# Spf scan/parse.
|
||||
bison_target(SpfParser parasitics/SpfParse.yy ${STA_HOME}/parasitics/SpfParse.cc
|
||||
DEFINES_FILE ${STA_HOME}/parasitics/SpfParse.hh
|
||||
COMPILE_FLAGS --name-prefix=SpfParse_
|
||||
)
|
||||
|
||||
flex_target(SpfLex parasitics/SpfLex.ll ${STA_HOME}/parasitics/SpfLex.cc
|
||||
DEFINES_FILE ${STA_HOME}/parasitics/SpfLex.hh
|
||||
COMPILE_FLAGS --prefix=SpfLex_
|
||||
)
|
||||
|
||||
add_flex_bison_dependency(SpfLex SpfParser)
|
||||
|
||||
# Verilog scan/parse.
|
||||
bison_target(VerilogParser verilog/VerilogParse.yy ${STA_HOME}/verilog/VerilogParse.cc
|
||||
DEFINES_FILE ${STA_HOME}/verilog/VerilogParse.hh
|
||||
|
|
|
|||
19
Dockerfile
19
Dockerfile
|
|
@ -1,29 +1,30 @@
|
|||
FROM ubuntu:18.04
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y wget apt-utils git libtool autoconf
|
||||
apt-get install -y wget apt-utils git
|
||||
|
||||
# download CUDD
|
||||
RUN wget https://www.davidkebo.com/source/cudd_versions/cudd-3.0.0.tar.gz && \
|
||||
RUN wget https://www.davidkebo.com/source/cudd_versions/cudd-3.0.0.tar.gz && \
|
||||
tar -xvf cudd-3.0.0.tar.gz
|
||||
|
||||
# install main dependencies
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update && \
|
||||
apt-get install -y clang gcc tcl tcl-dev swig bison flex
|
||||
apt-get install -y cmake gcc tcl tcl-dev swig bison flex
|
||||
|
||||
# install CUDD
|
||||
RUN cd cudd-3.0.0 && \
|
||||
./configure --enable-dddmp --enable-obj --enable-shared --enable-static && \
|
||||
mkdir ../cudd && \
|
||||
./configure --prefix=$HOME/cudd && \
|
||||
make && \
|
||||
make check
|
||||
make install
|
||||
|
||||
# clone and install OpenSTA
|
||||
RUN git clone https://github.com/abdelrahmanhosny/OpenSTA.git && \
|
||||
RUN git clone https://github.com/abk-openroad/OpenSTA.git && \
|
||||
cd OpenSTA && \
|
||||
libtoolize && \
|
||||
./bootstrap && \
|
||||
./configure && \
|
||||
mkdir build && \
|
||||
cd build && \
|
||||
cmake .. -DCUDD=$HOME/cudd && \
|
||||
make
|
||||
|
||||
# Run sta on entry
|
||||
|
|
|
|||
16
INSTALL
16
INSTALL
|
|
@ -49,6 +49,16 @@ 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.
|
||||
|
|
@ -70,8 +80,10 @@ 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
|
||||
|
|
@ -86,6 +98,10 @@ 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
|
||||
-----------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -188,11 +188,9 @@ static void
|
|||
sourceTclFileEchoVerbose(const char *filename,
|
||||
Tcl_Interp *interp)
|
||||
{
|
||||
const char *source_cmd = "source -echo -verbose ";
|
||||
size_t cmd_length = strlen(source_cmd) + strlen(filename) + 1;
|
||||
char *cmd = stringPrint(cmd_length, "%s%s", source_cmd, filename);
|
||||
Tcl_Eval(interp, cmd);
|
||||
delete [] cmd;
|
||||
string cmd;
|
||||
stringPrint(cmd, "source -echo -verbose %s", filename);
|
||||
Tcl_Eval(interp, cmd.c_str());
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_INIT(sta, 2.0.4)
|
||||
AC_INIT(sta, 2.0.5)
|
||||
AM_INIT_AUTOMAKE
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
|
|
|
|||
|
|
@ -82,17 +82,17 @@ proc report_edge_dcalc { edge corner min_max digits } {
|
|||
# Filter timing checks based on min_max.
|
||||
if {!(($min_max == "max" && $role == "hold") \
|
||||
|| ($min_max=="min" && $role=="setup"))} {
|
||||
puts "Library: [$library name]"
|
||||
puts "Cell: [$cell name]"
|
||||
puts "Library: [get_name $library]"
|
||||
puts "Cell: [get_name $cell]"
|
||||
puts "Arc sense: [$edge sense]"
|
||||
puts "Arc type: $role"
|
||||
|
||||
set arc_iter [$edge timing_arc_iterator]
|
||||
while {[$arc_iter has_next]} {
|
||||
set arc [$arc_iter next]
|
||||
set from [[$from_pin port] name]
|
||||
set from [get_name [$from_pin port]]
|
||||
set from_tr [$arc from_trans]
|
||||
set to [[$to_pin port] name]
|
||||
set to [get_name [$to_pin port]]
|
||||
set to_tr [$arc to_trans]
|
||||
puts "$from $from_tr -> $to $to_tr"
|
||||
puts -nonewline [report_delay_calc_cmd $edge $arc $corner $min_max $digits]
|
||||
|
|
|
|||
BIN
doc/OpenSTA.odt
BIN
doc/OpenSTA.odt
Binary file not shown.
BIN
doc/OpenSTA.pdf
BIN
doc/OpenSTA.pdf
Binary file not shown.
|
|
@ -416,13 +416,11 @@ delayAsString(const Delay &delay,
|
|||
float sigma_early = delay.sigma(EarlyLate::early());
|
||||
float sigma_late = delay.sigma(EarlyLate::late());
|
||||
if (fuzzyEqual(sigma_early, sigma_late))
|
||||
return stringPrintTmp((digits + 4) * 2 + 2,
|
||||
"%s|%s",
|
||||
return stringPrintTmp("%s|%s",
|
||||
unit->asString(delay.mean(), digits),
|
||||
unit->asString(sigma_early, digits));
|
||||
else
|
||||
return stringPrintTmp((digits + 4) * 3 + 3,
|
||||
"%s|%s:%s",
|
||||
return stringPrintTmp("%s|%s:%s",
|
||||
unit->asString(delay.mean(), digits),
|
||||
unit->asString(sigma_early, digits),
|
||||
unit->asString(sigma_late, digits));
|
||||
|
|
|
|||
|
|
@ -1169,8 +1169,7 @@ Vertex::name(const Network *network) const
|
|||
{
|
||||
if (network->direction(pin_)->isBidirect()) {
|
||||
const char *pin_name = network->pathName(pin_);
|
||||
int result_len = strlen(pin_name) + strlen("driver") + 2;
|
||||
return stringPrintTmp(result_len, "%s %s",
|
||||
return stringPrintTmp("%s %s",
|
||||
pin_name,
|
||||
is_bidirect_drvr_ ? "driver" : "load");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -385,7 +385,7 @@ public:
|
|||
const char *name,
|
||||
const char *filename);
|
||||
virtual ~LibertyCell();
|
||||
const LibertyLibrary *libertyLibrary() const { return liberty_library_; }
|
||||
LibertyLibrary *libertyLibrary() const { return liberty_library_; }
|
||||
LibertyLibrary *libertyLibrary() { return liberty_library_; }
|
||||
LibertyPort *findLibertyPort(const char *name) const;
|
||||
void findLibertyPortsMatching(PatternMatch *pattern,
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ LibertyBuilder::makeBusPortBit(ConcreteLibrary *library,
|
|||
const char *bus_name,
|
||||
int bit_index)
|
||||
{
|
||||
char *bit_name = stringPrintTmp(strlen(bus_name) + 6, "%s%c%d%c",
|
||||
char *bit_name = stringPrintTmp("%s%c%d%c",
|
||||
bus_name,
|
||||
library->busBrktLeft(),
|
||||
bit_index,
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ simple_attr_value:
|
|||
/* Unquoted NOT function. */
|
||||
/* clocked_on : !CP; */
|
||||
| '!' string
|
||||
{ $$ = sta::makeLibertyStringAttrValue(sta::stringPrint(strlen($2)+1, "!%s", $2)); sta::stringDelete($2); }
|
||||
{ $$ = sta::makeLibertyStringAttrValue(sta::stringPrint("!%s", $2)); sta::stringDelete($2); }
|
||||
;
|
||||
|
||||
complex_attr:
|
||||
|
|
|
|||
|
|
@ -461,11 +461,7 @@ LibertyReader::defineScalingFactorVisitors()
|
|||
while (tr_iter.hasNext()) {
|
||||
TransRiseFall *tr = tr_iter.next();
|
||||
const char *tr_name = (tr == TransRiseFall::rise()) ? "rise":"fall";
|
||||
const char *attr_name = stringPrintTmp(strlen(pvt_name)
|
||||
+ strlen(type_name)
|
||||
+ strlen(tr_name)
|
||||
+ 5, // k___\0
|
||||
"k_%s_%s_%s",
|
||||
const char *attr_name = stringPrintTmp("k_%s_%s_%s",
|
||||
pvt_name,
|
||||
type_name,
|
||||
tr_name);
|
||||
|
|
@ -477,11 +473,7 @@ LibertyReader::defineScalingFactorVisitors()
|
|||
while (tr_iter.hasNext()) {
|
||||
TransRiseFall *tr = tr_iter.next();
|
||||
const char *tr_name = (tr == TransRiseFall::rise()) ? "rise":"fall";
|
||||
const char *attr_name = stringPrintTmp(strlen(pvt_name)
|
||||
+ strlen(type_name)
|
||||
+ strlen(tr_name)
|
||||
+ 5, // k___\0
|
||||
"k_%s_%s_%s",
|
||||
const char *attr_name = stringPrintTmp("k_%s_%s_%s",
|
||||
pvt_name,
|
||||
tr_name,
|
||||
type_name);
|
||||
|
|
@ -493,11 +485,7 @@ LibertyReader::defineScalingFactorVisitors()
|
|||
while (tr_iter.hasNext()) {
|
||||
TransRiseFall *tr = tr_iter.next();
|
||||
const char *tr_name = (tr == TransRiseFall::rise()) ? "high":"low";
|
||||
const char *attr_name = stringPrintTmp(strlen(pvt_name)
|
||||
+ strlen(type_name)
|
||||
+ strlen(tr_name)
|
||||
+ 5, // k___\0
|
||||
"k_%s_%s_%s",
|
||||
const char *attr_name = stringPrintTmp("k_%s_%s_%s",
|
||||
pvt_name,
|
||||
tr_name,
|
||||
type_name);
|
||||
|
|
@ -505,10 +493,7 @@ LibertyReader::defineScalingFactorVisitors()
|
|||
}
|
||||
}
|
||||
else {
|
||||
const char *attr_name = stringPrintTmp(strlen(pvt_name)
|
||||
+ strlen(type_name)
|
||||
+ 4, // k__\0
|
||||
"k_%s_%s",
|
||||
const char *attr_name = stringPrintTmp("k_%s_%s",
|
||||
pvt_name,
|
||||
type_name);
|
||||
defineAttrVisitor(attr_name,&LibertyReader::visitScaleFactor);
|
||||
|
|
@ -4327,12 +4312,7 @@ LibertyReader::parseFunc(const char *func,
|
|||
const char *attr_name,
|
||||
int line)
|
||||
{
|
||||
const char *error_msg = stringPrintTmp(strlen(filename_)
|
||||
+ strlen(", line ")
|
||||
+ 8
|
||||
+ strlen(attr_name)
|
||||
+ 2,
|
||||
"%s, line %d %s",
|
||||
const char *error_msg = stringPrintTmp("%s, line %d %s",
|
||||
filename_,
|
||||
line,
|
||||
attr_name);
|
||||
|
|
@ -5221,8 +5201,7 @@ PortNameBitIterator::findRangeBusNameNext()
|
|||
? range_bit_ >= range_to_
|
||||
: range_bit_ <= range_to_) {
|
||||
LibertyLibrary *library = visitor_->library();
|
||||
const char *bus_bit_name = stringPrintTmp(strlen(range_bus_name_) + 10,
|
||||
"%s%c%d%c",
|
||||
const char *bus_bit_name = stringPrintTmp("%s%c%d%c",
|
||||
range_bus_name_,
|
||||
library->busBrktLeft(),
|
||||
range_bit_,
|
||||
|
|
|
|||
|
|
@ -592,14 +592,12 @@ reportPvt(const LibertyLibrary *library,
|
|||
if (pvt == NULL)
|
||||
pvt = library->defaultOperatingConditions();
|
||||
if (pvt) {
|
||||
const char *pvt_str = stringPrint(strlen("P = %.*f V = %.*f T = %.*f\n")
|
||||
+ (digits + 10) * 3 + 1,
|
||||
"P = %.*f V = %.*f T = %.*f\n",
|
||||
digits, pvt->process(),
|
||||
digits, pvt->voltage(),
|
||||
digits, pvt->temperature());
|
||||
string pvt_str;
|
||||
stringPrint(pvt_str, "P = %.*f V = %.*f T = %.*f\n",
|
||||
digits, pvt->process(),
|
||||
digits, pvt->voltage(),
|
||||
digits, pvt->temperature());
|
||||
*result += pvt_str;
|
||||
stringDelete(pvt_str);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -613,13 +611,11 @@ TableModel::reportPvtScaleFactor(const LibertyLibrary *library,
|
|||
if (pvt == NULL)
|
||||
pvt = library->defaultOperatingConditions();
|
||||
if (pvt) {
|
||||
const char *scale_str = stringPrint(strlen("PVT scale factor = %.*f\n")
|
||||
+ digits + 10 + 1,
|
||||
"PVT scale factor = %.*f\n",
|
||||
digits,
|
||||
scaleFactor(library, cell, pvt));
|
||||
string scale_str;
|
||||
stringPrint(scale_str, "PVT scale factor = %.*f\n",
|
||||
digits,
|
||||
scaleFactor(library, cell, pvt));
|
||||
*result += scale_str;
|
||||
stringDelete(scale_str);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -106,9 +106,7 @@ Unit::asString(float value,
|
|||
// prevent "-0.00" on slowaris
|
||||
if (abs(scaled_value) < 1E-6)
|
||||
scaled_value = 0.0;
|
||||
// Leave room for sign, E+-exponent.
|
||||
const int result_len = std::numeric_limits<float>::digits10 + 10;
|
||||
return stringPrintTmp(result_len, "%.*f%s", digits, scaled_value, suffix_);
|
||||
return stringPrintTmp("%.*f%s", digits, scaled_value, suffix_);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,9 @@ ConcreteLibrary::~ConcreteLibrary()
|
|||
}
|
||||
|
||||
ConcreteCell *
|
||||
ConcreteLibrary::makeCell(const char *name, bool is_leaf, const char *filename)
|
||||
ConcreteLibrary::makeCell(const char *name,
|
||||
bool is_leaf,
|
||||
const char *filename)
|
||||
{
|
||||
ConcreteCell *cell = new ConcreteCell(this, name, is_leaf, filename);
|
||||
addCell(cell);
|
||||
|
|
@ -55,7 +57,8 @@ ConcreteLibrary::addCell(ConcreteCell *cell)
|
|||
}
|
||||
|
||||
void
|
||||
ConcreteLibrary::renameCell(ConcreteCell *cell, const char *cell_name)
|
||||
ConcreteLibrary::renameCell(ConcreteCell *cell,
|
||||
const char *cell_name)
|
||||
{
|
||||
cell_map_.eraseKey(cell->name());
|
||||
cell_map_[cell_name] = cell;
|
||||
|
|
@ -93,7 +96,8 @@ ConcreteLibrary::findCellsMatching(const PatternMatch *pattern,
|
|||
}
|
||||
|
||||
void
|
||||
ConcreteLibrary::setBusBrkts(char left, char right)
|
||||
ConcreteLibrary::setBusBrkts(char left,
|
||||
char right)
|
||||
{
|
||||
bus_brkt_left_ = left;
|
||||
bus_brkt_right_ = right;
|
||||
|
|
@ -101,8 +105,10 @@ ConcreteLibrary::setBusBrkts(char left, char right)
|
|||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
ConcreteCell::ConcreteCell(ConcreteLibrary *library, const char *name,
|
||||
bool is_leaf, const char *filename):
|
||||
ConcreteCell::ConcreteCell(ConcreteLibrary *library,
|
||||
const char *name,
|
||||
bool is_leaf,
|
||||
const char *filename):
|
||||
library_(library),
|
||||
name_(stringCopy(name)),
|
||||
filename_(stringCopy(filename)),
|
||||
|
|
@ -137,7 +143,8 @@ ConcreteCell::makePort(const char *name)
|
|||
}
|
||||
|
||||
ConcretePort *
|
||||
ConcreteCell::makeBundlePort(const char *name, ConcretePortSeq *members)
|
||||
ConcreteCell::makeBundlePort(const char *name,
|
||||
ConcretePortSeq *members)
|
||||
{
|
||||
ConcretePort *port = new ConcretePort(this, name, false, -1, -1,
|
||||
true, members);
|
||||
|
|
@ -146,7 +153,9 @@ ConcreteCell::makeBundlePort(const char *name, ConcretePortSeq *members)
|
|||
}
|
||||
|
||||
ConcretePort *
|
||||
ConcreteCell::makeBusPort(const char *name, int from_index, int to_index)
|
||||
ConcreteCell::makeBusPort(const char *name,
|
||||
int from_index,
|
||||
int to_index)
|
||||
{
|
||||
ConcretePort *port = new ConcretePort(this, name, true, from_index, to_index,
|
||||
false, new ConcretePortSeq);
|
||||
|
|
@ -156,7 +165,9 @@ ConcreteCell::makeBusPort(const char *name, int from_index, int to_index)
|
|||
}
|
||||
|
||||
ConcretePort *
|
||||
ConcreteCell::makeBusPort(const char *name, int from_index, int to_index,
|
||||
ConcreteCell::makeBusPort(const char *name,
|
||||
int from_index,
|
||||
int to_index,
|
||||
ConcretePortSeq *members)
|
||||
{
|
||||
ConcretePort *port = new ConcretePort(this, name, true, from_index, to_index,
|
||||
|
|
@ -166,8 +177,10 @@ ConcreteCell::makeBusPort(const char *name, int from_index, int to_index,
|
|||
}
|
||||
|
||||
void
|
||||
ConcreteCell::makeBusPortBits(ConcretePort *bus_port, const char *name,
|
||||
int from_index, int to_index)
|
||||
ConcreteCell::makeBusPortBits(ConcretePort *bus_port,
|
||||
const char *name,
|
||||
int from_index,
|
||||
int to_index)
|
||||
{
|
||||
if (from_index < to_index) {
|
||||
for (int index = from_index; index <= to_index; index++)
|
||||
|
|
@ -180,21 +193,24 @@ ConcreteCell::makeBusPortBits(ConcretePort *bus_port, const char *name,
|
|||
}
|
||||
|
||||
void
|
||||
ConcreteCell::makeBusPortBit(ConcretePort *bus_port, const char *bus_name,
|
||||
ConcreteCell::makeBusPortBit(ConcretePort *bus_port,
|
||||
const char *bus_name,
|
||||
int bit_index)
|
||||
{
|
||||
char *bit_name = stringPrintTmp(strlen(bus_name) + 8, "%s%c%d%c",
|
||||
bus_name,
|
||||
library_->busBrktLeft(),
|
||||
bit_index,
|
||||
library_->busBrktRight());
|
||||
ConcretePort *port = makePort(bit_name, bit_index);
|
||||
string bit_name;
|
||||
stringPrint(bit_name, "%s%c%d%c",
|
||||
bus_name,
|
||||
library_->busBrktLeft(),
|
||||
bit_index,
|
||||
library_->busBrktRight());
|
||||
ConcretePort *port = makePort(bit_name.c_str(), bit_index);
|
||||
bus_port->addPortBit(port);
|
||||
addPortBit(port);
|
||||
}
|
||||
|
||||
ConcretePort *
|
||||
ConcreteCell::makePort(const char *bit_name, int bit_index)
|
||||
ConcreteCell::makePort(const char *bit_name,
|
||||
int bit_index)
|
||||
{
|
||||
ConcretePort *port = new ConcretePort(this, bit_name, false, bit_index,
|
||||
bit_index, false, NULL);
|
||||
|
|
@ -278,7 +294,9 @@ ConcreteCell::portBitIterator() const
|
|||
class BusPort
|
||||
{
|
||||
public:
|
||||
BusPort(const char *name, int from, PortDirection *direction);
|
||||
BusPort(const char *name,
|
||||
int from,
|
||||
PortDirection *direction);
|
||||
~BusPort();
|
||||
const char *name() const { return name_; }
|
||||
void pushMember(ConcretePort *port);
|
||||
|
|
@ -298,7 +316,9 @@ private:
|
|||
ConcretePortSeq *members_;
|
||||
};
|
||||
|
||||
BusPort::BusPort(const char *name, int from, PortDirection *direction) :
|
||||
BusPort::BusPort(const char *name,
|
||||
int from,
|
||||
PortDirection *direction) :
|
||||
name_(name),
|
||||
from_(from),
|
||||
to_(from),
|
||||
|
|
@ -392,9 +412,13 @@ ConcreteCell::groupBusPorts(const char *bus_brkts_left,
|
|||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
ConcretePort::ConcretePort(ConcreteCell *cell, const char *name,
|
||||
bool is_bus, int from_index, int to_index,
|
||||
bool is_bundle, ConcretePortSeq *member_ports) :
|
||||
ConcretePort::ConcretePort(ConcreteCell *cell,
|
||||
const char *name,
|
||||
bool is_bus,
|
||||
int from_index,
|
||||
int to_index,
|
||||
bool is_bundle,
|
||||
ConcretePortSeq *member_ports) :
|
||||
name_(stringCopy(name)),
|
||||
cell_(cell),
|
||||
direction_(PortDirection::unknown()),
|
||||
|
|
@ -428,8 +452,7 @@ ConcretePort::busName() const
|
|||
{
|
||||
if (is_bus_) {
|
||||
ConcreteLibrary *lib = cell_->library();
|
||||
return stringPrintTmp(strlen(name_) + 10,
|
||||
"%s%c%d:%d%c",
|
||||
return stringPrintTmp("%s%c%d:%d%c",
|
||||
name_,
|
||||
lib->busBrktLeft(),
|
||||
from_index_,
|
||||
|
|
|
|||
|
|
@ -52,7 +52,8 @@ public:
|
|||
void setName(const char *name);
|
||||
virtual const char *filename() const { return filename_; }
|
||||
void addCell(ConcreteCell *cell);
|
||||
virtual ConcreteCell *makeCell(const char *name, bool is_leaf,
|
||||
virtual ConcreteCell *makeCell(const char *name,
|
||||
bool is_leaf,
|
||||
const char *filename);
|
||||
void deleteCell(ConcreteCell *cell);
|
||||
ConcreteLibraryCellIterator *cellIterator() const;
|
||||
|
|
@ -61,10 +62,12 @@ public:
|
|||
CellSeq *cells) const;
|
||||
virtual char busBrktLeft() { return bus_brkt_left_; }
|
||||
virtual char busBrktRight() { return bus_brkt_right_; }
|
||||
void setBusBrkts(char left, char right);
|
||||
void setBusBrkts(char left,
|
||||
char right);
|
||||
|
||||
protected:
|
||||
void renameCell(ConcreteCell *cell, const char *cell_name);
|
||||
void renameCell(ConcreteCell *cell,
|
||||
const char *cell_name);
|
||||
|
||||
const char *name_;
|
||||
const char *filename_;
|
||||
|
|
@ -98,26 +101,39 @@ public:
|
|||
// Cell acts as port factory.
|
||||
ConcretePort *makePort(const char *name);
|
||||
// Bus port.
|
||||
ConcretePort *makeBusPort(const char *name, int from_index, int to_index);
|
||||
ConcretePort *makeBusPort(const char *name,
|
||||
int from_index,
|
||||
int to_index);
|
||||
// Bundle port.
|
||||
ConcretePort *makeBundlePort(const char *name, ConcretePortSeq *members);
|
||||
ConcretePort *makeBundlePort(const char *name,
|
||||
ConcretePortSeq *members);
|
||||
// Group previously defined bus bit ports together.
|
||||
void groupBusPorts(const char *bus_brkts_left, const char *bus_brkts_right);
|
||||
void groupBusPorts(const char *bus_brkts_left,
|
||||
const char *bus_brkts_right);
|
||||
size_t portCount() const;
|
||||
void setName(const char *name);
|
||||
virtual void addPort(ConcretePort *port);
|
||||
void addPortBit(ConcretePort *port);
|
||||
|
||||
protected:
|
||||
ConcreteCell(ConcreteLibrary *library, const char *name,
|
||||
bool is_leaf, const char *filename);
|
||||
ConcretePort *makeBusPort(const char *name, int from_index, int to_index,
|
||||
ConcreteCell(ConcreteLibrary *library,
|
||||
const char *name,
|
||||
bool is_leaf,
|
||||
const char *filename);
|
||||
ConcretePort *makeBusPort(const char *name,
|
||||
int from_index,
|
||||
int to_index,
|
||||
ConcretePortSeq *members);
|
||||
void makeBusPortBits(ConcretePort *bus_port, const char *name,
|
||||
int from_index, int to_index);
|
||||
void makeBusPortBits(ConcretePort *bus_port,
|
||||
const char *name,
|
||||
int from_index,
|
||||
int to_index);
|
||||
// Bus port bit (internal to makeBusPortBits).
|
||||
virtual ConcretePort *makePort(const char *bit_name, int bit_index);
|
||||
void makeBusPortBit(ConcretePort *bus_port, const char *name, int index);
|
||||
virtual ConcretePort *makePort(const char *bit_name,
|
||||
int bit_index);
|
||||
void makeBusPortBit(ConcretePort *bus_port,
|
||||
const char *name,
|
||||
int index);
|
||||
|
||||
ConcreteLibrary *library_;
|
||||
const char *name_;
|
||||
|
|
@ -182,9 +198,13 @@ public:
|
|||
|
||||
protected:
|
||||
// Constructors for factory in cell class.
|
||||
ConcretePort(ConcreteCell *cell, const char *name,
|
||||
bool is_bus, int from_index, int to_index,
|
||||
bool is_bundle, ConcretePortSeq *member_ports);
|
||||
ConcretePort(ConcreteCell *cell,
|
||||
const char *name,
|
||||
bool is_bus,
|
||||
int from_index,
|
||||
int to_index,
|
||||
bool is_bundle,
|
||||
ConcretePortSeq *member_ports);
|
||||
|
||||
const char *name_;
|
||||
ConcreteCell *cell_;
|
||||
|
|
|
|||
|
|
@ -1250,14 +1250,22 @@ ConcreteNetwork::connect(Instance *inst,
|
|||
ConcreteNet *prev_net = cpin->net_;
|
||||
if (prev_net)
|
||||
disconnectNetPin(prev_net, cpin);
|
||||
cpin->net_ = cnet;
|
||||
}
|
||||
else {
|
||||
cpin = new ConcretePin(cinst, cport, cnet);
|
||||
cinst->addPin(cpin);
|
||||
}
|
||||
if (cnet)
|
||||
if (cinst == top_instance_) {
|
||||
// makeTerm
|
||||
ConcreteTerm *cterm = new ConcreteTerm(cpin, cnet);
|
||||
cnet->addTerm(cterm);
|
||||
cpin->term_ = cterm;
|
||||
cpin->net_ = NULL;
|
||||
}
|
||||
else {
|
||||
cpin->net_ = cnet;
|
||||
connectNetPin(cnet, cpin);
|
||||
}
|
||||
return reinterpret_cast<Pin*>(cpin);
|
||||
}
|
||||
|
||||
|
|
@ -1288,13 +1296,15 @@ ConcreteNetwork::disconnectPin(Pin *pin)
|
|||
ConcretePin *cpin = reinterpret_cast<ConcretePin*>(pin);
|
||||
if (cpin->instance() == top_instance_) {
|
||||
ConcreteTerm *cterm = cpin->term_;
|
||||
ConcreteNet *cnet = cterm->net_;
|
||||
if (cnet) {
|
||||
cnet->deleteTerm(cterm);
|
||||
clearNetDrvPinrMap();
|
||||
if (cterm) {
|
||||
ConcreteNet *cnet = cterm->net_;
|
||||
if (cnet) {
|
||||
cnet->deleteTerm(cterm);
|
||||
clearNetDrvPinrMap();
|
||||
}
|
||||
cpin->term_ = NULL;
|
||||
delete cterm;
|
||||
}
|
||||
cpin->term_ = NULL;
|
||||
delete cterm;
|
||||
}
|
||||
else {
|
||||
ConcreteNet *cnet = cpin->net();
|
||||
|
|
|
|||
|
|
@ -901,17 +901,13 @@ Network::findInstPinsHierMatching(const Instance *instance,
|
|||
PinSeq *pins) const
|
||||
{
|
||||
const char *inst_name = name(instance);
|
||||
size_t inst_length = strlen(inst_name);
|
||||
InstancePinIterator *pin_iter = pinIterator(instance);
|
||||
while (pin_iter->hasNext()) {
|
||||
Pin *pin = pin_iter->next();
|
||||
const char *port_name = name(port(pin));
|
||||
const char *pin_name = stringPrintTmp(inst_length+strlen(port_name)+2,
|
||||
"%s%c%s",
|
||||
inst_name,
|
||||
divider_,
|
||||
port_name);
|
||||
if (pattern->match(pin_name))
|
||||
string pin_name;
|
||||
stringPrint(pin_name, "%s%c%s", inst_name,divider_, port_name);
|
||||
if (pattern->match(pin_name.c_str()))
|
||||
pins->push_back(pin);
|
||||
}
|
||||
delete pin_iter;
|
||||
|
|
|
|||
|
|
@ -528,8 +528,7 @@ const char *
|
|||
ConcreteParasiticSubNode::name(const Network *network) const
|
||||
{
|
||||
const char *net_name = network->pathName(net_);
|
||||
return stringPrintTmp(strlen(net_name) + INT_DIGITS + 2,
|
||||
"%s:%d", net_name, id_);
|
||||
return stringPrintTmp("%s:%d", net_name, id_);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -20,51 +20,31 @@ include_HEADERS = \
|
|||
ConcreteParasitics.hh \
|
||||
ConcreteParasiticsPvt.hh \
|
||||
EstimateParasitics.hh \
|
||||
MakeConcreteParasitics.hh \
|
||||
NullParasitics.hh \
|
||||
Parasitics.hh \
|
||||
ParasiticsClass.hh \
|
||||
ReadParasitics.hh \
|
||||
ReduceParasitics.hh \
|
||||
SpefNamespace.hh \
|
||||
SpefReader.hh \
|
||||
SpfReader.hh
|
||||
SpefReader.hh
|
||||
|
||||
libparasitics_la_SOURCES = \
|
||||
ConcreteParasitics.cc \
|
||||
EstimateParasitics.cc \
|
||||
NullParasitics.cc \
|
||||
Parasitics.cc \
|
||||
ReadParasitics.cc \
|
||||
ReduceParasitics.cc \
|
||||
SpefLex.ll \
|
||||
SpefNamespace.cc \
|
||||
SpefParse.yy \
|
||||
SpefReader.cc \
|
||||
SpefReaderPvt.hh \
|
||||
SpfLex.ll \
|
||||
SpfParse.yy \
|
||||
SpfReader.cc \
|
||||
SpfReaderPvt.hh \
|
||||
SpfSpefReader.cc \
|
||||
SpfSpefReader.hh
|
||||
|
||||
SpfLex.ll: SpfParse.hh
|
||||
|
||||
SpfLex.cc: SpfLex.ll
|
||||
$(LEX) $(LFLAGS) -o SpfLex.cc --prefix=SpfLex_ --header-file=SpfLex.hh SpfLex.ll
|
||||
SpfReaderPvt.hh
|
||||
|
||||
SpefLex.ll: SpefParse.hh
|
||||
|
||||
SpefLex.cc: SpefLex.ll
|
||||
$(LEX) $(LFLAGS) -o SpefLex.cc --prefix=SpefLex_ --header-file=SpefLex.hh SpefLex.ll
|
||||
|
||||
# Rules to support automake pre 1.12 that name header .h instead of .hh
|
||||
SpfParse.hh: SpfParse.cc
|
||||
if test -f SpfParse.h; then \
|
||||
cp SpfParse.h SpfParse.hh; \
|
||||
fi
|
||||
|
||||
SpefParse.hh: SpefParse.cc
|
||||
if test -f SpefParse.h; then \
|
||||
cp SpefParse.h SpefParse.hh; \
|
||||
|
|
@ -76,7 +56,6 @@ TCL_SRCS = \
|
|||
|
||||
EXTRA_DIST = \
|
||||
$(TCL_SRCS) \
|
||||
SpfParse.hh \
|
||||
SpefParse.hh
|
||||
|
||||
libs: $(lib_LTLIBRARIES)
|
||||
|
|
|
|||
|
|
@ -51,8 +51,13 @@ Parasitics::findParasiticNet(const Pin *pin) const
|
|||
Net *net = network_->net(pin);
|
||||
// Pins on the top level instance may not have nets.
|
||||
// Use the net connected to the pin's terminal.
|
||||
if (net == NULL && network_->isTopLevelPort(pin))
|
||||
net = network_->net(network_->term(pin));
|
||||
if (net == NULL && network_->isTopLevelPort(pin)) {
|
||||
Term *term = network_->term(pin);
|
||||
if (term)
|
||||
return network_->net(term);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
if (net)
|
||||
return network_->highestConnectedNet(net);
|
||||
else
|
||||
|
|
|
|||
|
|
@ -34,24 +34,24 @@ using sta::TmpFloatSeq;
|
|||
%inline %{
|
||||
|
||||
bool
|
||||
read_parasitics_cmd(const char *filename,
|
||||
Instance *instance,
|
||||
MinMaxAll *min_max,
|
||||
bool increment,
|
||||
bool pin_cap_included,
|
||||
bool keep_coupling_caps,
|
||||
float coupling_cap_factor,
|
||||
ReduceParasiticsTo reduce_to,
|
||||
bool delete_after_reduce,
|
||||
bool quiet,
|
||||
bool save)
|
||||
read_spef_cmd(const char *filename,
|
||||
Instance *instance,
|
||||
MinMaxAll *min_max,
|
||||
bool increment,
|
||||
bool pin_cap_included,
|
||||
bool keep_coupling_caps,
|
||||
float coupling_cap_factor,
|
||||
ReduceParasiticsTo reduce_to,
|
||||
bool delete_after_reduce,
|
||||
bool quiet,
|
||||
bool save)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
return Sta::sta()->readParasitics(filename, instance, min_max,
|
||||
increment, pin_cap_included,
|
||||
keep_coupling_caps, coupling_cap_factor,
|
||||
reduce_to, delete_after_reduce,
|
||||
save, quiet);
|
||||
return Sta::sta()->readSpef(filename, instance, min_max,
|
||||
increment, pin_cap_included,
|
||||
keep_coupling_caps, coupling_cap_factor,
|
||||
reduce_to, delete_after_reduce,
|
||||
save, quiet);
|
||||
}
|
||||
|
||||
TmpFloatSeq *
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
namespace eval sta {
|
||||
|
||||
define_cmd_args "read_parasitics" \
|
||||
define_cmd_args "read_spef" \
|
||||
{[-min]\
|
||||
[-max]\
|
||||
[-elmore]\
|
||||
|
|
@ -31,14 +31,13 @@ define_cmd_args "read_parasitics" \
|
|||
[-save]\
|
||||
filename}
|
||||
|
||||
proc_redirect read_parasitics {
|
||||
# The -elmore flag is required by dc.
|
||||
parse_key_args "read_parasitics" args \
|
||||
proc_redirect read_spef {
|
||||
parse_key_args "read_spef" args \
|
||||
keys {-path -coupling_reduction_factor -reduce_to} \
|
||||
flags {-min -max -elmore -increment -pin_cap_included \
|
||||
-keep_capacitive_coupling \
|
||||
-delete_after_reduce -quiet -save}
|
||||
check_argc_eq1 "report_parasitics" $args
|
||||
check_argc_eq1 "report_spef" $args
|
||||
|
||||
set instance [top_instance]
|
||||
if [info exists keys(-path)] {
|
||||
|
|
@ -69,7 +68,7 @@ proc_redirect read_parasitics {
|
|||
set quiet [info exists flags(-quiet)]
|
||||
set save [info exists flags(-save)]
|
||||
set filename $args
|
||||
return [read_parasitics_cmd $filename $instance $min_max $increment \
|
||||
return [read_spef_cmd $filename $instance $min_max $increment \
|
||||
$pin_cap_included $keep_coupling_caps $coupling_reduction_factor \
|
||||
$reduce_to $delete_after_reduce \
|
||||
$save $quiet]
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ INDEX "*"{POS_INTEGER}
|
|||
"*CELL" { return CELL; }
|
||||
"*CONN" { return CONN; }
|
||||
"*C_UNIT" { return C_UNIT; }
|
||||
"*SPEF" { return SPEF; }
|
||||
"*DATE" { return DATE; }
|
||||
"*DEFINE" { return DEFINE; }
|
||||
"*DELIMITER" { return DELIMITER; }
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ int SpefLex_lex();
|
|||
sta::Net *net;
|
||||
}
|
||||
|
||||
%token DESIGN DATE VENDOR PROGRAM DESIGN_FLOW
|
||||
%token SPEF DESIGN DATE VENDOR PROGRAM DESIGN_FLOW
|
||||
%token PVERSION DIVIDER DELIMITER
|
||||
%token BUS_DELIMITER T_UNIT C_UNIT R_UNIT L_UNIT NAME_MAP
|
||||
%token POWER_NETS GROUND_NETS KW_C KW_L KW_S KW_D KW_V
|
||||
|
|
@ -142,6 +142,7 @@ hchar:
|
|||
/****************************************************************/
|
||||
|
||||
header_def:
|
||||
spef_version
|
||||
design_name
|
||||
date
|
||||
vendor
|
||||
|
|
@ -154,6 +155,11 @@ header_def:
|
|||
unit_def
|
||||
;
|
||||
|
||||
spef_version:
|
||||
SPEF QSTRING
|
||||
{ sta::stringDelete($2); }
|
||||
;
|
||||
|
||||
design_name:
|
||||
DESIGN QSTRING
|
||||
{ sta::stringDelete($2); }
|
||||
|
|
|
|||
|
|
@ -17,14 +17,18 @@
|
|||
#include <limits>
|
||||
#include "Machine.hh"
|
||||
#include "Zlib.hh"
|
||||
#include "Report.hh"
|
||||
#include "Debug.hh"
|
||||
#include "StringUtil.hh"
|
||||
#include "Map.hh"
|
||||
#include "PortDirection.hh"
|
||||
#include "Transition.hh"
|
||||
#include "Network.hh"
|
||||
#include "Liberty.hh"
|
||||
#include "Sdc.hh"
|
||||
#include "Parasitics.hh"
|
||||
#include "SpefReaderPvt.hh"
|
||||
#include "SpefNamespace.hh"
|
||||
#include "SpefReader.hh"
|
||||
|
||||
int
|
||||
|
|
@ -38,8 +42,6 @@ SpefReader *spef_reader;
|
|||
|
||||
bool
|
||||
readSpefFile(const char *filename,
|
||||
gzFile stream,
|
||||
int line,
|
||||
Instance *instance,
|
||||
ParasiticAnalysisPt *ap,
|
||||
bool increment,
|
||||
|
|
@ -57,14 +59,22 @@ readSpefFile(const char *filename,
|
|||
Network *network,
|
||||
Parasitics *parasitics)
|
||||
{
|
||||
SpefReader reader(filename, stream, line, instance, ap, increment,
|
||||
pin_cap_included, keep_coupling_caps, coupling_cap_factor,
|
||||
reduce_to, delete_after_reduce, op_cond, corner,
|
||||
cnst_min_max, quiet, report, network, parasitics);
|
||||
spef_reader = &reader;
|
||||
::spefResetScanner();
|
||||
// yyparse returns 0 on success.
|
||||
bool success = (::SpefParse_parse() == 0);
|
||||
bool success = false;
|
||||
// Use zlib to uncompress gzip'd files automagically.
|
||||
gzFile stream = gzopen(filename, "rb");
|
||||
if (stream) {
|
||||
SpefReader reader(filename, stream, instance, ap, increment,
|
||||
pin_cap_included, keep_coupling_caps, coupling_cap_factor,
|
||||
reduce_to, delete_after_reduce, op_cond, corner,
|
||||
cnst_min_max, quiet, report, network, parasitics);
|
||||
spef_reader = &reader;
|
||||
::spefResetScanner();
|
||||
// yyparse returns 0 on success.
|
||||
success = (::SpefParse_parse() == 0);
|
||||
gzclose(stream);
|
||||
}
|
||||
else
|
||||
throw FileNotReadable(filename);
|
||||
if (success && save)
|
||||
parasitics->save();
|
||||
return success;
|
||||
|
|
@ -72,7 +82,6 @@ readSpefFile(const char *filename,
|
|||
|
||||
SpefReader::SpefReader(const char *filename,
|
||||
gzFile stream,
|
||||
int line,
|
||||
Instance *instance,
|
||||
ParasiticAnalysisPt *ap,
|
||||
bool increment,
|
||||
|
|
@ -88,16 +97,35 @@ SpefReader::SpefReader(const char *filename,
|
|||
Report *report,
|
||||
Network *network,
|
||||
Parasitics *parasitics) :
|
||||
SpfSpefReader(filename, stream, line, instance, ap,
|
||||
increment, pin_cap_included,
|
||||
keep_coupling_caps, coupling_cap_factor,
|
||||
reduce_to, delete_after_reduce,
|
||||
op_cond, corner, cnst_min_max, quiet,
|
||||
report, network, parasitics),
|
||||
filename_(filename),
|
||||
instance_(instance),
|
||||
ap_(ap),
|
||||
increment_(increment),
|
||||
pin_cap_included_(pin_cap_included),
|
||||
keep_coupling_caps_(keep_coupling_caps),
|
||||
reduce_to_(reduce_to),
|
||||
delete_after_reduce_(delete_after_reduce),
|
||||
op_cond_(op_cond),
|
||||
corner_(corner),
|
||||
cnst_min_max_(cnst_min_max),
|
||||
keep_device_names_(false),
|
||||
quiet_(quiet),
|
||||
stream_(stream),
|
||||
line_(1),
|
||||
// defaults
|
||||
divider_('\0'),
|
||||
delimiter_('\0'),
|
||||
bus_brkt_left_('\0'),
|
||||
bus_brkt_right_('\0'),
|
||||
net_(NULL),
|
||||
report_(report),
|
||||
network_(network),
|
||||
parasitics_(parasitics),
|
||||
triple_index_(0),
|
||||
design_flow_(NULL),
|
||||
parasitic_(NULL)
|
||||
{
|
||||
ap->setCouplingCapFactor(coupling_cap_factor);
|
||||
}
|
||||
|
||||
SpefReader::~SpefReader()
|
||||
|
|
@ -117,6 +145,18 @@ SpefReader::~SpefReader()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
SpefReader::setDivider(char divider)
|
||||
{
|
||||
divider_ = divider;
|
||||
}
|
||||
|
||||
void
|
||||
SpefReader::setDelimiter(char delimiter)
|
||||
{
|
||||
delimiter_ = delimiter;
|
||||
}
|
||||
|
||||
void
|
||||
SpefReader::setBusBrackets(char left, char right)
|
||||
{
|
||||
|
|
@ -127,7 +167,78 @@ SpefReader::setBusBrackets(char left, char right)
|
|||
|| (left == ':' && right == '\0')
|
||||
|| (left == '.' && right == '\0')))
|
||||
warn("illegal bus delimiters.\n");
|
||||
SpfSpefReader::setBusBrackets(left, right);
|
||||
bus_brkt_left_ = left;
|
||||
bus_brkt_right_ = right;
|
||||
}
|
||||
|
||||
Instance *
|
||||
SpefReader::findInstanceRelative(const char *name)
|
||||
{
|
||||
return network_->findInstanceRelative(instance_, name);
|
||||
}
|
||||
|
||||
Net *
|
||||
SpefReader::findNetRelative(const char *name)
|
||||
{
|
||||
return network_->findNetRelative(instance_, name);
|
||||
}
|
||||
|
||||
Pin *
|
||||
SpefReader::findPinRelative(const char *name)
|
||||
{
|
||||
return network_->findPinRelative(instance_, name);
|
||||
}
|
||||
|
||||
Pin *
|
||||
SpefReader::findPortPinRelative(const char *name)
|
||||
{
|
||||
return network_->findPin(instance_, name);
|
||||
}
|
||||
|
||||
void
|
||||
SpefReader::getChars(char *buf,
|
||||
int &result,
|
||||
size_t max_size)
|
||||
{
|
||||
char *status = gzgets(stream_, buf, max_size);
|
||||
if (status == Z_NULL)
|
||||
result = 0; // YY_NULL
|
||||
else
|
||||
result = static_cast<int>(strlen(buf));
|
||||
}
|
||||
|
||||
void
|
||||
SpefReader::getChars(char *buf,
|
||||
size_t &result,
|
||||
size_t max_size)
|
||||
{
|
||||
char *status = gzgets(stream_, buf, max_size);
|
||||
if (status == Z_NULL)
|
||||
result = 0; // YY_NULL
|
||||
else
|
||||
result = strlen(buf);
|
||||
}
|
||||
|
||||
char *
|
||||
SpefReader::translated(const char *token)
|
||||
{
|
||||
return spefToSta(token, divider_, network_->pathDivider(),
|
||||
network_->pathEscape());
|
||||
}
|
||||
|
||||
void
|
||||
SpefReader::incrLine()
|
||||
{
|
||||
line_++;
|
||||
}
|
||||
|
||||
void
|
||||
SpefReader::warn(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
report_->vfileWarn(filename_, line_, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -510,10 +621,11 @@ SpefReader::makeCouplingCap(int id,
|
|||
char *node_name2,
|
||||
float cap)
|
||||
{
|
||||
const char *name = 0;
|
||||
const char *name = NULL;
|
||||
const char *name_tmp = NULL;
|
||||
if (keep_device_names_)
|
||||
// Prepend device type because OA uses one namespace for all devices.
|
||||
name = stringPrint(INT_DIGITS + 2, "C%d", id);
|
||||
name = name_tmp = stringPrint("C%d", id);
|
||||
|
||||
ParasiticNode *node1, *node2;
|
||||
Net *ext_net1, *ext_net2;
|
||||
|
|
@ -537,6 +649,7 @@ SpefReader::makeCouplingCap(int id,
|
|||
else if (ext_pin1)
|
||||
parasitics_->makeCouplingCap(name, node2, ext_pin1, cap, ap_);
|
||||
}
|
||||
stringDelete(name_tmp);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -549,11 +662,13 @@ SpefReader::makeResistor(int id,
|
|||
ParasiticNode *node2 = findParasiticNode(node_name2);
|
||||
if (node1 && node2) {
|
||||
float res1 = res->value(triple_index_) * res_scale_;
|
||||
const char *name = 0;
|
||||
const char *name = NULL;
|
||||
const char *name_tmp = NULL;
|
||||
if (keep_device_names_)
|
||||
// Prepend device type because OA uses one namespace for all devices.
|
||||
name = stringPrint(INT_DIGITS + 2, "R%d", id);
|
||||
name = name_tmp = stringPrint("R%d", id);
|
||||
parasitics_->makeResistor(name, node1, node2, res1, ap_);
|
||||
stringDelete(name_tmp);
|
||||
}
|
||||
delete res;
|
||||
stringDelete(node_name1);
|
||||
|
|
|
|||
|
|
@ -33,8 +33,6 @@ class Instance;
|
|||
// Return true if successful.
|
||||
bool
|
||||
readSpefFile(const char *filename,
|
||||
gzFile stream,
|
||||
int line,
|
||||
Instance *instance,
|
||||
ParasiticAnalysisPt *ap,
|
||||
bool increment,
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
#include "Map.hh"
|
||||
#include "StringSeq.hh"
|
||||
#include "NetworkClass.hh"
|
||||
#include "SpfSpefReader.hh"
|
||||
#include "ParasiticsClass.hh"
|
||||
|
||||
// Global namespace.
|
||||
#define YY_INPUT(buf,result,max_size) \
|
||||
|
|
@ -34,21 +34,20 @@ SpefParse_error(const char *msg);
|
|||
|
||||
namespace sta {
|
||||
|
||||
class Parasitic;
|
||||
class ParasiticNode;
|
||||
class ParasiticNetwork;
|
||||
class Report;
|
||||
class OperatingConditions;
|
||||
class MinMax;
|
||||
class SpefRspfPi;
|
||||
class SpefTriple;
|
||||
class Corner;
|
||||
|
||||
typedef Map<int,char*,std::less<int> > SpefNameMap;
|
||||
|
||||
class SpefReader : public SpfSpefReader
|
||||
class SpefReader
|
||||
{
|
||||
public:
|
||||
SpefReader(const char *filename,
|
||||
gzFile stream,
|
||||
int line,
|
||||
Instance *instance,
|
||||
ParasiticAnalysisPt *ap,
|
||||
bool increment,
|
||||
|
|
@ -65,6 +64,25 @@ public:
|
|||
Network *network,
|
||||
Parasitics *parasitics);
|
||||
virtual ~SpefReader();
|
||||
char divider() const { return divider_; }
|
||||
void setDivider(char divider);
|
||||
char delimiter() const { return delimiter_; }
|
||||
void setDelimiter(char delimiter);
|
||||
void incrLine();
|
||||
int line() const { return line_; }
|
||||
const char *filename() const { return filename_; }
|
||||
// flex YY_INPUT yy_n_chars arg changed definition from int to size_t,
|
||||
// so provide both forms.
|
||||
void getChars(char *buf,
|
||||
int &result,
|
||||
size_t max_size);
|
||||
void getChars(char *buf,
|
||||
size_t &result,
|
||||
size_t max_size);
|
||||
// Translate from spf/spef namespace to sta namespace.
|
||||
char *translated(const char *token);
|
||||
void warn(const char *fmt, ...)
|
||||
__attribute__((format (printf, 2, 3)));
|
||||
void setBusBrackets(char left,
|
||||
char right);
|
||||
void setTimeScale(float scale,
|
||||
|
|
@ -106,6 +124,10 @@ public:
|
|||
PortDirection *portDirection(char *spef_dir);
|
||||
|
||||
private:
|
||||
Pin *findPinRelative(const char *name);
|
||||
Pin *findPortPinRelative(const char *name);
|
||||
Net *findNetRelative(const char *name);
|
||||
Instance *findInstanceRelative(const char *name);
|
||||
void makeCouplingCap(int id,
|
||||
char *node_name1,
|
||||
char *node_name2,
|
||||
|
|
@ -117,6 +139,31 @@ private:
|
|||
int &ext_node_id,
|
||||
Pin *&ext_pin);
|
||||
|
||||
const char *filename_;
|
||||
Instance *instance_;
|
||||
const ParasiticAnalysisPt *ap_;
|
||||
bool increment_;
|
||||
bool pin_cap_included_;
|
||||
bool keep_coupling_caps_;
|
||||
ReduceParasiticsTo reduce_to_;
|
||||
bool delete_after_reduce_;
|
||||
const OperatingConditions *op_cond_;
|
||||
const Corner *corner_;
|
||||
const MinMax *cnst_min_max_;
|
||||
// Normally no need to keep device names.
|
||||
bool keep_device_names_;
|
||||
bool quiet_;
|
||||
gzFile stream_;
|
||||
int line_;
|
||||
char divider_;
|
||||
char delimiter_;
|
||||
char bus_brkt_left_;
|
||||
char bus_brkt_right_;
|
||||
Net *net_;
|
||||
Report *report_;
|
||||
Network *network_;
|
||||
Parasitics *parasitics_;
|
||||
|
||||
int triple_index_;
|
||||
float time_scale_;
|
||||
float cap_scale_;
|
||||
|
|
@ -125,10 +172,6 @@ private:
|
|||
SpefNameMap name_map_;
|
||||
StringSeq *design_flow_;
|
||||
Parasitic *parasitic_;
|
||||
|
||||
using SpfSpefReader::findPortPinRelative;
|
||||
using SpfSpefReader::findNetRelative;
|
||||
using SpfSpefReader::findInstanceRelative;
|
||||
};
|
||||
|
||||
class SpefTriple
|
||||
|
|
|
|||
|
|
@ -548,8 +548,7 @@ ClockEdge::ClockEdge(Clock *clock,
|
|||
TransRiseFall *tr) :
|
||||
clock_(clock),
|
||||
tr_(tr),
|
||||
name_(stringPrint(strlen(clock_->name())+strlen(tr_->asString()) + 2,
|
||||
"%s %s", clock_->name(), tr_->asString())),
|
||||
name_(stringPrint("%s %s", clock_->name(), tr_->asString())),
|
||||
time_(0.0),
|
||||
index_(clock_->index() * TransRiseFall::index_count + tr_->index())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <cmath> // ceil
|
||||
#include <algorithm> // max
|
||||
#include "Machine.hh"
|
||||
#include "Debug.hh"
|
||||
#include "Fuzzy.hh"
|
||||
|
|
@ -53,59 +55,60 @@ CycleAccting::findDelays(StaState *sta)
|
|||
const int gclk_hold_index = TimingRole::gatedClockHold()->index();
|
||||
Clock *src_clk = src_->clock();
|
||||
Clock *tgt_clk = tgt_->clock();
|
||||
ClockEdge *tgt_opp = tgt_->opposite();
|
||||
double tgt_opp_time1 = tgt_->opposite()->time();
|
||||
double tgt_period = tgt_clk->period();
|
||||
double src_period = src_clk->period();
|
||||
if (tgt_period > 0.0 && src_period > 0.0) {
|
||||
int tgt_max_cycle_count, src_max_cycle_count;
|
||||
if (tgt_period > src_period) {
|
||||
tgt_max_cycle_count = small_period_clk_expansion_cycle_count;
|
||||
src_max_cycle_count = large_period_clk_expansion_cycle_count;
|
||||
}
|
||||
// If the clocks are related (ie, generated clock and its source) allow
|
||||
// allow enough cycles to match up the common period.
|
||||
int tgt_max_cycle;
|
||||
if (tgt_period > src_period)
|
||||
tgt_max_cycle = 100;
|
||||
else {
|
||||
tgt_max_cycle_count = large_period_clk_expansion_cycle_count;
|
||||
src_max_cycle_count = small_period_clk_expansion_cycle_count;
|
||||
int ratio = std::ceil(src_period / tgt_period);
|
||||
tgt_max_cycle = std::max(ratio, 100);
|
||||
}
|
||||
int tgt_cycle;
|
||||
bool tgt_past_src = false;
|
||||
bool src_past_tgt = false;
|
||||
int tgt_cycle, src_cycle;
|
||||
for (tgt_cycle = (tgt_->time() < tgt_period) ? 0 : -1;
|
||||
tgt_cycle < tgt_max_cycle_count;
|
||||
tgt_cycle <= tgt_max_cycle;
|
||||
tgt_cycle++) {
|
||||
double tgt_cycle_start = tgt_cycle * tgt_period;
|
||||
double tgt_time = tgt_cycle_start + tgt_->time();
|
||||
double tgt_opp_time = tgt_cycle_start + tgt_opp->time();
|
||||
int src_cycle;
|
||||
double tgt_opp_time = tgt_cycle_start + tgt_opp_time1;
|
||||
for (src_cycle = (src_->time() < src_period) ? 0 : -1;
|
||||
src_cycle < src_max_cycle_count;
|
||||
;
|
||||
src_cycle++) {
|
||||
double src_cycle_start = src_cycle * src_period;
|
||||
double src_time = src_cycle_start + src_->time();
|
||||
// Make sure both setup and hold required_ are determined.
|
||||
|
||||
// Make sure both setup and hold required are determined.
|
||||
if (tgt_past_src && src_past_tgt
|
||||
// Synchronicity achieved.
|
||||
&& fuzzyEqual(src_cycle_start, tgt_cycle_start)) {
|
||||
debugPrint2(debug, "cycle_acct", 1,
|
||||
" setup = %s, required = %s\n",
|
||||
debugPrint2(debug, "cycle_acct", 1, " setup = %s, required = %s\n",
|
||||
time_unit->asString(delay_[setup_index]),
|
||||
time_unit->asString(required_[setup_index]));
|
||||
debugPrint2(debug, "cycle_acct", 1,
|
||||
" hold = %s, required = %s\n",
|
||||
debugPrint2(debug, "cycle_acct", 1, " hold = %s, required = %s\n",
|
||||
time_unit->asString(delay_[hold_index]),
|
||||
time_unit->asString(required_[hold_index]));
|
||||
debugPrint2(debug, "cycle_acct", 1,
|
||||
" converged at src cycles = %d tgt cycles = %d\n",
|
||||
src_cycle, tgt_cycle);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fuzzyGreater(src_cycle_start, tgt_cycle_start + tgt_period)
|
||||
&& src_past_tgt)
|
||||
break;
|
||||
debugPrint5(debug, "cycle_acct", 2,
|
||||
" %s src cycle %d %s + %s = %s\n",
|
||||
debugPrint5(debug, "cycle_acct", 2, " %s src cycle %d %s + %s = %s\n",
|
||||
src_->name(),
|
||||
src_cycle,
|
||||
time_unit->asString(src_cycle_start),
|
||||
time_unit->asString(src_->time()),
|
||||
time_unit->asString(src_time));
|
||||
debugPrint5(debug, "cycle_acct", 2,
|
||||
" %s tgt cycle %d %s + %s = %s\n",
|
||||
debugPrint5(debug, "cycle_acct", 2, " %s tgt cycle %d %s + %s = %s\n",
|
||||
tgt_->name(),
|
||||
tgt_cycle,
|
||||
time_unit->asString(tgt_cycle_start),
|
||||
|
|
@ -125,6 +128,7 @@ CycleAccting::findDelays(StaState *sta)
|
|||
time_unit->asString(required_[setup_index]));
|
||||
}
|
||||
}
|
||||
|
||||
// Data check setup checks are zero cycle.
|
||||
if (fuzzyLessEqual(tgt_time, src_time)) {
|
||||
double setup_delay = src_time - tgt_time;
|
||||
|
|
@ -138,6 +142,7 @@ CycleAccting::findDelays(StaState *sta)
|
|||
src_cycle + 1, tgt_cycle, hold_delay, hold_required);
|
||||
}
|
||||
}
|
||||
|
||||
// Latch setup cycle accting for the enable is the data clk edge
|
||||
// closest to the disable (opposite) edge.
|
||||
if (fuzzyGreater(tgt_opp_time, src_time)) {
|
||||
|
|
@ -159,6 +164,7 @@ CycleAccting::findDelays(StaState *sta)
|
|||
time_unit->asString(required_[latch_setup_index]));
|
||||
}
|
||||
}
|
||||
|
||||
// For hold checks, target has to be BEFORE source.
|
||||
if (fuzzyLessEqual(tgt_time, src_time)) {
|
||||
double delay = src_time - tgt_time;
|
||||
|
|
@ -172,6 +178,7 @@ CycleAccting::findDelays(StaState *sta)
|
|||
time_unit->asString(required_[hold_index]));
|
||||
}
|
||||
}
|
||||
|
||||
// Gated clock hold checks are in the same cycle as the
|
||||
// setup check.
|
||||
if (fuzzyLessEqual(tgt_opp_time, src_time)) {
|
||||
|
|
@ -187,11 +194,11 @@ CycleAccting::findDelays(StaState *sta)
|
|||
}
|
||||
}
|
||||
}
|
||||
if (src_cycle == src_max_cycle_count)
|
||||
break;
|
||||
}
|
||||
max_cycles_exceeded_ = true;
|
||||
debugPrint0(debug, "cycle_acct", 1, " max cycles exceeded\n");
|
||||
debugPrint2(debug, "cycle_acct", 1,
|
||||
" max cycles exceeded after %d src cycles, %d tgt_cycles\n",
|
||||
src_cycle, tgt_cycle);
|
||||
}
|
||||
else if (tgt_period > 0.0)
|
||||
findDefaultArrivalSrcDelays();
|
||||
|
|
|
|||
|
|
@ -25,15 +25,11 @@
|
|||
|
||||
namespace sta {
|
||||
|
||||
// Maximum number of cycles we are willing to multiply the period by
|
||||
// looking for a minimum separation of edges to another clock.
|
||||
const int large_period_clk_expansion_cycle_count = 1000;
|
||||
const int small_period_clk_expansion_cycle_count = 101;
|
||||
|
||||
class CycleAccting
|
||||
{
|
||||
public:
|
||||
CycleAccting(const ClockEdge *src, const ClockEdge *tgt);
|
||||
CycleAccting(const ClockEdge *src,
|
||||
const ClockEdge *tgt);
|
||||
// Fill in required times.
|
||||
void findDelays(StaState *sta);
|
||||
// Find delays when source clk edge is the default arrival clock edge
|
||||
|
|
@ -88,7 +84,8 @@ private:
|
|||
class CycleAcctingLess
|
||||
{
|
||||
public:
|
||||
bool operator()(const CycleAccting *acct1, const CycleAccting *acct2) const;
|
||||
bool operator()(const CycleAccting *acct1,
|
||||
const CycleAccting *acct2) const;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -583,9 +583,7 @@ const char *
|
|||
PathDelay::asString(const Network *network) const
|
||||
{
|
||||
const char *from_thru_to = fromThruToString(network);
|
||||
const char *result = stringPrintTmp(strlen("PathDelay") + 10
|
||||
+ strlen(from_thru_to) + 1,
|
||||
"PathDelay %.3fns%s",
|
||||
const char *result = stringPrintTmp("PathDelay %.3fns%s",
|
||||
delay_ * 1E+9F,
|
||||
from_thru_to);
|
||||
return result;
|
||||
|
|
@ -776,9 +774,7 @@ const char *
|
|||
MultiCyclePath::asString(const Network *network) const
|
||||
{
|
||||
const char *from_thru_to = fromThruToString(network);
|
||||
const char *result = stringPrintTmp(strlen("Multicycle -max ") + 5
|
||||
+ strlen(from_thru_to) + 1,
|
||||
"Multicycle %s %d%s",
|
||||
const char *result = stringPrintTmp("Multicycle %s %d%s",
|
||||
(use_end_clk_) ? "-end" : "-start",
|
||||
path_multiplier_,
|
||||
from_thru_to);
|
||||
|
|
|
|||
27
sdc/Sdc.cc
27
sdc/Sdc.cc
|
|
@ -2033,15 +2033,20 @@ Sdc::makeClockGroups(const char *name,
|
|||
bool allow_paths,
|
||||
const char *comment)
|
||||
{
|
||||
char *gen_name = NULL;
|
||||
if (name == NULL
|
||||
|| name[0] == '\0')
|
||||
name = makeClockGroupsName();
|
||||
ClockGroups *groups = clk_groups_name_map_.findKey(name);
|
||||
if (groups)
|
||||
removeClockGroups(groups);
|
||||
groups = new ClockGroups(name, logically_exclusive, physically_exclusive,
|
||||
asynchronous, allow_paths, comment);
|
||||
name = gen_name = makeClockGroupsName();
|
||||
else {
|
||||
ClockGroups *groups = clk_groups_name_map_.findKey(name);
|
||||
if (groups)
|
||||
removeClockGroups(groups);
|
||||
}
|
||||
ClockGroups *groups = new ClockGroups(name, logically_exclusive,
|
||||
physically_exclusive,
|
||||
asynchronous, allow_paths, comment);
|
||||
clk_groups_name_map_[groups->name()] = groups;
|
||||
stringDelete(gen_name);
|
||||
return groups;
|
||||
}
|
||||
|
||||
|
|
@ -2049,11 +2054,12 @@ Sdc::makeClockGroups(const char *name,
|
|||
char *
|
||||
Sdc::makeClockGroupsName()
|
||||
{
|
||||
char *name;
|
||||
char *name = NULL;
|
||||
int i = 0;
|
||||
do {
|
||||
i++;
|
||||
name = stringPrintTmp(10, "group%d", i);
|
||||
stringDelete(name);
|
||||
name = stringPrint("group%d", i);
|
||||
} while (clk_groups_name_map_.hasKey(name));
|
||||
return name;
|
||||
}
|
||||
|
|
@ -2609,10 +2615,9 @@ Sdc::reportClkToClkMaxCycleWarnings()
|
|||
ClockPairSeq::Iterator pair_iter2(clk_warnings2);
|
||||
while (pair_iter2.hasNext()) {
|
||||
ClockPair *pair = pair_iter2.next();
|
||||
report_->warn("No common period was found between clocks %s and %s in %d cycles.\n",
|
||||
report_->warn("No common period was found between clocks %s and %s.\n",
|
||||
pair->first->name(),
|
||||
pair->second->name(),
|
||||
large_period_clk_expansion_cycle_count);
|
||||
pair->second->name());
|
||||
delete pair;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1265,9 +1265,9 @@ WriteSdc::writeDisabledEdgeSense(Edge *edge) const
|
|||
{
|
||||
fprintf(stream_, "set_disable_timing ");
|
||||
const char *sense = timingSenseString(edge->sense());
|
||||
const char *filter = stringPrintTmp(strlen(sense) + strlen("sense == ") + 1,
|
||||
"sense == %s", sense);
|
||||
writeGetTimingArcs(edge, filter);
|
||||
string filter;
|
||||
stringPrint(filter, "sense == %s", sense);
|
||||
writeGetTimingArcs(edge, filter.c_str());
|
||||
fprintf(stream_, "\n");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -283,11 +283,9 @@ ReportAnnotated::reportCheckCount(TimingRole *role,
|
|||
int index = role->index();
|
||||
if (edge_count_[index] > 0) {
|
||||
const char *role_name = role->asString();
|
||||
const char *title = stringPrintTmp(strlen("cell arcs")
|
||||
+ strlen(role_name) + 1,
|
||||
"cell %s arcs",
|
||||
role_name);
|
||||
reportCount(title, index, total, annotated_total);
|
||||
string title;
|
||||
stringPrint(title, "cell %s arcs", role_name);
|
||||
reportCount(title.c_str(), index, total, annotated_total);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1043,23 +1043,25 @@ SdfReader::sdfError(const char *fmt, ...)
|
|||
Pin *
|
||||
SdfReader::findPin(const char *name)
|
||||
{
|
||||
const char *path_name = (path_)
|
||||
? stringPrintTmp(strlen(name) + strlen(name) + 2, "%s%c%s",
|
||||
path_, divider_, name)
|
||||
: name;
|
||||
return network_->findPin(path_name);
|
||||
if (path_) {
|
||||
string path_name;
|
||||
stringPrint(path_name, path_, divider_, name);
|
||||
Pin *pin = network_->findPin(path_name.c_str());
|
||||
return pin;
|
||||
}
|
||||
else
|
||||
return network_->findPin(name);
|
||||
}
|
||||
|
||||
Instance *
|
||||
SdfReader::findInstance(const char *name)
|
||||
{
|
||||
const char *path_name = (path_)
|
||||
? stringPrintTmp(strlen(name) + strlen(name) + 2, "%s%c%s",
|
||||
path_, divider_, name)
|
||||
: name;
|
||||
Instance *inst = network_->findInstance(path_name);
|
||||
string inst_name = name;
|
||||
if (path_)
|
||||
stringPrint(inst_name, "%s%c%s", path_, divider_, name);
|
||||
Instance *inst = network_->findInstance(inst_name.c_str());
|
||||
if (inst == NULL)
|
||||
sdfError("instance %s not found.\n", path_name);
|
||||
sdfError("instance %s not found.\n", inst_name.c_str());
|
||||
return inst;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ ClkInfo::asString(const StaState *sta) const
|
|||
string str;
|
||||
|
||||
PathAnalysisPt *path_ap = corners->findPathAnalysisPt(path_ap_index_);
|
||||
str += stringPrintTmp(15, "%s/%d ",
|
||||
str += stringPrintTmp("%s/%d ",
|
||||
path_ap->pathMinMax()->asString(),
|
||||
path_ap_index_);
|
||||
if (clk_edge_)
|
||||
|
|
|
|||
|
|
@ -87,14 +87,15 @@ CheckCrpr::maxCrpr(ClkInfo *clk_info)
|
|||
const PathVertexRep &crpr_clk_path = clk_info->crprClkPath();
|
||||
if (!crpr_clk_path.isNull()) {
|
||||
PathVertex crpr_clk_vpath(crpr_clk_path, this);
|
||||
Arrival other_arrival = otherMinMaxArrival(&crpr_clk_vpath);
|
||||
float crpr_diff = abs(delayAsFloat(crpr_clk_vpath.arrival(this),
|
||||
EarlyLate::late())
|
||||
- delayAsFloat(other_arrival, EarlyLate::early()));
|
||||
return crpr_diff;
|
||||
if (!crpr_clk_vpath.isNull()) {
|
||||
Arrival other_arrival = otherMinMaxArrival(&crpr_clk_vpath);
|
||||
float crpr_diff = abs(delayAsFloat(crpr_clk_vpath.arrival(this),
|
||||
EarlyLate::late())
|
||||
- delayAsFloat(other_arrival, EarlyLate::early()));
|
||||
return crpr_diff;
|
||||
}
|
||||
}
|
||||
else
|
||||
return 0.0F;
|
||||
return 0.0F;
|
||||
}
|
||||
|
||||
Arrival
|
||||
|
|
|
|||
|
|
@ -40,9 +40,7 @@ Path::name(const StaState *sta) const
|
|||
int ap_index = path_ap->index();
|
||||
const char *min_max = path_ap->pathMinMax()->asString();
|
||||
TagIndex tag_index = tagIndex(sta);
|
||||
size_t result_len = strlen(vertex_name) + strlen(tr_str)
|
||||
+ 2 + strlen(min_max) + 16;
|
||||
return stringPrintTmp(result_len, "%s %s %s/%d %d",
|
||||
return stringPrintTmp("%s %s %s/%d %d",
|
||||
vertex_name, tr_str, min_max,
|
||||
ap_index, tag_index);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,16 +104,18 @@ PathVertex::init(Vertex *vertex,
|
|||
Tag *tag,
|
||||
const StaState *sta)
|
||||
{
|
||||
vertex_ = vertex;
|
||||
vertex_ = NULL;
|
||||
tag_ = NULL;
|
||||
arrival_index_ = 0;
|
||||
const Search *search = sta->search();
|
||||
TagGroup *tag_group = search->tagGroup(vertex_);
|
||||
TagGroup *tag_group = search->tagGroup(vertex);
|
||||
if (tag_group) {
|
||||
bool arrival_exists;
|
||||
tag_group->arrivalIndex(tag, arrival_index_, arrival_exists);
|
||||
if (arrival_exists)
|
||||
if (arrival_exists) {
|
||||
vertex_ = vertex;
|
||||
tag_ = tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,9 +31,12 @@
|
|||
#include "PathRef.hh"
|
||||
#include "Property.hh"
|
||||
#include "Sta.hh"
|
||||
#include "Property.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
using std::string;
|
||||
|
||||
static PropertyValue
|
||||
pinSlewProperty(const Pin *pin,
|
||||
const TransRiseFall *tr,
|
||||
|
|
@ -78,6 +81,13 @@ PropertyValue::PropertyValue(const char *value) :
|
|||
string_ = stringCopy(value);
|
||||
}
|
||||
|
||||
PropertyValue::PropertyValue(std::string &value) :
|
||||
type_(type_string)
|
||||
{
|
||||
init();
|
||||
string_ = stringCopy(value.c_str());
|
||||
}
|
||||
|
||||
PropertyValue::PropertyValue(float value) :
|
||||
type_(type_float)
|
||||
{
|
||||
|
|
@ -85,6 +95,27 @@ PropertyValue::PropertyValue(float value) :
|
|||
float_ = value;
|
||||
}
|
||||
|
||||
PropertyValue::PropertyValue(LibertyLibrary *value) :
|
||||
type_(type_liberty_library)
|
||||
{
|
||||
init();
|
||||
liberty_library_ = value;
|
||||
}
|
||||
|
||||
PropertyValue::PropertyValue(LibertyCell *value) :
|
||||
type_(type_liberty_cell)
|
||||
{
|
||||
init();
|
||||
liberty_cell_ = value;
|
||||
}
|
||||
|
||||
PropertyValue::PropertyValue(Cell *value) :
|
||||
type_(type_cell)
|
||||
{
|
||||
init();
|
||||
cell_ = value;
|
||||
}
|
||||
|
||||
PropertyValue::PropertyValue(Instance *value) :
|
||||
type_(type_instance)
|
||||
{
|
||||
|
|
@ -162,6 +193,9 @@ PropertyValue::PropertyValue(const PropertyValue &value) :
|
|||
type_(value.type_),
|
||||
string_(stringCopy(value.string_)),
|
||||
float_(value.float_),
|
||||
liberty_library_(value.liberty_library_),
|
||||
liberty_cell_(value.liberty_cell_),
|
||||
cell_(value.cell_),
|
||||
inst_(value.inst_),
|
||||
pin_(value.pin_),
|
||||
pins_(value.pins_ ? new PinSeq(*value.pins_) : NULL),
|
||||
|
|
@ -177,6 +211,9 @@ PropertyValue::init()
|
|||
{
|
||||
string_ = NULL;
|
||||
float_ = 0.0;
|
||||
liberty_library_ = NULL;
|
||||
liberty_cell_ = NULL;
|
||||
cell_ = NULL;
|
||||
inst_ = NULL;
|
||||
pin_ = NULL;
|
||||
pins_ = NULL;
|
||||
|
|
@ -200,6 +237,9 @@ PropertyValue::operator=(const PropertyValue &value)
|
|||
type_ = value.type_;
|
||||
string_ = stringCopy(value.string_);
|
||||
float_ = value.float_;
|
||||
liberty_library_ = value.liberty_library_;
|
||||
liberty_cell_ = value.liberty_cell_;
|
||||
cell_ = value.cell_;
|
||||
inst_ = value.inst_;
|
||||
pin_ = value.pin_;
|
||||
pins_ = value.pins_ ? new PinSeq(*value.pins_) : NULL;
|
||||
|
|
@ -209,18 +249,217 @@ PropertyValue::operator=(const PropertyValue &value)
|
|||
path_refs_ = value.path_refs_ ? new PathRefSeq(*value.path_refs_) : NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
PropertyValue
|
||||
getProperty(const Library *lib,
|
||||
const char *property,
|
||||
Sta *sta)
|
||||
{
|
||||
auto network = sta->cmdNetwork();
|
||||
if (stringEqual(property, "name")
|
||||
|| stringEqual(property, "full_name"))
|
||||
return PropertyValue(network->name(lib));
|
||||
#if 0
|
||||
else if (stringEqual(property, "filename"))
|
||||
return PropertyValue(network->filename(lib));
|
||||
#endif
|
||||
else
|
||||
return PropertyValue();
|
||||
}
|
||||
|
||||
PropertyValue
|
||||
getProperty(const LibertyLibrary *lib,
|
||||
const char *property,
|
||||
Sta *)
|
||||
{
|
||||
if (stringEqual(property, "name")
|
||||
|| stringEqual(property, "full_name"))
|
||||
return PropertyValue(lib->name());
|
||||
else if (stringEqual(property, "filename"))
|
||||
return PropertyValue(lib->filename());
|
||||
else
|
||||
return PropertyValue();
|
||||
}
|
||||
|
||||
PropertyValue
|
||||
getProperty(const LibertyCell *cell,
|
||||
const char *property,
|
||||
Sta *sta)
|
||||
{
|
||||
if (stringEqual(property, "name")
|
||||
|| stringEqual(property, "base_name"))
|
||||
return PropertyValue(cell->name());
|
||||
else if (stringEqual(property, "full_name")) {
|
||||
auto network = sta->cmdNetwork();
|
||||
auto lib = cell->libertyLibrary();
|
||||
const char *lib_name = lib->name();
|
||||
const char *cell_name = cell->name();
|
||||
string full_name;
|
||||
stringPrint(full_name, "%s%c%s",
|
||||
lib_name,
|
||||
network->pathDivider(),
|
||||
cell_name);
|
||||
return PropertyValue(full_name);
|
||||
}
|
||||
else if (stringEqual(property, "filename"))
|
||||
return PropertyValue(cell->filename());
|
||||
else if (stringEqual(property, "library"))
|
||||
return PropertyValue(cell->libertyLibrary());
|
||||
else
|
||||
return PropertyValue();
|
||||
}
|
||||
|
||||
PropertyValue
|
||||
getProperty(const Cell *cell,
|
||||
const char *property,
|
||||
Sta *sta)
|
||||
{
|
||||
auto network = sta->cmdNetwork();
|
||||
if (stringEqual(property, "name")
|
||||
|| stringEqual(property, "base_name"))
|
||||
return PropertyValue(network->name(cell));
|
||||
else if (stringEqual(property, "full_name")) {
|
||||
auto lib = network->library(cell);
|
||||
const char *lib_name = network->name(lib);
|
||||
const char *cell_name = network->name(cell);
|
||||
string full_name;
|
||||
stringPrint(full_name, "%s%c%s",
|
||||
lib_name,
|
||||
network->pathDivider(),
|
||||
cell_name);
|
||||
return PropertyValue(full_name);
|
||||
}
|
||||
else if (stringEqual(property, "filename"))
|
||||
return PropertyValue(network->filename(cell));
|
||||
else
|
||||
return PropertyValue();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
PropertyValue
|
||||
getProperty(const Port *port,
|
||||
const char *property,
|
||||
Sta *sta)
|
||||
{
|
||||
auto network = sta->cmdNetwork();
|
||||
if (stringEqual(property, "name")
|
||||
|| stringEqual(property, "full_name"))
|
||||
return PropertyValue(network->name(port));
|
||||
else if (stringEqual(property, "direction"))
|
||||
return PropertyValue(network->direction(port)->name());
|
||||
|
||||
else if (stringEqual(property, "actual_fall_transition_min"))
|
||||
return portSlewProperty(port, TransRiseFall::fall(), MinMax::min(), sta);
|
||||
else if (stringEqual(property, "actual_fall_transition_max"))
|
||||
return portSlewProperty(port, TransRiseFall::fall(), MinMax::max(), sta);
|
||||
else if (stringEqual(property, "actual_rise_transition_min"))
|
||||
return portSlewProperty(port, TransRiseFall::rise(), MinMax::min(), sta);
|
||||
else if (stringEqual(property, "actual_rise_transition_max"))
|
||||
return portSlewProperty(port, TransRiseFall::rise(), MinMax::max(), sta);
|
||||
|
||||
else if (stringEqual(property, "min_fall_slack"))
|
||||
return portSlackProperty(port, TransRiseFall::fall(), MinMax::min(), sta);
|
||||
else if (stringEqual(property, "max_fall_slack"))
|
||||
return portSlackProperty(port, TransRiseFall::fall(), MinMax::max(), sta);
|
||||
else if (stringEqual(property, "min_rise_slack"))
|
||||
return portSlackProperty(port, TransRiseFall::rise(), MinMax::min(), sta);
|
||||
else if (stringEqual(property, "max_rise_slack"))
|
||||
return portSlackProperty(port, TransRiseFall::rise(), MinMax::max(), sta);
|
||||
|
||||
else
|
||||
return PropertyValue();
|
||||
}
|
||||
|
||||
static PropertyValue
|
||||
portSlewProperty(const Port *port,
|
||||
const TransRiseFall *tr,
|
||||
const MinMax *min_max,
|
||||
Sta *sta)
|
||||
{
|
||||
auto network = sta->cmdNetwork();
|
||||
Instance *top_inst = network->topInstance();
|
||||
Pin *pin = network->findPin(top_inst, port);
|
||||
return pinSlewProperty(pin, tr, min_max, sta);
|
||||
}
|
||||
|
||||
static PropertyValue
|
||||
portSlackProperty(const Port *port,
|
||||
const TransRiseFall *tr,
|
||||
const MinMax *min_max,
|
||||
Sta *sta)
|
||||
{
|
||||
auto network = sta->cmdNetwork();
|
||||
Instance *top_inst = network->topInstance();
|
||||
Pin *pin = network->findPin(top_inst, port);
|
||||
return pinSlackProperty(pin, tr, min_max, sta);
|
||||
}
|
||||
|
||||
PropertyValue
|
||||
getProperty(const LibertyPort *port,
|
||||
const char *property,
|
||||
Sta *)
|
||||
{
|
||||
if (stringEqual(property, "name"))
|
||||
return PropertyValue(port->name());
|
||||
else if (stringEqual(property, "full_name"))
|
||||
return PropertyValue(port->name());
|
||||
else if (stringEqual(property, "direction"))
|
||||
return PropertyValue(port->direction()->name());
|
||||
else
|
||||
return PropertyValue();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
class PropertyError : public StaException
|
||||
{
|
||||
public:
|
||||
PropertyError(const char *type,
|
||||
const char *property);
|
||||
virtual const char *what() const throw();
|
||||
|
||||
protected:
|
||||
const char *type_;
|
||||
const char *property_;
|
||||
};
|
||||
|
||||
PropertyError::PropertyError(const char *type,
|
||||
const char *property) :
|
||||
type_(type),
|
||||
property_(property)
|
||||
{
|
||||
}
|
||||
|
||||
const char *
|
||||
PropertyError::what() const throw()
|
||||
{
|
||||
// leak
|
||||
return stringPrint("%s objects do not have a %s property.",
|
||||
type_, property_);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
PropertyValue
|
||||
getProperty(const Instance *inst,
|
||||
const char *property,
|
||||
Sta *sta)
|
||||
{
|
||||
Network *network = sta->network();
|
||||
if (stringEqual(property, "ref_name"))
|
||||
return PropertyValue(network->name(network->cell(inst)));
|
||||
auto network = sta->cmdNetwork();
|
||||
if (stringEqual(property, "name"))
|
||||
return PropertyValue(network->name(inst));
|
||||
else if (stringEqual(property, "full_name"))
|
||||
return PropertyValue(network->pathName(inst));
|
||||
else if (stringEqual(property, "ref_name"))
|
||||
return PropertyValue(network->name(network->cell(inst)));
|
||||
else if (stringEqual(property, "liberty_cell"))
|
||||
return PropertyValue(network->libertyCell(inst));
|
||||
else if (stringEqual(property, "cell"))
|
||||
return PropertyValue(network->cell(inst));
|
||||
else
|
||||
return PropertyValue();
|
||||
throw PropertyError("instance", property);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
|
@ -230,7 +469,7 @@ getProperty(const Pin *pin,
|
|||
const char *property,
|
||||
Sta *sta)
|
||||
{
|
||||
Network *network = sta->network();
|
||||
auto network = sta->cmdNetwork();
|
||||
if (stringEqual(property, "direction"))
|
||||
return PropertyValue(network->direction(pin)->name());
|
||||
else if (stringEqual(property, "full_name"))
|
||||
|
|
@ -262,7 +501,7 @@ getProperty(const Pin *pin,
|
|||
return pinSlewProperty(pin, TransRiseFall::fall(), MinMax::min(), sta);
|
||||
|
||||
else
|
||||
return PropertyValue();
|
||||
throw PropertyError("pin", property);
|
||||
}
|
||||
|
||||
static PropertyValue
|
||||
|
|
@ -305,135 +544,11 @@ getProperty(const Net *net,
|
|||
const char *property,
|
||||
Sta *sta)
|
||||
{
|
||||
Network *network = sta->network();
|
||||
auto network = sta->cmdNetwork();
|
||||
if (stringEqual(property, "full_name"))
|
||||
return PropertyValue(network->pathName(net));
|
||||
else
|
||||
return PropertyValue();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
PropertyValue
|
||||
getProperty(const Port *port,
|
||||
const char *property,
|
||||
Sta *sta)
|
||||
{
|
||||
Network *network = sta->network();
|
||||
if (stringEqual(property, "direction"))
|
||||
return PropertyValue(network->direction(port)->name());
|
||||
else if (stringEqual(property, "full_name"))
|
||||
return PropertyValue(network->name(port));
|
||||
|
||||
else if (stringEqual(property, "actual_fall_transition_min"))
|
||||
return portSlewProperty(port, TransRiseFall::fall(), MinMax::min(), sta);
|
||||
else if (stringEqual(property, "actual_fall_transition_max"))
|
||||
return portSlewProperty(port, TransRiseFall::fall(), MinMax::max(), sta);
|
||||
else if (stringEqual(property, "actual_rise_transition_min"))
|
||||
return portSlewProperty(port, TransRiseFall::rise(), MinMax::min(), sta);
|
||||
else if (stringEqual(property, "actual_rise_transition_max"))
|
||||
return portSlewProperty(port, TransRiseFall::rise(), MinMax::max(), sta);
|
||||
|
||||
else if (stringEqual(property, "min_fall_slack"))
|
||||
return portSlackProperty(port, TransRiseFall::fall(), MinMax::min(), sta);
|
||||
else if (stringEqual(property, "max_fall_slack"))
|
||||
return portSlackProperty(port, TransRiseFall::fall(), MinMax::max(), sta);
|
||||
else if (stringEqual(property, "min_rise_slack"))
|
||||
return portSlackProperty(port, TransRiseFall::rise(), MinMax::min(), sta);
|
||||
else if (stringEqual(property, "max_rise_slack"))
|
||||
return portSlackProperty(port, TransRiseFall::rise(), MinMax::max(), sta);
|
||||
|
||||
else
|
||||
return PropertyValue();
|
||||
}
|
||||
|
||||
static PropertyValue
|
||||
portSlewProperty(const Port *port,
|
||||
const TransRiseFall *tr,
|
||||
const MinMax *min_max,
|
||||
Sta *sta)
|
||||
{
|
||||
Network *network = sta->network();
|
||||
Instance *top_inst = network->topInstance();
|
||||
Pin *pin = network->findPin(top_inst, port);
|
||||
return pinSlewProperty(pin, tr, min_max, sta);
|
||||
}
|
||||
|
||||
static PropertyValue
|
||||
portSlackProperty(const Port *port,
|
||||
const TransRiseFall *tr,
|
||||
const MinMax *min_max,
|
||||
Sta *sta)
|
||||
{
|
||||
Network *network = sta->network();
|
||||
Instance *top_inst = network->topInstance();
|
||||
Pin *pin = network->findPin(top_inst, port);
|
||||
return pinSlackProperty(pin, tr, min_max, sta);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
PropertyValue
|
||||
getProperty(const LibertyCell *cell,
|
||||
const char *property,
|
||||
Sta *sta)
|
||||
{
|
||||
if (stringEqual(property, "base_name"))
|
||||
return PropertyValue(cell->name());
|
||||
else if (stringEqual(property, "full_name")) {
|
||||
Network *network = sta->network();
|
||||
const LibertyLibrary *lib = cell->libertyLibrary();
|
||||
const char *lib_name = lib->name();
|
||||
const char *cell_name = cell->name();
|
||||
char *full_name = stringPrintTmp(strlen(lib_name) + strlen(cell_name) + 2,
|
||||
"%s%c%s",
|
||||
lib_name,
|
||||
network->pathDivider(),
|
||||
cell_name);
|
||||
return PropertyValue(full_name);
|
||||
}
|
||||
else
|
||||
return PropertyValue();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
PropertyValue
|
||||
getProperty(const LibertyPort *port,
|
||||
const char *property,
|
||||
Sta *)
|
||||
{
|
||||
if (stringEqual(property, "direction"))
|
||||
return PropertyValue(port->direction()->name());
|
||||
else if (stringEqual(property, "full_name"))
|
||||
return PropertyValue(port->name());
|
||||
else
|
||||
return PropertyValue();
|
||||
}
|
||||
|
||||
PropertyValue
|
||||
getProperty(const Library *lib,
|
||||
const char *property,
|
||||
Sta *sta)
|
||||
{
|
||||
Network *network = sta->network();
|
||||
if (stringEqual(property, "name"))
|
||||
return PropertyValue(network->name(lib));
|
||||
else
|
||||
return PropertyValue();
|
||||
}
|
||||
|
||||
PropertyValue
|
||||
getProperty(const LibertyLibrary *lib,
|
||||
const char *property,
|
||||
Sta *)
|
||||
{
|
||||
if (stringEqual(property, "name"))
|
||||
return PropertyValue(lib->name());
|
||||
else if (stringEqual(property, "filename"))
|
||||
return PropertyValue(lib->filename());
|
||||
else
|
||||
return PropertyValue();
|
||||
throw PropertyError("net", property);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
|
@ -443,6 +558,13 @@ getProperty(Edge *edge,
|
|||
const char *property,
|
||||
Sta *sta)
|
||||
{
|
||||
if (stringEqual(property, "full_name")) {
|
||||
auto network = sta->cmdNetwork();
|
||||
auto graph = sta->graph();
|
||||
const char *from = edge->from(graph)->name(network);
|
||||
const char *to = edge->to(graph)->name(network);
|
||||
return stringPrintTmp("%s -> %s", from, to);
|
||||
}
|
||||
if (stringEqual(property, "delay_min_fall"))
|
||||
return edgeDelayProperty(edge, TransRiseFall::fall(), MinMax::min(), sta);
|
||||
else if (stringEqual(property, "delay_max_fall"))
|
||||
|
|
@ -458,7 +580,7 @@ getProperty(Edge *edge,
|
|||
else if (stringEqual(property, "to_pin"))
|
||||
return PropertyValue(edge->to(sta->graph())->pin());
|
||||
else
|
||||
return PropertyValue();
|
||||
throw PropertyError("edge", property);
|
||||
}
|
||||
|
||||
static PropertyValue
|
||||
|
|
@ -494,12 +616,33 @@ edgeDelayProperty(Edge *edge,
|
|||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
PropertyValue
|
||||
getProperty(TimingArcSet *arc_set,
|
||||
const char *property,
|
||||
Sta *)
|
||||
{
|
||||
if (stringEqual(property, "name")
|
||||
|| stringEqual(property, "full_name")) {
|
||||
auto from = arc_set->from()->name();
|
||||
auto to = arc_set->to()->name();
|
||||
auto cell_name = arc_set->libertyCell()->name();
|
||||
string name;
|
||||
stringPrint(name, "%s %s -> %s", cell_name, from, to);
|
||||
return PropertyValue(name);
|
||||
}
|
||||
else
|
||||
throw PropertyError("timing arc", property);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
PropertyValue
|
||||
getProperty(Clock *clk,
|
||||
const char *property,
|
||||
Sta *sta)
|
||||
{
|
||||
if (stringEqual(property, "name"))
|
||||
if (stringEqual(property, "name")
|
||||
|| stringEqual(property, "full_name"))
|
||||
return PropertyValue(clk->name());
|
||||
else if (stringEqual(property, "period"))
|
||||
return PropertyValue(sta->units()->timeUnit()->asString(clk->period(), 8));
|
||||
|
|
@ -508,7 +651,7 @@ getProperty(Clock *clk,
|
|||
else if (stringEqual(property, "propagated"))
|
||||
return PropertyValue(clk->isPropagated() ? "1" : "0");
|
||||
else
|
||||
return PropertyValue();
|
||||
throw PropertyError("clock", property);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
|
@ -542,7 +685,7 @@ getProperty(PathEnd *end,
|
|||
return PropertyValue(&paths);
|
||||
}
|
||||
else
|
||||
return PropertyValue();
|
||||
throw PropertyError("path end", property);
|
||||
}
|
||||
|
||||
PropertyValue
|
||||
|
|
@ -559,7 +702,7 @@ getProperty(PathRef *path,
|
|||
else if (stringEqual(property, "slack"))
|
||||
return PropertyValue(delayPropertyValue(path->slack(sta), sta));
|
||||
else
|
||||
return PropertyValue();
|
||||
throw PropertyError("path", property);
|
||||
}
|
||||
|
||||
static float
|
||||
|
|
|
|||
|
|
@ -17,22 +17,32 @@
|
|||
#ifndef STA_PROPERTY_H
|
||||
#define STA_PROPERTY_H
|
||||
|
||||
#include <string>
|
||||
#include "LibertyClass.hh"
|
||||
#include "NetworkClass.hh"
|
||||
#include "SearchClass.hh"
|
||||
#include "SdcClass.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
using std::string;
|
||||
|
||||
class Sta;
|
||||
|
||||
class PropertyValue
|
||||
{
|
||||
public:
|
||||
enum Type { type_none, type_string, type_float,
|
||||
type_liberty_library, type_liberty_cell, type_cell,
|
||||
type_instance, type_pin, type_pins, type_net,
|
||||
type_clock, type_clocks, type_path_refs };
|
||||
PropertyValue();
|
||||
PropertyValue(const char *value);
|
||||
PropertyValue(string &value);
|
||||
PropertyValue(float value);
|
||||
PropertyValue(LibertyLibrary *value);
|
||||
PropertyValue(LibertyCell *value);
|
||||
PropertyValue(Cell *value);
|
||||
PropertyValue(Instance *value);
|
||||
PropertyValue(Pin *value);
|
||||
PropertyValue(PinSeq *value);
|
||||
|
|
@ -46,8 +56,11 @@ public:
|
|||
PropertyValue(const PropertyValue &props);
|
||||
~PropertyValue();
|
||||
Type type() const { return type_; }
|
||||
const char *string() const { return string_; }
|
||||
const char *stringValue() const { return string_; }
|
||||
float floatValue() const { return float_; }
|
||||
LibertyLibrary *libertyLibrary() const { return liberty_library_; }
|
||||
LibertyCell *libertyCell() const { return liberty_cell_; }
|
||||
Cell *cell() const { return cell_; }
|
||||
Instance *instance() const { return inst_; }
|
||||
Pin *pin() const { return pin_; }
|
||||
PinSeq *pins() const { return pins_; }
|
||||
|
|
@ -63,6 +76,9 @@ private:
|
|||
Type type_;
|
||||
const char *string_;
|
||||
float float_;
|
||||
LibertyLibrary *liberty_library_;
|
||||
LibertyCell *liberty_cell_;
|
||||
Cell *cell_;
|
||||
Instance *inst_;
|
||||
Pin *pin_;
|
||||
PinSeq *pins_;
|
||||
|
|
@ -92,6 +108,11 @@ getProperty(const Port *port,
|
|||
const char *property,
|
||||
Sta *sta);
|
||||
|
||||
PropertyValue
|
||||
getProperty(const Cell *cell,
|
||||
const char *property,
|
||||
Sta *sta);
|
||||
|
||||
PropertyValue
|
||||
getProperty(const LibertyCell *cell,
|
||||
const char *property,
|
||||
|
|
@ -132,5 +153,10 @@ getProperty(PathRef *end,
|
|||
const char *property,
|
||||
Sta *sta);
|
||||
|
||||
PropertyValue
|
||||
getProperty(TimingArcSet *arc_set,
|
||||
const char *property,
|
||||
Sta *sta);
|
||||
|
||||
} // namespace
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -137,10 +137,8 @@ ReportPath::~ReportPath()
|
|||
delete field_edge_;
|
||||
delete field_case_;
|
||||
|
||||
if (plus_zero_) {
|
||||
stringDelete(plus_zero_);
|
||||
stringDelete(minus_zero_);
|
||||
}
|
||||
stringDelete(plus_zero_);
|
||||
stringDelete(minus_zero_);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -250,8 +248,8 @@ ReportPath::setDigits(int digits)
|
|||
stringDelete(plus_zero_);
|
||||
stringDelete(minus_zero_);
|
||||
}
|
||||
minus_zero_ = stringPrint(digits_ + 4, "-%.*f", digits_, 0.0);
|
||||
plus_zero_ = stringPrint(digits_ + 3, "%.*f", digits_, 0.0);
|
||||
minus_zero_ = stringPrint("-%.*f", digits_, 0.0);
|
||||
plus_zero_ = stringPrint("%.*f", digits_, 0.0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
|
@ -461,14 +459,11 @@ ReportPath::reportFull(const PathEndCheck *end,
|
|||
reportSlack(end, result);
|
||||
}
|
||||
|
||||
char *
|
||||
string
|
||||
ReportPath::checkRoleString(const PathEnd *end)
|
||||
{
|
||||
const char *check_role = end->checkRole(this)->asString();
|
||||
return stringPrintTmp(strlen("library time")
|
||||
+ strlen(check_role) + 1,
|
||||
"library %s time",
|
||||
check_role);
|
||||
return stdstrPrint("library %s time", check_role);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -477,42 +472,30 @@ ReportPath::reportEndpoint(const PathEndCheck *end,
|
|||
{
|
||||
Instance *inst = network_->instance(end->vertex(this)->pin());
|
||||
const char *inst_name = cmd_network_->pathName(inst);
|
||||
const char *clk_name = tgtClkName(end);
|
||||
string clk_name = tgtClkName(end);
|
||||
const char *rise_fall = asRisingFalling(end->targetClkEndTrans(this));
|
||||
const TimingRole *check_role = end->checkRole(this);
|
||||
const TimingRole *check_generic_role = check_role->genericRole();
|
||||
if (check_role == TimingRole::recovery()
|
||||
|| check_role == TimingRole::removal()) {
|
||||
const char *check_role_name = check_role->asString();
|
||||
char *reason = stringPrintTmp(strlen(" check against -edge clock ")
|
||||
+ strlen(check_role_name)
|
||||
+ strlen(rise_fall)
|
||||
+ strlen(clk_name) + 1,
|
||||
"%s check against %s-edge clock %s",
|
||||
check_role_name,
|
||||
rise_fall,
|
||||
clk_name);
|
||||
auto reason = stdstrPrint("%s check against %s-edge clock %s",
|
||||
check_role_name,
|
||||
rise_fall,
|
||||
clk_name.c_str());
|
||||
reportEndpoint(inst_name, reason, result);
|
||||
}
|
||||
else if (check_generic_role == TimingRole::setup()
|
||||
|| check_generic_role == TimingRole::hold()) {
|
||||
LibertyCell *cell = network_->libertyCell(inst);
|
||||
if (cell->isClockGate()) {
|
||||
const char *reason =
|
||||
stringPrintTmp(strlen( " clock gating-check end-point clocked by ")
|
||||
+ strlen(rise_fall)
|
||||
+ strlen(clk_name) + 1,
|
||||
"%s clock gating-check end-point clocked by %s",
|
||||
rise_fall, clk_name);
|
||||
auto reason = stdstrPrint("%s clock gating-check end-point clocked by %s",
|
||||
rise_fall, clk_name.c_str());
|
||||
reportEndpoint(inst_name, reason, result);
|
||||
}
|
||||
else {
|
||||
const char *reg_desc = clkRegLatchDesc(end);
|
||||
const char *reason = stringPrintTmp(strlen( " clocked by ")
|
||||
+ strlen(reg_desc)
|
||||
+ strlen(clk_name) + 1,
|
||||
"%s clocked by %s",
|
||||
reg_desc, clk_name);
|
||||
auto reason = stdstrPrint("%s clocked by %s", reg_desc, clk_name.c_str());
|
||||
reportEndpoint(inst_name, reason, result);
|
||||
}
|
||||
}
|
||||
|
|
@ -604,13 +587,9 @@ ReportPath::reportEndpoint(const PathEndLatchCheck *end,
|
|||
{
|
||||
Instance *inst = network_->instance(end->vertex(this)->pin());
|
||||
const char *inst_name = cmd_network_->pathName(inst);
|
||||
const char *clk_name = tgtClkName(end);
|
||||
string clk_name = tgtClkName(end);
|
||||
const char *reg_desc = latchDesc(end);
|
||||
const char *reason = stringPrintTmp(strlen( " clocked by ")
|
||||
+ strlen(reg_desc)
|
||||
+ strlen(clk_name) + 1,
|
||||
"%s clocked by %s",
|
||||
reg_desc, clk_name);
|
||||
auto reason = stdstrPrint("%s clocked by %s", reg_desc, clk_name.c_str());
|
||||
reportEndpoint(inst_name, reason, result);
|
||||
}
|
||||
|
||||
|
|
@ -646,25 +625,19 @@ ReportPath::reportBorrowing(const PathEndLatchCheck *end,
|
|||
if (borrow_limit_exists)
|
||||
reportLineTotal("user max time borrow", max_borrow, early_late, result);
|
||||
else {
|
||||
const char *tgt_clk_name = tgtClkName(end);
|
||||
string tgt_clk_name = tgtClkName(end);
|
||||
Arrival tgt_clk_width = end->targetClkWidth(this);
|
||||
const Path *tgt_clk_path = end->targetClkPath();
|
||||
if (tgt_clk_path->clkInfo(search_)->isPropagated()) {
|
||||
const char *width_msg = stringPrintTmp(strlen(" nominal pulse width")
|
||||
+ strlen(tgt_clk_name) + 1,
|
||||
"%s nominal pulse width",
|
||||
tgt_clk_name);
|
||||
reportLineTotal(width_msg, nom_pulse_width, early_late, result);
|
||||
auto width_msg = stdstrPrint("%s nominal pulse width", tgt_clk_name.c_str());
|
||||
reportLineTotal(width_msg.c_str(), nom_pulse_width, early_late, result);
|
||||
if (!delayFuzzyZero(latency_diff))
|
||||
reportLineTotalMinus("clock latency difference", latency_diff,
|
||||
early_late, result);
|
||||
}
|
||||
else {
|
||||
const char *width_msg = stringPrintTmp(strlen(" pulse width")
|
||||
+ strlen(tgt_clk_name) + 1,
|
||||
"%s pulse width",
|
||||
tgt_clk_name);
|
||||
reportLineTotal(width_msg, tgt_clk_width, early_late, result);
|
||||
auto width_msg = stdstrPrint("%s pulse width", tgt_clk_name.c_str());
|
||||
reportLineTotal(width_msg.c_str(), tgt_clk_width, early_late, result);
|
||||
}
|
||||
ArcDelay margin = end->margin(this);
|
||||
reportLineTotalMinus("library setup time", margin, early_late, result);
|
||||
|
|
@ -721,14 +694,9 @@ ReportPath::reportEndpoint(const PathEndPathDelay *end,
|
|||
{
|
||||
Instance *inst = network_->instance(end->vertex(this)->pin());
|
||||
const char *inst_name = cmd_network_->pathName(inst);
|
||||
const char *clk_name = tgtClkName(end);
|
||||
string clk_name = tgtClkName(end);
|
||||
const char *reg_desc = clkRegLatchDesc(end);
|
||||
const char *reason = stringPrintTmp(strlen(" clocked by ")
|
||||
+ strlen(reg_desc)
|
||||
+ strlen(clk_name) + 1,
|
||||
"%s clocked by %s",
|
||||
reg_desc,
|
||||
clk_name);
|
||||
auto reason = stdstrPrint("%s clocked by %s", reg_desc, clk_name.c_str());
|
||||
reportEndpoint(inst_name, reason, result);
|
||||
}
|
||||
|
||||
|
|
@ -760,18 +728,10 @@ ReportPath::reportFull(const PathEndPathDelay *end,
|
|||
if (min_max == MinMax::max())
|
||||
margin = -margin;
|
||||
|
||||
const char *margin_what;
|
||||
if (end->pathDelayMarginIsExternal())
|
||||
margin_what = "output external delay";
|
||||
else
|
||||
margin_what = checkRoleString(end);
|
||||
const char *min_max_str = min_max->asString();
|
||||
char *delay_msg = stringPrintTmp(strlen(" delay")
|
||||
+ strlen(min_max_str) + 1,
|
||||
"%s_delay",
|
||||
min_max_str);
|
||||
auto delay_msg = stdstrPrint("%s_delay", min_max_str);
|
||||
float delay = path_delay->delay();
|
||||
reportLine(delay_msg, delay, delay, early_late, result);
|
||||
reportLine(delay_msg.c_str(), delay, delay, early_late, result);
|
||||
if (!path_delay->ignoreClkLatency()) {
|
||||
const Path *tgt_clk_path = end->targetClkPath();
|
||||
if (tgt_clk_path) {
|
||||
|
|
@ -792,7 +752,10 @@ ReportPath::reportFull(const PathEndPathDelay *end,
|
|||
}
|
||||
}
|
||||
}
|
||||
reportRequired(end, margin_what, result);
|
||||
if (end->pathDelayMarginIsExternal())
|
||||
reportRequired(end, "output external delay", result);
|
||||
else
|
||||
reportRequired(end, checkRoleString(end), result);
|
||||
reportSlack(end, result);
|
||||
}
|
||||
|
||||
|
|
@ -864,11 +827,8 @@ ReportPath::reportEndpoint(const PathEndOutputDelay *end,
|
|||
if (network_->isTopLevelPort(pin)) {
|
||||
// Pin direction is "output" even for bidirects.
|
||||
if (tgt_clk) {
|
||||
const char *clk_name = tgtClkName(end);
|
||||
const char *reason = stringPrintTmp(strlen("output port clocked by ")
|
||||
+ strlen(clk_name) + 1,
|
||||
"output port clocked by %s",
|
||||
clk_name);
|
||||
string clk_name = tgtClkName(end);
|
||||
auto reason = stdstrPrint("output port clocked by %s", clk_name.c_str());
|
||||
reportEndpoint(pin_name, reason, result);
|
||||
}
|
||||
else
|
||||
|
|
@ -876,11 +836,8 @@ ReportPath::reportEndpoint(const PathEndOutputDelay *end,
|
|||
}
|
||||
else {
|
||||
if (tgt_clk) {
|
||||
const char *clk_name = tgtClkName(end);
|
||||
const char *reason = stringPrintTmp(strlen("internal path endpoint clocked by ")
|
||||
+ strlen(clk_name) + 1,
|
||||
"internal path endpoint clocked by %s",
|
||||
clk_name);
|
||||
string clk_name = tgtClkName(end);
|
||||
auto reason = stdstrPrint("internal path endpoint clocked by %s", clk_name.c_str());
|
||||
reportEndpoint(pin_name, reason, result);
|
||||
}
|
||||
else
|
||||
|
|
@ -926,18 +883,15 @@ ReportPath::reportEndpoint(const PathEndGatedClock *end,
|
|||
{
|
||||
Instance *inst = network_->instance(end->vertex(this)->pin());
|
||||
const char *inst_name = cmd_network_->pathName(inst);
|
||||
const char *clk_name = tgtClkName(end);
|
||||
string clk_name = tgtClkName(end);
|
||||
const TransRiseFall *clk_end_tr = end->targetClkEndTrans(this);
|
||||
const TransRiseFall *clk_tr =
|
||||
(end->minMax(this) == MinMax::max()) ? clk_end_tr : clk_end_tr->opposite();
|
||||
const char *rise_fall = asRisingFalling(clk_tr);
|
||||
// Note that target clock transition is ignored.
|
||||
const char *reason = stringPrintTmp(strlen(" clock gating-check end-point clocked by ")
|
||||
+ strlen(rise_fall)
|
||||
+ strlen(clk_name) + 1,
|
||||
"%s clock gating-check end-point clocked by %s",
|
||||
rise_fall,
|
||||
clk_name);
|
||||
auto reason = stdstrPrint("%s clock gating-check end-point clocked by %s",
|
||||
rise_fall,
|
||||
clk_name.c_str());
|
||||
reportEndpoint(inst_name, reason, result);
|
||||
}
|
||||
|
||||
|
|
@ -1002,12 +956,9 @@ ReportPath::reportEndpoint(const PathEndDataCheck *end,
|
|||
const char *inst_name = cmd_network_->pathName(inst);
|
||||
const char *tgt_clk_tr = asRisingFalling(end->dataClkPath()->transition(this));
|
||||
const char *tgt_clk_name = end->targetClk(this)->name();
|
||||
char *reason = stringPrintTmp(strlen(" edge-triggered data to data check clocked by ")
|
||||
+ strlen(tgt_clk_tr)
|
||||
+ strlen(tgt_clk_name) + 1,
|
||||
"%s edge-triggered data to data check clocked by %s",
|
||||
tgt_clk_tr,
|
||||
tgt_clk_name);
|
||||
auto reason = stdstrPrint("%s edge-triggered data to data check clocked by %s",
|
||||
tgt_clk_tr,
|
||||
tgt_clk_name);
|
||||
|
||||
reportEndpoint(inst_name, reason, result);
|
||||
}
|
||||
|
|
@ -1044,7 +995,8 @@ ReportPath::reportEndLine(PathEnd *end,
|
|||
string &result)
|
||||
{
|
||||
const EarlyLate *early_late = end->pathEarlyLate(this);
|
||||
reportDescription(pathEndpoint(end), result);
|
||||
string endpoint = pathEndpoint(end);
|
||||
reportDescription(endpoint.c_str(), result);
|
||||
reportSpaceFieldDelay(end->requiredTimeOffset(this), early_late, result);
|
||||
reportSpaceFieldDelay(end->dataArrivalTimeOffset(this), early_late, result);
|
||||
Slack slack = end->slack(this);
|
||||
|
|
@ -1074,8 +1026,10 @@ ReportPath::reportSummaryLine(PathEnd *end,
|
|||
{
|
||||
PathExpanded expanded(end->path(), this);
|
||||
const EarlyLate *early_late = end->pathEarlyLate(this);
|
||||
reportDescription(pathStartpoint(end, expanded), result);
|
||||
reportDescription(pathEndpoint(end), result);
|
||||
auto startpoint = pathStartpoint(end, expanded);
|
||||
reportDescription(startpoint.c_str(), result);
|
||||
auto endpoint = pathEndpoint(end);
|
||||
reportDescription(endpoint.c_str(), result);
|
||||
if (end->isUnconstrained())
|
||||
reportSpaceFieldDelay(end->dataArrivalTimeOffset(this), early_late, result);
|
||||
else
|
||||
|
|
@ -1083,7 +1037,7 @@ ReportPath::reportSummaryLine(PathEnd *end,
|
|||
reportEndOfLine(result);
|
||||
}
|
||||
|
||||
const char *
|
||||
string
|
||||
ReportPath::pathStartpoint(PathEnd *end,
|
||||
PathExpanded &expanded)
|
||||
{
|
||||
|
|
@ -1092,40 +1046,28 @@ ReportPath::pathStartpoint(PathEnd *end,
|
|||
const char *pin_name = cmd_network_->pathName(pin);
|
||||
if (network_->isTopLevelPort(pin)) {
|
||||
PortDirection *dir = network_->direction(pin);
|
||||
const char *dir_str = dir->name();
|
||||
return stringPrintTmp(strlen(pin_name) + strlen(dir_str) + 4,
|
||||
"%s (%s)",
|
||||
pin_name, dir_str);
|
||||
return stdstrPrint("%s (%s)", pin_name, dir->name());
|
||||
}
|
||||
else {
|
||||
Instance *inst = network_->instance(end->vertex(this)->pin());
|
||||
const char *cell_name = cmd_network_->name(network_->cell(inst));
|
||||
return stringPrintTmp(strlen(pin_name) + strlen(cell_name) + 4,
|
||||
"%s (%s)",
|
||||
pin_name,
|
||||
cell_name);
|
||||
return stdstrPrint("%s (%s)", pin_name, cell_name);
|
||||
}
|
||||
}
|
||||
|
||||
const char *
|
||||
string
|
||||
ReportPath::pathEndpoint(PathEnd *end)
|
||||
{
|
||||
Pin *pin = end->vertex(this)->pin();
|
||||
const char *pin_name = cmd_network_->pathName(pin);
|
||||
if (network_->isTopLevelPort(pin)) {
|
||||
PortDirection *dir = network_->direction(pin);
|
||||
const char *dir_str = dir->name();
|
||||
return stringPrintTmp(strlen(pin_name) + strlen(dir_str) + 4,
|
||||
"%s (%s)",
|
||||
pin_name, dir_str);
|
||||
return stdstrPrint("%s (%s)", pin_name, dir->name());
|
||||
}
|
||||
else {
|
||||
Instance *inst = network_->instance(end->vertex(this)->pin());
|
||||
const char *cell_name = cmd_network_->name(network_->cell(inst));
|
||||
return stringPrintTmp(strlen(pin_name) + strlen(cell_name) + 4,
|
||||
"%s (%s)",
|
||||
pin_name,
|
||||
cell_name);
|
||||
return stdstrPrint("%s (%s)", pin_name, cell_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1237,13 +1179,8 @@ ReportPath::reportShort(MinPulseWidthCheck *check,
|
|||
{
|
||||
const char *pin_name = cmd_network_->pathName(check->pin(this));
|
||||
const char *hi_low = mpwCheckHiLow(check);
|
||||
char *what = stringPrintTmp(strlen(" ()")
|
||||
+ strlen(pin_name)
|
||||
+ strlen(hi_low) + 1,
|
||||
"%s (%s)",
|
||||
pin_name,
|
||||
hi_low);
|
||||
reportDescription(what, result);
|
||||
auto what = stdstrPrint("%s (%s)", pin_name, hi_low);
|
||||
reportDescription(what.c_str(), result);
|
||||
reportSpaceFieldTime(check->minWidth(this), result);
|
||||
reportSpaceFieldDelay(check->width(this), EarlyLate::late(), result);
|
||||
Slack slack = check->slack(this);
|
||||
|
|
@ -1271,13 +1208,8 @@ ReportPath::reportVerbose(MinPulseWidthCheck *check,
|
|||
const char *open_clk_name = open_clk->name();
|
||||
const char *open_rise_fall = asRiseFall(open_clk_edge->transition());
|
||||
float open_clk_time = open_clk_edge->time();
|
||||
const char *open_clk_msg = stringPrintTmp(strlen("clock ( edge)")
|
||||
+ strlen(open_clk_name)
|
||||
+ strlen(open_rise_fall) + 1,
|
||||
"clock %s (%s edge)",
|
||||
open_clk_name,
|
||||
open_rise_fall);
|
||||
reportLine(open_clk_msg, open_clk_time, open_clk_time,
|
||||
auto open_clk_msg = stdstrPrint("clock %s (%s edge)", open_clk_name, open_rise_fall);
|
||||
reportLine(open_clk_msg.c_str(), open_clk_time, open_clk_time,
|
||||
open_el, result);
|
||||
Arrival open_arrival = check->openArrival(this);
|
||||
bool is_prop = isPropagated(check->openPath());
|
||||
|
|
@ -1295,13 +1227,8 @@ ReportPath::reportVerbose(MinPulseWidthCheck *check,
|
|||
const char *close_rise_fall = asRiseFall(close_clk_edge->transition());
|
||||
float close_offset = check->closeOffset(this);
|
||||
float close_clk_time = close_clk_edge->time() + close_offset;
|
||||
const char *close_clk_msg = stringPrintTmp(strlen("clock ( edge)")
|
||||
+ strlen(close_clk_name)
|
||||
+ strlen(close_rise_fall) + 1,
|
||||
"clock %s (%s edge)",
|
||||
close_clk_name,
|
||||
close_rise_fall);
|
||||
reportLine(close_clk_msg, close_clk_time, close_clk_time, close_el, result);
|
||||
auto close_clk_msg = stdstrPrint("clock %s (%s edge)", close_clk_name, close_rise_fall);
|
||||
reportLine(close_clk_msg.c_str(), close_clk_time, close_clk_time, close_el, result);
|
||||
Arrival close_arrival = check->closeArrival(this) + close_offset;
|
||||
reportLine(clk_ideal_prop, check->closeDelay(this), close_arrival,
|
||||
close_el, result);
|
||||
|
|
@ -1318,13 +1245,9 @@ ReportPath::reportVerbose(MinPulseWidthCheck *check,
|
|||
reportDashLine(result);
|
||||
float min_width = check->minWidth(this);
|
||||
const char *hi_low = mpwCheckHiLow(check);
|
||||
const char *rpw_msg = stringPrintTmp(strlen("required pulse width ()")
|
||||
+ strlen(hi_low) + 1,
|
||||
"required pulse width (%s)",
|
||||
hi_low);
|
||||
reportLine(rpw_msg, min_width, EarlyLate::early(), result);
|
||||
reportLine("actual pulse width", check->width(this),
|
||||
EarlyLate::early(), result);
|
||||
auto rpw_msg = stdstrPrint("required pulse width (%s)", hi_low);
|
||||
reportLine(rpw_msg.c_str(), min_width, EarlyLate::early(), result);
|
||||
reportLine("actual pulse width", check->width(this), EarlyLate::early(), result);
|
||||
reportDashLine(result);
|
||||
reportSlack(check->slack(this), result);
|
||||
}
|
||||
|
|
@ -1530,13 +1453,11 @@ ReportPath::reportShort(MaxSkewCheck *check,
|
|||
Pin *clk_pin = check->clkPin(this);
|
||||
const char *clk_pin_name = network_->pathName(clk_pin);
|
||||
TimingArc *check_arc = check->checkArc();
|
||||
const char *what = stringPrintTmp(strlen(clk_pin_name)
|
||||
+ strlen(" (r->r)") + 1,
|
||||
"%s (%s->%s)",
|
||||
clk_pin_name,
|
||||
check_arc->fromTrans()->asString(),
|
||||
check_arc->toTrans()->asString());
|
||||
reportDescription(what, result);
|
||||
auto what = stdstrPrint("%s (%s->%s)",
|
||||
clk_pin_name,
|
||||
check_arc->fromTrans()->asString(),
|
||||
check_arc->toTrans()->asString());
|
||||
reportDescription(what.c_str(), result);
|
||||
reportSpaceFieldDelay(check->maxSkew(this), EarlyLate::early(), result);
|
||||
reportSpaceFieldDelay(check->skew(this), EarlyLate::early(), result);
|
||||
Slack slack = check->slack(this);
|
||||
|
|
@ -1586,16 +1507,15 @@ ReportPath::reportSkewClkPath(const char *arrival_msg,
|
|||
const EarlyLate *early_late = clk_path->minMax(this);
|
||||
const TransRiseFall *clk_tr = clk_edge->transition();
|
||||
const TransRiseFall *clk_end_tr = clk_path->transition(this);
|
||||
const char *clk_name = (clk_end_tr == clk_tr)
|
||||
? clk->name()
|
||||
: clkNameInverted(clk->name());
|
||||
string clk_name = clkName(clk, clk_end_tr != clk_tr);
|
||||
float clk_time = clk_edge->time();
|
||||
const Arrival &clk_arrival = search_->clkPathArrival(clk_path);
|
||||
Arrival clk_delay = clk_arrival - clk_time;
|
||||
PathAnalysisPt *path_ap = clk_path->pathAnalysisPt(this);
|
||||
const MinMax *min_max = path_ap->pathMinMax();
|
||||
Vertex *clk_vertex = clk_path->vertex(this);
|
||||
reportClkLine(clk, clk_name, clk_end_tr, clk_time, min_max, result);
|
||||
reportClkLine(clk, clk_name.c_str(), clk_end_tr, clk_time, min_max, result);
|
||||
|
||||
bool is_prop = isPropagated(clk_path);
|
||||
if (is_prop && reportClkPath()) {
|
||||
const EarlyLate *early_late = TimingRole::skew()->tgtClkEarlyLate();
|
||||
|
|
@ -1614,8 +1534,8 @@ ReportPath::reportSkewClkPath(const char *arrival_msg,
|
|||
else {
|
||||
reportLine(clkNetworkDelayIdealProp(is_prop), clk_delay, clk_arrival,
|
||||
early_late, result);
|
||||
reportLine(descriptionField(clk_vertex), clk_arrival, early_late,
|
||||
clk_end_tr, result);
|
||||
reportLine(descriptionField(clk_vertex).c_str(), clk_arrival,
|
||||
early_late, clk_end_tr, result);
|
||||
}
|
||||
reportLine(arrival_msg, search_->clkPathArrival(clk_path),
|
||||
early_late, result);
|
||||
|
|
@ -1741,9 +1661,7 @@ ReportPath::reportStartpoint(const PathEnd *end,
|
|||
const char *pin_name = cmd_network_->pathName(pin);
|
||||
if (pathFromClkPin(path, pin)) {
|
||||
const char *clk_name = clk->name();
|
||||
const char *reason = stringPrintTmp(strlen("clock source ''")
|
||||
+ strlen(clk_name) + 1,
|
||||
"clock source '%s'", clk_name);
|
||||
auto reason = stdstrPrint("clock source '%s'", clk_name);
|
||||
reportStartpoint(pin_name, reason, result);
|
||||
}
|
||||
else if (network_->isTopLevelPort(pin)) {
|
||||
|
|
@ -1751,10 +1669,7 @@ ReportPath::reportStartpoint(const PathEnd *end,
|
|||
&& clk != sdc_->defaultArrivalClock()) {
|
||||
const char *clk_name = clk->name();
|
||||
// Pin direction is "input" even for bidirects.
|
||||
const char *reason=stringPrintTmp(strlen("input port clocked by ")
|
||||
+ strlen(clk_name) + 1,
|
||||
"input port clocked by %s",
|
||||
clk_name);
|
||||
auto reason = stdstrPrint("input port clocked by %s", clk_name);
|
||||
reportStartpoint(pin_name, reason, result);
|
||||
}
|
||||
else
|
||||
|
|
@ -1764,22 +1679,14 @@ ReportPath::reportStartpoint(const PathEnd *end,
|
|||
Instance *inst = network_->instance(pin);
|
||||
const char *inst_name = cmd_network_->pathName(inst);
|
||||
if (clk_edge) {
|
||||
const char *clk_name = clk->name();
|
||||
const TransRiseFall *clk_tr = clk_edge->transition();
|
||||
const TransRiseFall *clk_end_tr = clk_tr;
|
||||
PathRef clk_path;
|
||||
expanded.clkPath(clk_path);
|
||||
if (!clk_path.isNull()) {
|
||||
clk_end_tr = clk_path.transition(this);
|
||||
if (clk_end_tr != clk_tr)
|
||||
clk_name = clkNameInverted(clk_name);
|
||||
}
|
||||
bool clk_inverted = !clk_path.isNull()
|
||||
&& clk_tr != clk_path.transition(this);
|
||||
string clk_name = clkName(clk, clk_inverted);
|
||||
const char *reg_desc = edgeRegLatchDesc(prev_edge, prev_arc);
|
||||
const char *reason = stringPrintTmp(strlen(" clocked by ")
|
||||
+ strlen(reg_desc)
|
||||
+ strlen(clk_name) + 1,
|
||||
"%s clocked by %s",
|
||||
reg_desc, clk_name);
|
||||
auto reason = stdstrPrint("%s clocked by %s", reg_desc, clk_name.c_str());
|
||||
reportStartpoint(inst_name, reason, result);
|
||||
}
|
||||
else {
|
||||
|
|
@ -1792,11 +1699,7 @@ ReportPath::reportStartpoint(const PathEnd *end,
|
|||
Clock *clk = clk_edge->clock();
|
||||
if (clk != sdc_->defaultArrivalClock()) {
|
||||
const char *clk_name = clk->name();
|
||||
const char *reason =
|
||||
stringPrintTmp(strlen("internal path startpoint clocked by ")
|
||||
+ strlen(clk_name) + 1,
|
||||
"internal path startpoint clocked by %s",
|
||||
clk_name);
|
||||
auto reason = stdstrPrint("internal path startpoint clocked by %s", clk_name);
|
||||
reportStartpoint(pin_name, reason, result);
|
||||
}
|
||||
else
|
||||
|
|
@ -1830,7 +1733,7 @@ ReportPath::pathFromClkPin(const Path *path,
|
|||
|
||||
void
|
||||
ReportPath::reportStartpoint(const char *start,
|
||||
const char *reason,
|
||||
string reason,
|
||||
string &result)
|
||||
{
|
||||
reportStartEndPoint(start, reason, "Startpoint", result);
|
||||
|
|
@ -1880,19 +1783,21 @@ ReportPath::reportUnclockedEndpoint(const PathEnd *end,
|
|||
}
|
||||
|
||||
void
|
||||
ReportPath::reportEndpoint(const char *end, const char *reason, string &result)
|
||||
ReportPath::reportEndpoint(const char *end,
|
||||
string reason,
|
||||
string &result)
|
||||
{
|
||||
reportStartEndPoint(end, reason, "Endpoint", result);
|
||||
}
|
||||
|
||||
void
|
||||
ReportPath::reportStartEndPoint(const char *pt,
|
||||
const char *reason,
|
||||
string reason,
|
||||
const char *key,
|
||||
string &result)
|
||||
{
|
||||
// Account for punctuation in the line.
|
||||
int line_len = strlen(key) + 2 + strlen(pt) + 2 + strlen(reason) + 1;
|
||||
int line_len = strlen(key) + 2 + strlen(pt) + 2 + reason.size() + 1;
|
||||
if (!no_split_
|
||||
&& line_len > start_end_pt_width_) {
|
||||
result += key;
|
||||
|
|
@ -1936,34 +1841,31 @@ ReportPath::reportGroup(const PathEnd *end,
|
|||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
const char *
|
||||
string
|
||||
ReportPath::checkRoleReason(const PathEnd *end)
|
||||
{
|
||||
const char *setup_hold = end->checkRole(this)->asString();
|
||||
return stringPrintTmp(strlen(" time")
|
||||
+ strlen(setup_hold) + 1,
|
||||
"%s time",
|
||||
setup_hold);
|
||||
return stdstrPrint("%s time", setup_hold);
|
||||
}
|
||||
|
||||
const char *
|
||||
string
|
||||
ReportPath::tgtClkName(const PathEnd *end)
|
||||
{
|
||||
ClockEdge *tgt_clk_edge = end->targetClkEdge(this);
|
||||
const Clock *tgt_clk = tgt_clk_edge->clock();
|
||||
const TransRiseFall *clk_tr = tgt_clk_edge->transition();
|
||||
const TransRiseFall *clk_end_tr = end->targetClkEndTrans(this);
|
||||
const char *clk_name = tgt_clk->name();
|
||||
if (clk_end_tr == clk_tr)
|
||||
return clk_name;
|
||||
else
|
||||
return clkNameInverted(clk_name);
|
||||
return clkName(tgt_clk, clk_end_tr != clk_tr);
|
||||
}
|
||||
|
||||
const char *
|
||||
ReportPath::clkNameInverted(const char *clk_name)
|
||||
string
|
||||
ReportPath::clkName(const Clock *clk,
|
||||
bool inverted)
|
||||
{
|
||||
return stringPrintTmp(strlen(clk_name) + 2, "%s'", clk_name);
|
||||
string name = clk->name();
|
||||
if (inverted)
|
||||
name += '\'';
|
||||
return name;
|
||||
}
|
||||
|
||||
const char *
|
||||
|
|
@ -2055,18 +1957,13 @@ ReportPath::reportSrcClkAndPath(const Path *path,
|
|||
PathRef clk_path;
|
||||
expanded.clkPath(clk_path);
|
||||
const TransRiseFall *clk_end_tr;
|
||||
const char *clk_name;
|
||||
if (!clk_path.isNull()) {
|
||||
clk_end_time = search_->clkPathArrival(&clk_path) + time_offset;
|
||||
clk_delay = clk_end_time - clk_time;
|
||||
clk_end_tr = clk_path.transition(this);
|
||||
clk_name = (clk_end_tr == clk_tr)
|
||||
? clk->name()
|
||||
: clkNameInverted(clk->name());
|
||||
}
|
||||
else {
|
||||
// Path from input port or clk used as data.
|
||||
clk_name = clk->name();
|
||||
clk_end_tr = clk_tr;
|
||||
clk_delay = clk_insertion + clk_latency;
|
||||
clk_end_time = clk_time + clk_delay;
|
||||
|
|
@ -2088,6 +1985,7 @@ ReportPath::reportSrcClkAndPath(const Path *path,
|
|||
}
|
||||
}
|
||||
}
|
||||
string clk_name = clkName(clk, clk_tr != clk_end_tr);
|
||||
|
||||
bool clk_used_as_data = pathFromClkPin(expanded);
|
||||
bool is_prop = isPropagated(path);
|
||||
|
|
@ -2095,7 +1993,8 @@ ReportPath::reportSrcClkAndPath(const Path *path,
|
|||
if (reportGenClkSrcPath(clk_path.isNull() ? NULL : &clk_path,
|
||||
clk, clk_tr, min_max, early_late)
|
||||
&& !(path_from_input && !input_has_ref_path)) {
|
||||
reportClkLine(clk, clk_name, clk_end_tr, clk_time, min_max, result);
|
||||
reportClkLine(clk, clk_name.c_str(), clk_end_tr, clk_time,
|
||||
min_max, result);
|
||||
const PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
|
||||
reportGenClkSrcAndPath(path, clk, clk_tr, early_late, path_ap,
|
||||
time_offset, time_offset, clk_used_as_data,
|
||||
|
|
@ -2103,7 +2002,8 @@ ReportPath::reportSrcClkAndPath(const Path *path,
|
|||
}
|
||||
else if (clk_used_as_data
|
||||
&& pathFromGenPropClk(path, path->minMax(this))) {
|
||||
reportClkLine(clk, clk_name, clk_end_tr, clk_time, min_max, result);
|
||||
reportClkLine(clk, clk_name.c_str(), clk_end_tr, clk_time,
|
||||
min_max, result);
|
||||
ClkInfo *clk_info = path->tag(search_)->clkInfo();
|
||||
if (clk_info->isPropagated())
|
||||
reportClkSrcLatency(clk_insertion, clk_time, early_late, result);
|
||||
|
|
@ -2112,12 +2012,14 @@ ReportPath::reportSrcClkAndPath(const Path *path,
|
|||
else if (is_prop
|
||||
&& reportClkPath()
|
||||
&& !(path_from_input && !input_has_ref_path)) {
|
||||
reportClkLine(clk, clk_name, clk_end_tr, clk_time, early_late, result);
|
||||
reportClkLine(clk, clk_name.c_str(), clk_end_tr, clk_time,
|
||||
early_late, result);
|
||||
reportClkSrcLatency(clk_insertion, clk_time, early_late, result);
|
||||
reportPath1(path, expanded, false, time_offset, result);
|
||||
}
|
||||
else if (clk_used_as_data) {
|
||||
reportClkLine(clk, clk_name, clk_end_tr, clk_time, early_late, result);
|
||||
reportClkLine(clk, clk_name.c_str(), clk_end_tr, clk_time,
|
||||
early_late, result);
|
||||
if (clk_insertion > 0.0)
|
||||
reportClkSrcLatency(clk_insertion, clk_time, early_late, result);
|
||||
reportPath1(path, expanded, true, time_offset, result);
|
||||
|
|
@ -2129,7 +2031,8 @@ ReportPath::reportSrcClkAndPath(const Path *path,
|
|||
clk_end_time, early_late, result);
|
||||
}
|
||||
else {
|
||||
reportClkLine(clk, clk_name, clk_end_tr, clk_time, min_max, result);
|
||||
reportClkLine(clk, clk_name.c_str(), clk_end_tr, clk_time,
|
||||
min_max, result);
|
||||
Arrival clk_arrival = clk_end_time;
|
||||
reportLine(clkNetworkDelayIdealProp(is_prop), clk_delay,
|
||||
clk_arrival, early_late, result);
|
||||
|
|
@ -2170,9 +2073,7 @@ ReportPath::reportTgtClk(const PathEnd *end,
|
|||
Clock *clk = clk_edge->clock();
|
||||
const TransRiseFall *clk_tr = clk_edge->transition();
|
||||
const TransRiseFall *clk_end_tr = end->targetClkEndTrans(this);
|
||||
const char *clk_name = (clk_end_tr == clk_tr)
|
||||
? clk->name()
|
||||
: clkNameInverted(clk->name());
|
||||
string clk_name = clkName(clk, clk_end_tr != clk_tr);
|
||||
float clk_time = prev_time
|
||||
+ end->targetClkTime(this)
|
||||
+ end->targetClkMcpAdjustment(this)
|
||||
|
|
@ -2182,7 +2083,8 @@ ReportPath::reportTgtClk(const PathEnd *end,
|
|||
PathAnalysisPt *path_ap = end->pathAnalysisPt(this)->tgtClkAnalysisPt();
|
||||
const MinMax *min_max = path_ap->pathMinMax();
|
||||
const Path *clk_path = end->targetClkPath();
|
||||
reportClkLine(clk, clk_name, clk_end_tr, prev_time, clk_time, min_max, result);
|
||||
reportClkLine(clk, clk_name.c_str(), clk_end_tr, prev_time, clk_time,
|
||||
min_max, result);
|
||||
TimingRole *check_role = end->checkRole(this);
|
||||
if (is_prop && reportClkPath()) {
|
||||
float time_offset = prev_time
|
||||
|
|
@ -2224,7 +2126,7 @@ ReportPath::reportTgtClk(const PathEnd *end,
|
|||
reportCommonClkPessimism(end, clk_arrival, result);
|
||||
if (clk_path) {
|
||||
Vertex *clk_vertex = clk_path->vertex(this);
|
||||
reportLine(descriptionField(clk_vertex),
|
||||
reportLine(descriptionField(clk_vertex).c_str(),
|
||||
prev_time
|
||||
+ end->targetClkArrival(this)
|
||||
+ end->sourceClkOffset(this),
|
||||
|
|
@ -2311,18 +2213,13 @@ ReportPath::reportClkLine(const Clock *clk,
|
|||
string &result)
|
||||
{
|
||||
const char *rise_fall = asRiseFall(clk_tr);
|
||||
const char *clk_msg = stringPrintTmp(strlen("clock ( edge)")
|
||||
+ strlen(clk_name)
|
||||
+ strlen(rise_fall) + 1,
|
||||
"clock %s (%s edge)",
|
||||
clk_name,
|
||||
rise_fall);
|
||||
auto clk_msg = stdstrPrint("clock %s (%s edge)", clk_name, rise_fall);
|
||||
if (clk->isPropagated())
|
||||
reportLine(clk_msg, clk_time - prev_time, clk_time, min_max, result);
|
||||
reportLine(clk_msg.c_str(), clk_time - prev_time, clk_time, min_max, result);
|
||||
else {
|
||||
// Report ideal clock slew.
|
||||
float clk_slew = clk->slew(clk_tr, min_max);
|
||||
reportLine(clk_msg, clk_slew, clk_time - prev_time, clk_time,
|
||||
reportLine(clk_msg.c_str(), clk_slew, clk_time - prev_time, clk_time,
|
||||
min_max, result);
|
||||
}
|
||||
}
|
||||
|
|
@ -2453,7 +2350,7 @@ ReportPath::reportPathLine(const Path *path,
|
|||
{
|
||||
Vertex *vertex = path->vertex(this);
|
||||
Pin *pin = vertex->pin();
|
||||
const char *what = descriptionField(vertex);
|
||||
auto what = descriptionField(vertex);
|
||||
const TransRiseFall *tr = path->transition(this);
|
||||
bool is_driver = network_->isDriver(pin);
|
||||
PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
|
||||
|
|
@ -2465,13 +2362,13 @@ ReportPath::reportPathLine(const Path *path,
|
|||
// Don't show capacitance field for input pins.
|
||||
if (is_driver && field_capacitance_->enabled())
|
||||
cap = loadCap(pin, tr, dcalc_ap);
|
||||
reportLine(what, cap, slew, field_blank_,
|
||||
reportLine(what.c_str(), cap, slew, field_blank_,
|
||||
incr, time, false, early_late, tr, line_case, result);
|
||||
}
|
||||
|
||||
void
|
||||
ReportPath::reportRequired(const PathEnd *end,
|
||||
const char *margin_msg,
|
||||
string margin_msg,
|
||||
string &result)
|
||||
{
|
||||
Required req_time = end->requiredTimeOffset(this);
|
||||
|
|
@ -2479,7 +2376,7 @@ ReportPath::reportRequired(const PathEnd *end,
|
|||
ArcDelay margin = end->margin(this);
|
||||
if (end->minMax(this) == MinMax::max())
|
||||
margin = -margin;
|
||||
reportLine(margin_msg, margin, req_time, early_late, result);
|
||||
reportLine(margin_msg.c_str(), margin, req_time, early_late, result);
|
||||
reportLine("data required time", req_time, early_late, result);
|
||||
reportDashLine(result);
|
||||
}
|
||||
|
|
@ -2784,36 +2681,33 @@ ReportPath::reportPath5(const Path *path,
|
|||
// Don't show capacitance field for input pins.
|
||||
if (is_driver && field_capacitance_->enabled())
|
||||
cap = loadCap(pin, tr, dcalc_ap);
|
||||
const char *what = descriptionField(vertex);
|
||||
auto what = descriptionField(vertex);
|
||||
if (report_net_ && is_driver) {
|
||||
// Capacitance field is reported on the net line.
|
||||
reportLine(what, field_blank_, slew, field_blank_,
|
||||
reportLine(what.c_str(), field_blank_, slew, field_blank_,
|
||||
incr, time, false, min_max, tr, line_case, result);
|
||||
string what2;
|
||||
if (network_->isTopLevelPort(pin)) {
|
||||
const char *pin_name = cmd_network_->pathName(pin);
|
||||
what = stringPrintTmp(strlen(" (net)")
|
||||
+ strlen(pin_name) + 1,
|
||||
"%s (net)", pin_name);
|
||||
what2 = stdstrPrint("%s (net)", pin_name);
|
||||
}
|
||||
else {
|
||||
Net *net = network_->net(pin);
|
||||
if (net) {
|
||||
Net *highest_net = network_->highestNetAbove(net);
|
||||
const char *net_name = cmd_network_->pathName(highest_net);
|
||||
what = stringPrintTmp(strlen(" (net)")
|
||||
+ strlen(net_name) + 1,
|
||||
"%s (net)", net_name);
|
||||
what2 = stdstrPrint("%s (net)", net_name);
|
||||
}
|
||||
else
|
||||
what = "(unconnected)";
|
||||
what2 = "(unconnected)";
|
||||
}
|
||||
float fanout = drvrFanout(vertex, min_max);
|
||||
reportLine(what, cap, field_blank_, fanout,
|
||||
reportLine(what2.c_str(), cap, field_blank_, fanout,
|
||||
field_blank_, field_blank_, false, min_max, NULL,
|
||||
line_case, result);
|
||||
}
|
||||
else
|
||||
reportLine(what, cap, slew, field_blank_,
|
||||
reportLine(what.c_str(), cap, slew, field_blank_,
|
||||
incr, time, false, min_max, tr, line_case, result);
|
||||
prev_time = time;
|
||||
}
|
||||
|
|
@ -2834,7 +2728,7 @@ ReportPath::nextArcAnnotated(const PathRef *next_path,
|
|||
return graph_->arcDelayAnnotated(edge, arc, ap_index);
|
||||
}
|
||||
|
||||
char *
|
||||
string
|
||||
ReportPath::descriptionField(Vertex *vertex)
|
||||
{
|
||||
Pin *pin = vertex->pin();
|
||||
|
|
@ -2858,21 +2752,7 @@ ReportPath::descriptionField(Vertex *vertex)
|
|||
Instance *inst = network_->instance(pin);
|
||||
name2 = network_->cellName(inst);
|
||||
}
|
||||
// stringPrintTmp("%s (%s)", pin_name, name2)
|
||||
size_t pin_name_length = strlen(pin_name);
|
||||
size_t name2_length = strlen(name2);
|
||||
char *result = makeTmpString(pin_name_length + name2_length
|
||||
+ 4 /* strlen(" ()") + '\0' */);
|
||||
char *s = result;
|
||||
strcpy(s, pin_name);
|
||||
s += pin_name_length;
|
||||
*s++ = ' ';
|
||||
*s++ = '(';
|
||||
strcpy(s, name2);
|
||||
s += name2_length;
|
||||
*s++ = ')';
|
||||
*s++ = '\0';
|
||||
return result;
|
||||
return stdstrPrint("%s (%s)", pin_name, name2);
|
||||
}
|
||||
|
||||
float
|
||||
|
|
@ -3125,12 +3005,10 @@ ReportPath::reportLine(const char *what,
|
|||
else if (field == field_fanout_) {
|
||||
if (fanout == field_blank_)
|
||||
reportFieldBlank(field, result);
|
||||
else {
|
||||
char *field = stringPrintTmp(field_fanout_->width() + 1, "%*d",
|
||||
field_fanout_->width(),
|
||||
static_cast<int>(fanout));
|
||||
result += field;
|
||||
}
|
||||
else
|
||||
result += stdstrPrint("%*d",
|
||||
field_fanout_->width(),
|
||||
static_cast<int>(fanout));
|
||||
}
|
||||
else if (field == field_capacitance_)
|
||||
reportField(cap, field, result);
|
||||
|
|
|
|||
|
|
@ -232,9 +232,9 @@ protected:
|
|||
string &result);
|
||||
void reportEndpoint(const PathEndGatedClock *end,
|
||||
string &result);
|
||||
const char *pathEndpoint(PathEnd *end);
|
||||
const char *pathStartpoint(PathEnd *end,
|
||||
PathExpanded &expanded);
|
||||
string pathEndpoint(PathEnd *end);
|
||||
string pathStartpoint(PathEnd *end,
|
||||
PathExpanded &expanded);
|
||||
void reportBorrowing(const PathEndLatchCheck *end,
|
||||
Arrival &borrow,
|
||||
Arrival &time_given_to_startpoint,
|
||||
|
|
@ -243,8 +243,8 @@ protected:
|
|||
string &result);
|
||||
const char *clkNetworkDelayIdealProp(bool is_ideal);
|
||||
|
||||
const char *checkRoleReason(const PathEnd *end);
|
||||
char *checkRoleString(const PathEnd *end);
|
||||
string checkRoleReason(const PathEnd *end);
|
||||
string checkRoleString(const PathEnd *end);
|
||||
virtual void reportGroup(const PathEnd *end,
|
||||
string &result);
|
||||
void reportStartpoint(const PathEnd *end,
|
||||
|
|
@ -259,16 +259,16 @@ protected:
|
|||
string &result);
|
||||
const char *latchDesc(const PathEndLatchCheck *end);
|
||||
void reportStartpoint(const char *start,
|
||||
const char *reason,
|
||||
string reason,
|
||||
string &result);
|
||||
void reportEndpoint(const char *end,
|
||||
const char *reason,
|
||||
string reason,
|
||||
string &result);
|
||||
void reportStartEndPoint(const char *pt,
|
||||
const char *reason,
|
||||
string reason,
|
||||
const char *key,
|
||||
string &result);
|
||||
const char *tgtClkName(const PathEnd *end);
|
||||
string tgtClkName(const PathEnd *end);
|
||||
const char *clkRegLatchDesc(const PathEnd *end);
|
||||
void reportSrcPath(const PathEnd *end,
|
||||
PathExpanded &expanded,
|
||||
|
|
@ -344,7 +344,7 @@ protected:
|
|||
const MinMax *min_max,
|
||||
string &result);
|
||||
void reportRequired(const PathEnd *end,
|
||||
const char *margin_msg,
|
||||
string margin_msg,
|
||||
string &result);
|
||||
void reportSlack(const PathEnd *end,
|
||||
string &result);
|
||||
|
|
@ -486,9 +486,10 @@ protected:
|
|||
void reportDashLine(int line_width,
|
||||
string &result);
|
||||
void reportEndOfLine(string &result);
|
||||
char *descriptionField(Vertex *vertex);
|
||||
string descriptionField(Vertex *vertex);
|
||||
bool reportClkPath() const;
|
||||
const char *clkNameInverted(const char *clk_name);
|
||||
string clkName(const Clock *clk,
|
||||
bool inverted);;
|
||||
bool hasExtInputDriver(const Pin *pin,
|
||||
const TransRiseFall *tr,
|
||||
const MinMax *min_max);
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@
|
|||
#include "Latches.hh"
|
||||
#include "PathGroup.hh"
|
||||
#include "CheckTiming.hh"
|
||||
#include "ReadParasitics.hh"
|
||||
#include "SpefReader.hh"
|
||||
#include "CheckSlewLimits.hh"
|
||||
#include "CheckMinPulseWidths.hh"
|
||||
#include "CheckMinPeriods.hh"
|
||||
|
|
@ -231,6 +231,7 @@ initSta()
|
|||
Transition::init();
|
||||
TimingRole::init();
|
||||
PortDirection::init();
|
||||
initTmpStrings();
|
||||
initLiberty();
|
||||
initDelayConstants();
|
||||
registerDelayCalcs();
|
||||
|
|
@ -3407,17 +3408,17 @@ Sta::setResistance(Net *net,
|
|||
////////////////////////////////////////////////////////////////
|
||||
|
||||
bool
|
||||
Sta::readParasitics(const char *filename,
|
||||
Instance *instance,
|
||||
const MinMaxAll *min_max,
|
||||
bool increment,
|
||||
bool pin_cap_included,
|
||||
bool keep_coupling_caps,
|
||||
float coupling_cap_factor,
|
||||
ReduceParasiticsTo reduce_to,
|
||||
bool delete_after_reduce,
|
||||
bool save,
|
||||
bool quiet)
|
||||
Sta::readSpef(const char *filename,
|
||||
Instance *instance,
|
||||
const MinMaxAll *min_max,
|
||||
bool increment,
|
||||
bool pin_cap_included,
|
||||
bool keep_coupling_caps,
|
||||
float coupling_cap_factor,
|
||||
ReduceParasiticsTo reduce_to,
|
||||
bool delete_after_reduce,
|
||||
bool save,
|
||||
bool quiet)
|
||||
{
|
||||
Corner *corner = corners_->defaultCorner();
|
||||
const MinMax *cnst_min_max;
|
||||
|
|
@ -3434,12 +3435,12 @@ Sta::readParasitics(const char *filename,
|
|||
}
|
||||
const OperatingConditions *op_cond =
|
||||
sdc_->operatingConditions(cnst_min_max);
|
||||
bool success = readParasiticsFile(filename, instance, ap, increment,
|
||||
pin_cap_included,
|
||||
keep_coupling_caps, coupling_cap_factor,
|
||||
reduce_to, delete_after_reduce,
|
||||
op_cond, corner, cnst_min_max, save, quiet,
|
||||
report_, network_, parasitics_);
|
||||
bool success = readSpefFile(filename, instance, ap, increment,
|
||||
pin_cap_included,
|
||||
keep_coupling_caps, coupling_cap_factor,
|
||||
reduce_to, delete_after_reduce,
|
||||
op_cond, corner, cnst_min_max, save, quiet,
|
||||
report_, network_, parasitics_);
|
||||
parasiticsChangedAfter();
|
||||
return success;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1037,17 +1037,17 @@ public:
|
|||
// networks (dspf) are reduced and deleted after reading each net
|
||||
// with reduce_to and delete_after_reduce.
|
||||
// Return true if successful.
|
||||
bool readParasitics(const char *filename,
|
||||
Instance *instance,
|
||||
const MinMaxAll *min_max,
|
||||
bool increment,
|
||||
bool pin_cap_included,
|
||||
bool keep_coupling_caps,
|
||||
float coupling_cap_factor,
|
||||
ReduceParasiticsTo reduce_to,
|
||||
bool delete_after_reduce,
|
||||
bool save,
|
||||
bool quiet);
|
||||
bool readSpef(const char *filename,
|
||||
Instance *instance,
|
||||
const MinMaxAll *min_max,
|
||||
bool increment,
|
||||
bool pin_cap_included,
|
||||
bool keep_coupling_caps,
|
||||
float coupling_cap_factor,
|
||||
ReduceParasiticsTo reduce_to,
|
||||
bool delete_after_reduce,
|
||||
bool save,
|
||||
bool quiet);
|
||||
// Parasitics.
|
||||
void findPiElmore(Pin *drvr_pin,
|
||||
const TransRiseFall *tr,
|
||||
|
|
|
|||
|
|
@ -98,11 +98,11 @@ Tag::asString(bool report_index,
|
|||
string str;
|
||||
|
||||
if (report_index)
|
||||
str += stringPrintTmp(6, "%4d ", index_);
|
||||
str += stringPrintTmp("%4d ", index_);
|
||||
|
||||
const TransRiseFall *tr = transition();
|
||||
PathAnalysisPt *path_ap = corners->findPathAnalysisPt(path_ap_index_);
|
||||
str += stringPrintTmp(25, "%s %s/%d ",
|
||||
str += stringPrintTmp("%s %s/%d ",
|
||||
tr->asString(),
|
||||
path_ap->pathMinMax()->asString(),
|
||||
path_ap_index_);
|
||||
|
|
|
|||
|
|
@ -359,8 +359,7 @@ VisitPathEnds::visitOutputDelayEnd1(OutputDelay *output_delay,
|
|||
is_constrained = true;
|
||||
}
|
||||
else if (tgt_clk_edge
|
||||
&& sdc_->sameClockGroup(path->clock(this),
|
||||
tgt_clk_edge->clock())
|
||||
&& sdc_->sameClockGroup(path->clock(this), tgt_clk_edge->clock())
|
||||
// False paths and path delays override.
|
||||
&& (exception == NULL
|
||||
|| exception->isFilter()
|
||||
|
|
|
|||
|
|
@ -55,14 +55,11 @@ split(const string &text,
|
|||
const string &delims,
|
||||
// Return values.
|
||||
StringVector &tokens);
|
||||
|
||||
void
|
||||
streamPrint(ofstream &stream,
|
||||
const char *fmt,
|
||||
...) __attribute__((format (printf, 2, 3)));
|
||||
void
|
||||
stringPrint(string &str,
|
||||
const char *fmt,
|
||||
...) __attribute__((format (printf, 2, 3)));
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
@ -231,6 +228,7 @@ WritePathSpice::WritePathSpice(Path *path,
|
|||
|
||||
WritePathSpice::~WritePathSpice()
|
||||
{
|
||||
stringDelete(net_name_);
|
||||
cell_spice_port_names_.deleteContents();
|
||||
}
|
||||
|
||||
|
|
@ -257,17 +255,17 @@ WritePathSpice::writeSpice()
|
|||
void
|
||||
WritePathSpice::writeHeader()
|
||||
{
|
||||
const MinMax *min_max = path_->minMax(this);
|
||||
const Pvt *pvt = sdc_->operatingConditions(min_max);
|
||||
auto min_max = path_->minMax(this);
|
||||
auto pvt = sdc_->operatingConditions(min_max);
|
||||
if (pvt == NULL)
|
||||
pvt = network_->defaultLibertyLibrary()->defaultOperatingConditions();
|
||||
float temp = pvt->temperature();
|
||||
auto temp = pvt->temperature();
|
||||
streamPrint(spice_stream_, ".temp %.1f\n", temp);
|
||||
streamPrint(spice_stream_, ".include \"%s\"\n", model_filename_);
|
||||
streamPrint(spice_stream_, ".include \"%s\"\n", subckt_filename_);
|
||||
|
||||
float max_time = maxTime();
|
||||
float time_step = max_time / 1e+3;
|
||||
auto max_time = maxTime();
|
||||
auto time_step = max_time / 1e+3;
|
||||
streamPrint(spice_stream_, ".tran %.3g %.3g\n\n",
|
||||
time_step, max_time);
|
||||
}
|
||||
|
|
@ -275,8 +273,8 @@ WritePathSpice::writeHeader()
|
|||
float
|
||||
WritePathSpice::maxTime()
|
||||
{
|
||||
Stage input_stage = stageFirst();
|
||||
Path *input_path = stageDrvrPath(input_stage);
|
||||
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
|
||||
|
|
@ -293,7 +291,7 @@ WritePathSpice::writeStageInstances()
|
|||
streamPrint(spice_stream_, "*****************\n\n");
|
||||
|
||||
for (Stage stage = stageFirst(); stage <= stageLast(); stage++) {
|
||||
const char *stage_name = stageName(stage).c_str();
|
||||
auto stage_name = stageName(stage).c_str();
|
||||
if (stage == stageFirst())
|
||||
streamPrint(spice_stream_, "x%s %s %s %s\n",
|
||||
stage_name,
|
||||
|
|
@ -325,7 +323,7 @@ WritePathSpice::pgPortVoltage(LibertyPgPort *pg_port)
|
|||
auto cell = pg_port->cell();
|
||||
auto voltage_name = pg_port->voltageName();
|
||||
auto lib = cell->libertyLibrary();
|
||||
float voltage = lib->supplyVoltage(voltage_name);
|
||||
auto voltage = lib->supplyVoltage(voltage_name);
|
||||
return voltage;
|
||||
}
|
||||
|
||||
|
|
@ -336,7 +334,7 @@ WritePathSpice::writeInputSource()
|
|||
streamPrint(spice_stream_, "* Input source\n");
|
||||
streamPrint(spice_stream_, "**************\n\n");
|
||||
|
||||
Stage input_stage = stageFirst();
|
||||
auto input_stage = stageFirst();
|
||||
streamPrint(spice_stream_, "v1 %s 0 pwl(\n",
|
||||
stageDrvrPinName(input_stage));
|
||||
auto wire_arc = stageWireArc(input_stage);
|
||||
|
|
@ -349,13 +347,13 @@ WritePathSpice::writeInputSource()
|
|||
volt0 = power_voltage_;
|
||||
volt1 = gnd_voltage_;
|
||||
}
|
||||
Path *input_path = stageDrvrPath(input_stage);
|
||||
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.
|
||||
float time0 = input_slew;
|
||||
float time1 = time0 + input_slew;
|
||||
auto time0 = input_slew;
|
||||
auto time1 = time0 + input_slew;
|
||||
streamPrint(spice_stream_, "+%.3e %.3e\n", 0.0, volt0);
|
||||
streamPrint(spice_stream_, "+%.3e %.3e\n", time0, volt0);
|
||||
streamPrint(spice_stream_, "+%.3e %.3e\n", time1, volt1);
|
||||
|
|
@ -370,7 +368,7 @@ WritePathSpice::writeMeasureStmts()
|
|||
streamPrint(spice_stream_, "* Measure statements\n");
|
||||
streamPrint(spice_stream_, "********************\n\n");
|
||||
|
||||
for (Stage stage = stageFirst(); stage <= stageLast(); stage++) {
|
||||
for (auto stage = stageFirst(); stage <= stageLast(); stage++) {
|
||||
auto input_path = (stage == stageFirst())
|
||||
? stageDrvrPath(stage)
|
||||
: stageGateInputPath(stage);
|
||||
|
|
@ -455,7 +453,7 @@ WritePathSpice::writeStageSubckts()
|
|||
streamPrint(spice_stream_, "* Stage subckts\n");
|
||||
streamPrint(spice_stream_, "***************\n\n");
|
||||
|
||||
for (Stage stage = stageFirst(); stage <= stageLast(); stage++) {
|
||||
for (auto stage = stageFirst(); stage <= stageLast(); stage++) {
|
||||
if (stage == stageFirst())
|
||||
writeInputStage(stage);
|
||||
else
|
||||
|
|
@ -493,17 +491,17 @@ WritePathSpice::writeGateStage(Stage stage)
|
|||
input_pin_name,
|
||||
drvr_pin_name,
|
||||
load_pin_name);
|
||||
Instance *inst = network_->instance(input_pin);
|
||||
const char *inst_name = network_->pathName(inst);
|
||||
LibertyCell *cell = network_->libertyCell(inst);
|
||||
const char *cell_name = cell->name();
|
||||
auto inst = network_->instance(input_pin);
|
||||
auto inst_name = network_->pathName(inst);
|
||||
auto cell = network_->libertyCell(inst);
|
||||
auto cell_name = cell->name();
|
||||
auto spice_port_names = cell_spice_port_names_[cell_name];
|
||||
|
||||
// Instance subckt call.
|
||||
streamPrint(spice_stream_, "x%s", inst_name);
|
||||
StringVector::Iterator port_iter(spice_port_names);
|
||||
while (port_iter.hasNext()) {
|
||||
const char *subckt_port_name = port_iter.next().c_str();
|
||||
auto subckt_port_name = port_iter.next().c_str();
|
||||
auto pin = network_->findPin(inst, subckt_port_name);
|
||||
auto pg_port = cell->findPgPort(subckt_port_name);
|
||||
const char *pin_name;
|
||||
|
|
@ -542,8 +540,8 @@ sensitizationValues(FuncExpr *expr,
|
|||
break;
|
||||
}
|
||||
case FuncExpr::op_or: {
|
||||
FuncExpr *left = expr->left();
|
||||
FuncExpr *right = expr->right();
|
||||
auto left = expr->left();
|
||||
auto right = expr->right();
|
||||
if (left->port() == from_port
|
||||
&& right->op() == FuncExpr::op_port)
|
||||
port_values[right->port()] = logic_zero;
|
||||
|
|
@ -553,8 +551,8 @@ sensitizationValues(FuncExpr *expr,
|
|||
break;
|
||||
}
|
||||
case FuncExpr::op_and: {
|
||||
FuncExpr *left = expr->left();
|
||||
FuncExpr *right = expr->right();
|
||||
auto left = expr->left();
|
||||
auto right = expr->right();
|
||||
if (left->port() == from_port
|
||||
&& right->op() == FuncExpr::op_port)
|
||||
port_values[right->port()] = logic_one;
|
||||
|
|
@ -565,8 +563,8 @@ sensitizationValues(FuncExpr *expr,
|
|||
}
|
||||
case FuncExpr::op_xor: {
|
||||
// Need to know timing arc sense to get this right.
|
||||
FuncExpr *left = expr->left();
|
||||
FuncExpr *right = expr->right();
|
||||
auto left = expr->left();
|
||||
auto right = expr->right();
|
||||
if (left->port() == from_port
|
||||
&& right->op() == FuncExpr::op_port)
|
||||
port_values[right->port()] = logic_zero;
|
||||
|
|
@ -591,7 +589,7 @@ WritePathSpice::writeStageVoltageSources(LibertyCell *cell,
|
|||
{
|
||||
auto from_port_name = from_port->name();
|
||||
auto drvr_port_name = drvr_port->name();
|
||||
LibertyLibrary *lib = cell->libertyLibrary();
|
||||
auto lib = cell->libertyLibrary();
|
||||
LibertyPortLogicValues port_values;
|
||||
sensitizationValues(drvr_port->function(), from_port, port_values);
|
||||
int volt_source = 1;
|
||||
|
|
@ -613,7 +611,7 @@ WritePathSpice::writeStageVoltageSources(LibertyCell *cell,
|
|||
} else if (!(stringEq(subckt_port_name, from_port_name)
|
||||
|| stringEq(subckt_port_name, drvr_port_name))) {
|
||||
// Input voltage to sensitize path from gate input to output.
|
||||
LibertyPort *port = cell->findLibertyPort(subckt_port_name);
|
||||
auto port = cell->findLibertyPort(subckt_port_name);
|
||||
if (port) {
|
||||
const char *pg_port_name = NULL;
|
||||
bool port_has_value;
|
||||
|
|
@ -795,8 +793,7 @@ WritePathSpice::nodeName(ParasiticNode *node)
|
|||
node_index = next_node_index_++;
|
||||
node_map_[node] = node_index;
|
||||
}
|
||||
return stringPrintTmp(strlen(net_name_) + 10, "%s/%d",
|
||||
net_name_, node_index);
|
||||
return stringPrintTmp("%s/%d", net_name_, node_index);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -821,7 +818,7 @@ WritePathSpice::writeSubckts()
|
|||
split(line, " \t", tokens);
|
||||
if (tokens.size() >= 2
|
||||
&& stringEqual(tokens[0].c_str(), ".subckt")) {
|
||||
const char *cell_name = tokens[1].c_str();
|
||||
auto cell_name = tokens[1].c_str();
|
||||
if (path_cell_names.hasKey(cell_name)) {
|
||||
subckts_stream << line << "\n";
|
||||
bool found_ends = false;
|
||||
|
|
@ -848,7 +845,7 @@ WritePathSpice::writeSubckts()
|
|||
report_->error("The following subkcts are missing from %s\n",
|
||||
lib_subckt_filename_);
|
||||
while (cell_iter.hasNext()) {
|
||||
const char *cell_name = cell_iter.next();
|
||||
auto cell_name = cell_iter.next();
|
||||
report_->printError(" %s\n", cell_name);
|
||||
}
|
||||
}
|
||||
|
|
@ -866,10 +863,10 @@ void
|
|||
WritePathSpice::findPathCellnames(// Return values.
|
||||
StringSet &path_cell_names)
|
||||
{
|
||||
for (Stage stage = stageFirst(); stage <= stageLast(); stage++) {
|
||||
for (auto stage = stageFirst(); stage <= stageLast(); stage++) {
|
||||
auto arc = stageGateArc(stage);
|
||||
if (arc) {
|
||||
LibertyCell *cell = arc->set()->libertyCell();
|
||||
auto cell = arc->set()->libertyCell();
|
||||
if (cell) {
|
||||
debugPrint1(debug_, "write_spice", 2, "cell %s\n", cell->name());
|
||||
path_cell_names.insert(cell->name());
|
||||
|
|
@ -885,8 +882,8 @@ WritePathSpice::recordSpicePortNames(const char *cell_name,
|
|||
auto cell = network_->findLibertyCell(cell_name);
|
||||
if (cell) {
|
||||
auto spice_port_names = new StringVector;
|
||||
for (int i = 2; i < tokens.size(); i++) {
|
||||
const char *port_name = tokens[i].c_str();
|
||||
for (auto i = 2; i < tokens.size(); i++) {
|
||||
auto port_name = tokens[i].c_str();
|
||||
auto port = cell->findLibertyPort(port_name);
|
||||
auto pg_port = cell->findPgPort(port_name);
|
||||
if (port == NULL && pg_port == NULL)
|
||||
|
|
@ -941,28 +938,28 @@ WritePathSpice::stageLoadPathIndex(Stage stage)
|
|||
PathRef *
|
||||
WritePathSpice::stageGateInputPath(Stage stage)
|
||||
{
|
||||
int path_index = stageGateInputPathIndex(stage);
|
||||
auto path_index = stageGateInputPathIndex(stage);
|
||||
return path_expanded_.path(path_index);
|
||||
}
|
||||
|
||||
PathRef *
|
||||
WritePathSpice::stageDrvrPath(Stage stage)
|
||||
{
|
||||
int path_index = stageDrvrPathIndex(stage);
|
||||
auto path_index = stageDrvrPathIndex(stage);
|
||||
return path_expanded_.path(path_index);
|
||||
}
|
||||
|
||||
PathRef *
|
||||
WritePathSpice::stageLoadPath(Stage stage)
|
||||
{
|
||||
int path_index = stageLoadPathIndex(stage);
|
||||
auto path_index = stageLoadPathIndex(stage);
|
||||
return path_expanded_.path(path_index);
|
||||
}
|
||||
|
||||
TimingArc *
|
||||
WritePathSpice::stageGateArc(Stage stage)
|
||||
{
|
||||
int path_index = stageDrvrPathIndex(stage);
|
||||
auto path_index = stageDrvrPathIndex(stage);
|
||||
if (path_index >= 0)
|
||||
return path_expanded_.prevArc(path_index);
|
||||
else
|
||||
|
|
@ -972,70 +969,87 @@ WritePathSpice::stageGateArc(Stage stage)
|
|||
TimingArc *
|
||||
WritePathSpice::stageWireArc(Stage stage)
|
||||
{
|
||||
int path_index = stageLoadPathIndex(stage);
|
||||
auto path_index = stageLoadPathIndex(stage);
|
||||
return path_expanded_.prevArc(path_index);
|
||||
}
|
||||
|
||||
Edge *
|
||||
WritePathSpice::stageGateEdge(Stage stage)
|
||||
{
|
||||
PathRef *path = stageGateInputPath(stage);
|
||||
TimingArc *arc = stageGateArc(stage);
|
||||
auto path = stageGateInputPath(stage);
|
||||
auto arc = stageGateArc(stage);
|
||||
return path->prevEdge(arc, this);
|
||||
}
|
||||
|
||||
Edge *
|
||||
WritePathSpice::stageWireEdge(Stage stage)
|
||||
{
|
||||
PathRef *path = stageLoadPath(stage);
|
||||
TimingArc *arc = stageWireArc(stage);
|
||||
auto path = stageLoadPath(stage);
|
||||
auto arc = stageWireArc(stage);
|
||||
return path->prevEdge(arc, this);
|
||||
}
|
||||
|
||||
Pin *
|
||||
WritePathSpice::stageInputPin(Stage stage)
|
||||
{
|
||||
PathRef *path = stageGateInputPath(stage);
|
||||
auto path = stageGateInputPath(stage);
|
||||
return path->pin(this);
|
||||
}
|
||||
|
||||
Pin *
|
||||
WritePathSpice::stageDrvrPin(Stage stage)
|
||||
{
|
||||
PathRef *path = stageDrvrPath(stage);
|
||||
auto path = stageDrvrPath(stage);
|
||||
return path->pin(this);
|
||||
}
|
||||
|
||||
Pin *
|
||||
WritePathSpice::stageLoadPin(Stage stage)
|
||||
{
|
||||
PathRef *path = stageLoadPath(stage);
|
||||
auto path = stageLoadPath(stage);
|
||||
return path->pin(this);
|
||||
}
|
||||
|
||||
const char *
|
||||
WritePathSpice::stageGateInputPinName(Stage stage)
|
||||
{
|
||||
const Pin *pin = stageInputPin(stage);
|
||||
auto pin = stageInputPin(stage);
|
||||
return network_->pathName(pin);
|
||||
}
|
||||
|
||||
const char *
|
||||
WritePathSpice::stageDrvrPinName(Stage stage)
|
||||
{
|
||||
Pin *pin = stageDrvrPin(stage);
|
||||
auto pin = stageDrvrPin(stage);
|
||||
return network_->pathName(pin);
|
||||
}
|
||||
|
||||
const char *
|
||||
WritePathSpice::stageLoadPinName(Stage stage)
|
||||
{
|
||||
const Pin *pin = stageLoadPin(stage);
|
||||
auto pin = stageLoadPin(stage);
|
||||
return network_->pathName(pin);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// fprintf for c++ streams.
|
||||
// Yes, I hate formatted output to ostream THAT much.
|
||||
void
|
||||
streamPrint(ofstream &stream,
|
||||
const char *fmt,
|
||||
...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
char *result;
|
||||
vasprintf(&result, fmt, args);
|
||||
stream << result;
|
||||
free(result);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
split(const string &text,
|
||||
const string &delims,
|
||||
|
|
@ -1053,35 +1067,4 @@ split(const string &text,
|
|||
tokens.push_back(text.substr(start));
|
||||
}
|
||||
|
||||
// fprintf for c++ streams.
|
||||
// Yes, I hate formatted output to ostream THAT much.
|
||||
void
|
||||
streamPrint(ofstream &stream,
|
||||
const char *fmt,
|
||||
...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
char *result;
|
||||
vasprintf(&result, fmt, args);
|
||||
stream << result;
|
||||
free(result);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
// print for c++ strings.
|
||||
void
|
||||
stringPrint(string &str,
|
||||
const char *fmt,
|
||||
...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
char *result;
|
||||
vasprintf(&result, fmt, args);
|
||||
str = result;
|
||||
free(result);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
88
tcl/Cmds.tcl
88
tcl/Cmds.tcl
|
|
@ -22,6 +22,15 @@
|
|||
|
||||
namespace eval sta {
|
||||
|
||||
proc_redirect read_parasitics {
|
||||
variable native
|
||||
|
||||
if { $native } {
|
||||
sta_warn "The read_parasitics command is deprecated. Use read_spef."
|
||||
}
|
||||
eval [concat read_spef $args]
|
||||
}
|
||||
|
||||
proc check_setup_cmd { cmd cmd_args } {
|
||||
parse_key_args $cmd cmd_args keys {} flags {-verbose} 0
|
||||
# When nothing is everything.
|
||||
|
|
@ -290,12 +299,12 @@ proc set_assigned_delay_cmd { cmd cmd_args } {
|
|||
set inst [[lindex $from_pins 0] instance]
|
||||
foreach pin $from_pins {
|
||||
if {[$pin instance] != $inst} {
|
||||
sta_error "$cmd pin [$pin name] is not attached to instance [$inst path_name]."
|
||||
sta_error "$cmd pin [get_full_name $pin] is not attached to instance [get_full_name $inst]."
|
||||
}
|
||||
}
|
||||
foreach pin $to_pins {
|
||||
if {[$pin instance] != $inst} {
|
||||
sta_error "$cmd pin [$pin name] is not attached to instance [$inst path_name]"
|
||||
sta_error "$cmd pin [get_full_name $pin] is not attached to instance [get_full_name $inst]"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1068,7 +1077,7 @@ proc parse_clk_inst_port_pin_arg { objects clks_var insts_var pins_var } {
|
|||
set ports {}
|
||||
get_object_args $objects clks {} {} {} insts ports pins {} {} {}
|
||||
foreach port $ports {
|
||||
lappend pins [[top_instance] find_pin [$port name]]
|
||||
lappend pins [[top_instance] find_pin [get_name $port]]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1080,7 +1089,7 @@ proc parse_clk_port_pin_arg { objects clks_var pins_var } {
|
|||
set ports {}
|
||||
get_object_args $objects clks {} {} {} {} ports pins {} {} {}
|
||||
foreach port $ports {
|
||||
lappend pins [[top_instance] find_pin [$port name]]
|
||||
lappend pins [[top_instance] find_pin [get_name $port]]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1155,7 +1164,7 @@ proc parse_inst_port_pin_arg { objects insts_var pins_var } {
|
|||
set ports {}
|
||||
get_object_args $objects {} {} {} {} insts ports pins {} {} {}
|
||||
foreach port $ports {
|
||||
lappend pins [[top_instance] find_pin [$port name]]
|
||||
lappend pins [[top_instance] find_pin [get_name $port]]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1177,7 +1186,7 @@ proc parse_inst_port_pin_net_arg { objects insts_var pins_var nets_var } {
|
|||
set nets {}
|
||||
get_object_args $objects {} {} {} {} insts ports pins nets {} {}
|
||||
foreach port $ports {
|
||||
lappend pins [[top_instance] find_pin [$port name]]
|
||||
lappend pins [[top_instance] find_pin [get_name $port]]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1196,8 +1205,9 @@ proc parse_port_pin_net_arg { objects pins_var nets_var } {
|
|||
set pins {}
|
||||
set nets {}
|
||||
get_object_args $objects {} {} {} {} {} ports pins nets {} {}
|
||||
|
||||
foreach port $ports {
|
||||
lappend pins [[top_instance] find_pin [$port name]]
|
||||
lappend pins [[top_instance] find_pin [get_name $port]]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1497,7 +1507,7 @@ proc get_port_pin_arg { arg_name arg warn_error } {
|
|||
set pin $arg
|
||||
} elseif { $object_type == "Port" } {
|
||||
# Explicit port arg - convert to pin.
|
||||
set pin [find_pin [$arg name]]
|
||||
set pin [find_pin [get_name $arg]]
|
||||
} else {
|
||||
sta_warn_error $warn_error "$arg_name type '$object_type' is not a pin or port."
|
||||
}
|
||||
|
|
@ -1508,7 +1518,7 @@ proc get_port_pin_arg { arg_name arg warn_error } {
|
|||
if { $port == "NULL" } {
|
||||
set pin [find_pin $arg]
|
||||
} else {
|
||||
set pin [$top_instance find_pin [$port name]]
|
||||
set pin [$top_instance find_pin [get_name $port]]
|
||||
}
|
||||
if { $pin == "NULL" } {
|
||||
sta_warn_error $warn_error "pin $arg not found."
|
||||
|
|
@ -1531,7 +1541,7 @@ proc get_port_pins_error { arg_name arglist } {
|
|||
lappend pins $arg
|
||||
} elseif { $object_type == "Port" } {
|
||||
# Convert port to pin.
|
||||
lappend pins [find_pin [$arg name]]
|
||||
lappend pins [find_pin [get_name $arg]]
|
||||
} else {
|
||||
sta_error "$arg_name type '$object_type' is not a pin or port."
|
||||
}
|
||||
|
|
@ -1769,10 +1779,14 @@ proc get_property_cmd { cmd type_key cmd_args } {
|
|||
} else {
|
||||
sta_error "$cmd $type_key must be specified with object name argument."
|
||||
}
|
||||
set object [get_property_object $object_type $object $quiet]
|
||||
set object [get_property_object_type $object_type $object $quiet]
|
||||
}
|
||||
set object_type [object_type $object]
|
||||
set prop [lindex $cmd_args 1]
|
||||
return [get_object_property $object $prop]
|
||||
}
|
||||
|
||||
proc get_object_property { object prop } {
|
||||
set object_type [object_type $object]
|
||||
if { $object_type == "Instance" } {
|
||||
return [instance_property $object $prop]
|
||||
} elseif { $object_type == "Pin" } {
|
||||
|
|
@ -1787,6 +1801,8 @@ proc get_property_cmd { cmd type_key cmd_args } {
|
|||
return [liberty_port_property $object $prop]
|
||||
} elseif { $object_type == "LibertyCell" } {
|
||||
return [liberty_cell_property $object $prop]
|
||||
} elseif { $object_type == "Cell" } {
|
||||
return [cell_property $object $prop]
|
||||
} elseif { $object_type == "Library" } {
|
||||
return [library_property $object $prop]
|
||||
} elseif { $object_type == "LibertyLibrary" } {
|
||||
|
|
@ -1797,12 +1813,14 @@ proc get_property_cmd { cmd type_key cmd_args } {
|
|||
return [path_end_property $object $prop]
|
||||
} elseif { $object_type == "PathRef" } {
|
||||
return [path_ref_property $object $prop]
|
||||
} elseif { $object_type == "TimingArcSet" } {
|
||||
return [timing_arc_set_property $object $prop]
|
||||
} else {
|
||||
sta_error "$cmd unsupported object type $object_type."
|
||||
sta_error "get_property unsupported object type object_type."
|
||||
}
|
||||
}
|
||||
|
||||
proc get_property_object { object_type object_name quiet } {
|
||||
proc get_property_object_type { object_type object_name quiet } {
|
||||
set object "NULL"
|
||||
if { $object_type == "cell" } {
|
||||
set object [get_cells -quiet $object_name]
|
||||
|
|
@ -1856,8 +1874,46 @@ proc get_object_type { obj } {
|
|||
}
|
||||
}
|
||||
|
||||
proc object_name_cmp { obj1 obj2 } {
|
||||
return [string compare [$obj1 object_name] [$obj2 object_name]]
|
||||
proc sort_by_full_name { objects } {
|
||||
return [lsort -command full_name_cmp $objects]
|
||||
}
|
||||
|
||||
proc sort_by_name { objects } {
|
||||
return [lsort -command name_cmp $objects]
|
||||
}
|
||||
|
||||
proc full_name_cmp { obj1 obj2 } {
|
||||
return [string compare [get_full_name $obj1] [get_full_name $obj2]]
|
||||
}
|
||||
|
||||
proc name_cmp { obj1 obj2 } {
|
||||
return [string compare [get_name $obj1] [get_name $obj2]]
|
||||
}
|
||||
|
||||
proc get_name { object } {
|
||||
return [get_object_property $object "name"]
|
||||
}
|
||||
|
||||
proc get_full_name { object } {
|
||||
return [get_object_property $object "full_name"]
|
||||
}
|
||||
|
||||
if {0} {
|
||||
proc get_name { objects } {
|
||||
set names {}
|
||||
foreach object $objects {
|
||||
lappend names [get_object_property $object "name"]
|
||||
}
|
||||
return $names
|
||||
}
|
||||
|
||||
proc get_full_name { objects } {
|
||||
set names {}
|
||||
foreach object $objects {
|
||||
lappend names [get_object_property $object "full_name"]
|
||||
}
|
||||
return $names
|
||||
}
|
||||
}
|
||||
|
||||
################################################################
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ proc report_constant { obj } {
|
|||
|
||||
proc report_pin_constant { pin } {
|
||||
set sim_value [pin_sim_logic_value $pin]
|
||||
puts -nonewline "[$pin port_name] $sim_value"
|
||||
puts -nonewline "[pin_property $pin lib_pin_name] $sim_value"
|
||||
set case_value [pin_case_logic_value $pin]
|
||||
if { $case_value != "X" } {
|
||||
puts -nonewline " case=$case_value"
|
||||
|
|
@ -234,15 +234,15 @@ proc report_pin_constant { pin } {
|
|||
proc report_disabled_edges {} {
|
||||
foreach edge [disabled_edges_sorted] {
|
||||
if { [$edge role] == "wire" } {
|
||||
set from_pin_name [[[$edge from] pin] path_name]
|
||||
set to_pin_name [[[$edge to] pin] path_name]
|
||||
set from_pin_name [get_full_name [[$edge from] pin]]
|
||||
set to_pin_name [get_full_name [[$edge to] pin]]
|
||||
puts -nonewline "$from_pin_name $to_pin_name"
|
||||
} else {
|
||||
set from_pin [[$edge from] pin]
|
||||
set to_pin [[$edge to] pin]
|
||||
set inst_name [[$from_pin instance] path_name]
|
||||
set from_port_name [[$from_pin port] name]
|
||||
set to_port_name [[$to_pin port] name]
|
||||
set inst_name [get_full_name [$from_pin instance]]
|
||||
set from_port_name [get_name [$from_pin port]]
|
||||
set to_port_name [get_name [$to_pin port]]
|
||||
puts -nonewline "$inst_name $from_port_name $to_port_name"
|
||||
set cond [$edge cond]
|
||||
if { $cond != "" } {
|
||||
|
|
@ -267,8 +267,8 @@ proc edge_disable_reason_verbose { edge } {
|
|||
append disables " $sense"
|
||||
}
|
||||
set const_pins [$edge disabled_constant_pins]
|
||||
foreach pin [lsort -command path_name_cmp $const_pins] {
|
||||
set port_name [$pin port_name]
|
||||
foreach pin [sort_by_full_name $const_pins] {
|
||||
set port_name [pin_property $pin lib_pin_name]
|
||||
set value [pin_sim_logic_value $pin]
|
||||
append disables " $port_name=$value"
|
||||
}
|
||||
|
|
@ -302,18 +302,20 @@ proc report_slews { pin } {
|
|||
}
|
||||
|
||||
proc vertex_path_name { vertex } {
|
||||
return [vertex_name_ $vertex path_name]
|
||||
set pin [$vertex pin]
|
||||
set pin_name [get_full_name $pin]
|
||||
return [vertex_name_ $vertex $pin $pin_name]
|
||||
}
|
||||
|
||||
proc vertex_port_name { vertex } {
|
||||
return [vertex_name_ $vertex port_name]
|
||||
set pin [$vertex pin]
|
||||
set pin_name [pin_property $pin lib_pin_name]
|
||||
return [vertex_name_ $vertex $pin $pin_name]
|
||||
}
|
||||
|
||||
# Append driver/load for bidirect pin vertices.
|
||||
proc vertex_name_ { vertex name_proc } {
|
||||
set pin [$vertex pin]
|
||||
set pin_name [$pin $name_proc]
|
||||
if { [$pin direction] == "bidirect" } {
|
||||
proc vertex_name_ { vertex pin pin_name } {
|
||||
if { [pin_direction $pin] == "bidirect" } {
|
||||
if [$vertex is_bidirect_driver] {
|
||||
return "$pin_name driver"
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -60,11 +60,12 @@ proc report_instance1 { instance connections verbose } {
|
|||
if { $instance == [top_instance] } {
|
||||
set inst_name "top"
|
||||
} else {
|
||||
set inst_name [$instance path_name]
|
||||
set inst_name [get_full_name $instance]
|
||||
}
|
||||
puts "Instance $inst_name"
|
||||
puts " Cell: [[$instance cell] name]"
|
||||
puts " Library: [[[$instance cell] library] name]"
|
||||
set cell [instance_property $instance "cell"]
|
||||
puts " Cell: [get_name $cell]"
|
||||
puts " Library: [get_name [$cell library]]"
|
||||
puts " Path cells: [instance_cell_path $instance]"
|
||||
if { $connections } {
|
||||
report_instance_pins $instance $verbose
|
||||
|
|
@ -92,7 +93,7 @@ proc report_instance_pins1 {instance verbose header header_optional dirs} {
|
|||
set iter [$instance pin_iterator]
|
||||
while {[$iter has_next]} {
|
||||
set pin [$iter next]
|
||||
set dir [$pin direction]
|
||||
set dir [pin_direction $pin]
|
||||
if { [lsearch $dirs $dir] != -1 } {
|
||||
if { !$header_shown } {
|
||||
puts $header
|
||||
|
|
@ -105,20 +106,20 @@ proc report_instance_pins1 {instance verbose header header_optional dirs} {
|
|||
}
|
||||
|
||||
proc report_instance_pin { pin verbose } {
|
||||
puts -nonewline " [$pin port_name] [$pin direction]"
|
||||
puts -nonewline " [$pin port_name] [pin_direction $pin]"
|
||||
set net [$pin net]
|
||||
if { $net == "NULL" } {
|
||||
puts " (unconnected)"
|
||||
} else {
|
||||
puts " [[$net highest_connected_net] path_name]"
|
||||
puts " [get_full_name [$net highest_connected_net]]"
|
||||
if { $verbose } {
|
||||
set pins [net_connected_pins_sorted $net]
|
||||
foreach pin $pins {
|
||||
if [$pin is_load] {
|
||||
if [$pin is_top_level_port] {
|
||||
puts " [$pin path_name] [$pin direction] port"
|
||||
puts " [get_full_name $pin] [pin_direction $pin] port"
|
||||
} else {
|
||||
puts " [$pin path_name] [$pin direction]"
|
||||
puts " [get_full_name $pin] [pin_direction $pin]"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -128,11 +129,11 @@ proc report_instance_pin { pin verbose } {
|
|||
|
||||
# Concatenate the cell names of the instance parents.
|
||||
proc instance_cell_path { instance } {
|
||||
set cell_path "[[$instance cell] name]"
|
||||
set cell_path "[get_name [instance_property $instance "cell"]]"
|
||||
set parent [$instance parent]
|
||||
set top_instance [top_instance]
|
||||
while { $parent != "NULL" && $parent != $top_instance } {
|
||||
set cell_path "[[$parent cell] name]/$cell_path"
|
||||
set cell_path "[get_name [$parent cell]]/$cell_path"
|
||||
set parent [$parent parent]
|
||||
}
|
||||
return $cell_path
|
||||
|
|
@ -143,7 +144,7 @@ proc report_instance_children_ { instance } {
|
|||
if { $children != {} } {
|
||||
puts " Children:"
|
||||
foreach child $children {
|
||||
puts " [$child name] ([[$child cell] name])"
|
||||
puts " [get_name $child] ([instance_property $child ref_name])"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -155,15 +156,7 @@ proc instance_sorted_children { instance } {
|
|||
lappend children [$iter next]
|
||||
}
|
||||
$iter finish
|
||||
return [lsort -command path_name_cmp $children]
|
||||
}
|
||||
|
||||
proc path_name_cmp { obj1 obj2 } {
|
||||
return [string compare [$obj1 path_name] [$obj2 path_name]]
|
||||
}
|
||||
|
||||
proc name_cmp { obj1 obj2 } {
|
||||
return [string compare [$obj1 name] [$obj2 name]]
|
||||
return [sort_by_full_name $children]
|
||||
}
|
||||
|
||||
################################################################
|
||||
|
|
@ -183,9 +176,9 @@ proc report_lib_cell_ { cell } {
|
|||
global sta_report_default_digits
|
||||
|
||||
set lib [$cell liberty_library]
|
||||
puts "Cell [$cell name]"
|
||||
puts "Library [$lib name]"
|
||||
set filename [$cell filename]
|
||||
puts "Cell [get_name $cell]"
|
||||
puts "Library [get_name $lib]"
|
||||
set filename [liberty_cell_property $cell "filename"]
|
||||
if { $filename != "" } {
|
||||
puts "File $filename"
|
||||
}
|
||||
|
|
@ -193,9 +186,9 @@ proc report_lib_cell_ { cell } {
|
|||
while {[$iter has_next]} {
|
||||
set port [$iter next]
|
||||
if { [$port is_bus] } {
|
||||
puts -nonewline " [$port bus_name] [$port direction]"
|
||||
puts -nonewline " [$port bus_name] [liberty_port_direction $port]"
|
||||
} else {
|
||||
puts -nonewline " [$port name] [$port direction]"
|
||||
puts -nonewline " [get_name $port] [liberty_port_direction $port]"
|
||||
}
|
||||
set enable [$port tristate_enable]
|
||||
if { $enable != "" } {
|
||||
|
|
@ -212,9 +205,9 @@ proc report_lib_cell_ { cell } {
|
|||
|
||||
proc report_cell_ { cell } {
|
||||
set lib [$cell library]
|
||||
puts "Cell [$cell name]"
|
||||
puts "Library [$lib name]"
|
||||
set filename [$cell filename]
|
||||
puts "Cell [get_name $cell]"
|
||||
puts "Library [get_name $lib]"
|
||||
set filename [liberty_cell_property $cell "filename"]
|
||||
if { $filename != "" } {
|
||||
puts "File $filename"
|
||||
}
|
||||
|
|
@ -222,9 +215,9 @@ proc report_cell_ { cell } {
|
|||
while {[$iter has_next]} {
|
||||
set port [$iter next]
|
||||
if { [$port is_bus] } {
|
||||
puts " [$port bus_name] [$port direction]"
|
||||
puts " [$port bus_name] [port_direction $port]"
|
||||
} else {
|
||||
puts " [$port name] [$port direction]"
|
||||
puts " [get_name $port] [port_direction $port]"
|
||||
}
|
||||
}
|
||||
$iter finish
|
||||
|
|
@ -292,7 +285,7 @@ proc report_net_ { net } {
|
|||
}
|
||||
|
||||
proc report_net1 { net connections verbose hier_pins corner digits } {
|
||||
puts "Net [$net path_name]"
|
||||
puts "Net [get_full_name $net]"
|
||||
if {$connections} {
|
||||
set pins [net_connected_pins_sorted $net]
|
||||
if {$verbose} {
|
||||
|
|
@ -320,7 +313,7 @@ proc net_connected_pins_sorted { net } {
|
|||
lappend pins $pin
|
||||
}
|
||||
$iter finish
|
||||
set pins [lsort -command path_name_cmp $pins]
|
||||
set pins [sort_by_full_name $pins]
|
||||
return $pins
|
||||
}
|
||||
|
||||
|
|
@ -380,8 +373,8 @@ proc report_net_other_pins { pins verbose corner digits } {
|
|||
|
||||
proc report_net_pin { pin verbose corner digits } {
|
||||
if [$pin is_leaf] {
|
||||
set cell_name [[[$pin instance] cell] name]
|
||||
puts -nonewline " [$pin path_name] [$pin direction] ($cell_name)"
|
||||
set cell_name [get_name [[$pin instance] cell]]
|
||||
puts -nonewline " [get_full_name $pin] [pin_direction $pin] ($cell_name)"
|
||||
if { $verbose } {
|
||||
set liberty_port [$pin liberty_port]
|
||||
if { $liberty_port != "NULL" } {
|
||||
|
|
@ -390,7 +383,7 @@ proc report_net_pin { pin verbose corner digits } {
|
|||
}
|
||||
puts ""
|
||||
} elseif [$pin is_top_level_port] {
|
||||
puts -nonewline " [$pin path_name] [$pin direction] port"
|
||||
puts -nonewline " [get_full_name $pin] [pin_direction $pin] port"
|
||||
if { $verbose } {
|
||||
set port [$pin port]
|
||||
set cap_r_min [port_ext_wire_cap $port "rise" "min"]
|
||||
|
|
@ -412,7 +405,7 @@ proc report_net_pin { pin verbose corner digits } {
|
|||
}
|
||||
puts ""
|
||||
} elseif [$pin is_hierarchical] {
|
||||
puts " [$pin path_name] [$pin direction]"
|
||||
puts " [get_full_name $pin] [pin_direction $pin]"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -421,7 +414,7 @@ proc report_net_pin { pin verbose corner digits } {
|
|||
proc report_pin_ { pin } {
|
||||
global sta_report_default_digits
|
||||
|
||||
puts -nonewline "Pin [$pin path_name] [pin_direction_desc $pin]"
|
||||
puts -nonewline "Pin [get_full_name $pin] [pin_direction_desc $pin]"
|
||||
|
||||
set liberty_port [$pin liberty_port]
|
||||
if { $liberty_port != "NULL" } {
|
||||
|
|
@ -429,24 +422,29 @@ proc report_pin_ { pin } {
|
|||
}
|
||||
|
||||
if { [$pin is_top_level_port] } {
|
||||
set net [[$pin term] net]
|
||||
set term [$pin term]
|
||||
if { $term == "NULL" } {
|
||||
set net "NULL"
|
||||
} else {
|
||||
set net [$term net]
|
||||
}
|
||||
} else {
|
||||
set net [$pin net]
|
||||
}
|
||||
if { $net == "NULL" } {
|
||||
puts " (unconnected)"
|
||||
} else {
|
||||
puts " [[$net highest_connected_net] path_name]"
|
||||
puts " [get_full_name [$net highest_connected_net]]"
|
||||
}
|
||||
}
|
||||
|
||||
proc pin_direction_desc { pin } {
|
||||
if [$pin is_hierarchical] {
|
||||
return "hierarchical [$pin direction]"
|
||||
return "hierarchical [pin_direction $pin]"
|
||||
} elseif [$pin is_top_level_port] {
|
||||
return "[$pin direction] port"
|
||||
return "[pin_direction $pin] port"
|
||||
} else {
|
||||
return [$pin direction]
|
||||
return [pin_direction $pin]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ proc parse_connect_pins { arg } {
|
|||
set port [$pin port]
|
||||
} elseif { $object_type == "Port" } {
|
||||
# Explicit port arg - convert to pin.
|
||||
set pin [find_pin [$obj name]]
|
||||
set pin [find_pin [get_name $obj]]
|
||||
set inst [$pin instance]
|
||||
set port [$pin port]
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -106,9 +106,11 @@ proc report_power_col_percent { col_total total } {
|
|||
}
|
||||
|
||||
proc report_power_inst { inst corner digits } {
|
||||
puts "Instance: [$inst path_name]"
|
||||
puts "Cell: [[$inst liberty_cell] name]"
|
||||
puts "Liberty file: [[[$inst liberty_cell] liberty_library] filename]"
|
||||
puts "Instance: [get_full_name $inst]"
|
||||
set cell [instance_property $inst "liberty_cell"]
|
||||
puts "Cell: [get_name $cell]"
|
||||
set library [liberty_cell_property $cell "library"]
|
||||
puts "Liberty file: [liberty_library_property $library filename]"
|
||||
set power_result [instance_power $inst $corner]
|
||||
lassign $power_result internal switching leakage total
|
||||
report_power_line "Internal power" $internal $digits
|
||||
|
|
|
|||
40
tcl/Sdc.tcl
40
tcl/Sdc.tcl
|
|
@ -159,7 +159,7 @@ proc current_instance { {inst ""} } {
|
|||
} else {
|
||||
set current_instance [get_instance_error "instance" $inst]
|
||||
}
|
||||
set cell [[$current_instance cell] name]
|
||||
set cell [get_name [$current_instance cell]]
|
||||
puts "Current instance is $cell."
|
||||
# Current instance state variable must be part of the sta state so
|
||||
# the tcl interpreter can be shared by multiple sdc files.
|
||||
|
|
@ -289,7 +289,7 @@ proc all_ports_for_direction { direction } {
|
|||
set iter [$top_cell port_iterator]
|
||||
while {[$iter has_next]} {
|
||||
set port [$iter next]
|
||||
set port_dir [$port direction]
|
||||
set port_dir [port_direction $port]
|
||||
if { $port_dir == $direction || $port_dir == "bidirect" } {
|
||||
set ports [concat $ports [port_members $port]]
|
||||
}
|
||||
|
|
@ -384,11 +384,11 @@ proc current_design { {design ""} } {
|
|||
|
||||
if { $design == "" } {
|
||||
# top_instance errors if the network has not been linked.
|
||||
set current_design_name [[[top_instance] cell] name]
|
||||
set current_design_name [get_name [get_object_property [top_instance] cell]]
|
||||
} elseif { ![network_is_linked] } {
|
||||
set current_design_name $design
|
||||
return $design
|
||||
} elseif { [network_is_linked] && $design == [[[top_instance] cell] name] } {
|
||||
} elseif { [network_is_linked] && $design == [get_name [get_object_property [top_instance] cell]] } {
|
||||
set current_design_name $design
|
||||
return $design
|
||||
} else {
|
||||
|
|
@ -706,7 +706,7 @@ proc find_liberty_libraries_matching { pattern regexp nocase } {
|
|||
set matches {}
|
||||
while { [$lib_iter has_next] } {
|
||||
set lib [$lib_iter next]
|
||||
set lib_name [$lib name]
|
||||
set lib_name [get_name $lib]
|
||||
if { (!$regexp && [string match $pattern2 $lib_name]) \
|
||||
|| ($regexp && $nocase && [regexp -nocase $pattern2 $lib_name]) \
|
||||
|| ($regexp && !$nocase && [regexp $pattern2 $lib_name]) } {
|
||||
|
|
@ -980,7 +980,7 @@ proc create_clock { args } {
|
|||
sta_error "-add requires -name."
|
||||
}
|
||||
# Default clock name is the first pin name.
|
||||
set name [[lindex $pins 0] path_name]
|
||||
set name [get_full_name [lindex $pins 0]]
|
||||
} else {
|
||||
sta_error "-name or port_pin_list must be specified."
|
||||
}
|
||||
|
|
@ -1057,7 +1057,7 @@ proc create_generated_clock { args } {
|
|||
sta_error "-add requires -name."
|
||||
}
|
||||
# Default clock name is the first pin name.
|
||||
set name [[lindex $pins 0] path_name]
|
||||
set name [get_full_name [lindex $pins 0]]
|
||||
} else {
|
||||
sta_error "name or port_pin_list must be specified."
|
||||
}
|
||||
|
|
@ -1410,7 +1410,7 @@ proc set_clock_latency { args } {
|
|||
foreach pin $pins {
|
||||
# Source only allowed on clocks and clock pins.
|
||||
if { ![is_clock_src $pin] } {
|
||||
sta_error "-source '[$pin path_name]' is not a clock pin."
|
||||
sta_error "-source '[get_full_name $pin]' is not a clock pin."
|
||||
}
|
||||
set_clock_insertion_cmd $pin_clk $pin $tr $min_max $early_late $delay
|
||||
}
|
||||
|
|
@ -1465,7 +1465,7 @@ proc set_clock_sense { args } {
|
|||
}
|
||||
foreach pin $pins {
|
||||
if {[$pin is_hierarchical]} {
|
||||
sta_warn "hierarchical pin '[$pin path_name]' not supported."
|
||||
sta_warn "hierarchical pin '[get_full_name $pin]' not supported."
|
||||
}
|
||||
}
|
||||
set_clock_sense_cmd $pins $clks $positive $negative $stop_propagation
|
||||
|
|
@ -1724,16 +1724,16 @@ proc parse_disable_inst_ports { inst port_name } {
|
|||
if { $port_name == "" } {
|
||||
set ports "NULL"
|
||||
} else {
|
||||
set cell [$inst liberty_cell]
|
||||
set cell [instance_property $inst liberty_cell]
|
||||
set port [$cell find_liberty_port $port_name]
|
||||
if { $port == "NULL" } {
|
||||
sta_error "pin '[$inst path_name]${hierarchy_separator}${port_name}' not found."
|
||||
sta_error "pin '[get_full_name $inst]${hierarchy_separator}${port_name}' not found."
|
||||
} else {
|
||||
set ports [port_members $port]
|
||||
foreach port $ports {
|
||||
set member_name [$port name]
|
||||
set member_name [get_full_name $port]
|
||||
if { [$inst find_pin $member_name] == "NULL" } {
|
||||
sta_error "pin '[$inst path_name]${hierarchy_separator}${member_name}' not found."
|
||||
sta_error "pin '[get_full_name $inst]]${hierarchy_separator}${member_name}' not found."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1773,7 +1773,7 @@ proc parse_disable_cell_ports { cell port_name } {
|
|||
} else {
|
||||
set port [$cell find_liberty_port $port_name]
|
||||
if { $port == "NULL" } {
|
||||
sta_error "pin '[$cell name]${hierarchy_separator}${port_name}' not found."
|
||||
sta_error "pin '[get_name $cell]${hierarchy_separator}${port_name}' not found."
|
||||
} else {
|
||||
set ports [port_members $port]
|
||||
}
|
||||
|
|
@ -1920,8 +1920,8 @@ proc set_port_delay { cmd sta_cmd cmd_args port_dirs } {
|
|||
|
||||
foreach pin $pins {
|
||||
if { [$pin is_top_level_port] \
|
||||
&& [lsearch $port_dirs [$pin direction]] == -1 } {
|
||||
sta_warn "$cmd not allowed on [$pin direction] port '[$pin name]'."
|
||||
&& [lsearch $port_dirs [pin_direction $pin]] == -1 } {
|
||||
sta_warn "$cmd not allowed on [pin_direction $pin] port '[get_full_name $pin]'."
|
||||
} elseif { $clk != "NULL" && [lsearch [$clk sources] $pin] != -1 } {
|
||||
sta_warn "$cmd relative to a clock defined on the same port/pin not allowed."
|
||||
} else {
|
||||
|
|
@ -2147,7 +2147,7 @@ proc set_propagated_clock { objects } {
|
|||
parse_clk_port_pin_arg $objects clks pins
|
||||
foreach clk $clks {
|
||||
if { [$clk is_virtual] } {
|
||||
sta_warn "virtual clock [$clk name] can not be propagated."
|
||||
sta_warn "virtual clock [get_name $clk] can not be propagated."
|
||||
} else {
|
||||
set_propagated_clock_cmd $clk
|
||||
}
|
||||
|
|
@ -2257,7 +2257,7 @@ proc set_driving_cell { args } {
|
|||
set output_count 0
|
||||
while {[$port_iter has_next]} {
|
||||
set port [$port_iter next]
|
||||
set dir [$port direction]
|
||||
set dir [liberty_port_direction $port]
|
||||
if { [port_direction_any_output $dir] } {
|
||||
incr output_count
|
||||
if { $output_count > 1 } {
|
||||
|
|
@ -2482,9 +2482,9 @@ proc set_fanout_limit { fanout min_max objects } {
|
|||
check_positive_float "limit" $fanout
|
||||
parse_cell_port_args $objects cells ports
|
||||
foreach port $ports {
|
||||
set dir [$port direction]
|
||||
set dir [port_direction $port]
|
||||
if { !($dir == "input" || $dir == "bidirect") } {
|
||||
sta_error "port '[$port name]' is not an input."
|
||||
sta_error "port '[get_name $port]' is not an input."
|
||||
}
|
||||
set_port_fanout_limit $port $min_max $fanout
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ proc report_delays_wrt_clk { vertex what clk clk_tr } {
|
|||
set rise_fmt [format_delays $rise]
|
||||
set fall_fmt [format_delays $fall]
|
||||
if {$clk != "NULL"} {
|
||||
set clk_str " ([$clk name] [rise_fall_short_name $clk_tr])"
|
||||
set clk_str " ([get_name $clk] [rise_fall_short_name $clk_tr])"
|
||||
} else {
|
||||
set clk_str ""
|
||||
}
|
||||
|
|
@ -90,7 +90,7 @@ proc report_wrt_clk { vertex what clk clk_tr } {
|
|||
set rise_fmt [format_times $rise $sta_report_default_digits]
|
||||
set fall_fmt [format_times $fall $sta_report_default_digits]
|
||||
if {$clk != "NULL"} {
|
||||
set clk_str " ([$clk name] [rise_fall_short_name $clk_tr])"
|
||||
set clk_str " ([get_name $clk] [rise_fall_short_name $clk_tr])"
|
||||
} else {
|
||||
set clk_str ""
|
||||
}
|
||||
|
|
|
|||
76
tcl/Sta.tcl
76
tcl/Sta.tcl
|
|
@ -25,11 +25,13 @@ proc define_sta_cmd_args { cmd arglist } {
|
|||
# Import Sta commands to global namespace.
|
||||
proc define_sta_cmds {} {
|
||||
variable sta_cmd_args
|
||||
variable native
|
||||
|
||||
foreach cmd [array names sta_cmd_args] {
|
||||
define_cmd_args $cmd $sta_cmd_args($cmd)
|
||||
}
|
||||
define_report_path_fields
|
||||
set native 1
|
||||
}
|
||||
|
||||
proc define_report_path_fields {} {
|
||||
|
|
@ -421,7 +423,7 @@ proc_redirect report_check_types {
|
|||
set slack_min [expr -$sta::float_inf]
|
||||
set slack_max $sta::float_inf
|
||||
}
|
||||
set path_ends [find_path_ends "NULL" {} "NULL" \
|
||||
set path_ends [find_path_ends "NULL" {} "NULL" 0 \
|
||||
$corner $path_min_max $group_count 1 0 \
|
||||
$slack_min $slack_max \
|
||||
0 {} \
|
||||
|
|
@ -674,28 +676,16 @@ proc unset_timing_derate { args } {
|
|||
|
||||
define_sta_cmd_args "connect_pins" {net pins}
|
||||
|
||||
################################################################
|
||||
|
||||
define_sta_cmd_args "delete_instance" {cell_list}
|
||||
|
||||
################################################################
|
||||
|
||||
define_sta_cmd_args "delete_net" {net_list}
|
||||
|
||||
################################################################
|
||||
|
||||
define_sta_cmd_args "disconnect_pins" {net -all|pins}
|
||||
|
||||
################################################################
|
||||
|
||||
define_sta_cmd_args "make_instance" {inst_names lib_cell}
|
||||
|
||||
################################################################
|
||||
|
||||
define_sta_cmd_args "make_net" {}
|
||||
|
||||
################################################################
|
||||
|
||||
define_sta_cmd_args "replace_cell" {instances lib_cell}
|
||||
|
||||
################################################################
|
||||
|
|
@ -714,6 +704,22 @@ proc set_assigned_delay { args } {
|
|||
set_assigned_delay_cmd "set_assigned_delay" $args
|
||||
}
|
||||
|
||||
# compatibility
|
||||
define_sta_cmd_args "read_parasitics" \
|
||||
{[-min]\
|
||||
[-max]\
|
||||
[-elmore]\
|
||||
[-path path]\
|
||||
[-increment]\
|
||||
[-pin_cap_included]\
|
||||
[-keep_capacitive_coupling]\
|
||||
[-coupling_reduction_factor factor]\
|
||||
[-reduce_to pi_elmore|pi_pole_residue2]\
|
||||
[-delete_after_reduce]\
|
||||
[-quiet]\
|
||||
[-save]\
|
||||
filename}
|
||||
|
||||
################################################################a
|
||||
|
||||
define_sta_cmd_args "set_assigned_check" \
|
||||
|
|
@ -891,16 +897,8 @@ proc get_fanout { args } {
|
|||
|
||||
################################################################
|
||||
|
||||
define_sta_cmd_args "get_name_of_object" {object}
|
||||
|
||||
proc get_name_of_object { object } {
|
||||
if [is_object $object] {
|
||||
return [$object object_name]
|
||||
} elseif { [llength $object] > 1 } {
|
||||
# Should return list of names.
|
||||
sta_error "get_object_name cannot get the object name of multiple objects."
|
||||
}
|
||||
}
|
||||
define_sta_cmd_args "get_name" {objects}
|
||||
define_sta_cmd_args "get_full_name" {objects}
|
||||
|
||||
################################################################
|
||||
|
||||
|
|
@ -968,6 +966,30 @@ proc report_clock1 { clk } {
|
|||
|
||||
################################################################
|
||||
|
||||
define_sta_cmd_args "report_object_full_names" {[-verbose] objects}
|
||||
|
||||
proc report_object_full_names { args } {
|
||||
parse_key_args "report_object_names" args keys {} flags {-verbose}
|
||||
|
||||
set objects [lindex $args 0]
|
||||
if { [info exists flags(-verbose)] } {
|
||||
puts -nonewline "{"
|
||||
set first 1
|
||||
foreach obj [sort_by_full_name $objects] {
|
||||
if { !$first } {
|
||||
puts -nonewline ", "
|
||||
}
|
||||
puts -nonewline \"[get_object_type $obj]:[get_full_name $obj]\"
|
||||
set first 0
|
||||
}
|
||||
puts "}"
|
||||
} else {
|
||||
foreach obj [sort_by_full_name $objects] {
|
||||
puts [get_full_name $obj]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
define_sta_cmd_args "report_object_names" {[-verbose] objects}
|
||||
|
||||
proc report_object_names { args } {
|
||||
|
|
@ -977,17 +999,17 @@ proc report_object_names { args } {
|
|||
if { [info exists flags(-verbose)] } {
|
||||
puts -nonewline "{"
|
||||
set first 1
|
||||
foreach obj [lsort -command object_name_cmp $objects] {
|
||||
foreach obj [sort_name $objects] {
|
||||
if { !$first } {
|
||||
puts -nonewline ", "
|
||||
}
|
||||
puts -nonewline \"[get_object_type $obj]:[get_name_of_object $obj]\"
|
||||
puts -nonewline \"[get_object_type $obj]:[get_name $obj]\"
|
||||
set first 0
|
||||
}
|
||||
puts "}"
|
||||
} else {
|
||||
foreach obj [lsort -command object_name_cmp $objects] {
|
||||
puts [get_name_of_object $obj]
|
||||
foreach obj [sort_by_full_name $objects] {
|
||||
puts [get_name $obj]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
130
tcl/StaTcl.i
130
tcl/StaTcl.i
|
|
@ -458,7 +458,7 @@ tclError(Tcl_Interp *interp,
|
|||
const char *msg,
|
||||
const char *arg)
|
||||
{
|
||||
char *error = stringPrint(strlen(msg) + strlen(arg) + 1, msg, arg);
|
||||
char *error = stringPrint(msg, arg);
|
||||
Tcl_SetResult(interp, error, TCL_VOLATILE);
|
||||
stringDelete(error);
|
||||
}
|
||||
|
|
@ -1529,10 +1529,10 @@ using namespace sta;
|
|||
Tcl_SetResult(interp, const_cast<char*>(""), TCL_STATIC);
|
||||
break;
|
||||
case PropertyValue::Type::type_string:
|
||||
Tcl_SetResult(interp, const_cast<char*>(value.string()), TCL_VOLATILE);
|
||||
Tcl_SetResult(interp, const_cast<char*>(value.stringValue()), TCL_VOLATILE);
|
||||
break;
|
||||
case PropertyValue::Type::type_float: {
|
||||
char *float_string = stringPrint(10, "%.5f", value.floatValue());
|
||||
char *float_string = stringPrint("%.5f", value.floatValue());
|
||||
Tcl_SetResult(interp, float_string, TCL_VOLATILE);
|
||||
stringDelete(float_string);
|
||||
}
|
||||
|
|
@ -1566,6 +1566,24 @@ using namespace sta;
|
|||
Tcl_SetObjResult(interp, obj);
|
||||
}
|
||||
break;
|
||||
case PropertyValue::Type::type_liberty_cell: {
|
||||
Tcl_Obj *obj = SWIG_NewInstanceObj(value.libertyCell(),
|
||||
SWIGTYPE_p_LibertyCell, false);
|
||||
Tcl_SetObjResult(interp, obj);
|
||||
}
|
||||
break;
|
||||
case PropertyValue::Type::type_liberty_library: {
|
||||
Tcl_Obj *obj = SWIG_NewInstanceObj(value.libertyLibrary(),
|
||||
SWIGTYPE_p_LibertyLibrary, false);
|
||||
Tcl_SetObjResult(interp, obj);
|
||||
}
|
||||
break;
|
||||
case PropertyValue::Type::type_cell: {
|
||||
Tcl_Obj *obj = SWIG_NewInstanceObj(value.cell(),
|
||||
SWIGTYPE_p_Cell, false);
|
||||
Tcl_SetObjResult(interp, obj);
|
||||
}
|
||||
break;
|
||||
case PropertyValue::Type::type_clock: {
|
||||
Tcl_Obj *obj = SWIG_NewInstanceObj(value.clock(),
|
||||
SWIGTYPE_p_Clock, false);
|
||||
|
|
@ -1597,9 +1615,6 @@ using namespace sta;
|
|||
Tcl_SetObjResult(interp, list);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Tcl_SetResult(interp, const_cast<char*>(""), TCL_STATIC);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2267,6 +2282,24 @@ top_instance()
|
|||
return cmdLinkedNetwork()->topInstance();
|
||||
}
|
||||
|
||||
const char *
|
||||
liberty_port_direction(const LibertyPort *port)
|
||||
{
|
||||
return port->direction()->name();
|
||||
}
|
||||
|
||||
const char *
|
||||
port_direction(const Port *port)
|
||||
{
|
||||
return cmdLinkedNetwork()->direction(port)->name();
|
||||
}
|
||||
|
||||
const char *
|
||||
pin_direction(const Pin *pin)
|
||||
{
|
||||
return cmdLinkedNetwork()->direction(pin)->name();
|
||||
}
|
||||
|
||||
TmpPortSeq *
|
||||
find_ports_matching(const char *pattern,
|
||||
bool regexp,
|
||||
|
|
@ -2523,7 +2556,7 @@ filter_ports(const char *property,
|
|||
while (port_iter.hasNext()) {
|
||||
Port *port = port_iter.next();
|
||||
PropertyValue value(getProperty(port, property, sta));
|
||||
const char *prop = value.string();
|
||||
const char *prop = value.stringValue();
|
||||
if (prop &&
|
||||
((exact_match && stringEq(prop, pattern))
|
||||
|| (!exact_match && patternMatch(pattern, prop))))
|
||||
|
|
@ -2547,7 +2580,7 @@ filter_insts(const char *property,
|
|||
while (inst_iter.hasNext()) {
|
||||
Instance *inst = inst_iter.next();
|
||||
PropertyValue value(getProperty(inst, property, sta));
|
||||
const char *prop = value.string();
|
||||
const char *prop = value.stringValue();
|
||||
if (prop &&
|
||||
((exact_match && stringEq(prop, pattern))
|
||||
|| (!exact_match && patternMatch(pattern, prop))))
|
||||
|
|
@ -2570,7 +2603,7 @@ filter_pins(const char *property,
|
|||
while (pin_iter.hasNext()) {
|
||||
Pin *pin = pin_iter.next();
|
||||
PropertyValue value(getProperty(pin, property, sta));
|
||||
const char *prop = value.string();
|
||||
const char *prop = value.stringValue();
|
||||
if (prop &&
|
||||
((exact_match && stringEq(prop, pattern))
|
||||
|| (!exact_match && patternMatch(pattern, prop))))
|
||||
|
|
@ -2617,7 +2650,13 @@ PropertyValue
|
|||
liberty_cell_property(const LibertyCell *cell,
|
||||
const char *property)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
return getProperty(cell, property, Sta::sta());
|
||||
}
|
||||
|
||||
PropertyValue
|
||||
cell_property(const Cell *cell,
|
||||
const char *property)
|
||||
{
|
||||
return getProperty(cell, property, Sta::sta());
|
||||
}
|
||||
|
||||
|
|
@ -2625,7 +2664,6 @@ PropertyValue
|
|||
liberty_port_property(const LibertyPort *port,
|
||||
const char *property)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
return getProperty(port, property, Sta::sta());
|
||||
}
|
||||
|
||||
|
|
@ -2633,7 +2671,6 @@ PropertyValue
|
|||
library_property(const Library *lib,
|
||||
const char *property)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
return getProperty(lib, property, Sta::sta());
|
||||
}
|
||||
|
||||
|
|
@ -2676,6 +2713,14 @@ path_ref_property(PathRef *path,
|
|||
return getProperty(path, property, Sta::sta());
|
||||
}
|
||||
|
||||
PropertyValue
|
||||
timing_arc_set_property(TimingArcSet *arc_set,
|
||||
const char *property)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
return getProperty(arc_set, property, Sta::sta());
|
||||
}
|
||||
|
||||
LeafInstanceIterator *
|
||||
leaf_instance_iterator()
|
||||
{
|
||||
|
|
@ -2747,7 +2792,7 @@ filter_timing_arcs(const char *property,
|
|||
while (edge_iter.hasNext()) {
|
||||
Edge *edge = edge_iter.next();
|
||||
PropertyValue value(getProperty(edge, property, sta));
|
||||
const char *prop = value.string();
|
||||
const char *prop = value.stringValue();
|
||||
if (prop &&
|
||||
((exact_match && stringEq(prop, pattern))
|
||||
|| (!exact_match && patternMatch(pattern, prop))))
|
||||
|
|
@ -5093,8 +5138,6 @@ define_corners_cmd(StringSet *corner_names)
|
|||
////////////////////////////////////////////////////////////////
|
||||
|
||||
%extend Library {
|
||||
const char *name() { return cmdNetwork()->name(self); }
|
||||
const char *object_name() { return cmdNetwork()->name(self); }
|
||||
Cell *
|
||||
find_cell(const char *name)
|
||||
{
|
||||
|
|
@ -5116,10 +5159,6 @@ find_cells_matching(const char *pattern,
|
|||
|
||||
%extend LibertyLibrary {
|
||||
|
||||
const char *name() { return self->name(); }
|
||||
const char *filename() { return self->filename(); }
|
||||
const char *object_name() { return self->name(); }
|
||||
|
||||
LibertyCell *
|
||||
find_liberty_cell(const char *name)
|
||||
{
|
||||
|
|
@ -5177,9 +5216,6 @@ void finish() { delete self; }
|
|||
} // LibertyLibraryIterator methods
|
||||
|
||||
%extend Cell {
|
||||
const char *name() { return cmdNetwork()->name(self); }
|
||||
const char *filename() { return cmdNetwork()->filename(self); }
|
||||
const char *object_name() { return cmdNetwork()->name(self); }
|
||||
Library *library() { return cmdNetwork()->library(self); }
|
||||
LibertyCell *liberty_cell() { return cmdNetwork()->libertyCell(self); }
|
||||
bool is_leaf() { return cmdNetwork()->isLeaf(self); }
|
||||
|
|
@ -5206,9 +5242,6 @@ find_ports_matching(const char *pattern,
|
|||
} // Cell methods
|
||||
|
||||
%extend LibertyCell {
|
||||
const char *name() { return self->name(); }
|
||||
const char *filename() { return self->filename(); }
|
||||
const char *object_name() { return self->name(); }
|
||||
bool is_leaf() { return self->isLeaf(); }
|
||||
LibertyLibrary *liberty_library() { return self->libertyLibrary(); }
|
||||
Cell *cell() { return reinterpret_cast<Cell*>(self); }
|
||||
|
|
@ -5250,29 +5283,21 @@ void finish() { delete self; }
|
|||
} // LibertyCellPortIterator methods
|
||||
|
||||
%extend Port {
|
||||
const char *name() { return cmdNetwork()->name(self); }
|
||||
const char *bus_name() { return cmdNetwork()->busName(self); }
|
||||
Cell *cell() { return cmdNetwork()->cell(self); }
|
||||
LibertyPort *liberty_port() { return cmdNetwork()->libertyPort(self); }
|
||||
const char *object_name() { return cmdNetwork()->name(self); }
|
||||
bool is_bus() { return cmdNetwork()->isBus(self); }
|
||||
PortMemberIterator *
|
||||
member_iterator() { return cmdNetwork()->memberIterator(self); }
|
||||
const char *
|
||||
direction() { return cmdNetwork()->direction(self)->name(); }
|
||||
|
||||
} // Port methods
|
||||
|
||||
%extend LibertyPort {
|
||||
const char *name() { return self->name(); }
|
||||
const char *bus_name() { return self->busName(); }
|
||||
Cell *cell() { return self->cell(); }
|
||||
const char *object_name() { return self->name(); }
|
||||
bool is_bus() { return self->isBus(); }
|
||||
LibertyPortMemberIterator *
|
||||
member_iterator() { return new LibertyPortMemberIterator(self); }
|
||||
const char *
|
||||
direction() { return self->direction()->name(); }
|
||||
|
||||
const char *
|
||||
function()
|
||||
|
|
@ -5306,7 +5331,6 @@ capacitance(const TransRiseFall *tr,
|
|||
} // LibertyPort methods
|
||||
|
||||
%extend OperatingConditions {
|
||||
const char *name() { return self->name(); }
|
||||
float process() { return self->process(); }
|
||||
float voltage() { return self->voltage(); }
|
||||
float temperature() { return self->temperature(); }
|
||||
|
|
@ -5331,13 +5355,12 @@ TimingRole *role() { return self->role(); }
|
|||
const char *sdf_cond() { return self->sdfCond(); }
|
||||
|
||||
const char *
|
||||
object_name()
|
||||
full_name()
|
||||
{
|
||||
const char *from = self->from()->name();
|
||||
const char *to = self->to()->name();
|
||||
const char *cell_name = self->libertyCell()->name();
|
||||
return stringPrintTmp(strlen(from) + strlen(to) + strlen(cell_name) + 6,
|
||||
"%s %s -> %s",
|
||||
return stringPrintTmp("%s %s -> %s",
|
||||
cell_name,
|
||||
from,
|
||||
to);
|
||||
|
|
@ -5368,9 +5391,6 @@ void finish() { delete self; }
|
|||
}
|
||||
|
||||
%extend Instance {
|
||||
const char *name() { return cmdLinkedNetwork()->name(self); }
|
||||
const char *object_name() { return cmdLinkedNetwork()->pathName(self); }
|
||||
const char *path_name() { return cmdLinkedNetwork()->pathName(self); }
|
||||
Instance *parent() { return cmdLinkedNetwork()->parent(self); }
|
||||
Cell *cell() { return cmdLinkedNetwork()->cell(self); }
|
||||
LibertyCell *liberty_cell() { return cmdLinkedNetwork()->libertyCell(self); }
|
||||
|
|
@ -5413,16 +5433,12 @@ void finish() { delete self; }
|
|||
} // InstanceNetIterator methods
|
||||
|
||||
%extend Pin {
|
||||
const char *name() { return cmdLinkedNetwork()->name(self); }
|
||||
const char *object_name() { return cmdLinkedNetwork()->pathName(self); }
|
||||
const char *port_name() { return cmdLinkedNetwork()->portName(self); }
|
||||
const char *path_name() { return cmdLinkedNetwork()->pathName(self); }
|
||||
Instance *instance() { return cmdLinkedNetwork()->instance(self); }
|
||||
Net *net() { return cmdLinkedNetwork()->net(self); }
|
||||
Port *port() { return cmdLinkedNetwork()->port(self); }
|
||||
Term *term() { return cmdLinkedNetwork()->term(self); }
|
||||
LibertyPort *liberty_port() { return cmdLinkedNetwork()->libertyPort(self); }
|
||||
const char *direction() { return cmdLinkedNetwork()->direction(self)->name(); }
|
||||
bool is_driver() { return cmdLinkedNetwork()->isDriver(self); }
|
||||
bool is_load() { return cmdLinkedNetwork()->isLoad(self); }
|
||||
bool is_leaf() { return cmdLinkedNetwork()->isLeaf(self); }
|
||||
|
|
@ -5486,18 +5502,11 @@ void finish() { delete self; }
|
|||
} // PinConnectedPinIterator methods
|
||||
|
||||
%extend Term {
|
||||
const char *name() { return cmdLinkedNetwork()->name(self); }
|
||||
const char *object_name() { return cmdLinkedNetwork()->pathName(self); }
|
||||
const char *port_name() { return cmdLinkedNetwork()->portName(self); }
|
||||
const char *path_name() { return cmdLinkedNetwork()->pathName(self); }
|
||||
Net *net() { return cmdLinkedNetwork()->net(self); }
|
||||
Pin *pin() { return cmdLinkedNetwork()->pin(self); }
|
||||
} // Term methods
|
||||
|
||||
%extend Net {
|
||||
const char *name() { return cmdLinkedNetwork()->name(self); }
|
||||
const char *object_name() { return cmdLinkedNetwork()->pathName(self); }
|
||||
const char *path_name() { return cmdLinkedNetwork()->pathName(self); }
|
||||
Instance *instance() { return cmdLinkedNetwork()->instance(self); }
|
||||
Net *highest_connected_net()
|
||||
{ return cmdLinkedNetwork()->highestConnectedNet(self); }
|
||||
|
|
@ -5579,8 +5588,6 @@ void finish() { delete self; }
|
|||
} // NetConnectedPinIterator methods
|
||||
|
||||
%extend Clock {
|
||||
const char *name() { return self->name(); }
|
||||
const char *object_name() { return self->name(); }
|
||||
float period() { return self->period(); }
|
||||
FloatSeq *waveform() { return self->waveform(); }
|
||||
float time(TransRiseFall *tr) { return self->edge(tr)->time(); }
|
||||
|
|
@ -5601,8 +5608,6 @@ slew(const TransRiseFall *tr,
|
|||
}
|
||||
|
||||
%extend ClockEdge {
|
||||
const char *name() { return self->name(); }
|
||||
const char *object_name() { return self->name(); }
|
||||
Clock *clock() { return self->clock(); }
|
||||
TransRiseFall *transition() { return self->transition(); }
|
||||
float time() { return self->time(); }
|
||||
|
|
@ -5909,18 +5914,6 @@ mode_value()
|
|||
return self->timingArcSet()->modeValue();
|
||||
}
|
||||
|
||||
const char *
|
||||
object_name()
|
||||
{
|
||||
Sta *sta = Sta::sta();
|
||||
const Network *network = sta->cmdNetwork();
|
||||
const Graph *graph = sta->graph();
|
||||
const char *from = self->from(graph)->name(network);
|
||||
const char *to = self->to(graph)->name(network);
|
||||
return stringPrintTmp(strlen(from) + strlen(to) + 5,
|
||||
"%s -> %s", from, to);
|
||||
}
|
||||
|
||||
const char *
|
||||
latch_d_to_q_en()
|
||||
{
|
||||
|
|
@ -5937,8 +5930,7 @@ latch_d_to_q_en()
|
|||
TransRiseFall *enable_tr;
|
||||
lib_cell->latchEnable(d_q_set, enable_port, enable_func, enable_tr);
|
||||
const char *en_name = enable_port->name();
|
||||
return stringPrintTmp(strlen(en_name) + 3,
|
||||
"%s %s", en_name, enable_tr->asString());
|
||||
return stringPrintTmp("%s %s", en_name, enable_tr->asString());
|
||||
|
||||
}
|
||||
return "";
|
||||
|
|
|
|||
|
|
@ -46,9 +46,7 @@ InternalError::InternalError(const char *filename,
|
|||
const char *
|
||||
InternalError::what() const throw()
|
||||
{
|
||||
return stringPrintTmp(strlen("Internal error in : .")
|
||||
+ strlen(filename_) + strlen(msg_) + 5,
|
||||
"Internal error in %s:%d %s.",
|
||||
return stringPrintTmp("Internal error in %s:%d %s.",
|
||||
filename_, line_, msg_);
|
||||
}
|
||||
|
||||
|
|
@ -60,9 +58,7 @@ FileNotReadable::FileNotReadable(const char *filename) :
|
|||
const char *
|
||||
FileNotReadable::what() const throw()
|
||||
{
|
||||
return stringPrintTmp(strlen("Error: cannot read file .")
|
||||
+ strlen(filename_) + 1,
|
||||
"Error: cannot read file %s.", filename_);
|
||||
return stringPrintTmp("Error: cannot read file %s.", filename_);
|
||||
}
|
||||
|
||||
FileNotWritable::FileNotWritable(const char *filename) :
|
||||
|
|
@ -73,10 +69,7 @@ FileNotWritable::FileNotWritable(const char *filename) :
|
|||
const char *
|
||||
FileNotWritable::what() const throw()
|
||||
{
|
||||
return stringPrintTmp(strlen("Error: cannot write file .")
|
||||
+ strlen(filename_) + 1,
|
||||
"Error: cannot write file %s.",
|
||||
filename_);
|
||||
return stringPrintTmp("Error: cannot write file %s.", filename_);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -149,11 +149,10 @@ systemRunTime()
|
|||
size_t
|
||||
memoryUsage()
|
||||
{
|
||||
char *proc_filename = stringPrintTmp(strlen("/proc//status")+10,
|
||||
"/proc/%d/status",
|
||||
getpid());
|
||||
string proc_filename;
|
||||
stringPrint(proc_filename, "/proc/%d/status", getpid());
|
||||
size_t memory = 0;
|
||||
FILE *status = fopen(proc_filename, "r");
|
||||
FILE *status = fopen(proc_filename.c_str(), "r");
|
||||
if (status) {
|
||||
const size_t line_length = 128;
|
||||
char line[line_length];
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ RegexpCompileError::RegexpCompileError(const char *pattern) :
|
|||
StaException()
|
||||
{
|
||||
const char *msg = "Error: TCL failed to compile regular expression '%s'.";
|
||||
error_ = stringPrintTmp(strlen(msg) + strlen(pattern) + 1, msg, pattern);
|
||||
error_ = stringPrintTmp(msg, pattern);
|
||||
}
|
||||
|
||||
const char *
|
||||
|
|
|
|||
|
|
@ -23,6 +23,17 @@
|
|||
|
||||
namespace sta {
|
||||
|
||||
static void
|
||||
stringPrintTmp(const char *fmt,
|
||||
va_list args,
|
||||
// Return values.
|
||||
char *&str,
|
||||
size_t &length);
|
||||
static void
|
||||
getTmpString(// Return values.
|
||||
char *&str,
|
||||
size_t &length);
|
||||
|
||||
char *
|
||||
stringCopy(const char *str)
|
||||
{
|
||||
|
|
@ -50,97 +61,119 @@ isDigits(const char *str)
|
|||
char *
|
||||
integerString(int number)
|
||||
{
|
||||
// Leave room for sign and '\0'.
|
||||
return stringPrint(INT_DIGITS + 2, "%d", number);
|
||||
return stringPrint("%d", number);
|
||||
}
|
||||
|
||||
char *
|
||||
stringPrint(int length_estimate,
|
||||
// print for c++ strings.
|
||||
void
|
||||
stringPrint(string &str,
|
||||
const char *fmt,
|
||||
...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
char *result = stringPrintArgs(length_estimate, fmt, args);
|
||||
char *tmp;
|
||||
size_t tmp_length;
|
||||
stringPrintTmp(fmt, args, tmp, tmp_length);
|
||||
va_end(args);
|
||||
str = tmp;
|
||||
}
|
||||
|
||||
string
|
||||
stdstrPrint(const char *fmt,
|
||||
...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
char *tmp;
|
||||
size_t tmp_length;
|
||||
stringPrintTmp(fmt, args, tmp, tmp_length);
|
||||
va_end(args);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
char *
|
||||
stringPrint(const char *fmt,
|
||||
...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
char *result = stringPrintArgs(fmt, args);
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
char *
|
||||
stringPrintArgs(int length_estimate,
|
||||
const char *fmt,
|
||||
stringPrintArgs(const char *fmt,
|
||||
va_list args)
|
||||
{
|
||||
va_list args_copy;
|
||||
va_copy(args_copy, args);
|
||||
char *result = new char[length_estimate];
|
||||
int length = vsnprint(result, length_estimate, fmt, args);
|
||||
if (length >= length_estimate) {
|
||||
stringDelete(result);
|
||||
result = new char[length + 1];
|
||||
vsnprint(result, length + 1, fmt, args_copy);
|
||||
}
|
||||
va_end(args_copy);
|
||||
char *tmp;
|
||||
size_t tmp_length;
|
||||
stringPrintTmp(fmt, args, tmp, tmp_length);
|
||||
char *result = new char[tmp_length + 1];
|
||||
strcpy(result, tmp);
|
||||
return result;
|
||||
}
|
||||
|
||||
char *
|
||||
stringPrintTmp(int length_estimate,
|
||||
const char *fmt,
|
||||
stringPrintTmp(const char *fmt,
|
||||
...)
|
||||
{
|
||||
char *result = makeTmpString(length_estimate);
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
int length = vsnprint(result, length_estimate, fmt, args);
|
||||
char *tmp;
|
||||
size_t tmp_length;
|
||||
stringPrintTmp(fmt, args, tmp, tmp_length);
|
||||
va_end(args);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static void
|
||||
stringPrintTmp(const char *fmt,
|
||||
va_list args,
|
||||
// Return values.
|
||||
char *&tmp,
|
||||
// strlen(tmp), not including terminating '\0'.
|
||||
size_t &tmp_length)
|
||||
{
|
||||
size_t tmp_length1;
|
||||
getTmpString(tmp, tmp_length1);
|
||||
|
||||
va_list args_copy;
|
||||
va_copy(args_copy, args);
|
||||
// Returned length does NOT include trailing '\0'.
|
||||
if (length >= length_estimate) {
|
||||
result = makeTmpString(length + 1);
|
||||
va_start(args, fmt);
|
||||
vsnprint(result, length + 1, fmt, args);
|
||||
va_end(args);
|
||||
tmp_length = vsnprint(tmp, tmp_length1, fmt, args_copy);
|
||||
va_end(args_copy);
|
||||
|
||||
if (tmp_length >= tmp_length1) {
|
||||
tmp_length1 = tmp_length + 1;
|
||||
tmp = makeTmpString(tmp_length1);
|
||||
va_copy(args_copy, args);
|
||||
tmp_length = vsnprint(tmp, tmp_length1, fmt, args_copy);
|
||||
va_end(args_copy);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
static int tmp_string_count_ = 100;
|
||||
static size_t tmp_string_length_ = 100;
|
||||
static int tmp_string_next_ = 0;
|
||||
static char **tmp_strings_ = NULL;
|
||||
static size_t *tmp_string_lengths_ = NULL;
|
||||
static int tmp_string_next_;
|
||||
static Mutex string_lock_;
|
||||
|
||||
char *
|
||||
makeTmpString(size_t length)
|
||||
void
|
||||
initTmpStrings()
|
||||
{
|
||||
string_lock_.lock();
|
||||
if (tmp_strings_ == NULL) {
|
||||
tmp_strings_ = new char*[tmp_string_count_];
|
||||
tmp_string_lengths_ = new size_t[tmp_string_count_];
|
||||
for (int i = 0; i < tmp_string_count_; i++) {
|
||||
tmp_strings_[i] = new char[tmp_string_length_];
|
||||
tmp_string_lengths_[i] = tmp_string_length_;
|
||||
}
|
||||
size_t initial_length = 100;
|
||||
|
||||
tmp_strings_ = new char*[tmp_string_count_];
|
||||
tmp_string_lengths_ = new size_t[tmp_string_count_];
|
||||
for (int i = 0; i < tmp_string_count_; i++) {
|
||||
tmp_strings_[i] = new char[initial_length];
|
||||
tmp_string_lengths_[i] = initial_length;
|
||||
}
|
||||
if (tmp_string_next_ == tmp_string_count_)
|
||||
tmp_string_next_ = 0;
|
||||
char *tmp_str = tmp_strings_[tmp_string_next_];
|
||||
size_t tmp_length = tmp_string_lengths_[tmp_string_next_];
|
||||
if (tmp_length < length) {
|
||||
// String isn't long enough. Make a new one.
|
||||
stringDelete(tmp_str);
|
||||
tmp_str = new char[length];
|
||||
tmp_strings_[tmp_string_next_] = tmp_str;
|
||||
tmp_string_lengths_[tmp_string_next_] = length;
|
||||
}
|
||||
tmp_string_next_++;
|
||||
string_lock_.unlock();
|
||||
return tmp_str;
|
||||
tmp_string_next_ = 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -157,6 +190,40 @@ deleteTmpStrings()
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
getTmpString(// Return values.
|
||||
char *&str,
|
||||
size_t &length)
|
||||
{
|
||||
string_lock_.lock();
|
||||
if (tmp_string_next_ == tmp_string_count_)
|
||||
tmp_string_next_ = 0;
|
||||
str = tmp_strings_[tmp_string_next_];
|
||||
length = tmp_string_lengths_[tmp_string_next_];
|
||||
tmp_string_next_++;
|
||||
string_lock_.unlock();
|
||||
}
|
||||
|
||||
char *
|
||||
makeTmpString(size_t length)
|
||||
{
|
||||
string_lock_.lock();
|
||||
if (tmp_string_next_ == tmp_string_count_)
|
||||
tmp_string_next_ = 0;
|
||||
char *tmp_str = tmp_strings_[tmp_string_next_];
|
||||
size_t tmp_length = tmp_string_lengths_[tmp_string_next_];
|
||||
if (tmp_length < length) {
|
||||
// String isn't long enough. Make a new one.
|
||||
stringDelete(tmp_str);
|
||||
tmp_str = new char[length];
|
||||
tmp_strings_[tmp_string_next_] = tmp_str;
|
||||
tmp_string_lengths_[tmp_string_next_] = length;
|
||||
}
|
||||
tmp_string_next_++;
|
||||
string_lock_.unlock();
|
||||
return tmp_str;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -132,21 +132,25 @@ bool
|
|||
isDigits(const char *str);
|
||||
|
||||
// Print to a new string.
|
||||
// length_estimate should include room for the terminating '\0'.
|
||||
// Caller owns returned string.
|
||||
char *
|
||||
stringPrint(int length_estimate,
|
||||
const char *fmt,
|
||||
...);
|
||||
stringPrint(const char *fmt,
|
||||
...) __attribute__((format (printf, 1, 2)));
|
||||
string
|
||||
stdstrPrint(const char *fmt,
|
||||
...) __attribute__((format (printf, 1, 2)));
|
||||
char *
|
||||
stringPrintArgs(int length_estimate,
|
||||
const char *fmt,
|
||||
stringPrintArgs(const char *fmt,
|
||||
va_list args);
|
||||
void
|
||||
stringPrint(string &str,
|
||||
const char *fmt,
|
||||
...) __attribute__((format (printf, 2, 3)));
|
||||
|
||||
// Print to a temporary string.
|
||||
// length_estimate should include room for the terminating '\0'.
|
||||
char *
|
||||
stringPrintTmp(int length_estimate,
|
||||
const char *fmt,
|
||||
...);
|
||||
stringPrintTmp(const char *fmt,
|
||||
...) __attribute__((format (printf, 1, 2)));
|
||||
// Caller owns returned string.
|
||||
char *
|
||||
integerString(int number);
|
||||
|
|
@ -154,6 +158,8 @@ integerString(int number);
|
|||
char *
|
||||
makeTmpString(size_t length);
|
||||
void
|
||||
initTmpStrings();
|
||||
void
|
||||
deleteTmpStrings();
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -32,9 +32,7 @@ const char *
|
|||
ThreadException::what() const throw()
|
||||
{
|
||||
const char *msg = strerror(error_);
|
||||
return stringPrintTmp(strlen(filename_) + strlen(msg) + 30,
|
||||
"Thread error in %s:%d %s.",
|
||||
filename_, line_, msg);
|
||||
return stringPrintTmp("Thread error in %s:%d %s.", filename_, line_, msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@ namespace sta {
|
|||
class TokenParser
|
||||
{
|
||||
public:
|
||||
TokenParser(const char *str, const char *delimiters);
|
||||
TokenParser(const char *str,
|
||||
const char *delimiters);
|
||||
bool hasNext();
|
||||
char *next();
|
||||
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ VerilogReader::VerilogReader(Report *report,
|
|||
{
|
||||
network->setLinkFunc(linkVerilogNetwork);
|
||||
VerilogConstant10 constant10_max = 0;
|
||||
constant10_max_ = stringPrint(21, "%llu", ~constant10_max);
|
||||
constant10_max_ = stringPrint("%llu", ~constant10_max);
|
||||
constant10_max_length_ = strlen(constant10_max_);
|
||||
}
|
||||
|
||||
|
|
@ -851,8 +851,7 @@ VerilogModule::checkInstanceName(VerilogInst *inst,
|
|||
do {
|
||||
if (replacement_name)
|
||||
stringDelete(replacement_name);
|
||||
replacement_name = stringPrint(strlen(inst_name) + 4,
|
||||
"%s_%d", inst_name, i);
|
||||
replacement_name = stringPrint("%s_%d", inst_name, i);
|
||||
} while (inst_names.findKey(replacement_name));
|
||||
reader->warn(filename_, inst->line(),
|
||||
"instance name %s duplicated - renamed to %s.\n",
|
||||
|
|
@ -1161,14 +1160,14 @@ static const char *
|
|||
verilogBusBitNameTmp(const char *bus_name,
|
||||
int index)
|
||||
{
|
||||
return stringPrintTmp(strlen(bus_name) + 8, "%s[%d]", bus_name, index);
|
||||
return stringPrintTmp("%s[%d]", bus_name, index);
|
||||
}
|
||||
|
||||
static const char *
|
||||
verilogBusBitName(const char *bus_name,
|
||||
int index)
|
||||
{
|
||||
return stringPrint(strlen(bus_name) + 8, "%s[%d]", bus_name, index);
|
||||
return stringPrint("%s[%d]", bus_name, index);
|
||||
}
|
||||
|
||||
class VerilogConstantNetNameIterator : public VerilogNetNameIterator
|
||||
|
|
@ -2041,10 +2040,11 @@ VerilogReader::makeBlackBoxOrderedPorts(Cell *cell,
|
|||
while (pin_iter.hasNext()) {
|
||||
VerilogNet *net = pin_iter.next();
|
||||
size_t size = net->size(parent_module);
|
||||
char *port_name = stringPrintTmp(8, "p_%lu", port_index);
|
||||
char *port_name = stringPrint("p_%d", port_index);
|
||||
Port *port = (size == 1)
|
||||
? network_->makePort(cell, port_name)
|
||||
: network_->makeBusPort(cell, port_name, size - 1, 0);
|
||||
stringDelete(port_name);
|
||||
network_->setDirection(port, PortDirection::bidirect());
|
||||
port_index++;
|
||||
}
|
||||
|
|
@ -2161,7 +2161,7 @@ VerilogReader::linkWarn(const char *filename,
|
|||
{
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
char *msg_str = stringPrintArgs(strlen(msg) + 128, msg, args);
|
||||
char *msg_str = stringPrintArgs(msg, args);
|
||||
VerilogError *error = new VerilogError(filename, line, msg_str, true);
|
||||
link_errors_.push_back(error);
|
||||
va_end(args);
|
||||
|
|
@ -2174,7 +2174,7 @@ VerilogReader::linkError(const char *filename,
|
|||
{
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
char *msg_str = stringPrintArgs(strlen(msg) + 128, msg, args);
|
||||
char *msg_str = stringPrintArgs(msg, args);
|
||||
VerilogError *error = new VerilogError(filename, line, msg_str, false);
|
||||
link_errors_.push_back(error);
|
||||
va_end(args);
|
||||
|
|
|
|||
Loading…
Reference in New Issue