From 316742202f70505dd07c340365ed9af0dec4be3a Mon Sep 17 00:00:00 2001 From: James Cherry Date: Wed, 16 Jan 2019 15:37:31 -0800 Subject: [PATCH] sync --- CMakeLists.txt | 42 +--- INSTALL | 16 ++ app/StaMain.cc | 8 +- configure.ac | 2 +- dcalc/DelayCalc.tcl | 8 +- doc/OpenSTA.odt | Bin 74164 -> 74361 bytes doc/OpenSTA.pdf | Bin 153001 -> 152292 bytes graph/DelayNormal2.cc | 6 +- graph/Graph.cc | 3 +- liberty/Liberty.hh | 2 +- liberty/LibertyBuilder.cc | 2 +- liberty/LibertyParse.yy | 2 +- liberty/LibertyReader.cc | 33 +-- liberty/TableModel.cc | 22 +- liberty/Units.cc | 4 +- network/ConcreteLibrary.cc | 73 ++++-- network/ConcreteLibrary.hh | 52 ++-- network/ConcreteNetwork.cc | 26 +- network/Network.cc | 10 +- parasitics/ConcreteParasitics.cc | 3 +- parasitics/Makefile.am | 25 +- parasitics/Parasitics.cc | 9 +- parasitics/Parasitics.i | 32 +-- parasitics/Parasitics.tcl | 11 +- parasitics/SpefLex.ll | 1 + parasitics/SpefParse.yy | 8 +- parasitics/SpefReader.cc | 159 ++++++++++-- parasitics/SpefReader.hh | 2 - parasitics/SpefReaderPvt.hh | 63 ++++- sdc/Clock.cc | 3 +- sdc/CycleAccting.cc | 57 +++-- sdc/CycleAccting.hh | 11 +- sdc/ExceptionPath.cc | 8 +- sdc/Sdc.cc | 27 +- sdc/WriteSdc.cc | 6 +- sdf/ReportAnnotation.cc | 8 +- sdf/SdfReader.cc | 24 +- search/ClkInfo.cc | 2 +- search/Crpr.cc | 15 +- search/Path.cc | 4 +- search/PathVertex.cc | 8 +- search/Property.cc | 417 +++++++++++++++++++++---------- search/Property.hh | 28 ++- search/ReportPath.cc | 384 ++++++++++------------------ search/ReportPath.hh | 25 +- search/Sta.cc | 37 +-- search/Sta.hh | 22 +- search/Tag.cc | 4 +- search/VisitPathEnds.cc | 3 +- search/WritePathSpice.cc | 155 +++++------- tcl/Cmds.tcl | 88 +++++-- tcl/Graph.tcl | 30 +-- tcl/Network.tcl | 82 +++--- tcl/NetworkEdit.tcl | 2 +- tcl/Power.tcl | 8 +- tcl/Sdc.tcl | 40 +-- tcl/Search.tcl | 4 +- tcl/Sta.tcl | 76 ++++-- tcl/StaTcl.i | 130 +++++----- util/Error.cc | 13 +- util/Machine.cc | 7 +- util/PatternMatch.cc | 2 +- util/StringUtil.cc | 175 +++++++++---- util/StringUtil.hh | 26 +- util/ThreadException.cc | 4 +- util/TokenParser.hh | 3 +- verilog/VerilogReader.cc | 16 +- 67 files changed, 1449 insertions(+), 1129 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 269a14fa..202733b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 . +# 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 diff --git a/INSTALL b/INSTALL index 24ee7769..c293f50e 100644 --- a/INSTALL +++ b/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= 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= 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 ----------------------- diff --git a/app/StaMain.cc b/app/StaMain.cc index 17c738c7..8b38b4f3 100644 --- a/app/StaMain.cc +++ b/app/StaMain.cc @@ -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 diff --git a/configure.ac b/configure.ac index f11b57c3..c68f8ba4 100644 --- a/configure.ac +++ b/configure.ac @@ -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) diff --git a/dcalc/DelayCalc.tcl b/dcalc/DelayCalc.tcl index ea8064ca..beaca5bc 100644 --- a/dcalc/DelayCalc.tcl +++ b/dcalc/DelayCalc.tcl @@ -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] diff --git a/doc/OpenSTA.odt b/doc/OpenSTA.odt index 3ab8edb46bbed5daf3a883f9677714895f5a2f4e..fa4e5b1911bc8772e6f6579fffd33f6fa53089d7 100644 GIT binary patch delta 44262 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 z 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 Tz?n)Y0s@B+v9e05$PoQMa#B5h delta 50625 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æzF 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 V9gIx~!My_9#R)k%Wt3zI{~vQiizNU6 diff --git a/graph/DelayNormal2.cc b/graph/DelayNormal2.cc index ac40a05c..4b2755c6 100644 --- a/graph/DelayNormal2.cc +++ b/graph/DelayNormal2.cc @@ -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)); diff --git a/graph/Graph.cc b/graph/Graph.cc index b6222c9d..f83075d5 100644 --- a/graph/Graph.cc +++ b/graph/Graph.cc @@ -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"); } diff --git a/liberty/Liberty.hh b/liberty/Liberty.hh index baaf07ae..16f24c19 100644 --- a/liberty/Liberty.hh +++ b/liberty/Liberty.hh @@ -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, diff --git a/liberty/LibertyBuilder.cc b/liberty/LibertyBuilder.cc index 31dd2e0e..b6f145e6 100644 --- a/liberty/LibertyBuilder.cc +++ b/liberty/LibertyBuilder.cc @@ -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, diff --git a/liberty/LibertyParse.yy b/liberty/LibertyParse.yy index 109035cd..8047d84b 100644 --- a/liberty/LibertyParse.yy +++ b/liberty/LibertyParse.yy @@ -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: diff --git a/liberty/LibertyReader.cc b/liberty/LibertyReader.cc index 13722a79..f4057f7b 100644 --- a/liberty/LibertyReader.cc +++ b/liberty/LibertyReader.cc @@ -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_, diff --git a/liberty/TableModel.cc b/liberty/TableModel.cc index 3292c1eb..64a8e572 100644 --- a/liberty/TableModel.cc +++ b/liberty/TableModel.cc @@ -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); } } diff --git a/liberty/Units.cc b/liberty/Units.cc index 9eb7ede5..ae253926 100644 --- a/liberty/Units.cc +++ b/liberty/Units.cc @@ -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::digits10 + 10; - return stringPrintTmp(result_len, "%.*f%s", digits, scaled_value, suffix_); + return stringPrintTmp("%.*f%s", digits, scaled_value, suffix_); } } diff --git a/network/ConcreteLibrary.cc b/network/ConcreteLibrary.cc index 0326090c..708904c7 100644 --- a/network/ConcreteLibrary.cc +++ b/network/ConcreteLibrary.cc @@ -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_, diff --git a/network/ConcreteLibrary.hh b/network/ConcreteLibrary.hh index 06903f45..d929f702 100644 --- a/network/ConcreteLibrary.hh +++ b/network/ConcreteLibrary.hh @@ -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_; diff --git a/network/ConcreteNetwork.cc b/network/ConcreteNetwork.cc index bdacfad8..e84d4736 100644 --- a/network/ConcreteNetwork.cc +++ b/network/ConcreteNetwork.cc @@ -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(cpin); } @@ -1288,13 +1296,15 @@ ConcreteNetwork::disconnectPin(Pin *pin) ConcretePin *cpin = reinterpret_cast(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(); diff --git a/network/Network.cc b/network/Network.cc index daa964e7..7961e279 100644 --- a/network/Network.cc +++ b/network/Network.cc @@ -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; diff --git a/parasitics/ConcreteParasitics.cc b/parasitics/ConcreteParasitics.cc index 6db058ba..8c800a43 100644 --- a/parasitics/ConcreteParasitics.cc +++ b/parasitics/ConcreteParasitics.cc @@ -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_); } //////////////////////////////////////////////////////////////// diff --git a/parasitics/Makefile.am b/parasitics/Makefile.am index c6903c8b..9367e804 100644 --- a/parasitics/Makefile.am +++ b/parasitics/Makefile.am @@ -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) diff --git a/parasitics/Parasitics.cc b/parasitics/Parasitics.cc index a08d9f3c..54401d2c 100644 --- a/parasitics/Parasitics.cc +++ b/parasitics/Parasitics.cc @@ -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 diff --git a/parasitics/Parasitics.i b/parasitics/Parasitics.i index 3582afe4..9ecefbc9 100644 --- a/parasitics/Parasitics.i +++ b/parasitics/Parasitics.i @@ -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 * diff --git a/parasitics/Parasitics.tcl b/parasitics/Parasitics.tcl index f3c3d0fc..5f3e6309 100644 --- a/parasitics/Parasitics.tcl +++ b/parasitics/Parasitics.tcl @@ -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] diff --git a/parasitics/SpefLex.ll b/parasitics/SpefLex.ll index bca213fb..8daebbed 100644 --- a/parasitics/SpefLex.ll +++ b/parasitics/SpefLex.ll @@ -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; } diff --git a/parasitics/SpefParse.yy b/parasitics/SpefParse.yy index b05aa15a..100796a1 100755 --- a/parasitics/SpefParse.yy +++ b/parasitics/SpefParse.yy @@ -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); } diff --git a/parasitics/SpefReader.cc b/parasitics/SpefReader.cc index 337b80d5..1c65a667 100644 --- a/parasitics/SpefReader.cc +++ b/parasitics/SpefReader.cc @@ -17,14 +17,18 @@ #include #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(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); diff --git a/parasitics/SpefReader.hh b/parasitics/SpefReader.hh index 6639bdbf..d208cfdb 100644 --- a/parasitics/SpefReader.hh +++ b/parasitics/SpefReader.hh @@ -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, diff --git a/parasitics/SpefReaderPvt.hh b/parasitics/SpefReaderPvt.hh index a450b704..1ec304ed 100644 --- a/parasitics/SpefReaderPvt.hh +++ b/parasitics/SpefReaderPvt.hh @@ -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 > 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 diff --git a/sdc/Clock.cc b/sdc/Clock.cc index b43d753c..72564079 100644 --- a/sdc/Clock.cc +++ b/sdc/Clock.cc @@ -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()) { diff --git a/sdc/CycleAccting.cc b/sdc/CycleAccting.cc index a48952fa..ae3d037f 100644 --- a/sdc/CycleAccting.cc +++ b/sdc/CycleAccting.cc @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +#include // ceil +#include // 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(); diff --git a/sdc/CycleAccting.hh b/sdc/CycleAccting.hh index 24995ee1..5a970929 100644 --- a/sdc/CycleAccting.hh +++ b/sdc/CycleAccting.hh @@ -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 diff --git a/sdc/ExceptionPath.cc b/sdc/ExceptionPath.cc index 3087dddd..83456c55 100644 --- a/sdc/ExceptionPath.cc +++ b/sdc/ExceptionPath.cc @@ -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); diff --git a/sdc/Sdc.cc b/sdc/Sdc.cc index 900c86d5..54fc0d7c 100644 --- a/sdc/Sdc.cc +++ b/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; } } diff --git a/sdc/WriteSdc.cc b/sdc/WriteSdc.cc index dd2a0277..c42a6ecb 100644 --- a/sdc/WriteSdc.cc +++ b/sdc/WriteSdc.cc @@ -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"); } diff --git a/sdf/ReportAnnotation.cc b/sdf/ReportAnnotation.cc index d995950b..d80b8542 100644 --- a/sdf/ReportAnnotation.cc +++ b/sdf/ReportAnnotation.cc @@ -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); } } diff --git a/sdf/SdfReader.cc b/sdf/SdfReader.cc index 2487f8a0..7f30dc31 100644 --- a/sdf/SdfReader.cc +++ b/sdf/SdfReader.cc @@ -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; } diff --git a/search/ClkInfo.cc b/search/ClkInfo.cc index 9fbd5da5..a6b7ba81 100644 --- a/search/ClkInfo.cc +++ b/search/ClkInfo.cc @@ -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_) diff --git a/search/Crpr.cc b/search/Crpr.cc index 03fbfd5f..9e694879 100644 --- a/search/Crpr.cc +++ b/search/Crpr.cc @@ -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 diff --git a/search/Path.cc b/search/Path.cc index 44911afc..0b569a10 100644 --- a/search/Path.cc +++ b/search/Path.cc @@ -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); } diff --git a/search/PathVertex.cc b/search/PathVertex.cc index e9c28440..dc76bbe4 100644 --- a/search/PathVertex.cc +++ b/search/PathVertex.cc @@ -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; + } } } diff --git a/search/Property.cc b/search/Property.cc index 9b4c8207..f7d69fd9 100644 --- a/search/Property.cc +++ b/search/Property.cc @@ -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 diff --git a/search/Property.hh b/search/Property.hh index 214f27d0..cde42d79 100644 --- a/search/Property.hh +++ b/search/Property.hh @@ -17,22 +17,32 @@ #ifndef STA_PROPERTY_H #define STA_PROPERTY_H +#include +#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 diff --git a/search/ReportPath.cc b/search/ReportPath.cc index a63b8f84..2b4f4c1c 100644 --- a/search/ReportPath.cc +++ b/search/ReportPath.cc @@ -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(fanout)); - result += field; - } + else + result += stdstrPrint("%*d", + field_fanout_->width(), + static_cast(fanout)); } else if (field == field_capacitance_) reportField(cap, field, result); diff --git a/search/ReportPath.hh b/search/ReportPath.hh index d9de9820..e0ea40b5 100644 --- a/search/ReportPath.hh +++ b/search/ReportPath.hh @@ -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); diff --git a/search/Sta.cc b/search/Sta.cc index a02a6aa0..69a8924a 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -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; } diff --git a/search/Sta.hh b/search/Sta.hh index 8d6e8f18..a7f143c2 100644 --- a/search/Sta.hh +++ b/search/Sta.hh @@ -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, diff --git a/search/Tag.cc b/search/Tag.cc index 22bec177..14226340 100644 --- a/search/Tag.cc +++ b/search/Tag.cc @@ -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_); diff --git a/search/VisitPathEnds.cc b/search/VisitPathEnds.cc index a1603006..6a3f4f15 100644 --- a/search/VisitPathEnds.cc +++ b/search/VisitPathEnds.cc @@ -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() diff --git a/search/WritePathSpice.cc b/search/WritePathSpice.cc index ef7be1d0..83a0bc87 100644 --- a/search/WritePathSpice.cc +++ b/search/WritePathSpice.cc @@ -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 diff --git a/tcl/Cmds.tcl b/tcl/Cmds.tcl index 5c412bc7..1a974dc3 100644 --- a/tcl/Cmds.tcl +++ b/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 +} } ################################################################ diff --git a/tcl/Graph.tcl b/tcl/Graph.tcl index 8b51d372..8aa15583 100644 --- a/tcl/Graph.tcl +++ b/tcl/Graph.tcl @@ -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 { diff --git a/tcl/Network.tcl b/tcl/Network.tcl index 446cb8bb..750b4ff5 100644 --- a/tcl/Network.tcl +++ b/tcl/Network.tcl @@ -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] } } diff --git a/tcl/NetworkEdit.tcl b/tcl/NetworkEdit.tcl index 9d1f5eb3..5d9ec0ab 100644 --- a/tcl/NetworkEdit.tcl +++ b/tcl/NetworkEdit.tcl @@ -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 { diff --git a/tcl/Power.tcl b/tcl/Power.tcl index 1f9cb3a1..df04e94c 100644 --- a/tcl/Power.tcl +++ b/tcl/Power.tcl @@ -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 diff --git a/tcl/Sdc.tcl b/tcl/Sdc.tcl index 2209c489..98960e88 100644 --- a/tcl/Sdc.tcl +++ b/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 } diff --git a/tcl/Search.tcl b/tcl/Search.tcl index 236bd0cf..001c3074 100644 --- a/tcl/Search.tcl +++ b/tcl/Search.tcl @@ -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 "" } diff --git a/tcl/Sta.tcl b/tcl/Sta.tcl index 1909f781..a9d7d671 100644 --- a/tcl/Sta.tcl +++ b/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] } } } diff --git a/tcl/StaTcl.i b/tcl/StaTcl.i index 945064ea..9385b6ae 100644 --- a/tcl/StaTcl.i +++ b/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(""), TCL_STATIC); break; case PropertyValue::Type::type_string: - Tcl_SetResult(interp, const_cast(value.string()), TCL_VOLATILE); + Tcl_SetResult(interp, const_cast(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(""), 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(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 ""; diff --git a/util/Error.cc b/util/Error.cc index 8c5651e2..2ba320a3 100644 --- a/util/Error.cc +++ b/util/Error.cc @@ -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 diff --git a/util/Machine.cc b/util/Machine.cc index da81658b..f8391f9d 100644 --- a/util/Machine.cc +++ b/util/Machine.cc @@ -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]; diff --git a/util/PatternMatch.cc b/util/PatternMatch.cc index 278a929d..f3176065 100644 --- a/util/PatternMatch.cc +++ b/util/PatternMatch.cc @@ -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 * diff --git a/util/StringUtil.cc b/util/StringUtil.cc index 5f95309f..40e00441 100644 --- a/util/StringUtil.cc +++ b/util/StringUtil.cc @@ -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 diff --git a/util/StringUtil.hh b/util/StringUtil.hh index bf782336..d0f5ad54 100644 --- a/util/StringUtil.hh +++ b/util/StringUtil.hh @@ -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(); //////////////////////////////////////////////////////////////// diff --git a/util/ThreadException.cc b/util/ThreadException.cc index 6738a457..295648c0 100644 --- a/util/ThreadException.cc +++ b/util/ThreadException.cc @@ -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); } } diff --git a/util/TokenParser.hh b/util/TokenParser.hh index 274dee39..d22cd0a8 100644 --- a/util/TokenParser.hh +++ b/util/TokenParser.hh @@ -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(); diff --git a/verilog/VerilogReader.cc b/verilog/VerilogReader.cc index 2662e9f4..c4b90e67 100644 --- a/verilog/VerilogReader.cc +++ b/verilog/VerilogReader.cc @@ -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);