combined latest osta

Signed-off-by: dsengupta0628 <dsengupta@precisioninno.com>
This commit is contained in:
dsengupta0628 2026-03-25 20:03:03 +00:00
commit 4238a057dd
22 changed files with 208 additions and 96 deletions

View File

@ -410,15 +410,44 @@ find_package(Threads)
find_package(Eigen3 REQUIRED)
# fmt library: fallback when std::format is not available (e.g. GCC 11 on Ubuntu 22.04)
find_package(fmt QUIET)
if(NOT fmt_FOUND)
include(FetchContent)
FetchContent_Declare(fmt
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
GIT_TAG 10.2.1
)
FetchContent_MakeAvailable(fmt)
# See if std::format is available and if nor install fmt.
include(CheckCXXSourceCompiles)
set(_sta_fmt_check_saved_flags "${CMAKE_REQUIRED_FLAGS}")
if(MSVC)
string(APPEND CMAKE_REQUIRED_FLAGS " /std:c++20")
else()
string(APPEND CMAKE_REQUIRED_FLAGS " -std=c++20")
endif()
check_cxx_source_compiles("
#include <format>
#include <string>
int main() { (void)std::format(\"{}\", 42); return 0; }
" HAVE_CXX_STD_FORMAT)
set(CMAKE_REQUIRED_FLAGS "${_sta_fmt_check_saved_flags}")
if(HAVE_CXX_STD_FORMAT)
message(STATUS "std::format: available")
else()
# Set the fmt dir for the ubuntu/centos docker files.
if(EXISTS "/usr/local/lib/cmake/fmt/fmt-config.cmake")
set(fmt_DIR "/usr/local/lib/cmake/fmt")
elseif(EXISTS "/usr/lib/x86_64-linux-gnu/cmake/fmt/fmt-config.cmake")
set(fmt_DIR "/usr/lib/x86_64-linux-gnu/cmake/fmt")
elseif(EXISTS "/usr/lib/aarch64-linux-gnu/cmake/fmt/fmt-config.cmake")
set(fmt_DIR "/usr/lib/aarch64-linux-gnu/cmake/fmt")
endif()
find_package(fmt QUIET)
if(fmt_FOUND)
message(STATUS "std::format: using installed fmt library")
else()
message(STATUS "std::format: building fmt library")
include(FetchContent)
FetchContent_Declare(fmt
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
GIT_TAG 10.2.1
)
FetchContent_MakeAvailable(fmt)
endif()
endif()
include(cmake/FindCUDD.cmake)
@ -536,12 +565,15 @@ target_sources(OpenSTA
target_link_libraries(OpenSTA
Eigen3::Eigen
fmt::fmt
${TCL_LIBRARY}
${CMAKE_THREAD_LIBS_INIT}
${CUDD_LIB}
)
if(NOT HAVE_CXX_STD_FORMAT)
target_link_libraries(OpenSTA fmt::fmt)
endif()
if (ZLIB_LIBRARIES)
target_link_libraries(OpenSTA ${ZLIB_LIBRARIES})
endif()

View File

@ -68,6 +68,30 @@ cd ../..
rm -rf v1.14.0.tar.gz googletest-1.14.0
EOF
# Download and build fmt
# Ensure the Vault redirect is applied to everything including new installs
RUN sed -i s/mirror.centos.org/vault.centos.org/g /etc/yum.repos.d/*.repo && \
sed -i s/^#.*baseurl=http/baseurl=http/g /etc/yum.repos.d/*.repo && \
sed -i s/^mirrorlist=http/#mirrorlist=http/g /etc/yum.repos.d/*.repo && \
yum install -y ca-certificates git && \
update-ca-trust force-enable
# clone fmt compatible version (10.2.1)
RUN git config --global http.sslVerify false && \
git clone --depth 1 --branch 10.2.1 https://github.com/fmtlib/fmt.git /tmp/fmt
RUN source /opt/rh/devtoolset-11/enable && \
cd /tmp/fmt && \
mkdir build && cd build && \
cmake3 .. \
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
-DFMT_TEST=OFF \
-DCMAKE_BUILD_TYPE=Release \
-DFMT_DOC=OFF && \
make -j$(nproc) && \
make install
RUN rm -rf /tmp/fmt
################################################################
FROM base-dependencies AS builder
COPY . /OpenSTA

View File

@ -13,13 +13,14 @@ RUN apt-get update && \
gdb \
tcl-dev \
tcl-tclreadline \
libeigen3-dev \
swig \
bison \
flex \
automake \
autotools-dev \
libgtest-dev
libgtest-dev \
libeigen3-dev \
libfmt-dev
# Download CUDD
RUN wget https://raw.githubusercontent.com/davidkebo/cudd/main/cudd_versions/cudd-3.0.0.tar.gz && \

View File

@ -104,6 +104,7 @@ eigen 3.4.0 3.4.0 MPL2 required
cudd 3.0.0 3.0.0 BSD required
tclreadline 2.3.8 2.3.8 BSD optional
zLib 1.2.5 1.2.8 zlib optional
libfmt 8.1.1 N/A MIT required if std::format not available
```
The [TCL readline library](https://tclreadline.sourceforge.net/tclreadline.html)
@ -143,6 +144,11 @@ make
You can use the "configure --prefix" option and "make install" to install CUDD
in a different directory.
Modern c++ compilers that support c++20 include support for std::format.
With older compilers like gcc 11 on Ubuntu 22.04 and Centos7 the fmt library
is used instead. If it is not installed locally, the github repository is
downloaded and compiled in the build directory.
### Building with CMake
Use the following commands to checkout the git repository and build the

View File

@ -87,7 +87,7 @@ CcsCeffDelayCalc::gateDelay(const Pin *drvr_pin,
parasitic_ = parasitic;
output_waveforms_ = nullptr;
GateTableModel *table_model = arc->gateTableModel(scene, min_max);
const GateTableModel *table_model = arc->gateTableModel(scene, min_max);
if (table_model && parasitic) {
OutputWaveforms *output_waveforms = table_model->outputWaveforms();
Parasitics *parasitics = scene->parasitics(min_max);
@ -112,12 +112,36 @@ CcsCeffDelayCalc::gateDelay(const Pin *drvr_pin,
drvr_cell->ensureVoltageWaveforms(scenes_);
output_waveforms_ = output_waveforms;
ref_time_ = output_waveforms_->referenceTime(in_slew_);
debugPrint(debug_, "ccs_dcalc", 1, "{} {}", drvr_cell->name(),
debugPrint(debug_, "ccs_dcalc", 1, "{} {}",
drvr_cell->name(),
drvr_rf_->shortName());
double gate_delay, drvr_slew;
gateDelaySlew(drvr_library, drvr_rf_, gate_delay, drvr_slew);
return makeResult(drvr_library, drvr_rf_, gate_delay, drvr_slew,
load_pin_index_map);
gateDelaySlew(drvr_library, gate_delay, drvr_slew);
debugPrint(debug_, "ccs_dcalc", 2, "gate_delay {} drvr_slew {}",
delayAsString(gate_delay, this), delayAsString(drvr_slew, this));
// Fill in pocv parameters.
ArcDelay gate_delay2(gate_delay);
Slew drvr_slew2(drvr_slew);
if (variables_->pocvEnabled()) {
double ceff = region_ceff_[0];
const Pvt *pvt = pinPvt(drvr_pin_, scene, min_max);
table_model->gateDelayPocv(pvt, in_slew_, ceff, min_max,
variables_->pocvMode(),
gate_delay2, drvr_slew2);
}
ArcDcalcResult dcalc_result(load_pin_index_map.size());
dcalc_result.setGateDelay(gate_delay2);
dcalc_result.setDrvrSlew(drvr_slew2);
for (const auto &[load_pin, load_idx] : load_pin_index_map) {
double wire_delay, load_slew;
loadDelaySlew(load_pin, drvr_library, drvr_slew, wire_delay, load_slew);
dcalc_result.setWireDelay(load_idx, wire_delay);
dcalc_result.setLoadSlew(load_idx, load_slew);
}
return dcalc_result;
}
}
return table_dcalc_->gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic,
@ -126,12 +150,11 @@ CcsCeffDelayCalc::gateDelay(const Pin *drvr_pin,
void
CcsCeffDelayCalc::gateDelaySlew(const LibertyLibrary *drvr_library,
const RiseFall *rf,
// Return values.
double &gate_delay,
double &drvr_slew)
{
initRegions(drvr_library, rf);
initRegions(drvr_library, drvr_rf_);
findCsmWaveform();
ref_time_ = output_waveforms_->referenceTime(in_slew_);
gate_delay = region_times_[region_vth_idx_] - ref_time_;
@ -300,33 +323,10 @@ CcsCeffDelayCalc::findCsmWaveform()
////////////////////////////////////////////////////////////////
ArcDcalcResult
CcsCeffDelayCalc::makeResult(const LibertyLibrary *drvr_library,
const RiseFall *rf,
double &gate_delay,
double &drvr_slew,
const LoadPinIndexMap &load_pin_index_map)
{
ArcDcalcResult dcalc_result(load_pin_index_map.size());
debugPrint(debug_, "ccs_dcalc", 2, "gate_delay {} drvr_slew {}",
delayAsString(gate_delay, this), delayAsString(drvr_slew, this));
dcalc_result.setGateDelay(gate_delay);
dcalc_result.setDrvrSlew(drvr_slew);
for (const auto &[load_pin, load_idx] : load_pin_index_map) {
double wire_delay, load_slew;
loadDelaySlew(load_pin, drvr_library, rf, drvr_slew, wire_delay, load_slew);
dcalc_result.setWireDelay(load_idx, wire_delay);
dcalc_result.setLoadSlew(load_idx, load_slew);
}
return dcalc_result;
}
void
CcsCeffDelayCalc::loadDelaySlew(const Pin *load_pin,
const LibertyLibrary *drvr_library,
const RiseFall *rf,
double &drvr_slew,
double drvr_slew,
// Return values.
double &wire_delay,
double &load_slew)
@ -349,7 +349,7 @@ CcsCeffDelayCalc::loadDelaySlew(const Pin *load_pin,
else
loadDelaySlew(load_pin, drvr_slew, elmore, wire_delay, load_slew);
thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew);
thresholdAdjust(load_pin, drvr_library, drvr_rf_, wire_delay, load_slew);
}
void

View File

@ -71,22 +71,15 @@ protected:
typedef std::vector<double> Region;
void gateDelaySlew(const LibertyLibrary *drvr_library,
const RiseFall *rf,
// Return values.
double &gate_delay,
double &drvr_slew);
void initRegions(const LibertyLibrary *drvr_library,
const RiseFall *rf);
void findCsmWaveform();
ArcDcalcResult makeResult(const LibertyLibrary *drvr_library,
const RiseFall *rf,
double &gate_delay,
double &drvr_slew,
const LoadPinIndexMap &load_pin_index_map);
void loadDelaySlew(const Pin *load_pin,
const LibertyLibrary *drvr_library,
const RiseFall *rf,
double &drvr_slew,
double drvr_slew,
// Return values.
double &wire_delay,
double &load_slew);

View File

@ -448,10 +448,10 @@ DmpAlg::showJacobian()
{
std::string line = " ";
for (int j = 0; j < nr_order_; j++)
line += sta::format("{:12}", dmp_param_index_strings[j]);
line += sta::format("{:>12}", dmp_param_index_strings[j]);
report_->reportLine(line);
line.clear();
for (int i = 0; i < nr_order_; i++) {
line.clear();
line += sta::format("{:4} ", dmp_func_index_strings[i]);
for (int j = 0; j < nr_order_; j++)
line += sta::format("{:12.3e} ", fjac_[i][j]);
@ -551,10 +551,10 @@ DmpAlg::loadDelaySlew(const Pin *,
// Use the driver thresholds and rely on thresholdAdjust to
// convert the delay and slew to the load's thresholds.
try {
if (debug_->check("dmp_ceff", 4))
showVl();
elmore_ = elmore;
p3_ = 1.0 / elmore;
if (debug_->check("dmp_ceff", 4))
showVl();
double t_lower = t0_;
double t_upper = vlCrossingUpperBound();
double load_delay = findVlCrossing(vth_, t_lower, t_upper);
@ -1189,9 +1189,9 @@ DmpZeroC2::init(const LibertyLibrary *drvr_library,
}
void
DmpZeroC2::gateDelaySlew( // Return values.
double &delay,
double &slew)
DmpZeroC2::gateDelaySlew(// Return values.
double &delay,
double &slew)
{
try {
findDriverParams(c1_);

View File

@ -411,27 +411,27 @@ GraphDelayCalc::seedDrvrSlew(Vertex *drvr_vertex,
for (const MinMax *min_max : MinMax::range()) {
for (const RiseFall *rf : RiseFall::range()) {
InputDrive *drive = nullptr;
if (network_->isTopLevelPort(drvr_pin)) {
Port *port = network_->port(drvr_pin);
if (network_->isTopLevelPort(drvr_pin)) {
Port *port = network_->port(drvr_pin);
drive = sdc->findInputDrive(port);
}
if (drive) {
const LibertyCell *drvr_cell;
const LibertyPort *from_port, *to_port;
float *from_slews;
}
if (drive) {
const LibertyCell *drvr_cell;
const LibertyPort *from_port, *to_port;
float *from_slews;
drive->driveCell(rf, min_max, drvr_cell, from_port,
from_slews, to_port);
if (drvr_cell) {
if (from_port == nullptr)
from_port = driveCellDefaultFromPort(drvr_cell, to_port);
findInputDriverDelay(drvr_cell, drvr_pin, drvr_vertex, rf,
from_slews, to_port);
if (drvr_cell) {
if (from_port == nullptr)
from_port = driveCellDefaultFromPort(drvr_cell, to_port);
findInputDriverDelay(drvr_cell, drvr_pin, drvr_vertex, rf,
from_port, from_slews, to_port, scene, min_max);
}
else
}
else
seedNoDrvrCellSlew(drvr_vertex, drvr_pin, rf, drive, scene, min_max,
arc_delay_calc);
}
else
arc_delay_calc);
}
else
seedNoDrvrSlew(drvr_vertex, drvr_pin, rf, scene, min_max, arc_delay_calc);
}
}

View File

@ -35,10 +35,7 @@
#include <zlib.h>
#endif
// std::format is not supported in GCC 11 (e.g. Ubuntu 22.04).
// Use fmt library as fallback when __cpp_lib_format is not defined.
#if defined(__cpp_lib_format) && __cpp_lib_format >= 201907L
#if HAVE_CXX_STD_FORMAT
#include <format>
namespace sta {

View File

@ -3042,7 +3042,7 @@ OperatingConditions::OperatingConditions(const char *name) :
Pvt(0.0, 0.0, 0.0),
name_(name),
// Default wireload tree.
wire_load_tree_(WireloadTree::balanced)
wire_load_tree_(WireloadTree::unknown)
{
}

View File

@ -116,7 +116,9 @@ GateTableModel::gateDelay(const Pvt *pvt,
drvr_slew = findValue(pvt, slew_models_->model(), in_slew, load_cap, 0.0);
else
drvr_slew = 0.0;
// Clip negative slews to zero.
// Clip negative delays and slews to zero.
if (gate_delay < 0.0)
gate_delay = 0.0;
if (drvr_slew < 0.0)
drvr_slew = 0.0;
}

View File

@ -257,12 +257,12 @@ Parasitics::makeWireloadNetwork(const Pin *drvr_pin,
makeWireloadNetworkWorst(parasitic, drvr_pin, net, wireload_cap,
wireload_res, fanout);
break;
case WireloadTree::unknown:
case WireloadTree::balanced:
makeWireloadNetworkBalanced(parasitic, drvr_pin, wireload_cap, wireload_res,
fanout);
break;
case WireloadTree::best_case:
case WireloadTree::unknown:
makeWireloadNetworkBest(parasitic, drvr_pin, wireload_cap, wireload_res,
fanout);
break;

View File

@ -1427,8 +1427,12 @@ Power::findSwitchingPower(const Instance *inst,
float volt = portVoltage(scene_cell, to_port, scene, MinMax::max());
float switching = .5 * load_cap * volt * volt * activity.density();
debugPrint(debug_, "power", 2,
"switching {}/{} activity = {:.2e} volt = {:.2f} {:.3e}", cell->name(),
to_port->name(), activity.density(), volt, switching);
"switching {}/{} activity = {:.2e} volt = {:.2f} {:.3e}",
cell->name(),
to_port->name(),
activity.density(),
volt,
switching);
result.incrSwitching(switching);
}
}
@ -1477,14 +1481,18 @@ Power::findLeakagePower(const Instance *inst,
for (const LeakagePower &pwr : scene_cell->leakagePowers()) {
LibertyPort *pg_port = pwr.relatedPgPort();
if (pg_port == nullptr || pg_port->pwrGndType() == PwrGndType::primary_power) {
std::string pg_name = pg_port ? pg_port->name() : "?";
LeakageSummary &sum = leakage_summaries[pg_port];
float leakage = pwr.power();
FuncExpr *when = pwr.when();
if (when) {
LogicValue when_value = sim->evalExpr(when, inst);
if (when_value == LogicValue::one) {
debugPrint(debug_, "power", 2, "leakage {}/{} {}=1 {:.3e}", cell->name(),
pg_port->name(), when->to_string(), leakage);
debugPrint(debug_, "power", 2, "leakage {}/{} {}=1 {:.3e}",
cell->name(),
pg_name,
when->to_string(),
leakage);
sum.cond_true_leakage = leakage;
sum.cond_true_exists = true;
}
@ -1492,7 +1500,9 @@ Power::findLeakagePower(const Instance *inst,
PwrActivity cond_activity = evalActivity(when, inst);
float cond_duty = cond_activity.duty();
debugPrint(debug_, "power", 2, "leakage {} {} {} {:.3e} * {:.2f}",
cell->name(), pg_port->name(), when->to_string(),
cell->name(),
pg_name,
when->to_string(),
leakage, cond_duty);
// Leakage power average weighted by duty.
sum.cond_leakage += leakage * cond_duty;
@ -1502,8 +1512,10 @@ Power::findLeakagePower(const Instance *inst,
}
}
else {
debugPrint(debug_, "power", 2, "leakage {} {} -- {:.3e}", cell->name(),
pg_port->name(), leakage);
debugPrint(debug_, "power", 2, "leakage {} {} -- {:.3e}",
cell->name(),
pg_name,
leakage);
sum.uncond_leakage = leakage;
sum.uncond_exists = true;
}
@ -1529,8 +1541,10 @@ Power::findLeakagePower(const Instance *inst,
// Ignore unconditional leakage unless there are no conditional leakage groups.
else if (sum.uncond_exists)
leakage = sum.uncond_leakage;
debugPrint(debug_, "power", 2, "leakage {}/{} {:.3e}", cell->name(),
pg_port->name(), leakage);
debugPrint(debug_, "power", 2, "leakage {}/{} {:.3e}",
cell->name(),
pg_port ? pg_port->name() : "?",
leakage);
result.incrLeakage(leakage);
}
}

View File

@ -139,7 +139,9 @@ SaifReader::instancePush(const char *instance_name)
else {
// Inside annotation scope.
Instance *parent = path_.empty() ? sdc_network_->topInstance() : path_.back();
Instance *child = sdc_network_->findChild(parent, instance_name);
Instance *child = parent
? sdc_network_->findChild(parent, instance_name)
: nullptr;
path_.push_back(child);
}
stringDelete(instance_name);

View File

@ -0,0 +1,14 @@
library(min) {
technology(cmos);
time_unit : "1ns";
voltage_unit : "1V";
current_unit : "1mA";
capacitive_load_unit(1, pf);
cell(BUF) {
pin(A) { direction : input; }
pin(Y) { direction : output;
function : "A";
timing() { related_pin : "A"; }
}
}
}

View File

@ -0,0 +1 @@
Annotated 0 pin activities.

View File

@ -0,0 +1,16 @@
(SAIFILE
(SAIFVERSION "2.0")
(DIRECTION "backward")
(DIVIDER / )
(TIMESCALE 1ns)
(DURATION 1000)
(INSTANCE TOP
(INSTANCE child
(INSTANCE grandchild
(NET
(clk (T0 500) (T1 500) (TZ 0) (TX 0) (TB 0) (TC 1000))
)
)
)
)
)

View File

@ -0,0 +1,5 @@
# read_saif references missing instance
read_liberty read_saif_null_instance.lib
read_verilog read_saif_null_instance.v
link_design top
read_saif -scope TOP read_saif_null_instance.saif

View File

@ -0,0 +1,2 @@
module top(input clk);
endmodule

View File

@ -30,7 +30,7 @@
#
# This notice may not be removed or altered from any source distribution.
# Usage: regression -help | [-threads threads] [-j jobs] [-valgrind] [-report_stats]
# Usage: regression -help | [-j jobs] [-threads threads] [-valgrind] [-report_stats]
# test1 [test2...]
proc regression_main {} {
@ -82,8 +82,8 @@ proc parse_args {} {
set arg [lindex $argv 0]
if { $arg == "help" || $arg == "-help" } {
puts {Usage: regression [-help] [-threads threads] [-j jobs] [-valgrind] [-report_stats] tests...}
puts " -threads max|integer - number of threads to use"
puts " -j jobs - number of parallel jobs (processes) to run"
puts " -j jobs - number of parallel test jobs (processes) to run"
puts " -threads max|integer - number of threads the STA uses"
puts " -valgrind - run valgrind (linux memory checker)"
puts " -report_stats - report run time and memory"
puts " Wildcarding for test names is supported (enclose in \"'s)"

View File

@ -158,6 +158,7 @@ record_public_tests {
path_group_names
power_json
prima3
read_saif_null_instance
report_checks_sorted
report_checks_src_attr
report_json1

View File

@ -6,4 +6,6 @@
#cmakedefine ZLIB_FOUND
#cmakedefine01 HAVE_CXX_STD_FORMAT
#define TCL_READLINE ${TCL_READLINE}