Merge upstream STA update and adapt all tests to new API

Major upstream refactoring: Corner→Scene, Mode architecture, warning
format change (Warning ID:), command renames, and many API signature
changes. Adapted all C++ test files and TCL test scripts/expected
output files to pass with the new API. 6159/6159 tests pass.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
This commit is contained in:
Jaehyun Kim 2026-02-23 23:05:29 +09:00
commit 8adbcc0d6d
655 changed files with 43250 additions and 45989 deletions

View File

@ -10,7 +10,7 @@ AllowAllParametersOfDeclarationOnNextLine: false
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: TopLevel
BinPackArguments: false
BinPackArguments: true
# fails
BinPackParameters: AlwaysOnePerLine
BraceWrapping:

View File

@ -0,0 +1,33 @@
---
description: C++ coding standards and formatting for OpenSTA
globs: ["**/*.cc", "**/*.hh", "**/*.h"]
alwaysApply: false
---
# C++ Coding Standards
## Line Width
- **Keep lines under 90 characters** to match `.clang-format` (ColumnLimit: 90).
- Break long lines at logical points: after commas, before operators, after opening parens.
## Naming Conventions
- **Classes**: Upper camel case (`ClassName`)
- **Member functions**: Lower camel case (`memberFunction`)
- **Member variables**: Snake case with trailing underscore (`member_variable_`)
- **Functions**: Lower camel case (`functionName`)
- **Variables**: Snake case
## Code Style
- Use `#pragma once` for header guards.
- Return type on the line before the function name; arguments on separate lines when long.
- No braces for single-line if/for; use braces for multi-line bodies.
- Prefer `std::string` over `char*` for string members.
- Prefer pass-by-value and move for sink parameters (parameters that get stored).
## File Extensions
- C++ source: `.cc`
- C++ headers: `.hh`

View File

@ -0,0 +1,43 @@
---
description: C++ function call indentation for OpenSTA
globs: ["**/*.cc", "**/*.hh", "**/*.h"]
alwaysApply: false
---
# C++ Function Call Indentation
## Short Calls — Single Line
When arguments fit within the column limit (90 chars), keep them on one line:
```cpp
// ✅ GOOD
adjusted_data_arrival = delaySum(required, data_shift_to_enable_clk, this);
// ❌ BAD
adjusted_data_arrival = delaySum(required,
data_shift_to_enable_clk,
this);
```
## Nested Function Calls — Align Under Inner Call
When breaking nested calls across lines:
- Indent continuation lines of the inner call under its first argument (align with content after `innerFunc(`).
- Place remaining outer arguments on the same line as the inner call's closing `)`, indented under the outer function.
```cpp
// ✅ GOOD
required = delayDiff(delaySum(max_delay,
search_->clkPathArrival(disable_path),
this),
margin, this);
// ❌ BAD
required = delayDiff(
delaySum(max_delay,
search_->clkPathArrival(disable_path),
this),
margin,
this);
```

34
.github/workflows/on-delete.yml vendored Normal file
View File

@ -0,0 +1,34 @@
name: Cleanup staging branch on delete
on:
delete:
env:
ROT13_STAGING_OWNER: ${{ secrets.ROT13_STAGING_OWNER }}
ROT13_UPSTREAM_OWNER: ${{ secrets.ROT13_UPSTREAM_OWNER }}
ROT13_UPSTREAM_BRANCH: ${{ secrets.ROT13_UPSTREAM_BRANCH }}
jobs:
Delete-From-Staging:
name: Delete branch from staging
runs-on: ${{ vars.USE_SELF_HOSTED == 'true' && 'self-hosted' || 'ubuntu-latest' }}
permissions:
# Read-only access so we don't accidentally try to push to *this* repository.
contents: read
# Only run on the private repository.
if: github.event.repository.private
steps:
- name: Detect configuration.
uses: The-OpenROAD-Project/actions/auto_config@main
- name: Delete branch from staging repository.
uses: The-OpenROAD-Project/actions/delete_from@main
continue-on-error: true
with:
owner: ${{ env.STAGING_OWNER }}
repo: ${{ env.STAGING_REPO }}
branch: ${{ env.STAGING_BRANCH }}
deployToken: ${{ secrets.STAGING_GITHUB_TOKEN }}

64
.github/workflows/on-label.yml vendored Normal file
View File

@ -0,0 +1,64 @@
name: Labelled Ready to Sync Public
on:
pull_request:
types: [labeled]
env:
ROT13_STAGING_OWNER: ${{ secrets.ROT13_STAGING_OWNER }}
ROT13_UPSTREAM_OWNER: ${{ secrets.ROT13_UPSTREAM_OWNER }}
ROT13_UPSTREAM_BRANCH: ${{ secrets.ROT13_UPSTREAM_BRANCH }}
jobs:
Push-To-Staging:
name: Push to staging
runs-on: ${{ vars.USE_SELF_HOSTED == 'true' && 'self-hosted' || 'ubuntu-latest' }}
permissions:
# Read-only access so we don't accidentally try to push to *this* repository.
contents: read
# Pull request write access, so we can remove the label.
issues: write
pull-requests: write
# Deployment write access, so we can add the nice deployment info.
deployments: write
# Only run on the private repository.
if: github.event.repository.private && github.event.label.name == 'Ready To Sync Public'
steps:
- name: Detect configuration
uses: The-OpenROAD-Project/actions/auto_config@main
- name: Removing label '${{ github.event.label.name }}'
uses: The-OpenROAD-Project/actions/remove_label@main
continue-on-error: true
- name: Clone repository
uses: The-OpenROAD-Project/actions/clone_from@main
with:
branch: ${{ env.PRIVATE_BRANCH }}
checkout: true
- name: Run security scan
uses: The-OpenROAD-Project/actions/security_scan_on_push@main
- name: Push to staging repository.
uses: The-OpenROAD-Project/actions/push_to@main
with:
owner: ${{ env.STAGING_OWNER }}
repo: ${{ env.STAGING_REPO }}
branch: ${{ env.STAGING_BRANCH }}
deployToken: ${{ secrets.STAGING_GITHUB_TOKEN }}
force: true
- id: send_pr
name: Create PR if needed.
uses: The-OpenROAD-Project/actions/send_pr@main
env:
STAGING_GITHUB_TOKEN: ${{ secrets.STAGING_GITHUB_TOKEN }}
- name: Linking to PR using deployment.
uses: The-OpenROAD-Project/actions/link_pr@main
env:
GITHUB_TOKEN: ${{ github.token }}
UPSTREAM_PR: ${{ steps.send_pr.outputs.pr }}

16
.github/workflows/on-push.yml vendored Normal file
View File

@ -0,0 +1,16 @@
name: Scan Code with pre commit trigger
on:
push:
pull_request:
branches:
- master
jobs:
Security-Scan:
runs-on: ${{ vars.USE_SELF_HOSTED == 'true' && 'self-hosted' || 'ubuntu-latest' }}
steps:
- name: Check out repository code
uses: actions/checkout@v6
- name: run security_scan_on_push
uses: The-OpenROAD-Project/actions/security_scan_on_push@main

View File

@ -0,0 +1,46 @@
name: Automatically sync branch from upstream.
on:
schedule:
- cron: "*/5 * * * *"
workflow_dispatch:
inputs:
force:
description: Use GitHub --force push.
default:
repository_dispatch:
jobs:
Sync-Branch-From-Upstream:
name: Automatic sync 'master' from The-OpenROAD-Project/OpenSTA
runs-on: ${{ vars.USE_SELF_HOSTED == 'true' && 'self-hosted' || 'ubuntu-latest' }}
# Only allow one action to run at a time.
concurrency: sync-branch-from-upstream
# Action needs no permissions, as push is granted via adding a deploy key
# with write access to the $DEPLOY_KEY secret.
permissions:
contents: read
# Don't run on the upstream repository and only run on the right branch.
if: ${{ (github.repository != 'The-OpenROAD-Project/OpenSTA') && endsWith(github.ref, '/master') }}
steps:
- uses: The-OpenROAD-Project/actions/upstream_sync@main
env:
HAS_DEPLOY_KEY: ${{ !!(secrets.DEPLOY_KEY) }}
if: ${{ env.HAS_DEPLOY_KEY == 'true' }}
with:
upstreamRepo: The-OpenROAD-Project/OpenSTA
upstreamBranch: master
# To always overwrite master branch, set UPSTREAM_SYNC to the exact
# string 'always overwrite master branch'.
# You can also manually trigger a workflow dispatch with the force
# value equal to 'true'.
force: ${{ github.event.inputs.force || (secrets.UPSTREAM_SYNC == 'always overwrite master branch') }}
deployKey: ${{ secrets.DEPLOY_KEY }}

View File

@ -23,16 +23,23 @@
# This notice may not be removed or altered from any source distribution.
cmake_minimum_required (VERSION 3.10)
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13)
# Use standard target names
cmake_policy(SET CMP0078 NEW)
endif()
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.14)
# Allows SWIG_MODULE_NAME to be set
cmake_policy(SET CMP0086 NEW)
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12)
# Use <PACKAGENAME>_ROOT in find_package
cmake_policy(SET CMP0074 NEW)
endif()
project(STA VERSION 2.7.0
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13)
# Use standard target names
cmake_policy(SET CMP0078 NEW)
endif()
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.14)
# Allows SWIG_MODULE_NAME to be set
cmake_policy(SET CMP0086 NEW)
endif()
project(STA VERSION 3.0.0
LANGUAGES CXX
)
@ -63,6 +70,16 @@ message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
message(STATUS "Build CXX_FLAGS: ${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}}")
message(STATUS "Install prefix: ${CMAKE_INSTALL_PREFIX}")
# Enable Link-Time Optimization (LTO) for Release builds.
include(CheckIPOSupported)
check_ipo_supported(RESULT ipo_supported OUTPUT ipo_error)
if(ipo_supported)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE)
message(STATUS "IPO/LTO: enabled for Release builds")
else()
message(STATUS "IPO/LTO: not supported - ${ipo_error}")
endif()
################################################################
#
# Source files.
@ -77,7 +94,6 @@ set(STA_SOURCE
dcalc/ArnoldiDelayCalc.cc
dcalc/ArnoldiReduce.cc
dcalc/CcsCeffDelayCalc.cc
dcalc/DcalcAnalysisPt.cc
dcalc/DelayCalc.cc
dcalc/DelayCalcBase.cc
dcalc/DmpCeff.cc
@ -135,6 +151,7 @@ set(STA_SOURCE
parasitics/SpefReaderPvt.hh
power/Power.cc
power/ReportPower.cc
power/VcdReader.cc
power/SaifReader.cc
power/VcdParse.cc
@ -154,7 +171,6 @@ set(STA_SOURCE
sdc/PortDelay.cc
sdc/PortExtCap.cc
sdc/Sdc.cc
sdc/SdcGraph.cc
sdc/SdcCmdComment.cc
sdc/Variables.cc
sdc/WriteSdc.cc
@ -168,15 +184,14 @@ set(STA_SOURCE
search/CheckMaxSkews.cc
search/CheckMinPeriods.cc
search/CheckMinPulseWidths.cc
search/CheckCapacitanceLimits.cc
search/CheckFanoutLimits.cc
search/CheckSlewLimits.cc
search/CheckCapacitances.cc
search/CheckFanouts.cc
search/CheckSlews.cc
search/CheckTiming.cc
search/ClkInfo.cc
search/ClkLatency.cc
search/ClkNetwork.cc
search/ClkSkew.cc
search/Corner.cc
search/Crpr.cc
search/FindRegister.cc
search/GatedClk.cc
@ -184,8 +199,8 @@ set(STA_SOURCE
search/Latches.cc
search/Levelize.cc
search/MakeTimingModel.cc
search/Mode.cc
search/Path.cc
search/PathAnalysisPt.cc
search/Path.cc
search/PathEnd.cc
search/PathEnum.cc
@ -195,6 +210,7 @@ set(STA_SOURCE
search/ReportPath.cc
search/Search.cc
search/SearchPred.cc
search/Scene.cc
search/Sim.cc
search/Sta.cc
search/StaState.cc
@ -222,6 +238,7 @@ set(STA_SOURCE
util/ReportStd.cc
util/ReportTcl.cc
util/RiseFallMinMax.cc
util/RiseFallMinMaxDelay.cc
util/RiseFallValues.cc
util/Stats.cc
util/StringSeq.cc
@ -312,6 +329,20 @@ bison_target(SaifParse ${STA_HOME}/power/SaifParse.yy
${CMAKE_CURRENT_BINARY_DIR}/SaifParse.cc)
add_flex_bison_dependency(SaifLex SaifParse)
# Suppress -Wsign-compare in flex-generated code (yyleng vs int loop counter).
# Only needed with older GCC (e.g. CentOS 7 stock 4.8.5); newer GCC/flex handle it.
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set_source_files_properties(
${FLEX_VerilogLex_OUTPUTS}
${FLEX_LibertyLex_OUTPUTS}
${FLEX_LibExprLex_OUTPUTS}
${FLEX_SdfLex_OUTPUTS}
${FLEX_SpefLex_OUTPUTS}
${FLEX_SaifLex_OUTPUTS}
PROPERTIES COMPILE_FLAGS "-Wno-sign-compare"
)
endif()
################################################################
set(STA_TCL_INIT ${CMAKE_CURRENT_BINARY_DIR}/StaTclInitVar.cc)
@ -549,14 +580,14 @@ endif()
target_compile_options(OpenSTA
PRIVATE
$<$<CXX_COMPILER_ID:GNU>:${CXX_FLAGS}>
$<$<CXX_COMPILER_ID:GNU>:${CXX_FLAGS} -Wno-format-zero-length>
$<$<CXX_COMPILER_ID:Clang>:${CXX_FLAGS} -Wno-gnu-zero-variadic-macro-arguments>
$<$<CXX_COMPILER_ID:AppleClang>:${CXX_FLAGS} -Wno-gnu-zero-variadic-macro-arguments>
)
# Disable compiler specific extensions like gnu++11.
set_target_properties(OpenSTA PROPERTIES CXX_EXTENSIONS OFF)
target_compile_features(OpenSTA PUBLIC cxx_std_17)
target_compile_features(OpenSTA PUBLIC cxx_std_20)
message(STATUS "STA library: ${CMAKE_BINARY_DIR}/libOpenSTA.a")

View File

@ -14,6 +14,8 @@ RUN sed -i s/mirror.centos.org/vault.centos.org/g /etc/yum.repos.d/*.repo \
&& yum install -y devtoolset-11 wget cmake3 make eigen3-devel tcl swig3 flex zlib-devel valgrind \
&& yum clean -y all
RUN ln -sf /usr/bin/cmake3 /usr/bin/cmake
# Download Bison
RUN wget https://ftp.gnu.org/gnu/bison/bison-3.8.2.tar.gz && \
tar -xvf bison-3.8.2.tar.gz && \
@ -60,8 +62,9 @@ WORKDIR /OpenSTA
RUN rm -rf build && mkdir build
RUN source /opt/rh/devtoolset-11/enable && \
cd build && \
cmake3 .. && \
make -j`nproc`
cmake .. && \
# LTO fails with -j
make
# Run sta on entry
ENTRYPOINT ["/OpenSTA/build/sta"]

17
Jenkinsfile vendored
View File

@ -1,15 +1,4 @@
pipeline {
agent any
stages {
stage('Build') {
steps {
sh './jenkins/build.sh'
}
}
stage('Test') {
steps {
sh './jenkins/test.sh'
}
}
}
@Library('utils@main') _
node() {
pipelineOpenSTA()
}

View File

@ -27,6 +27,7 @@
#include <stdio.h>
#include <cstdlib> // exit
#include <filesystem>
#include <tcl.h>
#if TCL_READLINE
#include <tclreadline.h>
@ -47,7 +48,6 @@ using sta::evalTclInit;
using sta::sourceTclFile;
using sta::parseThreadsArg;
using sta::tcl_inits;
using sta::is_regular_file;
// Swig uses C linkage for init functions.
extern "C" {
@ -87,20 +87,11 @@ main(int argc,
}
else {
// Set argc to 1 so Tcl_Main doesn't source any files.
// Tcl_Main never returns.
#if 0
// It should be possible to pass argc/argv to staTclAppInit with
// a closure but I couldn't get the signature to match Tcl_AppInitProc.
Tcl_Main(1, argv, [=](Tcl_Interp *interp)
{ sta::staTclAppInit(argc, argv, interp);
return 1;
});
#else
// Workaround.
// Store argc and argv in static variables for tclAppInit.
cmd_argc = argc;
cmd_argv = argv;
// Tcl_Main never returns.
Tcl_Main(1, argv, tclAppInit);
#endif
return 0;
}
}
@ -141,7 +132,7 @@ staTclAppInit(int argc,
string init_path = home;
init_path += "/";
init_path += init_filename;
if (is_regular_file(init_path.c_str()))
if (std::filesystem::is_regular_file(init_path.c_str()))
sourceTclFile(init_path.c_str(), true, true, interp);
}
}

View File

@ -30,7 +30,6 @@
#include "Machine.hh"
#include "StringUtil.hh"
#include "Vector.hh"
#include "Sta.hh"
namespace sta {
@ -148,12 +147,4 @@ unencode(const char *inits[])
return unencoded;
}
// Hack until c++17 filesystem is better supported.
bool
is_regular_file(const char *filename)
{
struct stat sb;
return stat(filename, &sb) == 0 && S_ISREG(sb.st_mode);
}
} // namespace

View File

@ -31,7 +31,6 @@
#include "Network.hh"
#include "Graph.hh"
#include "ArcDelayCalc.hh"
#include "DcalcAnalysisPt.hh"
#include "GraphDelayCalc.hh"
namespace sta {
@ -40,7 +39,8 @@ using std::make_shared;
Waveform
ArcDcalcWaveforms::inputWaveform(ArcDcalcArg &dcalc_arg,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
const StaState *sta)
{
const Network *network = sta->network();
@ -55,7 +55,8 @@ ArcDcalcWaveforms::inputWaveform(ArcDcalcArg &dcalc_arg,
const Vertex *in_vertex = graph->pinLoadVertex(in_pin);
GraphDelayCalc *graph_dcalc = sta->graphDelayCalc();
Slew in_slew = graph_dcalc->edgeFromSlew(in_vertex, in_rf,
dcalc_arg.arc()->role(), dcalc_ap);
dcalc_arg.arc()->role(),
scene, min_max);
LibertyLibrary *library = port->libertyLibrary();
float vdd;
bool vdd_exists;
@ -64,10 +65,11 @@ ArcDcalcWaveforms::inputWaveform(ArcDcalcArg &dcalc_arg,
report->error(1751, "VDD not defined in library %s", library->name());
Waveform in_waveform = driver_waveform->waveform(delayAsFloat(in_slew));
// Delay time axis.
FloatSeq *time_values = new FloatSeq;
for (float time : *in_waveform.axis1()->values())
time_values->push_back(time + dcalc_arg.inputDelay());
TableAxisPtr time_axis = make_shared<TableAxis>(TableAxisVariable::time, time_values);
FloatSeq time_values;
for (float time : in_waveform.axis1()->values())
time_values.push_back(time + dcalc_arg.inputDelay());
TableAxisPtr time_axis = make_shared<TableAxis>(TableAxisVariable::time,
std::move(time_values));
// Scale the waveform from 0:vdd.
FloatSeq *scaled_values = new FloatSeq;
for (float value : *in_waveform.values()) {

View File

@ -31,8 +31,7 @@
namespace sta {
class StaState;
class Corner;
class DcalcAnalysisPt;
class Scene;
class ArcDcalcArg;
// Abstract class for delay calculation waveforms for ploting.
@ -47,7 +46,8 @@ public:
protected:
Waveform inputWaveform(ArcDcalcArg &dcalc_arg,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
const StaState *sta);
};

View File

@ -46,14 +46,15 @@ ArcDelayCalc::gateDelay(const TimingArc *arc,
const Parasitic *parasitic,
float,
const Pvt *,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew)
{
LoadPinIndexMap load_pin_index_map(network_);
ArcDcalcResult dcalc_result = gateDelay(nullptr, arc, in_slew, load_cap, parasitic,
load_pin_index_map, dcalc_ap);
load_pin_index_map, scene, min_max);
gate_delay = dcalc_result.gateDelay();
drvr_slew = dcalc_result.drvrSlew();
}

View File

@ -43,7 +43,6 @@
#include "Graph.hh"
#include "Parasitics.hh"
#include "Sdc.hh"
#include "DcalcAnalysisPt.hh"
#include "DelayCalc.hh"
#include "ArcDelayCalc.hh"
#include "LumpedCapDelayCalc.hh"
@ -129,17 +128,20 @@ public:
const char *name() const override { return "arnoldi"; }
Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
Parasitic *reduceParasitic(const Parasitic *parasitic_network,
const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
ArcDcalcResult inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
ArcDcalcResult gateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
@ -147,14 +149,16 @@ public:
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
string reportGateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
int digits) override;
void finishDrvrPin() override;
void delay_work_set_thresholds(delay_work *D,
@ -273,35 +277,34 @@ ArnoldiDelayCalc::~ArnoldiDelayCalc()
Parasitic *
ArnoldiDelayCalc::findParasitic(const Pin *drvr_pin,
const RiseFall *drvr_rf,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
Parasitic *parasitic = nullptr;
const Corner *corner = dcalc_ap->corner();
const Sdc *sdc = scene->sdc();
Parasitics *parasitics = scene->parasitics(min_max);
if (parasitics == nullptr
// set_load net has precedence over parasitics.
if (sdc_->drvrPinHasWireCap(drvr_pin, corner)
|| network_->direction(drvr_pin)->isInternal())
return nullptr;
const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
Parasitic *parasitic_network =
parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap);
const MinMax *min_max = dcalc_ap->constraintMinMax();
parasitics->findParasiticNetwork(drvr_pin);
if (parasitic_network == nullptr) {
Wireload *wireload = sdc_->wireload(min_max);
Wireload *wireload = sdc->wireload(min_max);
if (wireload) {
float pin_cap, wire_cap, fanout;
bool has_wire_cap;
graph_delay_calc_->netCaps(drvr_pin, drvr_rf, dcalc_ap,
graph_delay_calc_->netCaps(drvr_pin, drvr_rf, scene, min_max,
pin_cap, wire_cap, fanout, has_wire_cap);
parasitic_network = parasitics_->makeWireloadNetwork(drvr_pin, wireload,
fanout, min_max,
parasitic_ap);
parasitic_network = parasitics->makeWireloadNetwork(drvr_pin, wireload,
fanout, scene, min_max);
}
}
if (parasitic_network) {
rcmodel *rcmodel = reduce_->reduceToArnoldi(parasitic_network, drvr_pin,
parasitic_ap->couplingCapFactor(),
drvr_rf, corner, min_max, parasitic_ap);
parasitics->couplingCapFactor(),
drvr_rf, scene, min_max);
// Arnoldi parasitics are their own class that are not saved in the parasitic db.
unsaved_parasitics_.push_back(rcmodel);
parasitic = rcmodel;
@ -313,7 +316,8 @@ Parasitic *
ArnoldiDelayCalc::reduceParasitic(const Parasitic *,
const Pin *,
const RiseFall *,
const DcalcAnalysisPt *)
const Scene *,
const MinMax *)
{
// Decline because reduced arnoldi parasitics are not stored in the parasitics db.
return nullptr;
@ -333,7 +337,8 @@ ArnoldiDelayCalc::inputPortDelay(const Pin *,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
const Scene *,
const MinMax *)
{
rcmodel_ = nullptr;
_delayV[0] = 0.0;
@ -389,21 +394,22 @@ ArnoldiDelayCalc::gateDelay(const Pin *drvr_pin,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
const LibertyCell *drvr_cell = arc->from()->libertyCell();
ConcreteParasitic *cparasitic =
reinterpret_cast<ConcreteParasitic*>(const_cast<Parasitic*>(parasitic));
rcmodel_ = dynamic_cast<rcmodel*>(cparasitic);
pocv_enabled_ = variables_->pocvEnabled();
GateTableModel *table_model = arc->gateTableModel(dcalc_ap);
GateTableModel *table_model = arc->gateTableModel(scene, min_max);
if (table_model && rcmodel_) {
const Pvt *pvt = pinPvt(drvr_pin, dcalc_ap);
const Pvt *pvt = pinPvt(drvr_pin, scene, min_max);
return gateDelaySlew(drvr_cell, arc, table_model, in_slew, load_pin_index_map, pvt);
}
else
return LumpedCapDelayCalc::gateDelay(drvr_pin, arc, in_slew, load_cap,
parasitic, load_pin_index_map, dcalc_ap);
parasitic, load_pin_index_map, scene, min_max);
}
ArcDcalcResult
@ -470,12 +476,13 @@ ArnoldiDelayCalc::reportGateDelay(const Pin *drvr_pin,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
int digits)
{
return LumpedCapDelayCalc::reportGateDelay(drvr_pin, arc, in_slew, load_cap,
parasitic, load_pin_index_map,
dcalc_ap, digits);
scene, min_max, digits);
}
////////////////////////////////////////////////////////////////

View File

@ -154,17 +154,17 @@ ArnoldiReduce::reduceToArnoldi(Parasitic *parasitic,
const Pin *drvr_pin,
float coupling_cap_factor,
const RiseFall *rf,
const Corner *corner,
const MinMax *min_max,
const ParasiticAnalysisPt *ap)
const Scene *scene,
const MinMax *min_max)
{
parasitic_network_ = reinterpret_cast<ConcreteParasiticNetwork*>(parasitic);
drvr_pin_ = drvr_pin;
coupling_cap_factor_ = coupling_cap_factor;
rf_ = rf;
corner_ = corner;
scene_ = scene;
min_max_ = min_max;
ap_ = ap;
parasitics_ = scene->parasitics(min_max);
parasitic_network_ = reinterpret_cast<ConcreteParasiticNetwork*>(parasitic);
loadWork();
return makeRcmodelDrv();
}
@ -444,7 +444,7 @@ ArnoldiReduce::getRC()
}
}
for (ParasiticCapacitor *capacitor : parasitics_->capacitors(parasitic_network_)) {
float cap = parasitics_->value(capacitor) * ap_->couplingCapFactor();
float cap = parasitics_->value(capacitor) * parasitics_->couplingCapFactor();
ParasiticNode *node1 = parasitics_->node1(capacitor);
if (!parasitics_->isExternal(node1)) {
ts_point *pt = findPt(node1);
@ -466,10 +466,11 @@ ArnoldiReduce::pinCapacitance(ParasiticNode *node)
if (pin) {
Port *port = network_->port(pin);
LibertyPort *lib_port = network_->libertyPort(port);
const Sdc *sdc = scene_->sdc();
if (lib_port)
pin_cap = sdc_->pinCapacitance(pin,rf_, corner_, min_max_);
pin_cap = sdc->pinCapacitance(pin,rf_, scene_, min_max_);
else if (network_->isTopLevelPort(pin))
pin_cap = sdc_->portExtCap(port, rf_, corner_, min_max_);
pin_cap = sdc->portExtCap(port, rf_, min_max_);
}
return pin_cap;
}

View File

@ -28,7 +28,8 @@
#pragma once
#include "Map.hh"
#include <map>
#include "Transition.hh"
#include "NetworkClass.hh"
#include "ParasiticsClass.hh"
@ -39,13 +40,13 @@ namespace sta {
class ConcreteParasiticNetwork;
class ConcreteParasiticNode;
class Corner;
class Scene;
class rcmodel;
struct ts_edge;
struct ts_point;
typedef Map<ParasiticNode*, int> ArnolidPtMap;
using ArnolidPtMap = std::map<ParasiticNode*, int>;
class ArnoldiReduce : public StaState
{
@ -56,9 +57,8 @@ public:
const Pin *drvr_pin,
float coupling_cap_factor,
const RiseFall *rf,
const Corner *corner,
const MinMax *cnst_min_max,
const ParasiticAnalysisPt *ap);
const Scene *scene,
const MinMax *min_max);
protected:
void loadWork();
@ -73,13 +73,13 @@ protected:
void makeRcmodelFromTs();
rcmodel *makeRcmodelFromW();
Parasitics *parasitics_;
ConcreteParasiticNetwork *parasitic_network_;
const Pin *drvr_pin_;
float coupling_cap_factor_;
const RiseFall *rf_;
const Corner *corner_;
const Scene *scene_;
const MinMax *min_max_;
const ParasiticAnalysisPt *ap_;
// ParasiticNode -> ts_point index.
ArnolidPtMap pt_map_;

View File

@ -30,8 +30,7 @@
#include "TimingArc.hh"
#include "Network.hh"
#include "Graph.hh"
#include "Corner.hh"
#include "DcalcAnalysisPt.hh"
#include "Scene.hh"
#include "Parasitics.hh"
#include "GraphDelayCalc.hh"
#include "DmpDelayCalc.hh"
@ -86,17 +85,20 @@ CcsCeffDelayCalc::gateDelay(const Pin *drvr_pin,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
in_slew_ = delayAsFloat(in_slew);
load_cap_ = load_cap;
parasitics_ = scene->parasitics(min_max);
parasitic_ = parasitic;
output_waveforms_ = nullptr;
GateTableModel *table_model = arc->gateTableModel(dcalc_ap);
GateTableModel *table_model = arc->gateTableModel(scene, min_max);
if (table_model && parasitic) {
OutputWaveforms *output_waveforms = table_model->outputWaveforms();
parasitics_->piModel(parasitic, c2_, rpi_, c1_);
Parasitics *parasitics = scene->parasitics(min_max);
parasitics->piModel(parasitic, c2_, rpi_, c1_);
if (output_waveforms
&& rpi_ > 0.0 && c1_ > 0.0
// Bounds check because extrapolating waveforms does not work for shit.
@ -114,8 +116,7 @@ CcsCeffDelayCalc::gateDelay(const Pin *drvr_pin,
vl_ = drvr_library->slewLowerThreshold(drvr_rf_) * vdd_;
vh_ = drvr_library->slewUpperThreshold(drvr_rf_) * vdd_;
const DcalcAnalysisPtSeq &dcalc_aps = corners_->dcalcAnalysisPts();
drvr_cell->ensureVoltageWaveforms(dcalc_aps);
drvr_cell->ensureVoltageWaveforms(scenes_);
in_slew_ = delayAsFloat(in_slew);
output_waveforms_ = output_waveforms;
ref_time_ = output_waveforms_->referenceTime(in_slew_);
@ -129,7 +130,7 @@ CcsCeffDelayCalc::gateDelay(const Pin *drvr_pin,
}
}
return table_dcalc_->gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic,
load_pin_index_map, dcalc_ap);
load_pin_index_map, scene, min_max);
}
void
@ -529,12 +530,13 @@ CcsCeffDelayCalc::drvrWaveform()
}
}
TableAxisPtr drvr_time_axis = make_shared<TableAxis>(TableAxisVariable::time,
drvr_times);
Table1 drvr_table(drvr_volts, drvr_time_axis);
std::move(*drvr_times));
delete drvr_times;
Table drvr_table(drvr_volts, drvr_time_axis);
return drvr_table;
}
else
return Table1();
return Table();
}
Waveform
@ -560,12 +562,13 @@ CcsCeffDelayCalc::loadWaveform(const Pin *load_pin)
load_volts->push_back(v1);
}
TableAxisPtr load_time_axis = make_shared<TableAxis>(TableAxisVariable::time,
load_times);
Table1 load_table(load_volts, load_time_axis);
std::move(*load_times));
delete load_times;
Table load_table(load_volts, load_time_axis);
return load_table;
}
}
return Table1();
return Table();
}
Waveform
@ -574,7 +577,7 @@ CcsCeffDelayCalc::drvrRampWaveform(const Pin *in_pin,
const Pin *drvr_pin,
const RiseFall *drvr_rf,
const Pin *load_pin,
const Corner *corner,
const Scene *scene,
const MinMax *min_max)
{
bool elmore_exists = false;
@ -582,7 +585,7 @@ CcsCeffDelayCalc::drvrRampWaveform(const Pin *in_pin,
if (parasitic_) {
parasitics_->findElmore(parasitic_, load_pin, elmore, elmore_exists);
bool dcalc_success = makeWaveformPreamble(in_pin, in_rf, drvr_pin,
drvr_rf, corner, min_max);
drvr_rf, scene, min_max);
if (dcalc_success
&& elmore_exists) {
FloatSeq *load_times = new FloatSeq;
@ -604,12 +607,13 @@ CcsCeffDelayCalc::drvrRampWaveform(const Pin *in_pin,
load_volts->push_back(v1);
}
TableAxisPtr load_time_axis = make_shared<TableAxis>(TableAxisVariable::time,
load_times);
Table1 load_table(load_volts, load_time_axis);
std::move(*load_times));
delete load_times;
Table load_table(load_volts, load_time_axis);
return load_table;
}
}
return Table1();
return Table();
}
bool
@ -617,7 +621,7 @@ CcsCeffDelayCalc::makeWaveformPreamble(const Pin *in_pin,
const RiseFall *in_rf,
const Pin *drvr_pin,
const RiseFall *drvr_rf,
const Corner *corner,
const Scene *scene,
const MinMax *min_max)
{
Vertex *in_vertex = graph_->pinLoadVertex(in_pin);
@ -641,15 +645,15 @@ CcsCeffDelayCalc::makeWaveformPreamble(const Pin *in_pin,
}
}
if (arc) {
DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max);
const Slew &in_slew = graph_->slew(in_vertex, in_rf, dcalc_ap->index());
parasitic_ = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf, dcalc_ap);
DcalcAPIndex slew_index = scene->dcalcAnalysisPtIndex(min_max);
const Slew &in_slew = graph_->slew(in_vertex, in_rf, slew_index);
parasitic_ = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf, scene, min_max);
if (parasitic_) {
parasitics_->piModel(parasitic_, c2_, rpi_, c1_);
LoadPinIndexMap load_pin_index_map =
graph_delay_calc_->makeLoadPinIndexMap(drvr_vertex);
gateDelay(drvr_pin, arc, in_slew, load_cap_, parasitic_,
load_pin_index_map, dcalc_ap);
load_pin_index_map, scene, min_max);
return true;
}
}
@ -666,20 +670,19 @@ CcsCeffDelayCalc::reportGateDelay(const Pin *drvr_pin,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
int digits)
{
Parasitic *pi_elmore = nullptr;
const RiseFall *rf = arc->toEdge()->asRiseFall();
if (parasitic && !parasitics_->isPiElmore(parasitic)) {
const ParasiticAnalysisPt *ap = dcalc_ap->parasiticAnalysisPt();
pi_elmore = parasitics_->reduceToPiElmore(parasitic, drvr_pin_, rf,
dcalc_ap->corner(),
dcalc_ap->constraintMinMax(), ap);
scene, min_max);
}
string report = table_dcalc_->reportGateDelay(drvr_pin, arc, in_slew, load_cap,
pi_elmore, load_pin_index_map,
dcalc_ap, digits);
scene, min_max, digits);
parasitics_->deleteDrvrReducedParasitics(drvr_pin);
return report;
}

View File

@ -29,7 +29,7 @@
namespace sta {
typedef std::map<const Pin*, FloatSeq, PinIdLess> WatchPinValuesMap;
using WatchPinValuesMap = std::map<const Pin*, FloatSeq, PinIdLess>;
ArcDelayCalc *
makeCcsCeffDelayCalc(StaState *sta);
@ -49,14 +49,16 @@ public:
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
std::string reportGateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
int digits) override;
// Record waveform for drvr/load pin.
@ -100,7 +102,7 @@ protected:
const RiseFall *in_rf,
const Pin *drvr_pin,
const RiseFall *drvr_rf,
const Corner *corner,
const Scene *scene,
const MinMax *min_max);
Waveform drvrWaveform();
Waveform loadWaveform(const Pin *load_pin);
@ -109,7 +111,7 @@ protected:
const Pin *drvr_pin,
const RiseFall *drvr_rf,
const Pin *load_pin,
const Corner *corner,
const Scene *scene,
const MinMax *min_max);
void vl(double t,
double elmore,
@ -124,6 +126,7 @@ protected:
const RiseFall *drvr_rf_;
double in_slew_;
double load_cap_;
Parasitics *parasitics_;
const Parasitic *parasitic_;
OutputWaveforms *output_waveforms_;

View File

@ -1,68 +0,0 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software.
//
// Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// This notice may not be removed or altered from any source distribution.
#include "StringUtil.hh"
#include "DcalcAnalysisPt.hh"
#include "Corner.hh"
namespace sta {
DcalcAnalysisPt::DcalcAnalysisPt(Corner *corner,
DcalcAPIndex index,
const OperatingConditions *op_cond,
const MinMax *min_max,
const MinMax *check_clk_slew_min_max) :
corner_(corner),
index_(index),
op_cond_(op_cond),
min_max_(min_max),
check_clk_slew_min_max_(check_clk_slew_min_max)
{
}
void
DcalcAnalysisPt::setOperatingConditions(const OperatingConditions *op_cond)
{
op_cond_ = op_cond;
}
ParasiticAnalysisPt *
DcalcAnalysisPt::parasiticAnalysisPt() const
{
return corner_->findParasiticAnalysisPt(min_max_);
}
void
DcalcAnalysisPt::setCheckClkSlewIndex(DcalcAPIndex index)
{
check_clk_slew_index_ = index;
}
int
DcalcAnalysisPt::libertyIndex() const
{
return corner_->libertyIndex(min_max_);
}
} // namespace

View File

@ -24,7 +24,9 @@
#include "DelayCalc.hh"
#include "Map.hh"
#include <map>
#include "ContainerHelpers.hh"
#include "StringUtil.hh"
#include "UnitDelayCalc.hh"
#include "LumpedCapDelayCalc.hh"
@ -35,7 +37,7 @@
namespace sta {
typedef Map<const char*, MakeArcDelayCalc, CharPtrLess> DelayCalcMap;
typedef std::map<const char*, MakeArcDelayCalc, CharPtrLess> DelayCalcMap;
static DelayCalcMap *delay_calcs = nullptr;
@ -71,7 +73,7 @@ ArcDelayCalc *
makeDelayCalc(const char *name,
StaState *sta)
{
MakeArcDelayCalc maker = delay_calcs->findKey(name);
MakeArcDelayCalc maker = findKey(delay_calcs, name);
if (maker)
return maker(sta);
else
@ -81,7 +83,7 @@ makeDelayCalc(const char *name,
bool
isDelayCalcName(const char *name)
{
return delay_calcs->hasKey(name);
return delay_calcs->contains(name);
}
StringSeq

View File

@ -32,8 +32,6 @@
#include "dcalc/PrimaDelayCalc.hh"
#include "Sta.hh"
using std::string;
%}
%inline %{
@ -62,15 +60,15 @@ set_delay_calc_incremental_tolerance(float tol)
Sta::sta()->setIncrementalDelayTolerance(tol);
}
string
std::string
report_delay_calc_cmd(Edge *edge,
TimingArc *arc,
const Corner *corner,
const Scene *scene,
const MinMax *min_max,
int digits)
{
Sta *sta = Sta::sta();
return sta->reportDelayCalc(edge, arc, corner, min_max, digits);
return sta->reportDelayCalc(edge, arc, scene, min_max, digits);
}
void

View File

@ -25,7 +25,7 @@
namespace eval sta {
define_cmd_args "report_dcalc" \
{[-from from_pin] [-to to_pin] [-corner corner] [-min] [-max] [-digits digits]}
{[-from from_pin] [-to to_pin] [-scene scene] [-min] [-max] [-digits digits]}
proc_redirect report_dcalc {
report_dcalc_cmd "report_dcalc" $args "-digits"
@ -36,9 +36,9 @@ proc report_dcalc_cmd { cmd cmd_args digits_key } {
global sta_report_default_digits
parse_key_args $cmd cmd_args \
keys "$digits_key -from -to -corner" \
keys "$digits_key -from -to -scene -corner" \
flags {-min -max}
set corner [parse_corner keys]
set scene [parse_scene keys]
set min_max [parse_min_max_flags flags]
check_argc_eq0 $cmd $cmd_args
@ -56,7 +56,7 @@ proc report_dcalc_cmd { cmd cmd_args digits_key } {
while {[$iter has_next]} {
set edge [$iter next]
if { [$edge to] == $to_vertex } {
report_edge_dcalc $edge $corner $min_max $digits
report_edge_dcalc $edge $scene $min_max $digits
}
}
$iter finish
@ -68,7 +68,7 @@ proc report_dcalc_cmd { cmd cmd_args digits_key } {
set iter [$from_vertex out_edge_iterator]
while {[$iter has_next]} {
set edge [$iter next]
report_edge_dcalc $edge $corner $min_max $digits
report_edge_dcalc $edge $scene $min_max $digits
}
$iter finish
}
@ -78,14 +78,14 @@ proc report_dcalc_cmd { cmd cmd_args digits_key } {
set iter [$to_vertex in_edge_iterator]
while {[$iter has_next]} {
set edge [$iter next]
report_edge_dcalc $edge $corner $min_max $digits
report_edge_dcalc $edge $scene $min_max $digits
}
$iter finish
}
}
}
proc report_edge_dcalc { edge corner min_max digits } {
proc report_edge_dcalc { edge scene min_max digits } {
set role [$edge role]
if { $role != "wire" } {
set from_vertex [$edge from]
@ -111,9 +111,9 @@ proc report_edge_dcalc { edge corner min_max digits } {
set to [get_name [$to_pin port]]
set to_rf [$arc to_edge]
report_line "$from $from_rf -> $to $to_rf"
report_line [report_delay_calc_cmd $edge $arc $corner $min_max $digits]
if { [$edge delay_annotated $arc $corner $min_max] } {
set delay [$edge arc_delay $arc $corner $min_max]
report_line [report_delay_calc_cmd $edge $arc $scene $min_max $digits]
if { [$edge delay_annotated $arc $scene $min_max] } {
set delay [$edge arc_delay $arc $scene $min_max]
report_line "Annotated value = [format_time $delay $digits]"
}
report_line "............................................."
@ -140,16 +140,16 @@ define_cmd_args "set_pocv_sigma_factor" { factor }
################################################################
define_cmd_args "set_assigned_delay" \
{-cell|-net [-rise] [-fall] [-corner corner] [-min] [-max]\
{-cell|-net [-rise] [-fall] [-scene scene] [-min] [-max]\
[-from from_pins] [-to to_pins] delay}
# Change the delay for timing arcs between from_pins and to_pins matching
# on cell (instance) or net.
proc set_assigned_delay { args } {
parse_key_args "set_assigned_delay" args keys {-corner -from -to} \
parse_key_args "set_assigned_delay" args keys {-scene -corner -from -to} \
flags {-cell -net -rise -fall -max -min}
check_argc_eq1 "set_assigned_delay" $args
set corner [parse_corner keys]
set scene [parse_scene keys]
set min_max [parse_min_max_all_check_flags flags]
set to_rf [parse_rise_fall_flags flags]
@ -192,28 +192,28 @@ proc set_assigned_delay { args } {
foreach from_pin $from_pins {
set from_vertices [$from_pin vertices]
set_assigned_delay1 [lindex $from_vertices 0] \
$to_pins $to_rf $corner $min_max $delay
$to_pins $to_rf $scene $min_max $delay
if { [llength $from_vertices] == 2 } {
set_assigned_delay1 [lindex $from_vertices 1] \
$to_pins $to_rf $corner $min_max $delay
$to_pins $to_rf $scene $min_max $delay
}
}
}
proc set_assigned_delay1 { from_vertex to_pins to_rf corner min_max delay } {
proc set_assigned_delay1 { from_vertex to_pins to_rf scene min_max delay } {
foreach to_pin $to_pins {
set to_vertices [$to_pin vertices]
set_assigned_delay2 $from_vertex [lindex $to_vertices 0] \
$to_rf $corner $min_max $delay
$to_rf $scene $min_max $delay
if { [llength $to_vertices] == 2 } {
# Bidirect driver.
set_assigned_delay2 $from_vertex [lindex $to_vertices 1] \
$to_rf $corner $min_max $delay
$to_rf $scene $min_max $delay
}
}
}
proc set_assigned_delay2 {from_vertex to_vertex to_rf corner min_max delay} {
proc set_assigned_delay2 {from_vertex to_vertex to_rf scene min_max delay} {
set matched 0
set edge_iter [$from_vertex out_edge_iterator]
while {[$edge_iter has_next]} {
@ -223,7 +223,7 @@ proc set_assigned_delay2 {from_vertex to_vertex to_rf corner min_max delay} {
foreach arc [$edge timing_arcs] {
if { $to_rf == "rise_fall" \
|| $to_rf eq [$arc to_edge_name] } {
set_arc_delay $edge $arc $corner $min_max $delay
set_arc_delay $edge $arc $scene $min_max $delay
set matched 1
}
}
@ -239,13 +239,13 @@ proc set_assigned_delay2 {from_vertex to_vertex to_rf corner min_max delay} {
define_cmd_args "set_assigned_check" \
{-setup|-hold|-recovery|-removal [-rise] [-fall]\
[-corner corner] [-min] [-max]\
[-scene scene] [-min] [-max]\
[-from from_pins] [-to to_pins] [-clock rise|fall]\
[-cond sdf_cond] check_value}
proc set_assigned_check { args } {
parse_key_args "set_assigned_check" args \
keys {-from -to -corner -clock -cond} \
keys {-from -to -scene -corner -clock -cond} \
flags {-setup -hold -recovery -removal -rise -fall -max -min}
check_argc_eq1 "set_assigned_check" $args
@ -271,7 +271,7 @@ proc set_assigned_check { args } {
sta_error 190 "set_assigned_check missing -to argument."
}
set to_rf [parse_rise_fall_flags flags]
set corner [parse_corner keys]
set scene [parse_scene keys]
set min_max [parse_min_max_all_check_flags flags]
if { [info exists flags(-setup)] } {
@ -298,31 +298,31 @@ proc set_assigned_check { args } {
foreach from_pin $from_pins {
set from_vertices [$from_pin vertices]
set_assigned_check1 [lindex $from_vertices 0] $from_rf \
$to_pins $to_rf $role $corner $min_max $cond $check_value
$to_pins $to_rf $role $scene $min_max $cond $check_value
if { [llength $from_vertices] == 2 } {
set_assigned_check1 [lindex $from_vertices 1] $from_rf \
$to_pins $to_rf $role $corner $min_max $cond $check_value
$to_pins $to_rf $role $scene $min_max $cond $check_value
}
}
}
proc set_assigned_check1 { from_vertex from_rf to_pins to_rf \
role corner min_max cond check_value } {
role scene min_max cond check_value } {
foreach to_pin $to_pins {
set to_vertices [$to_pin vertices]
set_assigned_check2 $from_vertex $from_rf [lindex $to_vertices 0] \
$to_rf $role $corner $min_max $cond $check_value
$to_rf $role $scene $min_max $cond $check_value
if { [llength $to_vertices] == 2 } {
# Bidirect driver.
set_assigned_check2 $from_vertex $from_rf \
[lindex $to_vertices 1] $to_rf $role $corner $min_max \
[lindex $to_vertices 1] $to_rf $role $scene $min_max \
$cond $check_value
}
}
}
proc set_assigned_check2 { from_vertex from_rf to_vertex to_rf \
role corner min_max cond check_value } {
role scene min_max cond check_value } {
set edge_iter [$from_vertex out_edge_iterator]
set matched 0
while {[$edge_iter has_next]} {
@ -335,7 +335,7 @@ proc set_assigned_check2 { from_vertex from_rf to_vertex to_rf \
|| $to_rf eq [$arc to_edge_name]) \
&& [$arc role] eq $role \
&& ($cond eq "" || [$arc sdf_cond] eq $cond) } {
set_arc_delay $edge $arc $corner $min_max $check_value
set_arc_delay $edge $arc $scene $min_max $check_value
set matched 1
}
}
@ -350,14 +350,14 @@ proc set_assigned_check2 { from_vertex from_rf to_vertex to_rf \
################################################################a
define_cmd_args "set_assigned_transition" \
{[-rise] [-fall] [-corner corner] [-min] [-max] slew pins}
{[-rise] [-fall] [-scene scene] [-min] [-max] slew pins}
# Change the slew on a list of ports.
proc set_assigned_transition { args } {
parse_key_args "set_assigned_transition" args keys {-corner} \
parse_key_args "set_assigned_transition" args keys {-scene -corner} \
flags {-rise -fall -max -min}
set corner [parse_corner keys]
set scene [parse_scene keys]
set min_max [parse_min_max_all_check_flags flags]
set tr [parse_rise_fall_flags flags]
check_argc_eq2 "set_assigned_transition" $args
@ -371,7 +371,7 @@ proc set_assigned_transition { args } {
foreach pin $pins {
set vertices [$pin vertices]
set vertex [lindex $vertices 0]
set_annotated_slew $vertex $corner $min_max $tr $slew
set_annotated_slew $vertex $scene $min_max $tr $slew
if { [llength $vertices] == 2 } {
# Bidirect driver.
set vertex [lindex $vertices 1]
@ -380,5 +380,27 @@ proc set_assigned_transition { args } {
}
}
################################################################
define_cmd_args "report_slews" {[-scenes scenes] pin}
proc report_slews { args } {
global sta_report_default_digits
parse_key_args "report_slews" args keys {-corner -scenes} flags {}
check_argc_eq1 "report_slews" $args
set scenes [parse_scenes_or_all keys]
set pin [get_port_pin_error "pin" [lindex $args 0]]
set digits $sta_report_default_digits
foreach vertex [$pin vertices] {
set rise_min [format_time [$vertex slew_scenes rise $scenes min] $digits]
set rise_max [format_time [$vertex slew_scenes rise $scenes max] $digits]
set fall_min [format_time [$vertex slew_scenes fall $scenes min] $digits]
set fall_max [format_time [$vertex slew_scenes fall $scenes max] $digits]
report_line "[vertex_path_name $vertex] [rise_short_name] $rise_min:$rise_max [fall_short_name] $fall_min:$fall_max"
}
}
# sta namespace end
}

View File

@ -32,8 +32,7 @@
#include "Parasitics.hh"
#include "Graph.hh"
#include "Sdc.hh"
#include "Corner.hh"
#include "DcalcAnalysisPt.hh"
#include "Scene.hh"
#include "GraphDelayCalc.hh"
#include "Variables.hh"
@ -50,7 +49,7 @@ DelayCalcBase::DelayCalcBase(StaState *sta) :
void
DelayCalcBase::reduceParasitic(const Parasitic *parasitic_network,
const Net *net,
const Corner *corner,
const Scene *scene,
const MinMaxAll *min_max)
{
NetConnectedPinIterator *pin_iter = network_->connectedPinIterator(net);
@ -59,16 +58,12 @@ DelayCalcBase::reduceParasitic(const Parasitic *parasitic_network,
if (network_->isDriver(pin)) {
for (const RiseFall *rf : RiseFall::range()) {
for (const MinMax *min_max : min_max->range()) {
if (corner == nullptr) {
for (const Corner *corner1 : *corners_) {
DcalcAnalysisPt *dcalc_ap = corner1->findDcalcAnalysisPt(min_max);
reduceParasitic(parasitic_network, pin, rf, dcalc_ap);
}
}
else {
DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max);
reduceParasitic(parasitic_network, pin, rf, dcalc_ap);
if (scene == nullptr) {
for (const Scene *scene1 : scenes_)
reduceParasitic(parasitic_network, pin, rf, scene1, min_max);
}
else
reduceParasitic(parasitic_network, pin, rf, scene, min_max);
}
}
}
@ -162,13 +157,15 @@ DelayCalcBase::checkDelay(const Pin *check_pin,
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
CheckTimingModel *model = arc->checkModel(dcalc_ap);
CheckTimingModel *model = arc->checkModel(scene, min_max);
if (model) {
float from_slew1 = delayAsFloat(from_slew);
float to_slew1 = delayAsFloat(to_slew);
return model->checkDelay(pinPvt(check_pin, dcalc_ap), from_slew1, to_slew1,
return model->checkDelay(pinPvt(check_pin, scene, min_max),
from_slew1, to_slew1,
related_out_cap,
variables_->pocvEnabled());
}
@ -183,40 +180,46 @@ DelayCalcBase::reportCheckDelay(const Pin *check_pin,
const char *from_slew_annotation,
const Slew &to_slew,
float related_out_cap,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
int digits)
{
CheckTimingModel *model = arc->checkModel(dcalc_ap);
CheckTimingModel *model = arc->checkModel(scene, min_max);
if (model) {
float from_slew1 = delayAsFloat(from_slew);
float to_slew1 = delayAsFloat(to_slew);
return model->reportCheckDelay(pinPvt(check_pin, dcalc_ap), from_slew1,
from_slew_annotation, to_slew1,
related_out_cap, false, digits);
return model->reportCheckDelay(pinPvt(check_pin, scene, min_max),
from_slew1, from_slew_annotation,
to_slew1, related_out_cap, false,
digits);
}
return "";
}
const Pvt *
DelayCalcBase::pinPvt(const Pin *pin,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
const Instance *drvr_inst = network_->instance(pin);
const Pvt *pvt = sdc_->pvt(drvr_inst, dcalc_ap->constraintMinMax());
const Sdc *sdc = scene->sdc();
const Pvt *pvt = sdc->pvt(drvr_inst, min_max);
if (pvt == nullptr)
pvt = dcalc_ap->operatingConditions();
pvt = sdc->operatingConditions(min_max);
return pvt;
}
void
DelayCalcBase::setDcalcArgParasiticSlew(ArcDcalcArg &gate,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
const Pin *drvr_pin = gate.drvrPin();
if (drvr_pin) {
const Parasitic *parasitic;
float load_cap;
graph_delay_calc_->parasiticLoad(drvr_pin, gate.drvrEdge(), dcalc_ap,
graph_delay_calc_->parasiticLoad(drvr_pin, gate.drvrEdge(),
scene, min_max,
nullptr, this, load_cap,
parasitic);
gate.setLoadCap(load_cap);
@ -224,17 +227,19 @@ DelayCalcBase::setDcalcArgParasiticSlew(ArcDcalcArg &gate,
const Pin *in_pin = gate.inPin();
const Vertex *in_vertex = graph_->pinLoadVertex(in_pin);
const Slew &in_slew = graph_delay_calc_->edgeFromSlew(in_vertex, gate.inEdge(),
gate.edge(), dcalc_ap);
gate.edge(),
scene, min_max);
gate.setInSlew(in_slew);
}
}
void
DelayCalcBase::setDcalcArgParasiticSlew(ArcDcalcArgSeq &gates,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
for (ArcDcalcArg &gate : gates)
setDcalcArgParasiticSlew(gate, dcalc_ap);
setDcalcArgParasiticSlew(gate, scene, min_max);
}
} // namespace

View File

@ -34,23 +34,26 @@ class GateTableModel;
class DelayCalcBase : public ArcDelayCalc
{
public:
explicit DelayCalcBase(StaState *sta);
DelayCalcBase(StaState *sta);
void finishDrvrPin() override;
void reduceParasitic(const Parasitic *parasitic_network,
const Net *net,
const Corner *corner,
const Scene *scene,
const MinMaxAll *min_max) override;
void setDcalcArgParasiticSlew(ArcDcalcArg &gate,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
void setDcalcArgParasiticSlew(ArcDcalcArgSeq &gates,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
ArcDelay checkDelay(const Pin *check_pin,
const TimingArc *arc,
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
std::string reportCheckDelay(const Pin *check_pin,
const TimingArc *arc,
@ -58,7 +61,8 @@ public:
const char *from_slew_annotation,
const Slew &to_slew,
float related_out_cap,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
int digits) override;
protected:
@ -79,7 +83,8 @@ protected:
ArcDelay &wire_delay,
Slew &load_slew);
const Pvt *pinPvt(const Pin *pin,
const DcalcAnalysisPt *dcalc_ap);
const Scene *scene,
const MinMax *min_max);
using ArcDelayCalc::reduceParasitic;
};

View File

@ -44,7 +44,6 @@
#include "Network.hh"
#include "Sdc.hh"
#include "Parasitics.hh"
#include "DcalcAnalysisPt.hh"
#include "ArcDelayCalc.hh"
#include "FindRoot.hh"
#include "Variables.hh"
@ -1495,20 +1494,22 @@ DmpCeffDelayCalc::gateDelay(const Pin *drvr_pin,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
parasitics_ = scene->parasitics(min_max);
const RiseFall *rf = arc->toEdge()->asRiseFall();
const LibertyCell *drvr_cell = arc->from()->libertyCell();
const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary();
GateTableModel *table_model = arc->gateTableModel(dcalc_ap);
GateTableModel *table_model = arc->gateTableModel(scene, min_max);
if (table_model && parasitic) {
float in_slew1 = delayAsFloat(in_slew);
float c2, rpi, c1;
parasitics_->piModel(parasitic, c2, rpi, c1);
if (isnan(c2) || isnan(c1) || isnan(rpi))
report_->error(1040, "parasitic Pi model has NaNs.");
setCeffAlgorithm(drvr_library, drvr_cell, pinPvt(drvr_pin, dcalc_ap),
setCeffAlgorithm(drvr_library, drvr_cell, pinPvt(drvr_pin, scene, min_max),
table_model, rf, in_slew1, c2, rpi, c1);
double gate_delay, drvr_slew;
gateDelaySlew(gate_delay, drvr_slew);
@ -1529,7 +1530,7 @@ DmpCeffDelayCalc::gateDelay(const Pin *drvr_pin,
else {
ArcDcalcResult dcalc_result =
LumpedCapDelayCalc::gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic,
load_pin_index_map, dcalc_ap);
load_pin_index_map, scene, min_max);
if (parasitic
&& !unsuppored_model_warned_) {
unsuppored_model_warned_ = true;
@ -1589,12 +1590,13 @@ DmpCeffDelayCalc::reportGateDelay(const Pin *drvr_pin,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
int digits)
{
ArcDcalcResult dcalc_result = gateDelay(drvr_pin, arc, in_slew, load_cap,
parasitic, load_pin_index_map, dcalc_ap);
GateTableModel *model = arc->gateTableModel(dcalc_ap);
parasitic, load_pin_index_map, scene, min_max);
GateTableModel *model = arc->gateTableModel(scene, min_max);
float c_eff = 0.0;
string result;
const LibertyCell *drvr_cell = arc->to()->libertyCell();
@ -1603,9 +1605,11 @@ DmpCeffDelayCalc::reportGateDelay(const Pin *drvr_pin,
const Unit *cap_unit = units->capacitanceUnit();
const Unit *res_unit = units->resistanceUnit();
if (parasitic && dmp_alg_) {
Parasitics *parasitics = scene->parasitics(min_max);
c_eff = dmp_alg_->ceff();
float c2, rpi, c1;
parasitics_->piModel(parasitic, c2, rpi, c1);
parasitics->piModel(parasitic, c2, rpi, c1);
result += "Pi model C2=";
result += cap_unit->asString(c2, digits);
result += " Rpi=";
@ -1621,7 +1625,8 @@ DmpCeffDelayCalc::reportGateDelay(const Pin *drvr_pin,
if (model) {
const Unit *time_unit = units->timeUnit();
float in_slew1 = delayAsFloat(in_slew);
result += model->reportGateDelay(pinPvt(drvr_pin, dcalc_ap), in_slew1, c_eff,
result += model->reportGateDelay(pinPvt(drvr_pin, scene, min_max),
in_slew1, c_eff,
variables_->pocvEnabled(), digits);
result += "Driver waveform slew = ";
float drvr_slew = delayAsFloat(dcalc_result.drvrSlew());

View File

@ -49,14 +49,16 @@ public:
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
std::string reportGateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
int digits) override;
void copyState(const StaState *sta) override;
@ -87,6 +89,7 @@ protected:
double rpi,
double c1);
const Parasitics *parasitics_;
static bool unsuppored_model_warned_;
private:

View File

@ -31,7 +31,6 @@
#include "Network.hh"
#include "Sdc.hh"
#include "Parasitics.hh"
#include "DcalcAnalysisPt.hh"
#include "GraphDelayCalc.hh"
#include "DmpCeff.hh"
@ -50,7 +49,8 @@ public:
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
protected:
void loadDelaySlew(const Pin *load_pin,
@ -86,8 +86,10 @@ DmpCeffElmoreDelayCalc::inputPortDelay(const Pin *,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
const Scene *scene,
const MinMax *min_max)
{
Parasitics *parasitics = scene->parasitics(min_max);
ArcDcalcResult dcalc_result(load_pin_index_map.size());
LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
for (auto [load_pin, load_idx] : load_pin_index_map) {
@ -96,7 +98,7 @@ DmpCeffElmoreDelayCalc::inputPortDelay(const Pin *,
bool elmore_exists = false;
float elmore = 0.0;
if (parasitic)
parasitics_->findElmore(parasitic, load_pin, elmore, elmore_exists);
parasitics->findElmore(parasitic, load_pin, elmore, elmore_exists);
if (elmore_exists)
// Input port with no external driver.
dspfWireDelaySlew(load_pin, rf, in_slew, elmore, wire_delay, load_slew);
@ -140,20 +142,23 @@ public:
const char *name() const override { return "dmp_ceff_two_pole"; }
Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
ArcDcalcResult inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
ArcDcalcResult gateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
private:
void loadDelaySlew(const Pin *load_pin,
@ -213,42 +218,40 @@ DmpCeffTwoPoleDelayCalc::copy()
Parasitic *
DmpCeffTwoPoleDelayCalc::findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
Parasitic *parasitic = nullptr;
const Corner *corner = dcalc_ap->corner();
const Sdc *sdc = scene->sdc();
Parasitics *parasitics = scene->parasitics(min_max);
if (parasitics == nullptr
// set_load net has precedence over parasitics.
if (sdc_->drvrPinHasWireCap(drvr_pin, corner)
|| network_->direction(drvr_pin)->isInternal())
return nullptr;
const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
// Prefer PiPoleResidue.
parasitic = parasitics_->findPiPoleResidue(drvr_pin, rf, parasitic_ap);
parasitic = parasitics->findPiPoleResidue(drvr_pin, rf, min_max);
if (parasitic)
return parasitic;
parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap);
parasitic = parasitics->findPiElmore(drvr_pin, rf, min_max);
if (parasitic)
return parasitic;
Parasitic *parasitic_network =
parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap);
parasitics->findParasiticNetwork(drvr_pin);
if (parasitic_network) {
parasitic = parasitics_->reduceToPiPoleResidue2(parasitic_network, drvr_pin, rf,
corner,
dcalc_ap->constraintMinMax(),
parasitic_ap);
parasitic = parasitics->reduceToPiPoleResidue2(parasitic_network, drvr_pin, rf,
scene, min_max);
if (parasitic)
return parasitic;
}
const MinMax *cnst_min_max = dcalc_ap->constraintMinMax();
Wireload *wireload = sdc_->wireload(cnst_min_max);
Wireload *wireload = sdc->wireload(min_max);
if (wireload) {
float pin_cap, wire_cap, fanout;
bool has_wire_cap;
graph_delay_calc_->netCaps(drvr_pin, rf, dcalc_ap, pin_cap, wire_cap,
graph_delay_calc_->netCaps(drvr_pin, rf, scene, min_max, pin_cap, wire_cap,
fanout, has_wire_cap);
parasitic = parasitics_->estimatePiElmore(drvr_pin, rf, wireload,
fanout, pin_cap, corner,
cnst_min_max);
parasitic = parasitics->estimatePiElmore(drvr_pin, rf, wireload,
fanout, pin_cap,
scene, min_max);
}
return parasitic;
}
@ -259,21 +262,23 @@ DmpCeffTwoPoleDelayCalc::inputPortDelay(const Pin *,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
const Scene *scene,
const MinMax *min_max)
{
const Parasitics *parasitics = scene->parasitics(min_max);
ArcDcalcResult dcalc_result(load_pin_index_map.size());
ArcDelay wire_delay = 0.0;
Slew load_slew = in_slew;
LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
for (const auto [load_pin, load_idx] : load_pin_index_map) {
if (parasitics_->isPiPoleResidue(parasitic)) {
const Parasitic *pole_residue = parasitics_->findPoleResidue(parasitic, load_pin);
if (parasitics->isPiPoleResidue(parasitic)) {
const Parasitic *pole_residue = parasitics->findPoleResidue(parasitic, load_pin);
if (pole_residue) {
size_t pole_count = parasitics_->poleResidueCount(pole_residue);
size_t pole_count = parasitics->poleResidueCount(pole_residue);
if (pole_count >= 1) {
ComplexFloat pole1, residue1;
// Find the 1st (elmore) pole.
parasitics_->poleResidue(pole_residue, 0, pole1, residue1);
parasitics->poleResidue(pole_residue, 0, pole1, residue1);
if (pole1.imag() == 0.0
&& residue1.imag() == 0.0) {
float p1 = pole1.real();
@ -297,8 +302,10 @@ DmpCeffTwoPoleDelayCalc::gateDelay(const Pin *drvr_pin,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
parasitics_ = scene->parasitics(min_max);
const LibertyLibrary *drvr_library = arc->to()->libertyLibrary();
const RiseFall *rf = arc->toEdge()->asRiseFall();
vth_ = drvr_library->outputThreshold(rf);
@ -306,7 +313,7 @@ DmpCeffTwoPoleDelayCalc::gateDelay(const Pin *drvr_pin,
vh_ = drvr_library->slewUpperThreshold(rf);
slew_derate_ = drvr_library->slewDerateFromLibrary();
return DmpCeffDelayCalc::gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic,
load_pin_index_map, dcalc_ap) ;
load_pin_index_map, scene, min_max) ;
}
void

View File

@ -28,10 +28,10 @@
namespace sta {
typedef const std::function<void (double x,
using FindRootFunc = const std::function<void (double x,
// Return values.
double &y,
double &dy)> FindRootFunc;
double &dy)>;
double
findRoot(FindRootFunc func,

File diff suppressed because it is too large Load Diff

View File

@ -35,7 +35,6 @@
#include "Network.hh"
#include "Sdc.hh"
#include "Parasitics.hh"
#include "DcalcAnalysisPt.hh"
#include "GraphDelayCalc.hh"
#include "Variables.hh"
@ -64,35 +63,37 @@ LumpedCapDelayCalc::copy()
Parasitic *
LumpedCapDelayCalc::findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
Parasitic *parasitic = nullptr;
const Corner *corner = dcalc_ap->corner();
Parasitics *parasitics = scene->parasitics(min_max);
const Sdc *sdc = scene->sdc();
if (parasitics == nullptr
// set_load net has precedence over parasitics.
if (sdc_->drvrPinHasWireCap(drvr_pin, corner)
|| sdc->drvrPinHasWireCap(drvr_pin)
|| network_->direction(drvr_pin)->isInternal())
return nullptr;
const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
// Prefer PiElmore.
parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap);
parasitic = parasitics->findPiElmore(drvr_pin, rf, min_max);
if (parasitic)
return parasitic;
Parasitic *parasitic_network = parasitics_->findParasiticNetwork(drvr_pin,
parasitic_ap);
Parasitic *parasitic_network = parasitics->findParasiticNetwork(drvr_pin);
if (parasitic_network) {
parasitic = reduceParasitic(parasitic_network, drvr_pin, rf, dcalc_ap);
parasitic = reduceParasitic(parasitic_network, drvr_pin, rf, scene, min_max);
if (parasitic)
return parasitic;
}
const MinMax *min_max = dcalc_ap->constraintMinMax();
Wireload *wireload = sdc_->wireload(min_max);
Wireload *wireload = sdc->wireload(min_max);
if (wireload) {
float pin_cap, wire_cap, fanout;
bool has_net_load;
graph_delay_calc_->netCaps(drvr_pin, rf, dcalc_ap,
graph_delay_calc_->netCaps(drvr_pin, rf, scene, min_max,
pin_cap, wire_cap, fanout, has_net_load);
parasitic = parasitics_->estimatePiElmore(drvr_pin, rf, wireload, fanout,
pin_cap, corner, min_max);
parasitic = parasitics->estimatePiElmore(drvr_pin, rf, wireload, fanout,
pin_cap, scene, min_max);
}
return parasitic;
}
@ -101,14 +102,13 @@ Parasitic *
LumpedCapDelayCalc::reduceParasitic(const Parasitic *parasitic_network,
const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
const Corner *corner = dcalc_ap->corner();
const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
return parasitics_->reduceToPiElmore(parasitic_network, drvr_pin, rf,
corner, dcalc_ap->constraintMinMax(),
parasitic_ap);
Parasitics *parasitics = scene->parasitics(min_max);
return parasitics->reduceToPiElmore(parasitic_network, drvr_pin, rf,
scene, min_max);
}
ArcDcalcResult
@ -117,7 +117,8 @@ LumpedCapDelayCalc::inputPortDelay(const Pin *,
const RiseFall *rf,
const Parasitic *,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
const Scene *,
const MinMax *)
{
const LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
return makeResult(drvr_library,rf, 0.0, in_slew, load_pin_index_map);
@ -130,9 +131,10 @@ LumpedCapDelayCalc::gateDelay(const Pin *drvr_pin,
float load_cap,
const Parasitic *,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
GateTimingModel *model = arc->gateModel(dcalc_ap);
GateTimingModel *model = arc->gateModel(scene, min_max);
debugPrint(debug_, "delay_calc", 3,
" in_slew = %s load_cap = %s lumped",
delayAsString(in_slew, this),
@ -146,7 +148,7 @@ LumpedCapDelayCalc::gateDelay(const Pin *drvr_pin,
// NaNs cause seg faults during table lookup.
if (isnan(load_cap) || isnan(delayAsFloat(in_slew)))
report_->error(1350, "gate delay input variable is NaN");
model->gateDelay(pinPvt(drvr_pin, dcalc_ap), in_slew1, load_cap,
model->gateDelay(pinPvt(drvr_pin, scene, min_max), in_slew1, load_cap,
variables_->pocvEnabled(),
gate_delay, drvr_slew);
return makeResult(drvr_library, rf, gate_delay, drvr_slew, load_pin_index_map);
@ -182,14 +184,15 @@ LumpedCapDelayCalc::reportGateDelay(const Pin *check_pin,
float load_cap,
const Parasitic *,
const LoadPinIndexMap &,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
int digits)
{
GateTimingModel *model = arc->gateModel(dcalc_ap);
GateTimingModel *model = arc->gateModel(scene, min_max);
if (model) {
float in_slew1 = delayAsFloat(in_slew);
return model->reportGateDelay(pinPvt(check_pin, dcalc_ap), in_slew1, load_cap,
false, digits);
return model->reportGateDelay(pinPvt(check_pin, scene, min_max),
in_slew1, load_cap, false, digits);
}
return "";
}

View File

@ -38,32 +38,37 @@ public:
const char *name() const override { return "lumped_cap"; }
Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
bool reduceSupported() const override { return true; }
Parasitic *reduceParasitic(const Parasitic *parasitic_network,
const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
ArcDcalcResult inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
ArcDcalcResult gateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
std::string reportGateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
int digits) override;
protected:

View File

@ -25,7 +25,7 @@
#include "ParallelDelayCalc.hh"
#include "TimingArc.hh"
#include "Corner.hh"
#include "Scene.hh"
#include "Network.hh"
#include "Graph.hh"
#include "Sdc.hh"
@ -44,25 +44,28 @@ ParallelDelayCalc::ParallelDelayCalc(StaState *sta):
ArcDcalcResultSeq
ParallelDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
if (dcalc_args.size() == 1) {
ArcDcalcArg &dcalc_arg = dcalc_args[0];
ArcDcalcResult dcalc_result = gateDelay(dcalc_arg.drvrPin(), dcalc_arg.arc(),
dcalc_arg.inSlew(), dcalc_arg.loadCap(),
dcalc_arg.parasitic(),
load_pin_index_map, dcalc_ap);
load_pin_index_map,
scene, min_max);
ArcDcalcResultSeq dcalc_results;
dcalc_results.push_back(dcalc_result);
return dcalc_results;
}
return gateDelaysParallel(dcalc_args, load_pin_index_map, dcalc_ap);
return gateDelaysParallel(dcalc_args, load_pin_index_map, scene, min_max);
}
ArcDcalcResultSeq
ParallelDelayCalc::gateDelaysParallel(ArcDcalcArgSeq &dcalc_args,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
size_t drvr_count = dcalc_args.size();
ArcDcalcResultSeq dcalc_results(drvr_count);
@ -75,16 +78,16 @@ ParallelDelayCalc::gateDelaysParallel(ArcDcalcArgSeq &dcalc_args,
ArcDcalcResult &dcalc_result = dcalc_results[drvr_idx];
const Pin *drvr_pin = dcalc_arg.drvrPin();
const TimingArc *arc = dcalc_arg.arc();
Slew in_slew = dcalc_arg.inSlew();
const Slew &in_slew = dcalc_arg.inSlew();
ArcDcalcResult intrinsic_result = gateDelay(drvr_pin, arc, in_slew, 0.0, nullptr,
load_pin_index_map, dcalc_ap);
load_pin_index_map, scene, min_max);
ArcDelay intrinsic_delay = intrinsic_result.gateDelay();
intrinsic_delays[drvr_idx] = intrinsic_result.gateDelay();
ArcDcalcResult gate_result = gateDelay(drvr_pin, arc, in_slew, dcalc_arg.loadCap(),
dcalc_arg.parasitic(),
load_pin_index_map, dcalc_ap);
load_pin_index_map, scene, min_max);
ArcDelay gate_delay = gate_result.gateDelay();
Slew drvr_slew = gate_result.drvrSlew();
ArcDelay load_delay = gate_delay - intrinsic_delay;

View File

@ -38,11 +38,13 @@ public:
ParallelDelayCalc(StaState *sta);
ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &dcalc_args,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
protected:
ArcDcalcResultSeq gateDelaysParallel(ArcDcalcArgSeq &dcalc_args,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap);
const Scene *scene,
const MinMax *min_max);
};
} // namespace

View File

@ -33,8 +33,7 @@
#include "PortDirection.hh"
#include "Network.hh"
#include "Sdc.hh"
#include "DcalcAnalysisPt.hh"
#include "Corner.hh"
#include "Scene.hh"
#include "Graph.hh"
#include "Parasitics.hh"
#include "GraphDelayCalc.hh"
@ -64,9 +63,12 @@ makePrimaDelayCalc(StaState *sta)
PrimaDelayCalc::PrimaDelayCalc(StaState *sta) :
DelayCalcBase(sta),
dcalc_args_(nullptr),
scene_(nullptr),
min_max_(nullptr),
parasitics_(nullptr),
parasitic_network_(nullptr),
load_pin_index_map_(nullptr),
pin_node_map_(network_),
node_index_map_(ParasiticNodeLess(parasitics_, network_)),
prima_order_(3),
make_waveforms_(false),
waveform_drvr_pin_(nullptr),
@ -81,7 +83,7 @@ PrimaDelayCalc::PrimaDelayCalc(const PrimaDelayCalc &dcalc) :
dcalc_args_(nullptr),
load_pin_index_map_(nullptr),
pin_node_map_(network_),
node_index_map_(ParasiticNodeLess(parasitics_, network_)),
node_index_map_(dcalc.node_index_map_),
prima_order_(dcalc.prima_order_),
make_waveforms_(false),
waveform_drvr_pin_(nullptr),
@ -113,27 +115,26 @@ PrimaDelayCalc::copyState(const StaState *sta)
Parasitic *
PrimaDelayCalc::findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
const Corner *corner = dcalc_ap->corner();
const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
// set_load net has precidence over parasitics.
if (sdc_->drvrPinHasWireCap(drvr_pin, corner)
const Sdc *sdc = scene->sdc();
Parasitics *parasitics = scene->parasitics(min_max);
if (parasitics == nullptr
// set_load net has precedence over parasitics.
|| network_->direction(drvr_pin)->isInternal())
return nullptr;
Parasitic *parasitic = parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap);
Parasitic *parasitic = parasitics->findParasiticNetwork(drvr_pin);
if (parasitic)
return parasitic;
const MinMax *cnst_min_max = dcalc_ap->constraintMinMax();
Wireload *wireload = sdc_->wireload(cnst_min_max);
Wireload *wireload = sdc->wireload(min_max);
if (wireload) {
float pin_cap, wire_cap, fanout;
bool has_wire_cap;
graph_delay_calc_->netCaps(drvr_pin, rf, dcalc_ap, pin_cap, wire_cap,
graph_delay_calc_->netCaps(drvr_pin, rf, scene, min_max, pin_cap, wire_cap,
fanout, has_wire_cap);
parasitic = parasitics_->makeWireloadNetwork(drvr_pin, wireload,
fanout, cnst_min_max,
parasitic_ap);
parasitic = parasitics->makeWireloadNetwork(drvr_pin, wireload,
fanout, scene, min_max);
}
return parasitic;
}
@ -142,7 +143,8 @@ Parasitic *
PrimaDelayCalc::reduceParasitic(const Parasitic *,
const Pin *,
const RiseFall *,
const DcalcAnalysisPt *)
const Scene *,
const MinMax *)
{
return nullptr;
}
@ -153,18 +155,16 @@ PrimaDelayCalc::inputPortDelay(const Pin *drvr_pin,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
Parasitics *parasitics = scene->parasitics(min_max);
ArcDcalcResult dcalc_result(load_pin_index_map.size());
LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
const Parasitic *pi_elmore = nullptr;
if (parasitic && parasitics_->isParasiticNetwork(parasitic)) {
const ParasiticAnalysisPt *ap = dcalc_ap->parasiticAnalysisPt();
pi_elmore = parasitics_->reduceToPiElmore(parasitic, drvr_pin, rf,
dcalc_ap->corner(),
dcalc_ap->constraintMinMax(), ap);
}
if (parasitic && parasitics->isParasiticNetwork(parasitic))
pi_elmore = parasitics->reduceToPiElmore(parasitic, drvr_pin, rf,
scene, min_max);
for (auto load_pin_index : load_pin_index_map) {
const Pin *load_pin = load_pin_index.first;
@ -174,7 +174,7 @@ PrimaDelayCalc::inputPortDelay(const Pin *drvr_pin,
bool elmore_exists = false;
float elmore = 0.0;
if (pi_elmore)
parasitics_->findElmore(pi_elmore, load_pin, elmore, elmore_exists);
parasitics->findElmore(pi_elmore, load_pin, elmore, elmore_exists);
if (elmore_exists)
// Input port with no external driver.
dspfWireDelaySlew(load_pin, rf, in_slew, elmore, wire_delay, load_slew);
@ -192,33 +192,38 @@ PrimaDelayCalc::gateDelay(const Pin *drvr_pin,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
ArcDcalcArgSeq dcalc_args;
dcalc_args.emplace_back(nullptr, drvr_pin, nullptr, arc, in_slew, load_cap, parasitic);
ArcDcalcResultSeq dcalc_results = gateDelays(dcalc_args, load_pin_index_map, dcalc_ap);
ArcDcalcResultSeq dcalc_results = gateDelays(dcalc_args, load_pin_index_map,
scene, min_max);
return dcalc_results[0];
}
ArcDcalcResultSeq
PrimaDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
const Scene *scene,
const MinMax *min_max)
{
dcalc_args_ = &dcalc_args;
load_pin_index_map_ = &load_pin_index_map;
drvr_count_ = dcalc_args.size();
dcalc_ap_ = dcalc_ap;
scene_ = scene;
min_max_ = min_max;
drvr_rf_ = dcalc_args[0].arc()->toEdge()->asRiseFall();
parasitic_network_ = dcalc_args[0].parasitic();
load_cap_ = dcalc_args[0].loadCap();
parasitics_ = scene->parasitics(min_max);
node_index_map_ = NodeIndexMap(ParasiticNodeLess(parasitics_, network_));
bool failed = false;
output_waveforms_.resize(drvr_count_);
const DcalcAnalysisPtSeq &dcalc_aps = corners_->dcalcAnalysisPts();
for (size_t drvr_idx = 0; drvr_idx < drvr_count_; drvr_idx++) {
ArcDcalcArg &dcalc_arg = dcalc_args[drvr_idx];
GateTableModel *table_model = dcalc_arg.arc()->gateTableModel(dcalc_ap);
GateTableModel *table_model = dcalc_arg.arc()->gateTableModel(scene, min_max);
if (table_model && dcalc_arg.parasitic()) {
OutputWaveforms *output_waveforms = table_model->outputWaveforms();
float in_slew = dcalc_arg.inSlewFlt();
@ -236,7 +241,7 @@ PrimaDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args,
drvr_library->supplyVoltage("VDD", vdd_, vdd_exists);
if (!vdd_exists)
report_->error(1720, "VDD not defined in library %s", drvr_library->name());
drvr_cell->ensureVoltageWaveforms(dcalc_aps);
drvr_cell->ensureVoltageWaveforms(scenes_);
if (drvr_idx == 0) {
vth_ = drvr_library->outputThreshold(drvr_rf_) * vdd_;
vl_ = drvr_library->slewLowerThreshold(drvr_rf_) * vdd_;
@ -266,11 +271,13 @@ PrimaDelayCalc::tableDcalcResults()
const Pin *drvr_pin = dcalc_arg.drvrPin();
if (drvr_pin) {
const RiseFall *rf = dcalc_arg.drvrEdge();
const Parasitic *parasitic = table_dcalc_->findParasitic(drvr_pin, rf, dcalc_ap_);
const Parasitic *parasitic = table_dcalc_->findParasitic(drvr_pin, rf,
scene_, min_max_);
dcalc_arg.setParasitic(parasitic);
}
}
return table_dcalc_->gateDelays(*dcalc_args_, *load_pin_index_map_, dcalc_ap_);
return table_dcalc_->gateDelays(*dcalc_args_, *load_pin_index_map_,
scene_, min_max_);
}
void
@ -388,8 +395,7 @@ PrimaDelayCalc::driverResistance()
{
const Pin *drvr_pin = (*dcalc_args_)[0].drvrPin();
LibertyPort *drvr_port = network_->libertyPort(drvr_pin);
const MinMax *min_max = dcalc_ap_->delayMinMax();
return drvr_port->driveResistance(drvr_rf_, min_max);
return drvr_port->driveResistance(drvr_rf_, min_max_);
}
void
@ -458,17 +464,16 @@ PrimaDelayCalc::pinCapacitance(ParasiticNode *node)
{
const Pin *pin = parasitics_->pin(node);
float pin_cap = 0.0;
const Sdc *sdc = scene_->sdc();
if (pin) {
Port *port = network_->port(pin);
LibertyPort *lib_port = network_->libertyPort(port);
const Corner *corner = dcalc_ap_->corner();
const MinMax *cnst_min_max = dcalc_ap_->constraintMinMax();
if (lib_port) {
if (!includes_pin_caps_)
pin_cap = sdc_->pinCapacitance(pin, drvr_rf_, corner, cnst_min_max);
pin_cap = sdc->pinCapacitance(pin, drvr_rf_, scene_, min_max_);
}
else if (network_->isTopLevelPort(pin))
pin_cap = sdc_->portExtCap(port, drvr_rf_, corner, cnst_min_max);
pin_cap = sdc->portExtCap(port, drvr_rf_, min_max_);
}
return pin_cap;
}
@ -910,14 +915,15 @@ PrimaDelayCalc::reportGateDelay(const Pin *drvr_pin,
float load_cap,
const Parasitic *,
const LoadPinIndexMap &,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
int digits)
{
GateTimingModel *model = arc->gateModel(dcalc_ap);
GateTimingModel *model = arc->gateModel(scene, min_max);
if (model) {
float in_slew1 = delayAsFloat(in_slew);
return model->reportGateDelay(pinPvt(drvr_pin, dcalc_ap), in_slew1, load_cap,
false, digits);
return model->reportGateDelay(pinPvt(drvr_pin, scene, min_max),
in_slew1, load_cap, false, digits);
}
return "";
}
@ -954,8 +960,8 @@ PrimaDelayCalc::watchWaveform(const Pin *pin)
{
FloatSeq &voltages = watch_pin_values_[pin];
TableAxisPtr time_axis = make_shared<TableAxis>(TableAxisVariable::time,
new FloatSeq(times_));
Table1 waveform(new FloatSeq(voltages), time_axis);
FloatSeq(times_));
Table waveform(new FloatSeq(voltages), time_axis);
return waveform;
}

View File

@ -29,7 +29,6 @@
#include <Eigen/SparseCore>
#include <Eigen/SparseLU>
#include "Map.hh"
#include "LumpedCapDelayCalc.hh"
#include "ArcDcalcWaveforms.hh"
#include "Parasitics.hh"
@ -38,16 +37,16 @@ namespace sta {
class ArcDelayCalc;
class StaState;
class Corner;
class Scene;
typedef Map<const Pin*, size_t, PinIdLess> PinNodeMap;
typedef std::map<const ParasiticNode*, size_t, ParasiticNodeLess> NodeIndexMap;
typedef Map<const Pin*, size_t> PortIndexMap;
typedef Eigen::SparseMatrix<double> MatrixSd;
typedef Map<const Pin*, Eigen::VectorXd, PinIdLess> PinLMap;
typedef std::map<const Pin*, FloatSeq, PinIdLess> WatchPinValuesMap;
using PinNodeMap = std::map<const Pin*, size_t, PinIdLess>;
using NodeIndexMap = std::map<const ParasiticNode*, size_t, ParasiticNodeLess>;
using PortIndexMap = std::map<const Pin*, size_t>;
using MatrixSd = Eigen::SparseMatrix<double>;
using PinLMap = std::map<const Pin*, Eigen::VectorXd, PinIdLess>;
using WatchPinValuesMap = std::map<const Pin*, FloatSeq, PinIdLess>;
typedef Table1 Waveform;
using Waveform = Table;
ArcDelayCalc *
makePrimaDelayCalc(StaState *sta);
@ -65,35 +64,41 @@ public:
void setPrimaReduceOrder(size_t order);
Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
bool reduceSupported() const override { return false; }
Parasitic *reduceParasitic(const Parasitic *parasitic_network,
const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
ArcDcalcResult inputPortDelay(const Pin *drvr_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
ArcDcalcResult gateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &dcalc_args,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
std::string reportGateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
int digits) override;
// Record waveform for drvr/load pin.
@ -147,7 +152,7 @@ protected:
const Pin *drvr_pin,
const RiseFall *drvr_rf,
const Pin *load_pin,
const Corner *corner,
const Scene *scene,
const MinMax *min_max);
void primaReduce();
void primaReduce2();
@ -168,7 +173,9 @@ protected:
ArcDcalcArgSeq *dcalc_args_;
size_t drvr_count_;
float load_cap_;
const DcalcAnalysisPt *dcalc_ap_;
const Scene *scene_;
const MinMax *min_max_;
Parasitics *parasitics_;
const Parasitic *parasitic_network_;
const RiseFall *drvr_rf_;
const LoadPinIndexMap *load_pin_index_map_;
@ -243,4 +250,4 @@ protected:
using ArcDelayCalc::reduceParasitic;
};
} // namespacet
} // namespace

View File

@ -50,7 +50,8 @@ UnitDelayCalc::copy()
Parasitic *
UnitDelayCalc::findParasitic(const Pin *,
const RiseFall *,
const DcalcAnalysisPt *)
const Scene *,
const MinMax *)
{
return nullptr;
}
@ -59,7 +60,8 @@ Parasitic *
UnitDelayCalc::reduceParasitic(const Parasitic *,
const Pin *,
const RiseFall *,
const DcalcAnalysisPt *)
const Scene *,
const MinMax *)
{
return nullptr;
}
@ -67,20 +69,22 @@ UnitDelayCalc::reduceParasitic(const Parasitic *,
void
UnitDelayCalc::reduceParasitic(const Parasitic *,
const Net *,
const Corner *,
const Scene *,
const MinMaxAll *)
{
}
void
UnitDelayCalc::setDcalcArgParasiticSlew(ArcDcalcArg &,
const DcalcAnalysisPt *)
const Scene *,
const MinMax *)
{
}
void
UnitDelayCalc::setDcalcArgParasiticSlew(ArcDcalcArgSeq &,
const DcalcAnalysisPt *)
const Scene *,
const MinMax *)
{
}
@ -90,7 +94,8 @@ UnitDelayCalc::inputPortDelay(const Pin *,
const RiseFall *,
const Parasitic *,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
const Scene *,
const MinMax *)
{
return unitDelayResult(load_pin_index_map);
}
@ -102,7 +107,8 @@ UnitDelayCalc::gateDelay(const Pin *,
float,
const Parasitic *,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
const Scene *,
const MinMax *)
{
return unitDelayResult(load_pin_index_map);
}
@ -110,7 +116,8 @@ UnitDelayCalc::gateDelay(const Pin *,
ArcDcalcResultSeq
UnitDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
const Scene *,
const MinMax *)
{
size_t drvr_count = dcalc_args.size();
ArcDcalcResultSeq dcalc_results(drvr_count);
@ -142,7 +149,8 @@ UnitDelayCalc::reportGateDelay(const Pin *,
float,
const Parasitic *,
const LoadPinIndexMap &,
const DcalcAnalysisPt *,
const Scene *,
const MinMax *,
int)
{
string result("Delay = 1.0\n");
@ -156,7 +164,8 @@ UnitDelayCalc::checkDelay(const Pin *,
const Slew &,
const Slew &,
float,
const DcalcAnalysisPt *)
const Scene *,
const MinMax *)
{
return units_->timeUnit()->scale();
}
@ -168,7 +177,8 @@ UnitDelayCalc::reportCheckDelay(const Pin *,
const char *,
const Slew &,
float,
const DcalcAnalysisPt *,
const Scene *,
const MinMax *,
int)
{
return "Check = 1.0\n";

View File

@ -37,26 +37,31 @@ public:
const char *name() const override { return "unit"; }
Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
bool reduceSupported() const override { return false; }
Parasitic *reduceParasitic(const Parasitic *parasitic_network,
const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
void reduceParasitic(const Parasitic *parasitic_network,
const Net *net,
const Corner *corner,
const Scene *scene,
const MinMaxAll *min_max) override;
void setDcalcArgParasiticSlew(ArcDcalcArg &gate,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
void setDcalcArgParasiticSlew(ArcDcalcArgSeq &gates,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
ArcDcalcResult inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
ArcDcalcResult gateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
@ -64,23 +69,27 @@ public:
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &args,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
ArcDelay checkDelay(const Pin *check_pin,
const TimingArc *arc,
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
const DcalcAnalysisPt *dcalc_ap) override;
const Scene *scene,
const MinMax *min_max) override;
std::string reportGateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
int digits) override;
std::string reportCheckDelay(const Pin *check_pin,
const TimingArc *arc,
@ -88,7 +97,8 @@ public:
const char *from_slew_annotation,
const Slew &to_slew,
float related_out_cap,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
int digits) override;
void finishDrvrPin() override;

File diff suppressed because it is too large Load Diff

View File

@ -24,6 +24,44 @@
This file summarizes STA API changes for each release.
Release 3.0.0 2025/01/03
------------------------
OpenSTA now requires c++ 20.
Corner replaced by Scene
mode()
parasitics(min_max)
DcalcAnalysisPt replaced by scene/min_min
PathAnalysisPt replaced by scene/min_min
StaState::sdc_ moved to Mode
StaState::sim_ moved to Mode
StaState::clk_network__ moved to Mode
StaState::parasitics_ moved to Scene
Sta::findPathEnds group_paths arg has been changed from PathGroupNameSet*
to StdStringSeq&.
Sta::isClock has been removed. Use mode->clkNetwork()->isClock instead.
Sta::vertexSlew renamed to slew
Sta::vertexSlack renamed to slack
Sta::vertexSlacks renamed to slacks
Sta::vertexArrival renamed to arrival
Sta::vertexRequired renamed to required
Sta::pinSlack renamed to slack
Sta::pinArrival renamed to arrival
FuncExpr::Operator::op_* renamed to FuncExpr::Op::*
FuncExprPortIterator has been removed. Use FuncExpr::ports().
Sdc::clocks() now returns ClockSeq&.
Sdc::clks() has been removed.
The Vector/Map/Set/UnorderedSet classes have been removed and replaced by
the std containers. The member functions are now templated functions found
in ContainerHelpers.hh.
Release 2.6.2 2025/03/30
------------------------

View File

@ -3,6 +3,180 @@ OpenSTA Timing Analyzer Release Notes
This file summarizes user visible changes for each release.
Release 3.0.0 2025/11/26
------------------------
This release adds multi-corner multi-mode (mcmm) support. The SDC
constraints in each mode describe a different operating mode, such as
mission mode or scan mode.
A "scene" is the combination of a mode and corner. Each scene can have
separate min/max liberty and spef files.
THe basic structure of a multi-corner/multi-mode command file is
read_liberty
read_verilog
link_design
read_sdc -mode... or set_mode followed by sdc commands
read_spef -name...
define_scene...
report_checks [-scenes]
This is an example script with 2 corners, 2 modes and 3 scenes.
read_liberty bc.lib
read_liberty wc.lib
read_verilog design.v
link_design top
read_sdc -mode run design.sdc
read_sdc -mode scan design_scan.sdc
read_spef -name bc bc.spef
read_spef -name wc wc.spef
define_scene bc \
-mode run \
-liberty bc \
-spef bc
define_scene wc \
-mode run \
-liberty wc \
-spef wc
define_scene scan \
-mode scan \
-liberty wc \
-spef wc
report_checks
report_checks -scenes bc
report_checks -scenes wc
report_checks -scenes scan
................
Alternatively, the set_mode command can be used to define commands
for each mode at the command level instead of using SDC files.
set_mode run
create_clock -period 10 clock
set_input_delay 0 -clock clock [all_inputs -no_clocks]
set_output_delay 0 -clock clock [all_outputs]
set_mode scan
create_clock -period 100 scan_clock
set_input_delay 0 -clock scan_clock scan_in
set_output_delay 0 -clock scan_clock scan_out
................
The define_corners command is supported for compatiblity but should
not be used with mcmm flows. Similarly, the -min/-max arguemnts to
read_liberty and read_spaf are supported for compabibility but should
not be used with mcmm flows.
................
An initial mode and scene named "default" are defined for single mode,
single corner analysis. SDC commands defined interactively and read
with read_sdc without a -mode argument are defined in the "default"
mode.
Use the set_mode command to define a mode or set the command
interpreter to add following commands to mode mode_name.
set_mode mode_name
If mode_name does not exist it is created. When modes are created the
default mode is deleted.
The read_sdc command has a -mode argument to assign the commands in the file
to a mode.
read_sdc [-mode mode_name]
If the mode does not exist it is created. Multiple SDC files can
append commands to a mode by using the -mode_name argument for each
one. If no -mode arguement is is used the commands are added to the
current mode.
................
The define_scene command defines a scene for a mode (SDC), liberty files
and spef parasitics.
define_scene -mode mode_name
-liberty liberty_files | -liberty_min liberty_min_files -liberty_max liberty_max_files
[-spef spef_file | -spef_min spef_min_file -spef_max spef_max_file]
Use get_scenes to find defined scenes.
get_scenes [-modes mode_names] scene_name
................
Use the read_spef -name argument to append multiple parasitics files
to annotate hierarchical blocks. Scene definitions use the spef_name
to specify which parasitices to use for each scene.
read_spef -name spef_name
report_parasitic_annotation [-name spef_name]
If -name is omitted the base name of the file name is used.
The read_spef -corner/-min/-max arguments are supported for comppatibility
but will be removed in a future release.
The read_spef -reduce options don't work because sdc, liberty ap isn't known
................
The report_checks and report_check_typescommands support a -scenes
argument to report timing checks/paths from multiple scenes.
report_checks -scenes
report_check_types -scenes
report_slews -scenes
report_clock_latency -scenes
................
To annotate delays with SDF when there are multiple scenes, use
the -scene argument.
read_sdf -scene
report_annotated_delay -scene
report_annotated_check -scene
SDF annotation for mcmm analysis must follow the scene definitions.
................
VCD annotation with read_vcd now supports a -mode arguement.
read_vcd [-mode mode_name]
................
The -corner args has been removed from the following commands because they are no
longer necessary.
set_load -corner
set_port_fanout_number -corner
................
The report_pulse_width_checks command is no longer supported. Use
report_check_types -min_pulse_width.
................
Delay calculation slew values now propagate through set_case_analysis
and set_logic_zero, set_logic_one, set_logic_dc constraints.
Power analysis now ignores set_case_analysis and set_logic_zero,
set_logic_one, set_logic_dc.
Release 2.7.0 2025/05/19
-------------------------
@ -19,6 +193,9 @@ to remove paths through identical pins and rise/fall edges.
Instances now have pins for verilog netlist power/ground connections,
Sta::findPathEnds group_paths arg has been changed from PathGroupNameSet*
to StdStringSeq&.
Release 2.6.1 2025/03/30
-------------------------
@ -93,6 +270,8 @@ timing groups.
report_clock_skew -include_internal_latency
report_clock_latency -include_internal_latency
The report_clock_skew requires a -scene argument if multiple scenes are defined.
The all_inputs command now supports the -no_clocks argument to exclude
clocks from the list.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

2
examples/mcmm2_mode1.sdc Normal file
View File

@ -0,0 +1,2 @@
create_clock -name m1_clk -period 1000 {clk1 clk2 clk3}
set_input_delay -clock m1_clk 100 {in1 in2}

2
examples/mcmm2_mode2.sdc Normal file
View File

@ -0,0 +1,2 @@
create_clock -name m2_clk -period 500 {clk1 clk3}
set_output_delay -clock m2_clk 100 out

18
examples/mcmm3.tcl Normal file
View File

@ -0,0 +1,18 @@
# mmcm reg1 parasitics
read_liberty asap7_small_ff.lib.gz
read_liberty asap7_small_ss.lib.gz
read_verilog reg1_asap7.v
link_design top
read_sdc -mode mode1 mcmm2_mode1.sdc
read_sdc -mode mode2 mcmm2_mode2.sdc
read_spef -name reg1_ff reg1_asap7.spef
read_spef -name reg1_ss reg1_asap7_ss.spef
define_scene scene1 -mode mode1 -liberty asap7_small_ff -spef reg1_ff
define_scene scene2 -mode mode2 -liberty asap7_small_ss -spef reg1_ss
report_checks -scenes scene1
report_checks -scenes scene2
report_checks -group_path_count 4

View File

@ -1,15 +1,20 @@
# 3 corners with +/- 10% derating example
define_corners ss tt ff
read_liberty -corner ss nangate45_slow.lib.gz
read_liberty -corner tt nangate45_typ.lib.gz
read_liberty -corner ff nangate45_fast.lib.gz
# 3 liberty corners with +/- 10% derating example
read_liberty nangate45_slow.lib.gz
read_liberty nangate45_typ.lib.gz
read_liberty nangate45_fast.lib.gz
read_verilog example1.v
link_design top
set_timing_derate -early 0.9
set_timing_derate -late 1.1
create_clock -name clk -period 10 {clk1 clk2 clk3}
set_input_delay -clock clk 0 {in1 in2}
# report all corners
define_scene ss -liberty nangate45_slow
define_scene tt -liberty nangate45_typ
define_scene ff -liberty nangate45_fast
# report all scenes
report_checks -path_delay min_max
# report typical corner
report_checks -corner tt
# report typical scene
report_checks -scene tt

135
examples/reg1_asap7.spef Normal file
View File

@ -0,0 +1,135 @@
*SPEF "IEEE 1481-1998"
*DESIGN "reg1"
*DATE "Fri Nov 20 13:23:00 2002"
*VENDOR "Parallax Software, Inc"
*PROGRAM "Handjob"
*VERSION "1.0.1c"
*DESIGN_FLOW "MISSING_NETS"
*DIVIDER /
*DELIMITER :
*BUS_DELIMITER [ ]
*T_UNIT 1.0 PS
*C_UNIT 1.0 FF
*R_UNIT 1.0 KOHM
*L_UNIT 1.0 UH
*POWER_NETS VDD
*GROUND_NETS VSS
*PORTS
in1 I
in2 I
clk1 I
clk2 I
clk3 I
out O
*D_NET in1 13.4
*CONN
*P in1 I
*I r1:D I *L .0036
*CAP
1 in1 6.7
2 r1:D 6.7
*RES
3 in1 r1:D 2.42
*END
*D_NET in2 13.4
*CONN
*P in2 I
*I r2:D I *L .0036
*CAP
1 in2 6.7
2 r2:D 6.7
*RES
3 in2 r2:D 2.42
*END
*D_NET clk1 13.4
*CONN
*P clk1 I
*I r1:CLK I *L .0036
*CAP
1 clk1 6.7
2 r1:CLK 6.7
*RES
3 clk1 r1:CLK 2.42
*END
*D_NET clk2 13.4
*CONN
*P clk2 I
*I r2:CLK I *L .0036
*CAP
1 clk2 6.7
2 r2:CLK 6.7
*RES
3 clk2 r2:CLK 2.42
*END
*D_NET clk3 13.4
*CONN
*P clk3 I
*I r3:CLK I *L .0036
*CAP
1 clk3 6.7
2 r3:CLK 6.7
*RES
3 clk3 r3:CLK 2.42
*END
*D_NET r1q 13.4
*CONN
*I r1:Q O
*I u2:A I *L .0086
*CAP
1 r1:Q 6.7
2 u2:A 6.7
*RES
3 r1:Q u2:A 2.42
*END
*D_NET r2q 13.4
*CONN
*I r2:Q O
*I u1:A I *L .0086
*CAP
1 r2:Q 6.7
2 u1:A 6.7
*RES
3 r2:Q u1:A 2.42
*END
*D_NET u1z 13.4
*CONN
*I u1:Y O
*I u2:B I *L .0086
*CAP
1 u1:Y 6.7
2 u2:B 6.7
*RES
3 u1:Y u2:B 2.42
*END
*D_NET u2z 13.4
*CONN
*I u2:Y O
*I r3:D I *L .0086
*CAP
1 u2:Y 6.7
2 r3:D 6.7
*RES
3 u2:Y r3:D 2.42
*END
*D_NET out 13.4
*CONN
*I r3:Q O
*P out O
*CAP
1 r3:Q 6.7
2 out 6.7
*RES
3 r3:Q out 2.42
*END

11
examples/reg1_asap7.v Normal file
View File

@ -0,0 +1,11 @@
module top (in1, in2, clk1, clk2, clk3, out);
input in1, in2, clk1, clk2, clk3;
output out;
wire r1q, r2q, u1z, u2z;
DFFHQx4_ASAP7_75t_R r1 (.D(in1), .CLK(clk1), .Q(r1q));
DFFHQx4_ASAP7_75t_R r2 (.D(in2), .CLK(clk2), .Q(r2q));
BUFx2_ASAP7_75t_R u1 (.A(r2q), .Y(u1z));
AND2x2_ASAP7_75t_R u2 (.A(r1q), .B(u1z), .Y(u2z));
DFFHQx4_ASAP7_75t_R r3 (.D(u2z), .CLK(clk3), .Q(out));
endmodule // top

135
examples/reg1_asap7_ss.spef Normal file
View File

@ -0,0 +1,135 @@
*SPEF "IEEE 1481-1998"
*DESIGN "reg1"
*DATE "Fri Nov 20 13:23:00 2002"
*VENDOR "Parallax Software, Inc"
*PROGRAM "Handjob"
*VERSION "1.0.1c"
*DESIGN_FLOW "MISSING_NETS"
*DIVIDER /
*DELIMITER :
*BUS_DELIMITER [ ]
*T_UNIT 1.0 PS
*C_UNIT 1.0 FF
*R_UNIT 1.0 KOHM
*L_UNIT 1.0 UH
*POWER_NETS VDD
*GROUND_NETS VSS
*PORTS
in1 I
in2 I
clk1 I
clk2 I
clk3 I
out O
*D_NET in1 13.4
*CONN
*P in1 I
*I r1:D I *L .0036
*CAP
1 in1 8.1
2 r1:D 8.1
*RES
3 in1 r1:D 2.7
*END
*D_NET in2 13.4
*CONN
*P in2 I
*I r2:D I *L .0036
*CAP
1 in2 8.1
2 r2:D 8.1
*RES
3 in2 r2:D 2.7
*END
*D_NET clk1 13.4
*CONN
*P clk1 I
*I r1:CLK I *L .0036
*CAP
1 clk1 8.1
2 r1:CLK 8.1
*RES
3 clk1 r1:CLK 2.7
*END
*D_NET clk2 13.4
*CONN
*P clk2 I
*I r2:CLK I *L .0036
*CAP
1 clk2 8.1
2 r2:CLK 8.1
*RES
3 clk2 r2:CLK 2.7
*END
*D_NET clk3 13.4
*CONN
*P clk3 I
*I r3:CLK I *L .0036
*CAP
1 clk3 8.1
2 r3:CLK 8.1
*RES
3 clk3 r3:CLK 2.7
*END
*D_NET r1q 13.4
*CONN
*I r1:Q O
*I u2:A I *L .0086
*CAP
1 r1:Q 8.1
2 u2:A 8.1
*RES
3 r1:Q u2:A 2.7
*END
*D_NET r2q 13.4
*CONN
*I r2:Q O
*I u1:A I *L .0086
*CAP
1 r2:Q 8.1
2 u1:A 8.1
*RES
3 r2:Q u1:A 2.7
*END
*D_NET u1z 13.4
*CONN
*I u1:Y O
*I u2:B I *L .0086
*CAP
1 u1:Y 8.1
2 u2:B 8.1
*RES
3 u1:Y u2:B 2.7
*END
*D_NET u2z 13.4
*CONN
*I u2:Y O
*I r3:D I *L .0086
*CAP
1 u2:Y 8.1
2 r3:D 8.1
*RES
3 u2:Y r3:D 2.7
*END
*D_NET out 13.4
*CONN
*I r3:Q O
*P out O
*CAP
1 r3:Q 8.1
2 out 8.1
*RES
3 r3:Q out 2.7
*END

View File

@ -24,6 +24,7 @@
#include "Graph.hh"
#include "ContainerHelpers.hh"
#include "Debug.hh"
#include "Stats.hh"
#include "MinMax.hh"
@ -34,7 +35,6 @@
#include "Liberty.hh"
#include "PortDirection.hh"
#include "Network.hh"
#include "DcalcAnalysisPt.hh"
#include "FuncExpr.hh"
namespace sta {
@ -56,7 +56,7 @@ Graph::Graph(StaState *sta,
slew_rf_count_(slew_rf_count),
ap_count_(ap_count),
period_check_annotations_(nullptr),
reg_clk_vertices_(new VertexSet(graph_))
reg_clk_vertices_(makeVertexSet(this))
{
// For the benifit of reg_clk_vertices_ that references graph_.
graph_ = this;
@ -68,7 +68,6 @@ Graph::~Graph()
delete edges_;
vertices_->clear();
delete vertices_;
delete reg_clk_vertices_;
removePeriodCheckAnnotations();
}
@ -254,7 +253,7 @@ Graph::makeInstDrvrWireEdges(const Instance *inst,
while (pin_iter->hasNext()) {
Pin *pin = pin_iter->next();
if (network_->isDriver(pin)
&& !visited_drvrs.hasKey(pin))
&& !visited_drvrs.contains(pin))
makeWireEdgesFromPin(pin, visited_drvrs);
}
delete pin_iter;
@ -391,6 +390,13 @@ Graph::makeWireEdge(const Pin *from_pin,
}
}
void
Graph::makeSceneAfter()
{
ap_count_ = dcalcAnalysisPtCount();
initSlews();
}
////////////////////////////////////////////////////////////////
Vertex *
@ -440,7 +446,7 @@ Graph::makeVertex(Pin *pin,
vertex->init(pin, is_bidirect_drvr, is_reg_clk);
initSlews(vertex);
if (is_reg_clk)
reg_clk_vertices_->insert(vertex);
reg_clk_vertices_.insert(vertex);
return vertex;
}
@ -452,7 +458,7 @@ Graph::pinVertices(const Pin *pin,
{
vertex = Graph::vertex(network_->vertexId(pin));
if (network_->direction(pin)->isBidirect())
bidirect_drvr_vertex = pin_bidirect_drvr_vertex_map_.findKey(pin);
bidirect_drvr_vertex = findKey(pin_bidirect_drvr_vertex_map_, pin);
else
bidirect_drvr_vertex = nullptr;
}
@ -461,7 +467,7 @@ Vertex *
Graph::pinDrvrVertex(const Pin *pin) const
{
if (network_->direction(pin)->isBidirect())
return pin_bidirect_drvr_vertex_map_.findKey(pin);
return findKey(pin_bidirect_drvr_vertex_map_, pin);
else
return Graph::vertex(network_->vertexId(pin));
}
@ -476,7 +482,7 @@ void
Graph::deleteVertex(Vertex *vertex)
{
if (vertex->isRegClk())
reg_clk_vertices_->erase(vertex);
reg_clk_vertices_.erase(vertex);
Pin *pin = vertex->pin_;
if (vertex->isBidirectDriver())
pin_bidirect_drvr_vertex_map_.erase(pin_bidirect_drvr_vertex_map_
@ -574,30 +580,6 @@ Graph::gateEdgeArc(const Pin *in_pin,
////////////////////////////////////////////////////////////////
Path *
Graph::makePaths(Vertex *vertex,
uint32_t count)
{
Path *paths = new Path[count];
vertex->setPaths(paths);
return paths;
}
Path *
Graph::paths(const Vertex *vertex) const
{
return vertex->paths();
}
void
Graph::deletePaths(Vertex *vertex)
{
vertex->setPaths(nullptr);
vertex->tag_group_index_ = tag_group_index_max;
}
////////////////////////////////////////////////////////////////
const Slew &
Graph::slew(const Vertex *vertex,
const RiseFall *rf,
@ -831,19 +813,6 @@ Graph::initArcDelays(Edge *edge)
arc_delays[i] = 0.0;
}
bool
Graph::delayAnnotated(Edge *edge)
{
TimingArcSet *arc_set = edge->timingArcSet();
for (TimingArc *arc : arc_set->arcs()) {
for (DcalcAPIndex ap_index = 0; ap_index < ap_count_; ap_index++) {
if (!arcDelayAnnotated(edge, arc, ap_index))
return false;
}
}
return true;
}
////////////////////////////////////////////////////////////////
void
@ -906,7 +875,7 @@ Graph::periodCheckAnnotation(const Pin *pin,
{
exists = false;
if (period_check_annotations_) {
float *periods = period_check_annotations_->findKey(pin);
float *periods = findKey(period_check_annotations_, pin);
if (periods) {
period = periods[ap_index];
if (period >= 0.0)
@ -922,7 +891,7 @@ Graph::setPeriodCheckAnnotation(const Pin *pin,
{
if (period_check_annotations_ == nullptr)
period_check_annotations_ = new PeriodCheckAnnotations(network_);
float *periods = period_check_annotations_->findKey(pin);
float *periods = findKey(period_check_annotations_, pin);
if (periods == nullptr) {
periods = new float[ap_count_];
// Use negative (illegal) period values to indicate unannotated checks.
@ -986,16 +955,13 @@ Vertex::init(Pin *pin,
paths_ = nullptr;
tag_group_index_ = tag_group_index_max;
slew_annotated_ = false;
sim_value_ = unsigned(LogicValue::unknown);
is_disabled_constraint_ = false;
is_gated_clk_enable_ = false;
has_checks_ = false;
is_check_clk_ = false;
is_constrained_ = false;
has_downstream_clk_pin_ = false;
level_ = 0;
visited1_ = false;
visited2_ = false;
has_sim_value_ = false;
bfs_in_queue_ = 0;
}
@ -1082,11 +1048,17 @@ Vertex::setSlews(Slew *slews)
slews_ = slews;
}
void
Vertex::setHasSimValue(bool has_sim)
{
has_sim_value_ = has_sim;
}
bool
Vertex::slewAnnotated(const RiseFall *rf,
const MinMax *min_max) const
{
int index = min_max->index() * transitionCount() + rf->index();
int index = min_max->index() * RiseFall::index_count+ rf->index();
return ((1 << index) & slew_annotated_) != 0;
}
@ -1105,7 +1077,7 @@ Vertex::setSlewAnnotated(bool annotated,
// only rise/fall.
if (ap_index > 1)
ap_index = 0;
int index = ap_index * transitionCount() + rf->index();
int index = ap_index * RiseFall::index_count + rf->index();
if (annotated)
slew_annotated_ |= (1 << index);
else
@ -1130,6 +1102,15 @@ Vertex::setTagGroupIndex(TagGroupIndex tag_index)
tag_group_index_ = tag_index;
}
Path *
Vertex::makePaths(uint32_t count)
{
delete [] paths_;
Path *paths = new Path[count];
paths_ = paths;
return paths;
}
void
Vertex::setPaths(Path *paths)
{
@ -1137,30 +1118,12 @@ Vertex::setPaths(Path *paths)
paths_ = paths;
}
LogicValue
Vertex::simValue() const
{
return static_cast<LogicValue>(sim_value_);
}
void
Vertex::setSimValue(LogicValue value)
Vertex::deletePaths()
{
sim_value_ = unsigned(value);
}
bool
Vertex::isConstant() const
{
LogicValue value = static_cast<LogicValue>(sim_value_);
return value == LogicValue::zero
|| value == LogicValue::one;
}
void
Vertex::setIsDisabledConstraint(bool disabled)
{
is_disabled_constraint_ = disabled;
delete [] paths_;
paths_ = nullptr;
tag_group_index_ = tag_group_index_max;
}
bool
@ -1187,18 +1150,6 @@ Vertex::setIsCheckClk(bool is_check_clk)
is_check_clk_ = is_check_clk;
}
void
Vertex::setIsGatedClkEnable(bool enable)
{
is_gated_clk_enable_ = enable;
}
void
Vertex::setIsConstrained(bool constrained)
{
is_constrained_ = constrained;
}
void
Vertex::setHasDownstreamClkPin(bool has_clk_pin)
{
@ -1251,10 +1202,9 @@ Edge::init(VertexId from,
arc_delay_annotated_is_bits_ = true;
arc_delay_annotated_.bits_ = 0;
delay_annotation_is_incremental_ = false;
sim_timing_sense_ = unsigned(TimingSense::unknown);
is_disabled_constraint_ = false;
is_disabled_cond_ = false;
is_disabled_loop_ = false;
has_sim_sense_ = false;
has_disabled_cond_ = false;
}
Edge::~Edge()
@ -1384,48 +1334,6 @@ Edge::sense() const
return arc_set_->sense();
}
TimingSense
Edge::simTimingSense() const
{
return static_cast<TimingSense>(sim_timing_sense_);
}
void
Edge::setSimTimingSense(TimingSense sense)
{
sim_timing_sense_ = unsigned(sense);
}
bool
Edge::isDisabledConstraint() const
{
const TimingRole *role = arc_set_->role();
bool is_wire = role->isWire();
return is_disabled_constraint_
|| arc_set_->isDisabledConstraint()
// set_disable_timing cell does not disable timing checks.
|| (!(role->isTimingCheck() || is_wire)
&& arc_set_->libertyCell()->isDisabledConstraint())
|| (!is_wire
&& arc_set_->from()->isDisabledConstraint())
|| (!is_wire
&& arc_set_->to()->isDisabledConstraint());
}
void
Edge::setIsDisabledConstraint(bool disabled)
{
is_disabled_constraint_ = disabled;
}
void
Edge::setIsDisabledCond(bool disabled)
{
is_disabled_cond_ = disabled;
}
void
Edge::setIsDisabledLoop(bool disabled)
{
@ -1444,6 +1352,18 @@ Edge::setIsBidirectNetPath(bool is_bidir)
is_bidirect_net_path_ = is_bidir;
}
void
Edge::setHasSimSense(bool has_sense)
{
has_sim_sense_ = has_sense;
}
void
Edge::setHasDisabledCond(bool has_disabled)
{
has_disabled_cond_ = has_disabled;
}
////////////////////////////////////////////////////////////////
VertexIterator::VertexIterator(Graph *graph) :
@ -1483,7 +1403,7 @@ VertexIterator::findNextPin()
Pin *pin = pin_iter_->next();
vertex_ = graph_->vertex(network_->vertexId(pin));
bidir_vertex_ = network_->direction(pin)->isBidirect()
? graph_->pin_bidirect_drvr_vertex_map_.findKey(pin)
? findKey(graph_->pin_bidirect_drvr_vertex_map_, pin)
: nullptr;
if (vertex_ || bidir_vertex_)
return true;
@ -1600,7 +1520,19 @@ EdgesThruHierPinIterator::EdgesThruHierPinIterator(const Pin *hpin,
{
FindEdgesThruHierPinVisitor visitor(edges_, graph);
visitDrvrLoadsThruHierPin(hpin, network, &visitor);
edge_iter_.init(edges_);
edge_iter_ = edges_.begin();
}
bool
EdgesThruHierPinIterator::hasNext()
{
return edge_iter_ != edges_.end();
}
Edge *
EdgesThruHierPinIterator::next()
{
return *edge_iter_++;
}
////////////////////////////////////////////////////////////////
@ -1617,9 +1549,5 @@ VertexIdLess::operator()(const Vertex *vertex1,
return graph_->id(vertex1) < graph_->id(vertex2);
}
VertexSet::VertexSet(Graph *&graph) :
Set<Vertex*, VertexIdLess>(VertexIdLess(graph))
{
}
} // namespace

View File

@ -31,8 +31,9 @@
#include "Liberty.hh"
#include "Network.hh"
#include "Clock.hh"
#include "Corner.hh"
#include "Scene.hh"
#include "Search.hh"
#include "Sdc.hh"
#include "Sta.hh"
using namespace sta;
@ -93,21 +94,21 @@ vertex_iterator()
void
set_arc_delay(Edge *edge,
TimingArc *arc,
const Corner *corner,
const Scene *scene,
const MinMaxAll *min_max,
float delay)
{
Sta::sta()->setArcDelay(edge, arc, corner, min_max, delay);
Sta::sta()->setArcDelay(edge, arc, scene, min_max, delay);
}
void
set_annotated_slew(Vertex *vertex,
const Corner *corner,
const Scene *scene,
const MinMaxAll *min_max,
const RiseFallBoth *rf,
float slew)
{
Sta::sta()->setAnnotatedSlew(vertex, corner, min_max, rf, slew);
Sta::sta()->setAnnotatedSlew(vertex, scene, min_max, rf, slew);
}
// Remove all delay and slew annotations.
@ -132,20 +133,20 @@ int level() { return Sta::sta()->vertexLevel(self); }
int tag_group_index() { return self->tagGroupIndex(); }
Slew
slew(const RiseFall *rf,
slew(const RiseFallBoth *rf,
const MinMax *min_max)
{
Sta *sta = Sta::sta();
return sta->vertexSlew(self, rf, min_max);
return sta->slew(self, rf, sta->scenes(), min_max);
}
Slew
slew_corner(const RiseFall *rf,
const Corner *corner,
slew_scenes(const RiseFallBoth *rf,
const SceneSeq scenes,
const MinMax *min_max)
{
Sta *sta = Sta::sta();
return sta->vertexSlew(self, rf, corner, min_max);
return sta->slew(self, rf, scenes, min_max);
}
VertexOutEdgeIterator *
@ -160,162 +161,13 @@ in_edge_iterator()
return new VertexInEdgeIterator(self, Sta::sta()->graph());
}
FloatSeq
arrivals_clk(const RiseFall *rf,
Clock *clk,
const RiseFall *clk_rf)
{
Sta *sta = Sta::sta();
FloatSeq arrivals;
const ClockEdge *clk_edge = nullptr;
if (clk)
clk_edge = clk->edge(clk_rf);
for (auto path_ap : sta->corners()->pathAnalysisPts()) {
arrivals.push_back(delayAsFloat(sta->vertexArrival(self, rf, clk_edge,
path_ap, nullptr)));
}
return arrivals;
}
float
arrival(const MinMax *min_max)
{
Sta *sta = Sta::sta();
return delayAsFloat(sta->vertexArrival(self, min_max));
}
StringSeq
arrivals_clk_delays(const RiseFall *rf,
Clock *clk,
const RiseFall *clk_rf,
int digits)
{
Sta *sta = Sta::sta();
StringSeq arrivals;
const ClockEdge *clk_edge = nullptr;
if (clk)
clk_edge = clk->edge(clk_rf);
for (auto path_ap : sta->corners()->pathAnalysisPts()) {
arrivals.push_back(delayAsString(sta->vertexArrival(self, rf, clk_edge,
path_ap, nullptr),
sta, digits));
}
return arrivals;
}
FloatSeq
requireds_clk(const RiseFall *rf,
Clock *clk,
const RiseFall *clk_rf)
{
Sta *sta = Sta::sta();
FloatSeq reqs;
const ClockEdge *clk_edge = nullptr;
if (clk)
clk_edge = clk->edge(clk_rf);
for (auto path_ap : sta->corners()->pathAnalysisPts()) {
reqs.push_back(delayAsFloat(sta->vertexRequired(self, rf, clk_edge,
path_ap)));
}
return reqs;
}
StringSeq
requireds_clk_delays(const RiseFall *rf,
Clock *clk,
const RiseFall *clk_rf,
int digits)
{
Sta *sta = Sta::sta();
StringSeq reqs;
const ClockEdge *clk_edge = nullptr;
if (clk)
clk_edge = clk->edge(clk_rf);
for (auto path_ap : sta->corners()->pathAnalysisPts()) {
reqs.push_back(delayAsString(sta->vertexRequired(self, rf, clk_edge, path_ap),
sta, digits));
}
return reqs;
}
Slack
slack(MinMax *min_max)
{
Sta *sta = Sta::sta();
return sta->vertexSlack(self, min_max);
}
FloatSeq
slacks(RiseFall *rf)
{
Sta *sta = Sta::sta();
FloatSeq slacks;
for (auto path_ap : sta->corners()->pathAnalysisPts()) {
slacks.push_back(delayAsFloat(sta->vertexSlack(self, rf, path_ap)));
}
return slacks;
}
// Slack with respect to a clock rise/fall edge.
FloatSeq
slacks_clk(const RiseFall *rf,
Clock *clk,
const RiseFall *clk_rf)
{
Sta *sta = Sta::sta();
FloatSeq slacks;
const ClockEdge *clk_edge = nullptr;
if (clk)
clk_edge = clk->edge(clk_rf);
for (auto path_ap : sta->corners()->pathAnalysisPts()) {
slacks.push_back(delayAsFloat(sta->vertexSlack(self, rf, clk_edge,
path_ap)));
}
return slacks;
}
StringSeq
slacks_clk_delays(const RiseFall *rf,
Clock *clk,
const RiseFall *clk_rf,
int digits)
{
Sta *sta = Sta::sta();
StringSeq slacks;
const ClockEdge *clk_edge = nullptr;
if (clk)
clk_edge = clk->edge(clk_rf);
for (auto path_ap : sta->corners()->pathAnalysisPts()) {
slacks.push_back(delayAsString(sta->vertexSlack(self, rf, clk_edge,
path_ap),
sta, digits));
}
return slacks;
}
VertexPathIterator *
path_iterator(const RiseFall *rf,
const MinMax *min_max)
{
return Sta::sta()->vertexPathIterator(self, rf, min_max);
return new VertexPathIterator(self, rf, min_max, Sta::sta());
}
bool
has_downstream_clk_pin()
{
return self->hasDownstreamClkPin();
}
bool
is_clock()
{
Sta *sta = Sta::sta();
Search *search = sta->search();
return search->isClock(self);
}
bool is_disabled_constraint() { return self->isDisabledConstraint(); }
} // Vertex methods
%extend Edge {
@ -328,28 +180,51 @@ const char *sense() { return to_string(self->sense()); }
TimingArcSeq &
timing_arcs() { return self->timingArcSet()->arcs(); }
bool is_disabled_loop() { return Sta::sta()->isDisabledLoop(self); }
bool is_disabled_constraint() { return Sta::sta()->isDisabledConstraint(self);}
bool is_disabled_constant() { return Sta::sta()->isDisabledConstant(self); }
bool is_disabled_constraint()
{
Sta *sta = Sta::sta();
const Sdc *sdc = sta->cmdSdc();
return sta->isDisabledConstraint(self, sdc);
}
bool is_disabled_constant()
{
Sta *sta = Sta::sta();
const Mode *mode = sta->cmdMode();
return sta->isDisabledConstant(self, mode);
}
bool is_disabled_cond_default()
{ return Sta::sta()->isDisabledCondDefault(self); }
PinSet
disabled_constant_pins() { return Sta::sta()->disabledConstantPins(self); }
disabled_constant_pins()
{
Sta *sta = Sta::sta();
const Mode *mode = sta->cmdMode();
return sta->disabledConstantPins(self, mode);
}
bool is_disabled_bidirect_inst_path()
{ return Sta::sta()->isDisabledBidirectInstPath(self); }
bool is_disabled_bidirect_net_path()
{ return Sta::sta()->isDisabledBidirectNetPath(self); }
bool is_disabled_preset_clear()
{ return Sta::sta()->isDisabledPresetClr(self); }
const char *
sim_timing_sense(){return to_string(Sta::sta()->simTimingSense(self));}
sim_timing_sense(){
Sta *sta = Sta::sta();
const Mode *mode = sta->cmdMode();
return to_string(sta->simTimingSense(self, mode));
}
FloatSeq
arc_delays(TimingArc *arc)
{
Sta *sta = Sta::sta();
FloatSeq delays;
for (auto dcalc_ap : sta->corners()->dcalcAnalysisPts())
delays.push_back(delayAsFloat(sta->arcDelay(self, arc, dcalc_ap)));
DcalcAPIndex ap_count = sta->dcalcAnalysisPtCount();
for (DcalcAPIndex ap_index = 0; ap_index < ap_count; ap_index++)
delays.push_back(delayAsFloat(sta->arcDelay(self, arc, ap_index)));
return delays;
}
@ -359,31 +234,31 @@ arc_delay_strings(TimingArc *arc,
{
Sta *sta = Sta::sta();
StringSeq delays;
for (auto dcalc_ap : sta->corners()->dcalcAnalysisPts())
delays.push_back(delayAsString(sta->arcDelay(self, arc, dcalc_ap),
DcalcAPIndex ap_count = sta->dcalcAnalysisPtCount();
for (DcalcAPIndex ap_index = 0; ap_index < ap_count; ap_index++)
delays.push_back(delayAsString(sta->arcDelay(self, arc, ap_index),
sta, digits));
return delays;
}
bool
delay_annotated(TimingArc *arc,
const Corner *corner,
const Scene *scene,
const MinMax *min_max)
{
DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max);
return Sta::sta()->arcDelayAnnotated(self, arc, dcalc_ap);
return Sta::sta()->arcDelayAnnotated(self, arc, scene, min_max);
}
float
arc_delay(TimingArc *arc,
const Corner *corner,
const Scene *scene,
const MinMax *min_max)
{
DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max);
return delayAsFloat(Sta::sta()->arcDelay(self, arc, dcalc_ap));
DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max);
return delayAsFloat(Sta::sta()->arcDelay(self, arc, ap_index));
}
string
std::string
cond()
{
FuncExpr *cond = self->timingArcSet()->cond();
@ -396,13 +271,13 @@ cond()
const char *
mode_name()
{
return self->timingArcSet()->modeName();
return self->timingArcSet()->modeName().c_str();
}
const char *
mode_value()
{
return self->timingArcSet()->modeValue();
return self->timingArcSet()->modeValue().c_str();
}
const char *

View File

@ -180,10 +180,6 @@ proc edge_disable_reason { edge } {
if { $disables != "" } { append disables ", " }
append disables "bidirect instance path"
}
if [$edge is_disabled_bidirect_net_path] {
if { $disables != "" } { append disables ", " }
append disables "bidirect net path"
}
if { [$edge is_disabled_preset_clear] } {
if { $disables != "" } { append disables ", " }
append disables "sta_preset_clear_arcs_enabled"
@ -295,28 +291,6 @@ proc edge_disable_reason_verbose { edge } {
return $disables
}
################################################################
define_cmd_args "report_slews" {[-corner corner] pin}
proc report_slews { args } {
global sta_report_default_digits
parse_key_args "report_slews" args keys {-corner} flags {}
check_argc_eq1 "report_slews" $args
set corner [parse_corner_or_all keys]
set pin [get_port_pin_error "pin" [lindex $args 0]]
set digits $sta_report_default_digits
foreach vertex [$pin vertices] {
if { $corner == "NULL" } {
report_line "[vertex_path_name $vertex] [rise_short_name] [format_time [$vertex slew rise min] $digits]:[format_time [$vertex slew rise max] $digits] [fall_short_name] [format_time [$vertex slew fall min] $digits]:[format_time [$vertex slew fall max] $digits]"
} else {
report_line "[vertex_path_name $vertex] [rise_short_name] [format_time [$vertex slew_corner rise $corner min] $digits]:[format_time [$vertex slew_corner rise $corner max] $digits] [fall_short_name] [format_time [$vertex slew_corner fall $corner min] $digits]:[format_time [$vertex slew_corner fall $corner max] $digits]"
}
}
}
proc vertex_path_name { vertex } {
set pin [$vertex pin]
set pin_name [get_full_name $pin]

View File

@ -22,6 +22,7 @@
//
// This notice may not be removed or altered from any source distribution.
#include "ContainerHelpers.hh"
#include "StringUtil.hh"
#include "Network.hh"
#include "NetworkCmp.hh"

View File

@ -125,12 +125,9 @@ TEST(VertexStandaloneTest, DefaultConstructor)
EXPECT_FALSE(v.visited());
EXPECT_FALSE(v.visited2());
EXPECT_FALSE(v.isRegClk());
EXPECT_FALSE(v.isDisabledConstraint());
EXPECT_FALSE(v.hasChecks());
EXPECT_FALSE(v.isCheckClk());
EXPECT_FALSE(v.isGatedClkEnable());
EXPECT_FALSE(v.hasDownstreamClkPin());
EXPECT_FALSE(v.isConstrained());
EXPECT_FALSE(v.slewAnnotated());
}
@ -163,15 +160,6 @@ TEST(VertexStandaloneTest, SetVisited2)
EXPECT_FALSE(v.visited2());
}
TEST(VertexStandaloneTest, SetIsDisabledConstraint)
{
Vertex v;
v.setIsDisabledConstraint(true);
EXPECT_TRUE(v.isDisabledConstraint());
v.setIsDisabledConstraint(false);
EXPECT_FALSE(v.isDisabledConstraint());
}
TEST(VertexStandaloneTest, SetHasChecks)
{
Vertex v;
@ -190,15 +178,6 @@ TEST(VertexStandaloneTest, SetIsCheckClk)
EXPECT_FALSE(v.isCheckClk());
}
TEST(VertexStandaloneTest, SetIsGatedClkEnable)
{
Vertex v;
v.setIsGatedClkEnable(true);
EXPECT_TRUE(v.isGatedClkEnable());
v.setIsGatedClkEnable(false);
EXPECT_FALSE(v.isGatedClkEnable());
}
TEST(VertexStandaloneTest, SetHasDownstreamClkPin)
{
Vertex v;
@ -208,31 +187,16 @@ TEST(VertexStandaloneTest, SetHasDownstreamClkPin)
EXPECT_FALSE(v.hasDownstreamClkPin());
}
TEST(VertexStandaloneTest, SetIsConstrained)
TEST(VertexStandaloneTest, HasSimValue)
{
Vertex v;
v.setIsConstrained(true);
EXPECT_TRUE(v.isConstrained());
v.setIsConstrained(false);
EXPECT_FALSE(v.isConstrained());
}
EXPECT_FALSE(v.hasSimValue());
TEST(VertexStandaloneTest, SimValue)
{
Vertex v;
EXPECT_EQ(v.simValue(), LogicValue::unknown);
EXPECT_FALSE(v.isConstant());
v.setHasSimValue(true);
EXPECT_TRUE(v.hasSimValue());
v.setSimValue(LogicValue::zero);
EXPECT_EQ(v.simValue(), LogicValue::zero);
EXPECT_TRUE(v.isConstant());
v.setSimValue(LogicValue::one);
EXPECT_EQ(v.simValue(), LogicValue::one);
EXPECT_TRUE(v.isConstant());
v.setSimValue(LogicValue::unknown);
EXPECT_FALSE(v.isConstant());
v.setHasSimValue(false);
EXPECT_FALSE(v.hasSimValue());
}
TEST(VertexStandaloneTest, TagGroupIndex)
@ -256,10 +220,7 @@ TEST(VertexStandaloneTest, BfsInQueue)
EXPECT_FALSE(v.bfsInQueue(BfsIndex::dcalc));
}
TEST(VertexStandaloneTest, TransitionCount)
{
EXPECT_EQ(Vertex::transitionCount(), 2);
}
// Vertex::transitionCount() was removed from upstream API
TEST(VertexStandaloneTest, ObjectIdx)
{
@ -332,7 +293,7 @@ TEST(EdgeStandaloneTest, DefaultConstructor)
EXPECT_FALSE(e.delay_Annotation_Is_Incremental());
EXPECT_FALSE(e.isBidirectInstPath());
EXPECT_FALSE(e.isBidirectNetPath());
EXPECT_FALSE(e.isDisabledCond());
EXPECT_FALSE(e.hasDisabledCond());
EXPECT_FALSE(e.isDisabledLoop());
}
@ -366,10 +327,10 @@ TEST(EdgeStandaloneTest, SetIsBidirectNetPath)
TEST(EdgeStandaloneTest, SetIsDisabledCond)
{
Edge e;
e.setIsDisabledCond(true);
EXPECT_TRUE(e.isDisabledCond());
e.setIsDisabledCond(false);
EXPECT_FALSE(e.isDisabledCond());
e.setHasDisabledCond(true);
EXPECT_TRUE(e.hasDisabledCond());
e.setHasDisabledCond(false);
EXPECT_FALSE(e.hasDisabledCond());
}
TEST(EdgeStandaloneTest, SetIsDisabledLoop)
@ -381,21 +342,6 @@ TEST(EdgeStandaloneTest, SetIsDisabledLoop)
EXPECT_FALSE(e.isDisabledLoop());
}
TEST(EdgeStandaloneTest, SimTimingSense)
{
Edge e;
EXPECT_EQ(e.simTimingSense(), TimingSense::unknown);
e.setSimTimingSense(TimingSense::positive_unate);
EXPECT_EQ(e.simTimingSense(), TimingSense::positive_unate);
e.setSimTimingSense(TimingSense::negative_unate);
EXPECT_EQ(e.simTimingSense(), TimingSense::negative_unate);
e.setSimTimingSense(TimingSense::non_unate);
EXPECT_EQ(e.simTimingSense(), TimingSense::non_unate);
}
TEST(EdgeStandaloneTest, ObjectIdx)
{
Edge e;
@ -403,17 +349,6 @@ TEST(EdgeStandaloneTest, ObjectIdx)
EXPECT_EQ(e.objectIdx(), 77u);
}
TEST(EdgeStandaloneTest, SetIsDisabledConstraint)
{
ASSERT_NO_THROW(( [&](){
Edge e;
e.setIsDisabledConstraint(true);
// Can only fully test when arc_set is set; test the setter at least
e.setIsDisabledConstraint(false);
}() ));
}
TEST(EdgeStandaloneTest, RemoveDelayAnnotated)
{
Edge e;
@ -534,20 +469,6 @@ TEST(VertexStandaloneTest, SetPaths)
EXPECT_EQ(v.paths(), nullptr);
}
// Test Edge timing sense combinations
TEST(EdgeStandaloneTest, SimTimingSenseCombinations)
{
Edge e;
e.setSimTimingSense(TimingSense::positive_unate);
EXPECT_EQ(e.simTimingSense(), TimingSense::positive_unate);
e.setSimTimingSense(TimingSense::negative_unate);
EXPECT_EQ(e.simTimingSense(), TimingSense::negative_unate);
e.setSimTimingSense(TimingSense::non_unate);
EXPECT_EQ(e.simTimingSense(), TimingSense::non_unate);
e.setSimTimingSense(TimingSense::unknown);
EXPECT_EQ(e.simTimingSense(), TimingSense::unknown);
}
// Test multiple BFS queue indices
TEST(VertexStandaloneTest, BfsMultipleQueues)
{
@ -683,39 +604,32 @@ TEST(VertexStandaloneTest, BfsAllIndices)
EXPECT_FALSE(v.bfsInQueue(BfsIndex::other));
}
// Test Vertex SimValue with all LogicValues
// Covers: Vertex::setSimValue, Vertex::simValue, Vertex::isConstant
TEST(VertexStandaloneTest, SimValueAllStates)
// Test Vertex hasSimValue flag
// Covers: Vertex::setHasSimValue, Vertex::hasSimValue
TEST(VertexStandaloneTest, HasSimValueToggle)
{
Vertex v;
v.setSimValue(LogicValue::zero);
EXPECT_EQ(v.simValue(), LogicValue::zero);
EXPECT_TRUE(v.isConstant());
EXPECT_FALSE(v.hasSimValue());
v.setSimValue(LogicValue::one);
EXPECT_EQ(v.simValue(), LogicValue::one);
EXPECT_TRUE(v.isConstant());
v.setHasSimValue(true);
EXPECT_TRUE(v.hasSimValue());
v.setSimValue(LogicValue::unknown);
EXPECT_EQ(v.simValue(), LogicValue::unknown);
EXPECT_FALSE(v.isConstant());
v.setHasSimValue(false);
EXPECT_FALSE(v.hasSimValue());
}
// Test Edge simTimingSense all values
// Covers: Edge::setSimTimingSense, Edge::simTimingSense
TEST(EdgeStandaloneTest, SimTimingSenseAllValues)
// Test Edge hasSimSense flag
// Covers: Edge::setHasSimSense, Edge::hasSimSense
TEST(EdgeStandaloneTest, HasSimSenseAllValues)
{
Edge e;
e.setSimTimingSense(TimingSense::unknown);
EXPECT_EQ(e.simTimingSense(), TimingSense::unknown);
e.setSimTimingSense(TimingSense::positive_unate);
EXPECT_EQ(e.simTimingSense(), TimingSense::positive_unate);
e.setSimTimingSense(TimingSense::negative_unate);
EXPECT_EQ(e.simTimingSense(), TimingSense::negative_unate);
e.setSimTimingSense(TimingSense::non_unate);
EXPECT_EQ(e.simTimingSense(), TimingSense::non_unate);
e.setSimTimingSense(TimingSense::unknown);
EXPECT_EQ(e.simTimingSense(), TimingSense::unknown);
EXPECT_FALSE(e.hasSimSense());
e.setHasSimSense(true);
EXPECT_TRUE(e.hasSimSense());
e.setHasSimSense(false);
EXPECT_FALSE(e.hasSimSense());
}
// Test Vertex slewAnnotated with all rf/mm combinations
@ -798,40 +712,28 @@ TEST(VertexStandaloneTest, MultipleFlagCombinations)
{
Vertex v;
// Set multiple flags and verify they don't interfere
v.setIsDisabledConstraint(true);
v.setHasChecks(true);
v.setIsCheckClk(true);
v.setIsGatedClkEnable(true);
v.setHasDownstreamClkPin(true);
v.setIsConstrained(true);
v.setVisited(true);
v.setVisited2(true);
EXPECT_TRUE(v.isDisabledConstraint());
EXPECT_TRUE(v.hasChecks());
EXPECT_TRUE(v.isCheckClk());
EXPECT_TRUE(v.isGatedClkEnable());
EXPECT_TRUE(v.hasDownstreamClkPin());
EXPECT_TRUE(v.isConstrained());
EXPECT_TRUE(v.visited());
EXPECT_TRUE(v.visited2());
// Clear all
v.setIsDisabledConstraint(false);
v.setHasChecks(false);
v.setIsCheckClk(false);
v.setIsGatedClkEnable(false);
v.setHasDownstreamClkPin(false);
v.setIsConstrained(false);
v.setVisited(false);
v.setVisited2(false);
EXPECT_FALSE(v.isDisabledConstraint());
EXPECT_FALSE(v.hasChecks());
EXPECT_FALSE(v.isCheckClk());
EXPECT_FALSE(v.isGatedClkEnable());
EXPECT_FALSE(v.hasDownstreamClkPin());
EXPECT_FALSE(v.isConstrained());
EXPECT_FALSE(v.visited());
EXPECT_FALSE(v.visited2());
}
@ -843,25 +745,25 @@ TEST(EdgeStandaloneTest, MultipleFlagCombinations)
Edge e;
e.setIsBidirectInstPath(true);
e.setIsBidirectNetPath(true);
e.setIsDisabledCond(true);
e.setHasDisabledCond(true);
e.setIsDisabledLoop(true);
e.setDelayAnnotationIsIncremental(true);
EXPECT_TRUE(e.isBidirectInstPath());
EXPECT_TRUE(e.isBidirectNetPath());
EXPECT_TRUE(e.isDisabledCond());
EXPECT_TRUE(e.hasDisabledCond());
EXPECT_TRUE(e.isDisabledLoop());
EXPECT_TRUE(e.delay_Annotation_Is_Incremental());
e.setIsBidirectInstPath(false);
e.setIsBidirectNetPath(false);
e.setIsDisabledCond(false);
e.setHasDisabledCond(false);
e.setIsDisabledLoop(false);
e.setDelayAnnotationIsIncremental(false);
EXPECT_FALSE(e.isBidirectInstPath());
EXPECT_FALSE(e.isBidirectNetPath());
EXPECT_FALSE(e.isDisabledCond());
EXPECT_FALSE(e.hasDisabledCond());
EXPECT_FALSE(e.isDisabledLoop());
EXPECT_FALSE(e.delay_Annotation_Is_Incremental());
}
@ -903,27 +805,23 @@ TEST(VertexStandaloneTest, MultipleFlagInteraction)
Vertex v;
v.setHasChecks(true);
v.setIsCheckClk(true);
v.setIsGatedClkEnable(true);
v.setHasDownstreamClkPin(true);
v.setIsConstrained(true);
v.setVisited(true);
v.setVisited2(true);
v.setIsDisabledConstraint(true);
v.setHasSimValue(true);
EXPECT_TRUE(v.hasChecks());
EXPECT_TRUE(v.isCheckClk());
EXPECT_TRUE(v.isGatedClkEnable());
EXPECT_TRUE(v.hasDownstreamClkPin());
EXPECT_TRUE(v.isConstrained());
EXPECT_TRUE(v.visited());
EXPECT_TRUE(v.visited2());
EXPECT_TRUE(v.isDisabledConstraint());
EXPECT_TRUE(v.hasSimValue());
// Clear each individually and verify others unaffected
v.setHasChecks(false);
EXPECT_FALSE(v.hasChecks());
EXPECT_TRUE(v.isCheckClk());
EXPECT_TRUE(v.isConstrained());
EXPECT_TRUE(v.hasSimValue());
}
// Test Edge multiple flag combinations
@ -933,13 +831,13 @@ TEST(EdgeStandaloneTest, MultipleFlagInteraction)
Edge e;
e.setIsBidirectInstPath(true);
e.setIsBidirectNetPath(true);
e.setIsDisabledCond(true);
e.setHasDisabledCond(true);
e.setIsDisabledLoop(true);
e.setDelayAnnotationIsIncremental(true);
EXPECT_TRUE(e.isBidirectInstPath());
EXPECT_TRUE(e.isBidirectNetPath());
EXPECT_TRUE(e.isDisabledCond());
EXPECT_TRUE(e.hasDisabledCond());
EXPECT_TRUE(e.isDisabledLoop());
EXPECT_TRUE(e.delay_Annotation_Is_Incremental());
@ -956,11 +854,10 @@ TEST(EdgeStandaloneTest, MultipleFlagInteraction)
#include "Network.hh"
#include "Liberty.hh"
#include "ReportTcl.hh"
#include "Corner.hh"
#include "Scene.hh"
#include "Search.hh"
#include "TimingArc.hh"
#include "PortDirection.hh"
#include "DcalcAnalysisPt.hh"
namespace sta {
@ -976,7 +873,7 @@ protected:
if (report)
report->setTclInterp(interp_);
Corner *corner = sta_->cmdCorner();
Scene *corner = sta_->cmdScene();
const MinMaxAll *min_max = MinMaxAll::all();
bool infer_latches = false;
@ -1151,7 +1048,7 @@ protected:
if (report)
report->setTclInterp(interp_);
Corner *corner = sta_->cmdCorner();
Scene *corner = sta_->cmdScene();
const MinMaxAll *min_max = MinMaxAll::all();
LibertyLibrary *lib = sta_->readLiberty(
"test/nangate45/Nangate45_typ.lib", corner, min_max, false);
@ -1172,28 +1069,28 @@ protected:
FloatSeq *waveform = new FloatSeq;
waveform->push_back(0.0f);
waveform->push_back(5.0f);
sta_->makeClock("clk", clk_pins, false, 10.0f, waveform, nullptr);
sta_->makeClock("clk", clk_pins, false, 10.0f, waveform, nullptr, sta_->cmdMode());
Clock *clk = sta_->sdc()->findClock("clk");
Clock *clk = sta_->cmdSdc()->findClock("clk");
ASSERT_NE(clk, nullptr);
Pin *d1_pin = network->findPin(top, "d1");
ASSERT_NE(d1_pin, nullptr);
sta_->setInputDelay(d1_pin, RiseFallBoth::riseFall(), clk,
RiseFall::rise(), nullptr, false, false,
MinMaxAll::all(), false, 1.0f);
MinMaxAll::all(), false, 1.0f, sta_->cmdSdc());
Pin *d2_pin = network->findPin(top, "d2");
ASSERT_NE(d2_pin, nullptr);
sta_->setInputDelay(d2_pin, RiseFallBoth::riseFall(), clk,
RiseFall::rise(), nullptr, false, false,
MinMaxAll::all(), false, 1.0f);
MinMaxAll::all(), false, 1.0f, sta_->cmdSdc());
Pin *en_pin = network->findPin(top, "en");
ASSERT_NE(en_pin, nullptr);
sta_->setInputDelay(en_pin, RiseFallBoth::riseFall(), clk,
RiseFall::rise(), nullptr, false, false,
MinMaxAll::all(), false, 1.0f);
MinMaxAll::all(), false, 1.0f, sta_->cmdSdc());
design_loaded_ = true;
}
@ -1530,7 +1427,7 @@ protected:
if (report)
report->setTclInterp(interp_);
Corner *corner = sta_->cmdCorner();
Scene *corner = sta_->cmdScene();
const MinMaxAll *min_max = MinMaxAll::all();
LibertyLibrary *lib = sta_->readLiberty(
"test/nangate45/Nangate45_typ.lib", corner, min_max, false);
@ -1552,7 +1449,7 @@ protected:
FloatSeq *wave1 = new FloatSeq;
wave1->push_back(0.0f);
wave1->push_back(5.0f);
sta_->makeClock("clk1", clk1_pins, false, 10.0f, wave1, nullptr);
sta_->makeClock("clk1", clk1_pins, false, 10.0f, wave1, nullptr, sta_->cmdMode());
// Create clock2
Pin *clk2_pin = network->findPin(top, "clk2");
@ -1562,10 +1459,10 @@ protected:
FloatSeq *wave2 = new FloatSeq;
wave2->push_back(0.0f);
wave2->push_back(2.5f);
sta_->makeClock("clk2", clk2_pins, false, 5.0f, wave2, nullptr);
sta_->makeClock("clk2", clk2_pins, false, 5.0f, wave2, nullptr, sta_->cmdMode());
// Input delays
Clock *clk1 = sta_->sdc()->findClock("clk1");
Clock *clk1 = sta_->cmdSdc()->findClock("clk1");
ASSERT_NE(clk1, nullptr);
const char *inputs[] = {"d1", "d2", "d3", "d4"};
for (const char *name : inputs) {
@ -1573,7 +1470,7 @@ protected:
ASSERT_NE(pin, nullptr);
sta_->setInputDelay(pin, RiseFallBoth::riseFall(), clk1,
RiseFall::rise(), nullptr, false, false,
MinMaxAll::all(), false, 1.0f);
MinMaxAll::all(), false, 1.0f, sta_->cmdSdc());
}
design_loaded_ = true;
@ -1741,7 +1638,7 @@ protected:
if (report)
report->setTclInterp(interp_);
Corner *corner = sta_->cmdCorner();
Scene *corner = sta_->cmdScene();
const MinMaxAll *min_max = MinMaxAll::all();
LibertyLibrary *lib = sta_->readLiberty(
"test/nangate45/Nangate45_typ.lib", corner, min_max, false);
@ -1761,22 +1658,22 @@ protected:
FloatSeq *waveform = new FloatSeq;
waveform->push_back(0.0f);
waveform->push_back(5.0f);
sta_->makeClock("clk", clk_pins, false, 10.0f, waveform, nullptr);
sta_->makeClock("clk", clk_pins, false, 10.0f, waveform, nullptr, sta_->cmdMode());
Clock *clk = sta_->sdc()->findClock("clk");
Clock *clk = sta_->cmdSdc()->findClock("clk");
ASSERT_NE(clk, nullptr);
Pin *d1_pin = network->findPin(top, "d1");
ASSERT_NE(d1_pin, nullptr);
sta_->setInputDelay(d1_pin, RiseFallBoth::riseFall(), clk,
RiseFall::rise(), nullptr, false, false,
MinMaxAll::all(), false, 1.0f);
MinMaxAll::all(), false, 1.0f, sta_->cmdSdc());
Pin *d2_pin = network->findPin(top, "d2");
ASSERT_NE(d2_pin, nullptr);
sta_->setInputDelay(d2_pin, RiseFallBoth::riseFall(), clk,
RiseFall::rise(), nullptr, false, false,
MinMaxAll::all(), false, 1.0f);
MinMaxAll::all(), false, 1.0f, sta_->cmdSdc());
design_loaded_ = true;
}
@ -1992,13 +1889,13 @@ protected:
report->setTclInterp(interp_);
// Define two corners
StringSet corner_names;
corner_names.insert("fast");
corner_names.insert("slow");
sta_->makeCorners(&corner_names);
StringSeq scene_names;
scene_names.push_back("fast");
scene_names.push_back("slow");
sta_->makeScenes(&scene_names);
Corner *fast_corner = sta_->findCorner("fast");
Corner *slow_corner = sta_->findCorner("slow");
Scene *fast_corner = sta_->findScene("fast");
Scene *slow_corner = sta_->findScene("slow");
ASSERT_NE(fast_corner, nullptr);
ASSERT_NE(slow_corner, nullptr);
@ -2026,16 +1923,16 @@ protected:
FloatSeq *waveform = new FloatSeq;
waveform->push_back(0.0f);
waveform->push_back(5.0f);
sta_->makeClock("clk", clk_pins, false, 10.0f, waveform, nullptr);
sta_->makeClock("clk", clk_pins, false, 10.0f, waveform, nullptr, sta_->cmdMode());
Clock *clk = sta_->sdc()->findClock("clk");
Clock *clk = sta_->cmdSdc()->findClock("clk");
ASSERT_NE(clk, nullptr);
Pin *d1_pin = network->findPin(top, "d1");
ASSERT_NE(d1_pin, nullptr);
sta_->setInputDelay(d1_pin, RiseFallBoth::riseFall(), clk,
RiseFall::rise(), nullptr, false, false,
MinMaxAll::all(), false, 1.0f);
MinMaxAll::all(), false, 1.0f, sta_->cmdSdc());
fast_corner_ = fast_corner;
slow_corner_ = slow_corner;
@ -2051,8 +1948,8 @@ protected:
Sta *sta_;
Tcl_Interp *interp_;
Corner *fast_corner_ = nullptr;
Corner *slow_corner_ = nullptr;
Scene *fast_corner_ = nullptr;
Scene *slow_corner_ = nullptr;
bool design_loaded_ = false;
};
@ -2078,8 +1975,8 @@ TEST_F(GraphMultiCornerTest, DelaysDifferByCorner) {
ASSERT_NE(arc, nullptr);
// Get delay for each corner
DcalcAPIndex fast_idx = fast_corner_->findDcalcAnalysisPt(MinMax::max())->index();
DcalcAPIndex slow_idx = slow_corner_->findDcalcAnalysisPt(MinMax::max())->index();
DcalcAPIndex fast_idx = fast_corner_->dcalcAnalysisPtIndex(MinMax::max());
DcalcAPIndex slow_idx = slow_corner_->dcalcAnalysisPtIndex(MinMax::max());
ArcDelay fast_delay = graph->arcDelay(edge, arc, fast_idx);
ArcDelay slow_delay = graph->arcDelay(edge, arc, slow_idx);
@ -2101,8 +1998,8 @@ TEST_F(GraphMultiCornerTest, SlewsDifferByCorner) {
Vertex *v = graph->pinDrvrVertex(buf1_z);
ASSERT_NE(v, nullptr);
DcalcAPIndex fast_idx = fast_corner_->findDcalcAnalysisPt(MinMax::max())->index();
DcalcAPIndex slow_idx = slow_corner_->findDcalcAnalysisPt(MinMax::max())->index();
DcalcAPIndex fast_idx = fast_corner_->dcalcAnalysisPtIndex(MinMax::max());
DcalcAPIndex slow_idx = slow_corner_->dcalcAnalysisPtIndex(MinMax::max());
const Slew &fast_slew = graph->slew(v, RiseFall::rise(), fast_idx);
const Slew &slow_slew = graph->slew(v, RiseFall::rise(), slow_idx);

View File

@ -344,7 +344,7 @@ Path Type: max
--- report_checks -group_count 2 ---
Warning: graph_advanced.tcl line 1, report_checks -group_count is deprecated. Use -group_path_count instead.
Warning 503: graph_advanced.tcl line 1, report_checks -group_count is deprecated. Use -group_path_count instead.
Startpoint: reg2 (rising edge-triggered flip-flop clocked by clk)
Endpoint: q (output port clocked by clk)
Path Group: clk
@ -399,7 +399,7 @@ Path Type: max
--- report_checks -endpoint_count 2 ---
Warning: graph_advanced.tcl line 1, report_checks -endpoint_count is deprecated. Use -endpoint_path_count instead.
Warning 502: graph_advanced.tcl line 1, report_checks -endpoint_count is deprecated. Use -endpoint_path_count instead.
Startpoint: reg2 (rising edge-triggered flip-flop clocked by clk)
Endpoint: q (output port clocked by clk)
Path Group: clk

View File

@ -68,7 +68,7 @@ No paths found.
No paths found.
No paths found.
--- Test 3: report with fields ---
Warning: graph_bidirect.tcl line 1, unknown field nets.
Warning 168: graph_bidirect.tcl line 1, unknown field nets.
Startpoint: d1 (input port clocked by clk)
Endpoint: reg2 (rising edge-triggered flip-flop clocked by clk)
Path Group: clk

View File

@ -58,7 +58,7 @@ Path Type: min
1.03 slack (MET)
Warning: graph_delete_modify.tcl line 1, unknown field nets.
Warning 168: graph_delete_modify.tcl line 1, unknown field nets.
Startpoint: d2 (input port clocked by clk)
Endpoint: reg2 (rising edge-triggered flip-flop clocked by clk)
Path Group: clk

View File

@ -706,7 +706,7 @@ Path Type: max
--- report_checks counts ---
Warning: graph_incremental.tcl line 1, report_checks -group_count is deprecated. Use -group_path_count instead.
Warning 503: graph_incremental.tcl line 1, report_checks -group_count is deprecated. Use -group_path_count instead.
Startpoint: d1 (input port clocked by clk)
Endpoint: reg2 (rising edge-triggered flip-flop clocked by clk)
Path Group: clk
@ -795,7 +795,7 @@ Path Type: max
8.92 slack (MET)
Warning: graph_incremental.tcl line 1, report_checks -endpoint_count is deprecated. Use -endpoint_path_count instead.
Warning 502: graph_incremental.tcl line 1, report_checks -endpoint_count is deprecated. Use -endpoint_path_count instead.
Startpoint: d1 (input port clocked by clk)
Endpoint: reg2 (rising edge-triggered flip-flop clocked by clk)
Path Group: clk
@ -890,7 +890,7 @@ Path Type: max
8.84 slack (MET)
Warning: graph_incremental.tcl line 1, report_checks -endpoint_count is deprecated. Use -endpoint_path_count instead.
Warning 502: graph_incremental.tcl line 1, report_checks -endpoint_count is deprecated. Use -endpoint_path_count instead.
Startpoint: en (input port clocked by clk)
Endpoint: reg1 (rising edge-triggered flip-flop clocked by clk)
Path Group: clk

View File

@ -976,7 +976,7 @@ Driver waveform slew = 0.02
slow reg3 CK->Q: done
--- network modification and graph update ---
Warning: graph_modify.tcl line 1, library 'NangateOpenCellLibrary' not found.
Warning 118: graph_modify.tcl line 1, library 'NangateOpenCellLibrary' not found.
Startpoint: d1 (input port clocked by clk1)
Endpoint: q3 (output port clocked by clk1)
Path Group: clk1
@ -1095,7 +1095,7 @@ Corner: slow
4.61 slack (MET)
Warning: graph_modify.tcl line 1, pin added_buf/A not found.
Warning 130: graph_modify.tcl line 1, pin added_buf/A not found.
Startpoint: d1 (input port clocked by clk1)
Endpoint: q3 (output port clocked by clk1)
Path Group: clk1
@ -1215,7 +1215,7 @@ Corner: slow
--- replace_cell ---
Warning: graph_modify.tcl line 1, library 'NangateOpenCellLibrary' not found.
Warning 118: graph_modify.tcl line 1, library 'NangateOpenCellLibrary' not found.
Startpoint: d1 (input port clocked by clk1)
Endpoint: q3 (output port clocked by clk1)
Path Group: clk1
@ -1334,7 +1334,7 @@ Corner: slow
4.61 slack (MET)
Warning: graph_modify.tcl line 1, library 'NangateOpenCellLibrary' not found.
Warning 118: graph_modify.tcl line 1, library 'NangateOpenCellLibrary' not found.
Startpoint: d1 (input port clocked by clk1)
Endpoint: q3 (output port clocked by clk1)
Path Group: clk1
@ -2415,7 +2415,7 @@ Corner: slow
0.14 1.14 v buf1/Z (BUF_X1)
0.09 1.23 v and1/ZN (AND2_X1)
0.09 1.32 ^ nand1/ZN (NAND2_X1)
0.06 1.38 ^ buf4/Z (BUF_X4)
0.07 1.38 ^ buf4/Z (BUF_X4)
0.00 1.38 ^ q3 (out)
1.38 data arrival time
@ -2551,7 +2551,7 @@ A2 -> ZN combinational
^ -> ^ 0.02:0.02:0.09:0.09
v -> v 0.02:0.02:0.16:0.16
--- fields per corner ---
Warning: graph_modify.tcl line 1, unknown field nets.
Warning 168: graph_modify.tcl line 1, unknown field nets.
Startpoint: d1 (input port clocked by clk1)
Endpoint: q3 (output port clocked by clk1)
Path Group: clk1
@ -2615,7 +2615,7 @@ Fanout Cap Slew Delay Time Description
4.93 slack (MET)
Warning: graph_modify.tcl line 1, unknown field nets.
Warning 168: graph_modify.tcl line 1, unknown field nets.
Startpoint: d1 (input port clocked by clk1)
Endpoint: q3 (output port clocked by clk1)
Path Group: clk1
@ -2915,7 +2915,7 @@ Corner: slow
4.61 slack (MET)
Warning: graph_modify.tcl line 1, report_checks -group_count is deprecated. Use -group_path_count instead.
Warning 503: graph_modify.tcl line 1, report_checks -group_count is deprecated. Use -group_path_count instead.
Startpoint: d1 (input port clocked by clk1)
Endpoint: q3 (output port clocked by clk1)
Path Group: clk1
@ -3067,7 +3067,7 @@ Corner: fast
13.94 slack (MET)
Warning: graph_modify.tcl line 1, report_checks -endpoint_count is deprecated. Use -endpoint_path_count instead.
Warning 502: graph_modify.tcl line 1, report_checks -endpoint_count is deprecated. Use -endpoint_path_count instead.
Startpoint: d1 (input port clocked by clk1)
Endpoint: q3 (output port clocked by clk1)
Path Group: clk1

View File

@ -1784,7 +1784,7 @@ Path Type: max
--- report_checks options ---
Warning: graph_operations.tcl line 1, unknown field nets.
Warning 168: graph_operations.tcl line 1, unknown field nets.
Startpoint: d1 (input port clocked by clk1)
Endpoint: q3 (output port clocked by clk1)
Path Group: clk1
@ -1960,7 +1960,7 @@ Path Type: max
4.88 slack (MET)
Warning: graph_operations.tcl line 1, report_checks -group_count is deprecated. Use -group_path_count instead.
Warning 503: graph_operations.tcl line 1, report_checks -group_count is deprecated. Use -group_path_count instead.
Startpoint: d1 (input port clocked by clk1)
Endpoint: q3 (output port clocked by clk1)
Path Group: clk1
@ -2107,7 +2107,7 @@ Path Type: max
13.90 slack (MET)
Warning: graph_operations.tcl line 1, report_checks -endpoint_count is deprecated. Use -endpoint_path_count instead.
Warning 502: graph_operations.tcl line 1, report_checks -endpoint_count is deprecated. Use -endpoint_path_count instead.
Startpoint: d1 (input port clocked by clk1)
Endpoint: q3 (output port clocked by clk1)
Path Group: clk1
@ -2423,7 +2423,7 @@ Path Type: max
7.87 slack (MET)
Warning: graph_operations.tcl line 1, report_checks -endpoint_count is deprecated. Use -endpoint_path_count instead.
Warning 502: graph_operations.tcl line 1, report_checks -endpoint_count is deprecated. Use -endpoint_path_count instead.
Startpoint: d1 (input port clocked by clk1)
Endpoint: reg1 (rising edge-triggered flip-flop clocked by clk1)
Path Group: clk1

View File

@ -40,17 +40,16 @@
namespace sta {
class Corner;
class Scene;
class Parasitic;
class DcalcAnalysisPt;
class MultiDrvrNet;
class ArcDcalcArg;
typedef std::vector<ArcDcalcArg*> ArcDcalcArgPtrSeq;
typedef std::vector<ArcDcalcArg> ArcDcalcArgSeq;
using ArcDcalcArgPtrSeq = std::vector<ArcDcalcArg*>;
using ArcDcalcArgSeq = std::vector<ArcDcalcArg>;
// Driver load pin -> index in driver loads.
typedef std::map<const Pin *, size_t, PinIdLess> LoadPinIndexMap;
using LoadPinIndexMap = std::map<const Pin *, size_t, PinIdLess>;
// Arguments for gate delay calculation delay/slew at one driver pin
// through one timing arc at one delay calc analysis point.
@ -81,7 +80,7 @@ public:
const Net *drvrNet(const Network *network) const;
Edge *edge() const { return edge_; }
const TimingArc *arc() const { return arc_; }
Slew inSlew() const { return in_slew_; }
const Slew &inSlew() const { return in_slew_; }
float inSlewFlt() const;
void setInSlew(Slew in_slew);
const Parasitic *parasitic() const { return parasitic_; }
@ -138,8 +137,7 @@ protected:
std::vector<Slew> load_slews_;
};
typedef std::vector<ArcDcalcArg> ArcDcalcArgSeq;
typedef std::vector<ArcDcalcResult> ArcDcalcResultSeq;
using ArcDcalcResultSeq = std::vector<ArcDcalcResult>;
// Delay calculator class hierarchy.
// ArcDelayCalc
@ -160,7 +158,7 @@ typedef std::vector<ArcDcalcResult> ArcDcalcResultSeq;
class ArcDelayCalc : public StaState
{
public:
explicit ArcDelayCalc(StaState *sta);
ArcDelayCalc(StaState *sta);
virtual ~ArcDelayCalc() {}
virtual ArcDelayCalc *copy() = 0;
virtual const char *name() const = 0;
@ -169,25 +167,29 @@ public:
// calculator by probing parasitics_.
virtual Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) = 0;
const Scene *scene,
const MinMax *min_max) = 0;
virtual bool reduceSupported() const = 0;
// Reduce parasitic_network to a representation acceptable to the delay calculator.
virtual Parasitic *reduceParasitic(const Parasitic *parasitic_network,
const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) = 0;
const Scene *scene,
const MinMax *min_max) = 0;
// Reduce parasitic_network to a representation acceptable to the delay calculator
// for one or more corners and min/max rise/fall.
// Null corner means reduce all corners.
// for one or more scenes and min/max rise/fall.
// Null scene means reduce all scenes.
virtual void reduceParasitic(const Parasitic *parasitic_network,
const Net *net,
const Corner *corner,
const Scene *scene,
const MinMaxAll *min_max) = 0;
// Set the in_slew, load_cap, parasitic for gates.
virtual void setDcalcArgParasiticSlew(ArcDcalcArg &gate,
const DcalcAnalysisPt *dcalc_ap) = 0;
const Scene *scene,
const MinMax *min_max) = 0;
virtual void setDcalcArgParasiticSlew(ArcDcalcArgSeq &gates,
const DcalcAnalysisPt *dcalc_ap) = 0;
const Scene *scene,
const MinMax *min_max) = 0;
// Find the wire delays and slews for an input port without a driving cell.
// This call primarily initializes the load delay/slew iterator.
virtual ArcDcalcResult inputPortDelay(const Pin *port_pin,
@ -195,7 +197,8 @@ public:
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) = 0;
const Scene *scene,
const MinMax *min_max) = 0;
// Find the delay and slew for arc driving drvr_pin.
virtual ArcDcalcResult gateDelay(const Pin *drvr_pin,
@ -205,7 +208,8 @@ public:
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) = 0;
const Scene *scene,
const MinMax *min_max) = 0;
// deprecated 2024-02-27
virtual void gateDelay(const TimingArc *arc,
const Slew &in_slew,
@ -213,7 +217,8 @@ public:
const Parasitic *parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew) __attribute__ ((deprecated));
@ -221,7 +226,8 @@ public:
// Find gate delays and slews for parallel gates.
virtual ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &args,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) = 0;
const Scene *scene,
const MinMax *min_max) = 0;
// Find the delay for a timing check arc given the arc's
// from/clock, to/data slews and related output pin parasitic.
@ -230,7 +236,8 @@ public:
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
const DcalcAnalysisPt *dcalc_ap) = 0;
const Scene *scene,
const MinMax *min_max) = 0;
// Report delay and slew calculation.
virtual std::string reportGateDelay(const Pin *drvr_pin,
const TimingArc *arc,
@ -238,7 +245,8 @@ public:
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
int digits) = 0;
// Report timing check delay calculation.
virtual std::string reportCheckDelay(const Pin *check_pin,
@ -247,7 +255,8 @@ public:
const char *from_slew_annotation,
const Slew &to_slew,
float related_out_cap,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
int digits) = 0;
virtual void finishDrvrPin() = 0;
};

View File

@ -34,8 +34,8 @@ struct DdManager;
namespace sta {
typedef std::map<const LibertyPort*, DdNode*, LibertyPortLess> BddPortVarMap;
typedef std::map<unsigned, const LibertyPort*> BddVarIdxPortMap;
using BddPortVarMap = std::map<const LibertyPort*, DdNode*, LibertyPortLess>;
using BddVarIdxPortMap = std::map<unsigned, const LibertyPort*>;
class Bdd : public StaState
{

View File

@ -25,9 +25,9 @@
#pragma once
#include <mutex>
#include <vector>
#include "Iterator.hh"
#include "Set.hh"
#include "GraphClass.hh"
#include "VertexVisitor.hh"
#include "StaState.hh"
@ -39,7 +39,7 @@ class BfsFwdIterator;
class BfsBkwdIterator;
// LevelQueue is a vector of vertex vectors indexed by logic level.
typedef Vector<VertexSeq> LevelQueue;
using LevelQueue = std::vector<VertexSeq>;
// Abstract base class for forward and backward breadth first search iterators.
// Visit all of the vertices at a level before moving to the next.
@ -58,19 +58,19 @@ public:
void ensureSize();
// Reset to virgin state.
void clear();
bool empty() const;
[[nodiscard]] bool empty() const;
// Enqueue a vertex to search from.
void enqueue(Vertex *vertex);
// Enqueue vertices adjacent to a vertex.
void enqueueAdjacentVertices(Vertex *vertex);
void enqueueAdjacentVertices(Vertex *vertex,
SearchPred *search_pred);
void enqueueAdjacentVertices(Vertex *vertex,
Level to_level);
virtual void enqueueAdjacentVertices(Vertex *vertex,
const Mode *mode);
virtual void enqueueAdjacentVertices(Vertex *vertex,
SearchPred *search_pred,
Level to_level) = 0;
bool inQueue(Vertex *vertex);
const Mode *mode) = 0;
virtual void enqueueAdjacentVertices(Vertex *vertex,
SearchPred *search_pred) = 0;
[[nodiscard]] bool inQueue(Vertex *vertex);
void checkInQueue(Vertex *vertex);
// Notify iterator that vertex will be deleted.
void deleteVertexBefore(Vertex *vertex);
@ -131,9 +131,11 @@ public:
SearchPred *search_pred,
StaState *sta);
virtual ~BfsFwdIterator();
virtual void enqueueAdjacentVertices(Vertex *vertex,
SearchPred *search_pred);
virtual void enqueueAdjacentVertices(Vertex *vertex,
SearchPred *search_pred,
Level to_level);
const Mode *mode);
using BfsIterator::enqueueAdjacentVertices;
protected:
@ -151,9 +153,11 @@ public:
SearchPred *search_pred,
StaState *sta);
virtual ~BfsBkwdIterator();
virtual void enqueueAdjacentVertices(Vertex *vertex,
SearchPred *search_pred);
virtual void enqueueAdjacentVertices(Vertex *vertex,
SearchPred *search_pred,
Level to_level);
const Mode *mode);
using BfsIterator::enqueueAdjacentVertices;
protected:

256
include/sta/BoundedHeap.hh Normal file
View File

@ -0,0 +1,256 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software.
//
// Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// This notice may not be removed or altered from any source distribution.
#pragma once
#include <vector>
#include <algorithm>
#include <functional>
namespace sta {
// BoundedHeap: A container that maintains the top N elements using a min-heap.
// This provides O(log n) insertion when the heap is full, O(1) when not full,
// and O(n log n) extraction of all elements. Useful for maintaining top K
// elements without storing all elements.
//
// The heap maintains the "worst" (minimum according to Compare) element at
// the root, so new elements that are better than the worst can replace it.
// For example, with Compare = std::greater<int>, this maintains the N largest
// values (greater values are "better").
//
// Template parameters:
// T: The element type
// Compare: Comparison function object type (default: std::less<T>)
// For top N largest, use std::greater<T>
// For top N smallest, use std::less<T>
template <typename T, typename Compare = std::less<T>>
class BoundedHeap {
public:
using value_type = T;
using size_type = size_t;
using const_reference = const T&;
using compare_type = Compare;
// Constructors
explicit BoundedHeap(size_type max_size,
const Compare& comp = Compare()) :
max_size_(max_size),
comp_(comp),
min_heap_comp_(comp)
{
heap_.reserve(max_size);
}
// Copy constructor
BoundedHeap(const BoundedHeap& other) :
heap_(other.heap_),
max_size_(other.max_size_),
comp_(other.comp_),
min_heap_comp_(other.comp_)
{}
// Assignment operator
BoundedHeap& operator=(const BoundedHeap& other)
{
if (this != &other) {
heap_ = other.heap_;
max_size_ = other.max_size_;
comp_ = other.comp_;
min_heap_comp_ = MinHeapCompare(other.comp_);
}
return *this;
}
// Move constructor
BoundedHeap(BoundedHeap&& other) noexcept :
heap_(std::move(other.heap_)),
max_size_(other.max_size_),
comp_(std::move(other.comp_)),
min_heap_comp_(comp_)
{}
// Move assignment operator
BoundedHeap& operator=(BoundedHeap&& other) noexcept
{
if (this != &other) {
heap_ = std::move(other.heap_);
max_size_ = other.max_size_;
comp_ = std::move(other.comp_);
min_heap_comp_ = MinHeapCompare(comp_);
}
return *this;
}
void
setMaxSize(size_t max_size)
{
max_size_ = max_size;
heap_.reserve(max_size);
}
// Insert an element into the heap.
// If the heap is not full, the element is added.
// If the heap is full and the new element is better than the worst element,
// the worst element is replaced. Otherwise, the element is ignored.
// Returns true if the element was inserted, false if it was ignored.
bool
insert(const T& value) {
if (heap_.size() < max_size_) {
heap_.push_back(value);
std::push_heap(heap_.begin(), heap_.end(), min_heap_comp_);
return true;
}
else if (!heap_.empty()) {
// When keeping N worst (smallest) values: if new value is smaller than worst,
// we should keep it and remove the largest element to make room.
// If new value is larger than worst, we reject it (already have worse values).
// comp_(value, worst) is true when value < worst (value is smaller/worse)
if (comp_(value, heap_.front())) {
// New value is smaller than worst - find and replace the largest element
auto max_it = std::max_element(heap_.begin(), heap_.end(), comp_);
*max_it = value;
// Rebuild heap since we modified an internal element
std::make_heap(heap_.begin(), heap_.end(), min_heap_comp_);
return true;
}
// Otherwise, new value is >= worst, so we already have worse values - reject it
}
return false;
}
// Insert an element using move semantics
bool insert(T&& value)
{
if (heap_.size() < max_size_) {
heap_.push_back(std::move(value));
std::push_heap(heap_.begin(), heap_.end(), min_heap_comp_);
return true;
}
else if (!heap_.empty()) {
// When keeping N worst (smallest) values: if new value is smaller than worst,
// we should keep it and remove the largest element to make room.
// If new value is larger than worst, we reject it (already have worse values).
// comp_(value, worst) is true when value < worst (value is smaller/worse)
if (comp_(value, heap_.front())) {
// New value is smaller than worst - find and replace the largest element
auto max_it = std::max_element(heap_.begin(), heap_.end(), comp_);
*max_it = std::move(value);
// Rebuild heap since we modified an internal element
std::make_heap(heap_.begin(), heap_.end(), min_heap_comp_);
return true;
}
// Otherwise, new value is >= worst, so we already have worse values - reject it
}
return false;
}
// Extract all elements sorted from best to worst.
// This destroys the heap structure but preserves the elements.
std::vector<T> extract()
{
// Convert heap to sorted vector (best to worst)
std::sort_heap(heap_.begin(), heap_.end(), min_heap_comp_);
// Reverse to get best first (according to user's comparison)
std::reverse(heap_.begin(), heap_.end());
std::vector<T> result = std::move(heap_);
heap_.clear();
return result;
}
// Extract all elements sorted from best to worst (const version).
// Creates a copy since we can't modify the heap.
std::vector<T> extract() const
{
std::vector<T> temp_heap = heap_;
std::sort_heap(temp_heap.begin(), temp_heap.end(), min_heap_comp_);
std::reverse(temp_heap.begin(), temp_heap.end());
return temp_heap;
}
// Get the worst element (the one that would be replaced next).
// Requires !empty()
const_reference worst() const
{
return heap_.front();
}
// Check if the heap is empty
bool empty() const
{
return heap_.empty();
}
// Get the current number of elements in the heap
size_type size() const
{
return heap_.size();
}
// Get the maximum size of the heap
size_type max_size() const
{
return max_size_;
}
// Check if the heap is full
bool full() const
{
return heap_.size() >= max_size_;
}
// Clear all elements from the heap
void clear()
{
heap_.clear();
}
// Get the comparison function
Compare compare() const
{
return comp_;
}
private:
std::vector<T> heap_;
size_type max_size_;
Compare comp_;
// Helper comparator for min-heap: we want the worst element at root
// so we can easily remove it when adding better elements.
// This is the inverse of the user's comparison.
struct MinHeapCompare
{
Compare comp_;
explicit MinHeapCompare(const Compare& c) : comp_(c) {}
bool operator()(const T& a, const T& b) const {
return comp_(b, a); // Inverted: worst is at root
}
};
MinHeapCompare min_heap_comp_;
};
} // namespace sta

View File

@ -24,8 +24,8 @@
#pragma once
#include "Map.hh"
#include "Set.hh"
#include <map>
#include "StaState.hh"
#include "NetworkClass.hh"
#include "GraphClass.hh"
@ -33,31 +33,34 @@
namespace sta {
typedef Map<const Pin*, ClockSet> PinClksMap;
typedef Map<const Clock *, PinSet*> ClkPinsMap;
using PinClksMap = std::map<const Pin*, ClockSet>;
using ClkPinsMap = std::map<const Clock *, PinSet*>;
class Sta;
// Find clock network pins.
// This is not as reliable as Search::isClock but is much cheaper.
class ClkNetwork : public StaState
{
public:
ClkNetwork(StaState *sta);
ClkNetwork(Mode *mode,
StaState *sta);
~ClkNetwork();
void ensureClkNetwork();
void clear();
bool isClock(const Pin *pin) const;
bool isClock(const Vertex *vertex) const;
bool isClock(const Net *net) const;
bool isIdealClock(const Pin *pin) const;
bool isIdealClock(const Vertex *vertex) const;
bool isPropagatedClock(const Pin *pin) const;
const ClockSet *clocks(const Pin *pin);
const ClockSet *idealClocks(const Pin *pin);
const ClockSet *clocks(const Pin *pin) const;
const ClockSet *clocks(const Vertex *vertex) const;
const ClockSet *idealClocks(const Pin *pin) const;
const PinSet *pins(const Clock *clk);
void clkPinsInvalid();
float idealClkSlew(const Pin *pin,
const RiseFall *rf,
const MinMax *min_max);
const MinMax *min_max) const;
protected:
void deletePinBefore(const Pin *pin);
@ -66,6 +69,8 @@ protected:
friend class Sta;
private:
Mode *mode_;
void findClkPins();
void findClkPins(bool ideal_only,
PinClksMap &clk_pin_map);

View File

@ -24,6 +24,8 @@
#pragma once
#include <map>
#include "MinMax.hh"
#include "RiseFallMinMax.hh"
#include "SdcClass.hh"
@ -32,7 +34,7 @@
namespace sta {
typedef Map<Pin*, PinSet*> ClkHpinEdgeMap;
using ClkHpinEdgeMap = std::map<Pin*, PinSet*>;
class Clock : public SdcCmdComment
{
@ -264,7 +266,7 @@ public:
const RiseFallBoth *tgt_rf,
const SetupHoldAll *setup_hold);
const RiseFallMinMax *uncertainties(const RiseFall *src_rf) const;
bool empty() const;
[[nodiscard]] bool empty() const;
private:
const Clock *src_;

View File

@ -25,9 +25,9 @@
#pragma once
#include <functional>
#include <vector>
#include <map>
#include "Vector.hh"
#include "Map.hh"
#include "StringUtil.hh"
#include "NetworkClass.hh"
@ -45,17 +45,17 @@ class PatternMatch;
class LibertyCell;
class LibertyPort;
typedef Map<std::string, ConcreteCell*> ConcreteCellMap;
typedef Vector<ConcretePort*> ConcretePortSeq;
typedef Map<std::string, ConcretePort*> ConcretePortMap;
typedef ConcreteCellMap::ConstIterator ConcreteLibraryCellIterator;
typedef ConcretePortSeq::ConstIterator ConcreteCellPortIterator;
typedef ConcretePortSeq::ConstIterator ConcretePortMemberIterator;
using ConcreteCellMap = std::map<std::string, ConcreteCell*>;
using ConcretePortSeq = std::vector<ConcretePort*>;
using ConcretePortMap = std::map<std::string, ConcretePort*>;
using ConcreteLibraryCellIterator = MapIterator<ConcreteCellMap, ConcreteCell*>;
using ConcreteCellPortIterator = VectorIterator<ConcretePortSeq, ConcretePort*>;
using ConcretePortMemberIterator = VectorIterator<ConcretePortSeq, ConcretePort*>;
class ConcreteLibrary
{
public:
explicit ConcreteLibrary(const char *name,
ConcreteLibrary(const char *name,
const char *filename,
bool is_liberty);
virtual ~ConcreteLibrary();
@ -263,14 +263,15 @@ private:
class ConcreteCellPortBitIterator : public Iterator<ConcretePort*>
{
public:
explicit ConcreteCellPortBitIterator(const ConcreteCell *cell);
ConcreteCellPortBitIterator(const ConcreteCell *cell);
virtual bool hasNext();
virtual ConcretePort *next();
private:
void findNext();
ConcretePortSeq::ConstIterator port_iter_;
const ConcretePortSeq &ports_;
ConcretePortSeq::const_iterator port_iter_;
ConcretePortMemberIterator *member_iter_;
ConcretePort *next_;
};

View File

@ -25,9 +25,10 @@
#pragma once
#include <functional>
#include <vector>
#include <map>
#include <set>
#include "Map.hh"
#include "Set.hh"
#include "StringUtil.hh"
#include "Network.hh"
#include "LibertyClass.hh"
@ -45,16 +46,14 @@ class ConcretePort;
class ConcreteBindingTbl;
class ConcreteLibertyLibraryIterator;
typedef Vector<ConcreteLibrary*> ConcreteLibrarySeq;
typedef Map<const char*, ConcreteLibrary*, CharPtrLess> ConcreteLibraryMap;
typedef ConcreteLibrarySeq::ConstIterator ConcreteLibraryIterator;
typedef Map<const char *, ConcreteInstance*,
CharPtrLess> ConcreteInstanceChildMap;
typedef Map<const char *, ConcreteNet*, CharPtrLess> ConcreteInstanceNetMap;
typedef Vector<ConcreteNet*> ConcreteNetSeq;
typedef Vector<ConcretePin*> ConcretePinSeq;
typedef Map<Cell*, Instance*> CellNetworkViewMap;
typedef Set<const ConcreteNet*> ConcreteNetSet;
using ConcreteLibrarySeq = std::vector<ConcreteLibrary*>;
using ConcreteLibraryMap = std::map<const char*, ConcreteLibrary*, CharPtrLess>;
using ConcreteInstanceChildMap = std::map<const char *, ConcreteInstance*, CharPtrLess>;
using ConcreteInstanceNetMap = std::map<const char *, ConcreteNet*, CharPtrLess>;
using ConcreteNetSeq = std::vector<ConcreteNet*>;
using ConcretePinSeq = std::vector<ConcretePin*>;
using CellNetworkViewMap = std::map<Cell*, Instance*>;
using ConcreteNetSet = std::set<const ConcreteNet*>;
// This adapter implements the network api for the concrete network.
// A superset of the Network api methods are implemented in the interface.

View File

@ -0,0 +1,429 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software.
//
// Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// This notice may not be removed or altered from any source distribution.
#pragma once
#include <type_traits>
#include <utility> // for std::declval
#include <map>
#include <set>
#include <vector>
#include <algorithm>
#include <ranges>
#include <functional>
namespace sta {
// C++ kung foo courtesy of chat gtp.
// ------------------------------------------------------------
// 1. Sequence containers (vector<T*>, list<T*>, deque<T*>, …)
// ------------------------------------------------------------
template <typename Container>
std::enable_if_t<std::is_pointer_v<typename Container::value_type>>
deleteContents(Container& c)
{
for (auto ptr : c)
delete ptr;
c.clear();
}
template <typename Container>
std::enable_if_t<std::is_pointer_v<typename Container::value_type>>
deleteContents(Container *c)
{
for (auto ptr : *c)
delete ptr;
c->clear();
}
// ------------------------------------------------------------
// 2. Maps (map<K, T*>, unordered_map<K, T*>)
// ------------------------------------------------------------
template <typename Map>
std::enable_if_t<std::is_pointer_v<typename Map::mapped_type>
>
deleteContents(Map& m)
{
for (auto& kv : m)
delete kv.second;
m.clear();
}
template <typename Map>
std::enable_if_t<std::is_pointer_v<typename Map::mapped_type>
>
deleteContents(Map *m)
{
for (auto& kv : *m)
delete kv.second;
m->clear();
}
// ------------------------------------------------------------
// 3. Sets (set<T*>, unordered_set<T*>)
// ------------------------------------------------------------
template <typename Set>
std::enable_if_t<
std::is_pointer_v<typename Set::value_type> &&
!std::is_same_v<typename Set::value_type, typename Set::mapped_type>
>
deleteContents(Set& s)
{
for (auto ptr : s)
delete ptr;
s.clear();
}
////////////////////////////////////////////////////////////////
// detect whether container has mapped_type
template<typename, typename = void>
struct has_mapped_type : std::false_type {};
template<typename T>
struct has_mapped_type<T, std::void_t<typename T::mapped_type>>
: std::true_type {};
// handle pointer types
template<typename T>
struct has_mapped_type<T*, void> : has_mapped_type<T> {};
// return-type chooser: use struct, NOT alias template
template<typename C, bool = has_mapped_type<C>::value>
struct find_return;
// pointer to map
template<typename C>
struct find_return<C*, true>
{
using type = typename C::mapped_type;
};
// pointer to set
template<typename C>
struct find_return<C*, false>
{
using type = typename C::key_type;
};
// map ref
template<typename C>
struct find_return<C, true>
{
using type = typename C::mapped_type;
};
// set ref
template<typename C>
struct find_return<C, false>
{
using type = typename C::key_type;
};
// Find an pointer value in a reference to a contaiiner of pointers.
// Return nullptr if not found.
template<typename AssocContainer>
auto
findKey(const AssocContainer& c,
typename AssocContainer::key_type key)
-> typename find_return<AssocContainer>::type
{
using ReturnType = typename find_return<AssocContainer>::type;
static_assert(std::is_pointer_v<ReturnType>,
"findKey requires pointer types");
auto it = c.find(key);
if (it == c.end())
return nullptr;
if constexpr (has_mapped_type<AssocContainer>::value)
return it->second; // map
else
return *it; // set
}
// Find an pointer value in a pointer to a contaiiner of pointers.
// Return nullptr if not found.
template<typename AssocContainer>
auto
findKey(const AssocContainer *c,
typename AssocContainer::key_type key)
-> typename find_return<AssocContainer>::type
{
using ReturnType = typename find_return<AssocContainer>::type;
static_assert(std::is_pointer_v<ReturnType>,
"findKey requires pointer types");
auto it = c->find(key);
if (it == c->end())
return nullptr;
if constexpr (has_mapped_type<AssocContainer>::value)
// map
return it->second;
else
// set
return *it;
}
////////////////////////////////////////////////////////////////
// Find a value reference in a container. Returns reference to the value if found,
// otherwise returns reference to a static empty value of the same type.
template<typename AssocContainer>
auto
findKeyValue(const AssocContainer& c,
typename AssocContainer::key_type key)
-> const typename find_return<AssocContainer>::type &
{
auto it = c.find(key);
if (it != c.end()) {
if constexpr (has_mapped_type<AssocContainer>::value)
return it->second;
else
return *it;
}
static const typename find_return<AssocContainer>::type empty{};
return empty;
}
// Find an value reference in a reference to a contaiiner of objects.
// Return exists.
template<typename AssocContainer>
void
findKeyValue(const AssocContainer& c,
typename AssocContainer::key_type key,
typename find_return<AssocContainer>::type &value,
bool &exists)
{
auto it = c.find(key);
if (it == c.end()) {
exists = false;
return;
}
if constexpr (has_mapped_type<AssocContainer>::value) {
// map
value = it->second;
exists = true;
}
else {
// set
value = *it;
exists = true;
}
}
// Find an value reference in a pointer to a contaiiner of objects.
// Return exists.
template<typename AssocContainer>
void
findKeyValue(const AssocContainer *c,
typename AssocContainer::key_type key,
typename find_return<AssocContainer>::type &value,
bool &exists)
{
auto it = c->find(key);
if (it == c->end()) {
exists = false;
return;
}
if constexpr (has_mapped_type<AssocContainer>::value) {
// map
value = it->second;
exists = true;
}
else {
// set
value = *it;
exists = true;
}
}
////////////////////////////////////////////////////////////////
// Find an value pointer in a reference to a contaiiner of objects.
template<typename AssocContainer>
auto
findKeyValuePtr(AssocContainer& c,
typename AssocContainer::key_type key)
-> typename find_return<AssocContainer>::type*
{
auto it = c.find(key);
if (it == c.end())
return nullptr;
if constexpr (has_mapped_type<AssocContainer>::value)
// map
return &it->second;
else
// set
return *it;
}
// Find an pointger to a value in a const reference to a contaiiner objects.
// Return nullptr if not found.
template<typename AssocContainer>
auto
findKeyValuePtr(const AssocContainer& c,
typename AssocContainer::key_type key)
-> const typename find_return<AssocContainer>::type*
{
auto it = c.find(key);
if (it == c.end())
return nullptr;
if constexpr (has_mapped_type<AssocContainer>::value)
// map
return &it->second;
else
// set
return *it;
}
////////////////////////////////////////////////////////////////
// Determine if two std::set's intersect.
// Returns true if there is at least one common element.
template <typename Set>
bool
intersects(const Set &set1,
const Set &set2,
typename Set::key_compare key_less)
{
auto iter1 = set1.begin();
auto end1 = set1.end();
auto iter2 = set2.begin();
auto end2 = set2.end();
while (iter1 != end1 && iter2 != end2) {
if (key_less(*iter1, *iter2))
iter1++;
else if (key_less(*iter2, *iter1))
iter2++;
else
return true;
}
return false;
}
// Determine if two std::set's intersect (pointer version).
// Returns true if there is at least one common element.
template <typename Set>
bool
intersects(const Set *set1,
const Set *set2,
typename Set::key_compare key_less)
{
if (set1 && set2) {
auto iter1 = set1->begin();
auto end1 = set1->end();
auto iter2 = set2->begin();
auto end2 = set2->end();
while (iter1 != end1 && iter2 != end2) {
if (key_less(*iter1, *iter2))
iter1++;
else if (key_less(*iter2, *iter1))
iter2++;
else
return true;
}
}
return false;
}
////////////////////////////////////////////////////////////////
// Compare set contents.
template <typename Set>
int
compare(const Set *set1,
const Set *set2,
typename Set::key_compare key_less)
{
size_t size1 = set1 ? set1->size() : 0;
size_t size2 = set2 ? set2->size() : 0;
if (size1 == size2) {
if (set1 == nullptr || set2 == nullptr) {
// Both are null or empty, so they're equal
return 0;
}
auto iter1 = set1->begin();
auto iter2 = set2->begin();
auto end1 = set1->end();
auto end2 = set2->end();
while (iter1 != end1 && iter2 != end2) {
if (key_less(*iter1, *iter2))
return -1;
else if (key_less(*iter2, *iter1))
return 1;
++iter1;
++iter2;
}
// Sets are equal.
return 0;
}
else
return (size1 > size2) ? 1 : -1;
}
////////////////////////////////////////////////////////////////
// Sort functions that do not require begin()/end() range.
// reference arg
template<std::ranges::random_access_range Range,
typename Comp = std::less<>>
requires std::predicate<Comp&,
std::ranges::range_reference_t<Range>,
std::ranges::range_reference_t<Range>>
void
sort(Range& r,
Comp comp = Comp{})
{
std::sort(std::ranges::begin(r), std::ranges::end(r), comp);
}
// pointer arg
template<typename Range,
typename Comp = std::less<>>
requires std::ranges::random_access_range<Range> &&
std::predicate<Comp&,
std::ranges::range_reference_t<Range>,
std::ranges::range_reference_t<Range>>
void
sort(Range* r,
Comp comp = Comp{})
{
std::sort(std::ranges::begin(*r), std::ranges::end(*r), comp);
}
} // namespace

View File

@ -1,139 +0,0 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software.
//
// Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// This notice may not be removed or altered from any source distribution.
#pragma once
#include "MinMax.hh"
#include "Vector.hh"
#include "StringSet.hh"
#include "GraphClass.hh"
#include "SearchClass.hh"
#include "StaState.hh"
namespace sta {
class ParasiticAnalysisPt;
class DcalcAnalysisPt;
class PathAnalysisPt;
class Corner;
class Corners;
class LibertyLibrary;
typedef Vector<Corner*> CornerSeq;
typedef Map<const char *, Corner*, CharPtrLess> CornerMap;
typedef Vector<ParasiticAnalysisPt*> ParasiticAnalysisPtSeq;
typedef Vector<DcalcAnalysisPt*> DcalcAnalysisPtSeq;
typedef Vector<PathAnalysisPt*> PathAnalysisPtSeq;
typedef Vector<LibertyLibrary*> LibertySeq;
class Corners : public StaState
{
public:
explicit Corners(StaState *sta);
~Corners();
void clear();
int count() const;
void copy(Corners *corners);
bool multiCorner() const;
Corner *findCorner(const char *corner);
Corner *findCorner(int corner_index);
void makeCorners(StringSet *corner_names);
void analysisTypeChanged();
void operatingConditionsChanged();
// Make one parasitic analysis points.
void makeParasiticAnalysisPts(bool per_corner);
int parasiticAnalysisPtCount() const;
ParasiticAnalysisPtSeq &parasiticAnalysisPts();
DcalcAPIndex dcalcAnalysisPtCount() const;
DcalcAnalysisPtSeq &dcalcAnalysisPts();
const DcalcAnalysisPtSeq &dcalcAnalysisPts() const;
PathAPIndex pathAnalysisPtCount() const;
PathAnalysisPt *findPathAnalysisPt(PathAPIndex path_index) const;
PathAnalysisPtSeq &pathAnalysisPts();
const PathAnalysisPtSeq &pathAnalysisPts() const;
CornerSeq &corners() { return corners_; }
// Iterators for range iteration.
// for (auto corner : *sta->corners()) {}
CornerSeq::iterator begin() { return corners_.begin(); }
CornerSeq::iterator end() { return corners_.end(); }
protected:
void makeAnalysisPts();
void makeDcalcAnalysisPts(Corner *corner);
DcalcAnalysisPt *makeDcalcAnalysisPt(Corner *corner,
const MinMax *min_max,
const MinMax *check_clk_slew_min_max);
void makePathAnalysisPts(Corner *corner);
void makePathAnalysisPts(Corner *corner,
bool swap_clk_min_max,
DcalcAnalysisPt *dcalc_ap_min,
DcalcAnalysisPt *dcalc_ap_max);
private:
CornerMap corner_map_;
CornerSeq corners_;
ParasiticAnalysisPtSeq parasitic_analysis_pts_;
DcalcAnalysisPtSeq dcalc_analysis_pts_;
PathAnalysisPtSeq path_analysis_pts_;
};
class Corner
{
public:
Corner(const char *name,
int index);
const char *name() const { return name_.c_str(); }
int index() const { return index_; }
ParasiticAnalysisPt *findParasiticAnalysisPt(const MinMax *min_max) const;
int parasiticAnalysisPtcount();
DcalcAnalysisPt *findDcalcAnalysisPt(const MinMax *min_max) const;
PathAnalysisPt *findPathAnalysisPt(const MinMax *min_max) const;
void addLiberty(LibertyLibrary *lib,
const MinMax *min_max);
const LibertySeq &libertyLibraries(const MinMax *min_max) const;
int libertyIndex(const MinMax *min_max) const;
protected:
void setParasiticAnalysisPtcount(int ap_count);
void setParasiticAP(ParasiticAnalysisPt *path_ap,
int mm_index);
void setDcalcAnalysisPtcount(DcalcAPIndex ap_count);
void addDcalcAP(DcalcAnalysisPt *dcalc_ap);
void addPathAP(PathAnalysisPt *path_ap);
private:
std::string name_;
int index_;
ParasiticAnalysisPtSeq parasitic_analysis_pts_;
DcalcAnalysisPtSeq dcalc_analysis_pts_;
PathAnalysisPtSeq path_analysis_pts_;
LibertySeq liberty_[MinMax::index_count];
friend class Corners;
};
} // namespace

View File

@ -24,7 +24,8 @@
#pragma once
#include "UnorderedSet.hh"
#include <unordered_set>
#include "MinMax.hh"
#include "TimingRole.hh"
#include "StaState.hh"
@ -52,7 +53,9 @@ public:
const CycleAccting *acct2) const;
};
typedef UnorderedSet<CycleAccting*, CycleAcctingHash, CycleAcctingEqual> CycleAcctingSet;
using CycleAcctingSet = std::unordered_set<CycleAccting*,
CycleAcctingHash,
CycleAcctingEqual>;
class CycleAcctings
{

View File

@ -55,7 +55,7 @@ public:
void removeMargin(const RiseFallBoth *from_rf,
const RiseFallBoth *to_rf,
const SetupHoldAll *setup_hold);
bool empty() const;
[[nodiscard]] bool empty() const;
void marginIsOneValue(const SetupHold *setup_hold,
// Return values.
float &value,

View File

@ -1,81 +0,0 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software.
//
// Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// This notice may not be removed or altered from any source distribution.
#pragma once
#include "Iterator.hh"
#include "MinMax.hh"
#include "LibertyClass.hh"
#include "SdcClass.hh"
#include "ParasiticsClass.hh"
#include "GraphClass.hh"
#include "StaState.hh"
namespace sta {
class Corner;
// Delay calculation analysis point.
// This collects all of the parameters used to find one set of
// delay calculation results.
class DcalcAnalysisPt
{
public:
DcalcAnalysisPt(Corner *corner,
DcalcAPIndex index,
const OperatingConditions *op_cond,
const MinMax *min_max,
const MinMax *check_clk_slew_min_max);
Corner *corner() const { return corner_; }
// Which of the delay_count results this analysis point corresponds to.
DcalcAPIndex index() const { return index_; }
// Slew index of timing check data.
DcalcAPIndex checkDataSlewIndex() const { return index_; }
// Slew index of timing check clock.
DcalcAPIndex checkClkSlewIndex() const { return check_clk_slew_index_; }
// Slew min/max of timing check clock.
const MinMax *checkClkSlewMinMax() const { return check_clk_slew_min_max_; }
// Constraint min/max values to use.
const MinMax *constraintMinMax() const { return min_max_; }
// Constraints::operatingCondition(cnst_min_max_)
const OperatingConditions *operatingConditions() const { return op_cond_; }
void setOperatingConditions(const OperatingConditions *op_cond);
// Delay merging min/max operator (for wires).
const MinMax *delayMinMax() const { return min_max_; }
// Merge min/max slews across timing arcs.
const MinMax *slewMinMax() const { return min_max_; }
ParasiticAnalysisPt *parasiticAnalysisPt() const;
void setCheckClkSlewIndex(DcalcAPIndex index);
int libertyIndex() const;
private:
Corner *corner_;
DcalcAPIndex index_;
DcalcAPIndex check_clk_slew_index_;
const OperatingConditions *op_cond_;
const MinMax *min_max_;
const MinMax *check_clk_slew_min_max_;
};
} // namespace

View File

@ -24,10 +24,11 @@
#pragma once
#include <string>
#include <cstdarg>
#include <map>
#include <mutex>
#include "Map.hh"
#include "StringUtil.hh"
namespace sta {
@ -35,13 +36,12 @@ namespace sta {
class Report;
class Pin;
typedef Map<const char *, int, CharPtrLess> DebugMap;
using DebugMap = std::map<std::string, int>;
class Debug
{
public:
explicit Debug(Report *report);
~Debug();
Debug(Report *report);
int level(const char *what);
void setLevel(const char *what,
int level);
@ -57,18 +57,15 @@ protected:
Report *report_;
std::mutex buffer_lock_;
bool debug_on_;
DebugMap *debug_map_;
DebugMap debug_map_;
int stats_level_;
};
// Inlining a varargs function would eval the args, which can
// be expensive, so use a macro.
// Note that "##__VA_ARGS__" is a gcc extension to support zero arguments (no comma).
// clang -Wno-gnu-zero-variadic-macro-arguments suppresses the warning.
// c++20 has "__VA_OPT__" to deal with the zero arg case so this is temporary.
#define debugPrint(debug, what, level, ...) \
if (debug->check(what, level)) { \
debug->reportLine(what, ##__VA_ARGS__); \
debug->reportLine(what __VA_OPT__(,) __VA_ARGS__); \
}
} // namespace

View File

@ -41,10 +41,10 @@
namespace sta {
typedef Delay ArcDelay;
typedef Delay Slew;
typedef Delay Arrival;
typedef Delay Required;
typedef Delay Slack;
using ArcDelay = Delay;
using Slew = Delay;
using Arrival = Delay;
using Required = Delay;
using Slack = Delay;
} // namespace

View File

@ -31,7 +31,7 @@ namespace sta {
class ArcDelayCalc;
class StaState;
typedef ArcDelayCalc *(*MakeArcDelayCalc)(StaState *sta);
using MakeArcDelayCalc = ArcDelayCalc *(*)(StaState *sta);
// Register builtin delay calculators.
void

View File

@ -32,9 +32,9 @@ namespace sta {
class StaState;
typedef float Delay;
using Delay = float;
// Delay double for accumulating Delays.
typedef double DelayDbl;
using DelayDbl = double;
const Delay delay_zero = 0.0;

View File

@ -24,7 +24,9 @@
#pragma once
#include "Map.hh"
#include <set>
#include <vector>
#include "NetworkClass.hh"
#include "LibertyClass.hh"
#include "SdcClass.hh"
@ -35,10 +37,10 @@ class TimingRole;
class DisabledCellPorts;
class DisabledInstancePorts;
typedef Vector<DisabledInstancePorts*> DisabledInstancePortsSeq;
typedef Vector<DisabledCellPorts*> DisabledCellPortsSeq;
typedef Vector<LibertyPortPair> LibertyPortPairSeq;
typedef Set<TimingArcSet*> TimingArcSetSet;
using DisabledInstancePortsSeq = std::vector<DisabledInstancePorts*>;
using DisabledCellPortsSeq = std::vector<DisabledCellPorts*>;
using LibertyPortPairSeq = std::vector<LibertyPortPair>;
using TimingArcSetSet = std::set<TimingArcSet*, TimingArcSetLess>;
// Base class for disabled cell and instance ports.
class DisabledPorts
@ -56,13 +58,13 @@ public:
LibertyPort *to);
void removeDisabledFromTo(LibertyPort *from,
LibertyPort *to);
bool isDisabled(LibertyPort *from,
[[nodiscard]] bool isDisabled(LibertyPort *from,
LibertyPort *to,
const TimingRole *role);
LibertyPortPairSet *fromTo() const { return from_to_; }
LibertyPortSet *from() const { return from_; }
LibertyPortSet *to() const { return to_; }
bool all() const { return all_; }
[[nodiscard]] bool all() const { return all_; }
private:
bool all_;
@ -80,7 +82,7 @@ public:
LibertyCell *cell() const { return cell_; }
void setDisabled(TimingArcSet *arc_set);
void removeDisabled(TimingArcSet *arc_set);
bool isDisabled(TimingArcSet *arc_set) const;
[[nodiscard]] bool isDisabled(TimingArcSet *arc_set) const;
TimingArcSetSet *timingArcSets() const { return arc_sets_; }
using DisabledPorts::isDisabled;
@ -102,7 +104,7 @@ private:
};
DisabledCellPortsSeq
sortByName(DisabledCellPortsMap *cell_map);
sortByName(const DisabledCellPortsMap *cell_map);
DisabledInstancePortsSeq
sortByPathName(const DisabledInstancePortsMap *inst_map,
const Network *network);

View File

@ -24,15 +24,15 @@
#pragma once
#include "Vector.hh"
#include "Map.hh"
#include "UnorderedMap.hh"
#include <map>
#include <unordered_map>
#include "LibertyClass.hh"
namespace sta {
typedef Map<LibertyCell*, LibertyCellSeq*> EquivCellMap;
typedef UnorderedMap<unsigned, LibertyCellSeq*> LibertyCellHashMap;
using EquivCellMap = std::map<LibertyCell*, LibertyCellSeq*>;
using LibertyCellHashMap = std::unordered_map<unsigned, LibertyCellSeq*>;
class EquivCells
{

View File

@ -67,7 +67,7 @@ protected:
class FileNotReadable : public Exception
{
public:
explicit FileNotReadable(const char *filename);
FileNotReadable(const char *filename);
virtual const char *what() const noexcept;
protected:
@ -78,7 +78,7 @@ protected:
class FileNotWritable : public Exception
{
public:
explicit FileNotWritable(const char *filename);
FileNotWritable(const char *filename);
virtual const char *what() const noexcept;
protected:

View File

@ -24,8 +24,9 @@
#pragma once
#include <vector>
#include "Error.hh"
#include "Set.hh"
#include "SdcCmdComment.hh"
#include "SdcClass.hh"
@ -44,7 +45,7 @@ class ExceptionThru;
class ExceptionTo;
class ExceptionState;
typedef Vector<ExceptionPath*> ExceptionPathSeq;
using ExceptionPathSeq = std::vector<ExceptionPath*>;
class ExceptionPath : public SdcCmdComment
{
@ -593,14 +594,14 @@ exceptionThrusClone(ExceptionThruSeq *thrus,
class ExceptionPtIterator
{
public:
explicit ExceptionPtIterator(const ExceptionPath *exception);
ExceptionPtIterator(const ExceptionPath *exception);
bool hasNext();
ExceptionPt *next();
private:
const ExceptionPath *exception_;
bool from_done_;
ExceptionThruSeq::Iterator thru_iter_;
ExceptionThruSeq::iterator thru_iter_;
bool to_done_;
};
@ -667,8 +668,8 @@ private:
int index_;
};
bool
exceptionStateLess(const ExceptionState *state1,
int
exceptionStateCmp(const ExceptionState *state1,
const ExceptionState *state2);
// Exception thrown by check.

View File

@ -26,7 +26,6 @@
#include <string>
#include "Set.hh"
#include "NetworkClass.hh"
#include "LibertyClass.hh"
@ -35,19 +34,21 @@ namespace sta {
class FuncExpr
{
public:
enum Operator {op_port,
op_not,
op_or,
op_and,
op_xor,
op_one,
op_zero};
enum class Op {port,
not_,
or_,
and_,
xor_,
one,
zero};
// Constructors.
FuncExpr(Operator op,
FuncExpr(Op op,
FuncExpr *left,
FuncExpr *right,
LibertyPort *port);
~FuncExpr();
void shallowDelete();
static FuncExpr *makePort(LibertyPort *port);
static FuncExpr *makeNot(FuncExpr *expr);
static FuncExpr *makeAnd(FuncExpr *left,
@ -62,19 +63,20 @@ public:
const FuncExpr *expr2);
static bool less(const FuncExpr *expr1,
const FuncExpr *expr2);
// Invert expr by deleting leading NOT if found.
FuncExpr *invert();
// Deep copy.
FuncExpr *copy();
// Delete expression and all of its subexpressions.
void deleteSubexprs();
// op == op_port
// op == port
LibertyPort *port() const;
Operator op() const { return op_; }
Op op() const { return op_; }
// When operator is NOT left is the only operand.
FuncExpr *left() const { return left_; }
// nullptr when op == op_not
// nullptr when op == not_
FuncExpr *right() const { return right_; }
TimingSense portTimingSense(const LibertyPort *port) const;
LibertyPortSet ports() const;
// Return true if expression has port as an input.
bool hasPort(const LibertyPort *port) const;
std::string to_string() const;
@ -86,11 +88,14 @@ public:
bool checkSize(LibertyPort *port);
private:
void findPorts(const FuncExpr *expr,
LibertyPortSet &ports) const;
std::string to_string(bool with_parens) const;
std::string to_string(bool with_parens,
char op) const;
Operator op_;
Op op_;
FuncExpr *left_;
FuncExpr *right_;
LibertyPort *port_;
@ -100,18 +105,4 @@ private:
FuncExpr *
funcExprNot(FuncExpr *expr);
class FuncExprPortIterator : public Iterator<LibertyPort*>
{
public:
explicit FuncExprPortIterator(const FuncExpr *expr);
virtual bool hasNext() { return iter_.hasNext(); }
virtual LibertyPort *next() { return iter_.next(); }
private:
void findPorts(const FuncExpr *expr);
LibertyPortSet ports_;
LibertyPortSet::ConstIterator iter_;
};
} // namespace

View File

@ -26,10 +26,9 @@
#include <mutex>
#include <atomic>
#include <map>
#include "Iterator.hh"
#include "Map.hh"
#include "Vector.hh"
#include "ObjectTable.hh"
#include "LibertyClass.hh"
#include "NetworkClass.hh"
@ -44,12 +43,12 @@ namespace sta {
class MinMax;
class Sdc;
typedef ObjectTable<Vertex> VertexTable;
typedef ObjectTable<Edge> EdgeTable;
typedef Map<const Pin*, Vertex*> PinVertexMap;
typedef Iterator<Edge*> VertexEdgeIterator;
typedef Map<const Pin*, float*, PinIdLess> PeriodCheckAnnotations;
typedef ObjectId EdgeId;
using VertexTable = ObjectTable<Vertex>;
using EdgeTable = ObjectTable<Edge>;
using PinVertexMap = std::map<const Pin*, Vertex*>;
using VertexEdgeIterator = Iterator<Edge*>;
using PeriodCheckAnnotations = std::map<const Pin*, float*, PinIdLess>;
using EdgeId = ObjectId;
static constexpr EdgeId edge_id_null = object_id_null;
static constexpr ObjectIdx edge_idx_null = object_id_null;
@ -94,10 +93,6 @@ public:
void deleteVertex(Vertex *vertex);
bool hasFaninOne(Vertex *vertex) const;
VertexId vertexCount() { return vertices_->size(); }
Path *makePaths(Vertex *vertex,
uint32_t count);
Path *paths(const Vertex *vertex) const;
void deletePaths(Vertex *vertex);
// Reported slew are the same as those in the liberty tables.
// reported_slews = measured_slews / slew_derate_from_library
@ -163,8 +158,6 @@ public:
const RiseFall *rf,
DcalcAPIndex ap_index,
bool annotated);
// True if any edge arc is annotated.
bool delayAnnotated(Edge *edge);
void minPulseWidthArc(Vertex *vertex,
const RiseFall *hi_low,
@ -188,7 +181,8 @@ public:
// Remove all delay and slew annotations.
void removeDelaySlewAnnotations();
VertexSet *regClkVertices() { return reg_clk_vertices_; }
VertexSet &regClkVertices() { return reg_clk_vertices_; }
void makeSceneAfter();
static constexpr int vertex_level_bits = 24;
static constexpr int vertex_level_max = (1<<vertex_level_bits)-1;
@ -233,7 +227,7 @@ protected:
// Sdf period check annotations.
PeriodCheckAnnotations *period_check_annotations_;
// Register/latch clock vertices to search from.
VertexSet *reg_clk_vertices_;
VertexSet reg_clk_vertices_;
friend class Vertex;
friend class VertexIterator;
@ -253,21 +247,23 @@ public:
std::string to_string(const StaState *sta) const;
// compatibility
const char *name(const Network *network) const;
bool isBidirectDriver() const { return is_bidirect_drvr_; }
bool isDriver(const Network *network) const;
[[nodiscard]] bool isBidirectDriver() const { return is_bidirect_drvr_; }
[[nodiscard]] bool isDriver(const Network *network) const;
Level level() const { return level_; }
void setLevel(Level level);
bool visited() const { return visited1_; }
[[nodiscard]] bool visited() const { return visited1_; }
void setVisited(bool visited);
bool visited2() const { return visited2_; }
[[nodiscard]] bool visited2() const { return visited2_; }
void setVisited2(bool visited);
bool isRoot() const{ return level_ == 0; }
bool hasFanin() const;
bool hasFanout() const;
[[nodiscard]] bool isRoot() const{ return level_ == 0; }
[[nodiscard]] bool hasFanin() const;
[[nodiscard]] bool hasFanout() const;
Slew *slews() { return slews_; }
const Slew *slews() const { return slews_; }
Path *paths() const { return paths_; }
Path *makePaths(uint32_t count);
void setPaths(Path *paths);
void deletePaths();
TagGroupIndex tagGroupIndex() const;
void setTagGroupIndex(TagGroupIndex tag_index);
// Slew is annotated by sdc set_annotated_transition cmd.
@ -279,38 +275,24 @@ public:
const RiseFall *rf,
DcalcAPIndex ap_index);
void removeSlewAnnotated();
// Constant zero/one from simulation.
bool isConstant() const;
LogicValue simValue() const;
void setSimValue(LogicValue value);
bool isDisabledConstraint() const { return is_disabled_constraint_; }
void setIsDisabledConstraint(bool disabled);
// True when vertex has timing check edges that constrain it.
bool hasChecks() const { return has_checks_; }
[[nodiscard]] bool hasChecks() const { return has_checks_; }
void setHasChecks(bool has_checks);
bool isCheckClk() const { return is_check_clk_; }
[[nodiscard]] bool isCheckClk() const { return is_check_clk_; }
void setIsCheckClk(bool is_check_clk);
bool isGatedClkEnable() const { return is_gated_clk_enable_; }
void setIsGatedClkEnable(bool enable);
bool hasDownstreamClkPin() const { return has_downstream_clk_pin_; }
[[nodiscard]] bool hasDownstreamClkPin() const { return has_downstream_clk_pin_; }
void setHasDownstreamClkPin(bool has_clk_pin);
// Vertices are constrained if they have one or more of the
// following timing constraints:
// output delay constraints
// data check constraints
// path delay constraints
bool isConstrained() const { return is_constrained_; }
void setIsConstrained(bool constrained);
bool bfsInQueue(BfsIndex index) const;
[[nodiscard]] bool bfsInQueue(BfsIndex index) const;
void setBfsInQueue(BfsIndex index, bool value);
bool isRegClk() const { return is_reg_clk_; }
[[nodiscard]] bool isRegClk() const { return is_reg_clk_; }
// Has sim value in some mode.
[[nodiscard]] bool hasSimValue() const { return has_sim_value_; }
void setHasSimValue(bool has_sim);
// ObjectTable interface.
ObjectIdx objectIdx() const { return object_idx_; }
[[nodiscard]] ObjectIdx objectIdx() const { return object_idx_; }
void setObjectIdx(ObjectIdx idx);
static int transitionCount() { return 2; } // rise/fall
protected:
void init(Pin *pin,
bool is_bidirect_drvr,
@ -336,23 +318,19 @@ protected:
int level_:Graph::vertex_level_bits; // 24
unsigned int slew_annotated_:slew_annotated_bits; // 4
// LogicValue gcc barfs if this is dcl'd.
unsigned sim_value_:3;
// Bidirect pins have two vertices.
// This flag distinguishes the driver and load vertices.
bool is_bidirect_drvr_:1;
bool is_reg_clk_:1;
bool is_disabled_constraint_:1;
bool is_gated_clk_enable_:1;
// Constrained by timing check edge.
bool has_checks_:1;
// Is the clock for a timing check.
bool is_check_clk_:1;
bool is_constrained_:1;
bool has_downstream_clk_pin_:1;
bool visited1_:1;
bool visited2_:1;
bool has_sim_value_;
private:
friend class Graph;
@ -382,18 +360,8 @@ public:
void setArcDelays(ArcDelay *arc_delays);
bool delay_Annotation_Is_Incremental() const {return delay_annotation_is_incremental_;};
void setDelayAnnotationIsIncremental(bool is_incr);
// Edge is disabled by set_disable_timing constraint.
bool isDisabledConstraint() const;
void setIsDisabledConstraint(bool disabled);
// Timing sense for the to_pin function after simplifying the
// function based constants on the instance pins.
TimingSense simTimingSense() const;
void setSimTimingSense(TimingSense sense);
// Edge is disabled by constants in condition (when) function.
bool isDisabledCond() const { return is_disabled_cond_; }
void setIsDisabledCond(bool disabled);
// Edge is disabled to break combinational loops.
bool isDisabledLoop() const { return is_disabled_loop_; }
[[nodiscard]] bool isDisabledLoop() const { return is_disabled_loop_; }
void setIsDisabledLoop(bool disabled);
// Edge is disabled to prevent converging clocks from merging (Xilinx).
bool isBidirectInstPath() const { return is_bidirect_inst_path_; }
@ -401,6 +369,10 @@ public:
bool isBidirectNetPath() const { return is_bidirect_net_path_; }
void setIsBidirectNetPath(bool is_bidir);
void removeDelayAnnotated();
[[nodiscard]] bool hasSimSense() const { return has_sim_sense_; }
void setHasSimSense(bool has_sense);
[[nodiscard]] bool hasDisabledCond() const { return has_disabled_cond_; }
void setHasDisabledCond(bool has_disabled);
// ObjectTable interface.
ObjectIdx objectIdx() const { return object_idx_; }
@ -435,11 +407,9 @@ protected:
bool delay_annotation_is_incremental_:1;
bool is_bidirect_inst_path_:1;
bool is_bidirect_net_path_:1;
// Timing sense from function and constants on edge instance.
unsigned sim_timing_sense_:timing_sense_bit_count;
bool is_disabled_constraint_:1;
bool is_disabled_cond_:1;
bool is_disabled_loop_:1;
bool has_sim_sense_:1;
bool has_disabled_cond_:1;
unsigned object_idx_:VertexTable::idx_bits;
private:
@ -456,7 +426,7 @@ private:
class VertexIterator : public Iterator<Vertex*>
{
public:
explicit VertexIterator(Graph *graph);
VertexIterator(Graph *graph);
virtual bool hasNext() { return vertex_ || bidir_vertex_; }
virtual Vertex *next();
@ -508,29 +478,19 @@ public:
EdgesThruHierPinIterator(const Pin *hpin,
Network *network,
Graph *graph);
virtual bool hasNext() { return edge_iter_.hasNext(); }
virtual Edge *next() { return edge_iter_.next(); }
virtual bool hasNext();
virtual Edge *next();
private:
EdgeSet edges_;
EdgeSet::Iterator edge_iter_;
EdgeSet::iterator edge_iter_;
};
class VertexIdLess
// Helper function to create a VertexSet with the comparator initialized
inline VertexSet
makeVertexSet(StaState *sta)
{
public:
VertexIdLess(Graph *&graph);
bool operator()(const Vertex *vertex1,
const Vertex *vertex2) const;
private:
Graph *&graph_;
};
class VertexSet : public Set<Vertex*, VertexIdLess>
{
public:
VertexSet(Graph *&graph);
};
return VertexSet(VertexIdLess(sta->graphRef()));
}
} // namespace

View File

@ -25,10 +25,10 @@
#pragma once
#include <limits>
#include <vector>
#include <set>
#include "ObjectId.hh"
#include "Set.hh"
#include "Vector.hh"
#include "MinMax.hh"
#include "Transition.hh"
#include "Delay.hh"
@ -42,19 +42,29 @@ class Edge;
class VertexIterator;
class VertexInEdgeIterator;
class VertexOutEdgeIterator;
class GraphLoop;
class VertexSet;
typedef ObjectId VertexId;
typedef ObjectId EdgeId;
typedef Vector<Vertex*> VertexSeq;
typedef Vector<Edge*> EdgeSeq;
typedef Set<Edge*> EdgeSet;
typedef int Level;
typedef int DcalcAPIndex;
typedef int TagGroupIndex;
typedef Vector<GraphLoop*> GraphLoopSeq;
typedef std::vector<Slew> SlewSeq;
class VertexIdLess
{
public:
VertexIdLess() = delete;
VertexIdLess(Graph *&graph);
bool operator()(const Vertex *vertex1,
const Vertex *vertex2) const;
private:
Graph *&graph_;
};
using VertexId = ObjectId;
using EdgeId = ObjectId;
using VertexSeq = std::vector<Vertex*>;
using VertexSet = std::set<Vertex*, VertexIdLess>;
using EdgeSeq = std::vector<Edge*>;
using EdgeSet = std::set<Edge*>;
using Level = int;
using DcalcAPIndex = int;
using TagGroupIndex = int;
using SlewSeq = std::vector<Slew>;
static constexpr int level_max = std::numeric_limits<Level>::max();

View File

@ -33,7 +33,7 @@ namespace sta {
class VertexNameLess
{
public:
explicit VertexNameLess(Network *network);
VertexNameLess(Network *network);
bool operator()(const Vertex *vertex1,
const Vertex *vertex2);

View File

@ -24,15 +24,15 @@
#pragma once
#include <vector>
#include <mutex>
#include <array>
#include <vector>
#include <map>
#include <mutex>
#include "Map.hh"
#include "NetworkClass.hh"
#include "GraphClass.hh"
#include "SearchClass.hh"
#include "DcalcAnalysisPt.hh"
#include "SdcClass.hh"
#include "StaState.hh"
#include "ArcDelayCalc.hh"
@ -42,9 +42,10 @@ class DelayCalcObserver;
class MultiDrvrNet;
class FindVertexDelays;
class NetCaps;
class SearchPred;
typedef Map<const Vertex*, MultiDrvrNet*> MultiDrvrNetMap;
typedef std::vector<SlewSeq> DrvrLoadSlews;
using MultiDrvrNetMap = std::map<const Vertex*, MultiDrvrNet*>;
using DrvrLoadSlews = std::vector<SlewSeq>;
// This class traverses the graph calling the arc delay calculator and
// annotating delays on graph edges.
@ -73,7 +74,7 @@ public:
// Returned string is owned by the caller.
virtual std::string reportDelayCalc(const Edge *edge,
const TimingArc *arc,
const Corner *corner,
const Scene *scene,
const MinMax *min_max,
int digits);
// Percentage (0.0:1.0) change in delay that causes downstream
@ -82,19 +83,23 @@ public:
virtual void setIncrementalDelayTolerance(float tol);
float loadCap(const Pin *drvr_pin,
const DcalcAnalysisPt *dcalc_ap) const;
const Scene *scene,
const MinMax *min_max) const;
float loadCap(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) const;
const Scene *scene,
const MinMax *min_max) const;
void loadCap(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
// Return values.
float &pin_cap,
float &wire_cap) const;
void netCaps(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
// Return values.
float &pin_cap,
float &wire_cap,
@ -102,7 +107,8 @@ public:
bool &has_set_load) const;
void parasiticLoad(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
const MultiDrvrNet *multi_drvr,
ArcDelayCalc *arc_delay_calc,
// Return values.
@ -112,14 +118,15 @@ public:
void findDriverArcDelays(Vertex *drvr_vertex,
Edge *edge,
const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
ArcDelayCalc *arc_delay_calc);
// Precedence:
// SDF annotation
// Liberty port timing group timing_type minimum_period.
// Liberty port min_period attribute.
void minPeriod(const Pin *pin,
const Corner *corner,
const Scene *scene,
// Return values.
float &min_period,
bool &exists);
@ -127,11 +134,13 @@ public:
Slew edgeFromSlew(const Vertex *from_vertex,
const RiseFall *from_rf,
const Edge *edge,
const DcalcAnalysisPt *dcalc_ap);
const Scene *scene,
const MinMax *min_max);
Slew edgeFromSlew(const Vertex *from_vertex,
const RiseFall *from_rf,
const TimingRole *role,
const DcalcAnalysisPt *dcalc_ap);
const Scene *scene,
const MinMax *min_max);
bool bidirectDrvrSlewFromLoad(const Pin *pin) const;
protected:
@ -145,13 +154,15 @@ protected:
void seedNoDrvrSlew(Vertex *drvr_vertex,
const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
ArcDelayCalc *arc_delay_calc);
void seedNoDrvrCellSlew(Vertex *drvr_vertex,
const Pin *drvr_pin,
const RiseFall *rf,
const InputDrive *drive,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
ArcDelayCalc *arc_delay_calc);
void seedLoadSlew(Vertex *vertex);
void setInputPortWireDelays(Vertex *vertex);
@ -162,7 +173,8 @@ protected:
const LibertyPort *from_port,
float *from_slews,
const LibertyPort *to_port,
const DcalcAnalysisPt *dcalc_ap);
const Scene *scene,
const MinMax *min_max);
LibertyPort *driveCellDefaultFromPort(const LibertyCell *cell,
const LibertyPort *to_port);
int findPortIndex(const LibertyCell *cell,
@ -171,7 +183,8 @@ protected:
Vertex *drvr_vertex,
const TimingArc *arc,
float from_slew,
const DcalcAnalysisPt *dcalc_ap);
const Scene *scene,
const MinMax *min_max);
void findDriverDelays(Vertex *drvr_vertex,
ArcDelayCalc *arc_delay_calc,
LoadPinIndexMap &load_pin_index_map);
@ -196,14 +209,16 @@ protected:
const MultiDrvrNet *multi_drvr,
Edge *edge,
const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
ArcDelayCalc *arc_delay_calc,
LoadPinIndexMap &load_pin_index_map);
ArcDcalcArgSeq makeArcDcalcArgs(Vertex *drvr_vertex,
const MultiDrvrNet *multi_drvr,
Edge *edge,
const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
ArcDelayCalc *arc_delay_calc);
void findParallelEdge(Vertex *vertex,
const TimingArc *drvr_arc,
@ -225,34 +240,40 @@ protected:
const TimingArc *arc,
ArcDcalcResult &dcalc_result,
LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap);
const Scene *scene,
const MinMax *min_max);
bool annotateDelaySlew(Edge *edge,
const TimingArc *arc,
ArcDelay &gate_delay,
Slew &gate_slew,
const DcalcAnalysisPt *dcalc_ap);
const Scene *scene,
const MinMax *min_max);
bool annotateLoadDelays(Vertex *drvr_vertex,
const RiseFall *drvr_rf,
ArcDcalcResult &dcalc_result,
LoadPinIndexMap &load_pin_index_map,
const ArcDelay &extra_delay,
bool merge,
const DcalcAnalysisPt *dcalc_ap);
const Scene *scene,
const MinMax *min_max);
void findLatchEdgeDelays(Edge *edge);
void findCheckEdgeDelays(Edge *edge,
ArcDelayCalc *arc_delay_calc);
void deleteMultiDrvrNets();
Slew checkEdgeClkSlew(const Vertex *from_vertex,
const RiseFall *from_rf,
const DcalcAnalysisPt *dcalc_ap);
const Scene *scene,
const MinMax *min_max);
float loadCap(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
ArcDelayCalc *arc_delay_calc) const;
void parasiticLoad(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
const MultiDrvrNet *multi_drvr,
ArcDelayCalc *arc_delay_calc,
// Return values.
@ -261,7 +282,8 @@ protected:
const Parasitic *&parasitic) const;
void netCaps(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
const MultiDrvrNet *multi_drvr,
// Return values.
float &pin_cap,
@ -275,7 +297,7 @@ protected:
bool incremental_;
bool delays_exist_;
// Vertices with invalid -to delays.
VertexSet *invalid_delays_;
VertexSet invalid_delays_;
// Timing check edges with invalid delays.
EdgeSet invalid_check_edges_;
// Latch D->Q edges with invalid delays.
@ -284,7 +306,6 @@ protected:
std::mutex invalid_edge_lock_;
SearchPred *search_pred_;
SearchPred *search_non_latch_pred_;
SearchPred *clk_pred_;
BfsFwdIterator *iter_;
MultiDrvrNetMap multi_drvr_net_map_;
std::mutex multi_drvr_lock_;
@ -319,13 +340,14 @@ public:
Vertex *dcalcDrvr() const { return dcalc_drvr_; }
void setDcalcDrvr(Vertex *drvr);
void netCaps(const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
const Scene *scene,
const MinMax *min_max,
// Return values.
float &pin_cap,
float &wire_cap,
float &fanout,
bool &has_net_load) const;
void findCaps(const Sdc *sdc);
void findCaps(const StaState *sta);
private:
// Driver that triggers delay calculation for all the drivers on the net.

View File

@ -24,7 +24,6 @@
#pragma once
#include "Set.hh"
#include "NetworkClass.hh"
namespace sta {

View File

@ -40,7 +40,7 @@ class InputDriveCell;
class InputDrive
{
public:
explicit InputDrive();
InputDrive();
~InputDrive();
void setSlew(const RiseFallBoth *rf,
const MinMaxAll *min_max,

View File

@ -24,64 +24,52 @@
#pragma once
#include <array>
#include <memory>
#include <string>
#include "LibertyClass.hh"
#include "Transition.hh"
namespace sta {
class InternalPowerAttrs;
class InternalPowerModel;
class InternalPowerAttrs
{
public:
InternalPowerAttrs();
virtual ~InternalPowerAttrs();
void deleteContents();
FuncExpr *when() const { return when_; }
void setWhen(FuncExpr *when);
void setModel(const RiseFall *rf,
InternalPowerModel *model);
InternalPowerModel *model(const RiseFall *rf) const;
const char *relatedPgPin() const { return related_pg_pin_; }
void setRelatedPgPin(const char *related_pg_pin);
protected:
FuncExpr *when_;
InternalPowerModel *models_[RiseFall::index_count];
const char *related_pg_pin_;
};
using InternalPowerModels =
std::array<std::shared_ptr<InternalPowerModel>, RiseFall::index_count>;
class InternalPower
{
public:
InternalPower(LibertyCell *cell,
LibertyPort *port,
InternalPower(LibertyPort *port,
LibertyPort *related_port,
InternalPowerAttrs *attrs);
~InternalPower();
LibertyPort *related_pg_pin,
const std::shared_ptr<FuncExpr> &when,
InternalPowerModels &models);
//InternalPower(InternalPower &&other) noexcept;
LibertyCell *libertyCell() const;
LibertyPort *port() const { return port_; }
LibertyPort *relatedPort() const { return related_port_; }
FuncExpr *when() const { return when_; }
const char *relatedPgPin() const { return related_pg_pin_; }
FuncExpr *when() const { return when_.get(); }
LibertyPort *relatedPgPin() const { return related_pg_pin_; }
float power(const RiseFall *rf,
const Pvt *pvt,
float in_slew,
float load_cap);
float load_cap) const;
const InternalPowerModel *model(const RiseFall *rf) const;
protected:
LibertyPort *port_;
LibertyPort *related_port_;
FuncExpr *when_;
const char *related_pg_pin_;
InternalPowerModel *models_[RiseFall::index_count];
LibertyPort *related_pg_pin_;
std::shared_ptr<FuncExpr> when_;
InternalPowerModels models_;
};
class InternalPowerModel
{
public:
explicit InternalPowerModel(TableModel *model);
InternalPowerModel(TableModel *model);
~InternalPowerModel();
float power(const LibertyCell *cell,
const Pvt *pvt,
@ -92,6 +80,7 @@ public:
float in_slew,
float load_cap,
int digits) const;
const TableModel *model() const { return model_; }
protected:
void findAxisValues(float in_slew,

View File

@ -40,4 +40,80 @@ public:
virtual OBJ next() = 0;
};
template <typename VECTOR_TYPE, typename OBJ_TYPE>
class VectorIterator : public Iterator<OBJ_TYPE>
{
public:
VectorIterator(const VECTOR_TYPE *seq) :
seq_(seq)
{
if (seq_)
itr_ = seq_->begin();
}
VectorIterator(const VECTOR_TYPE &seq) :
seq_(&seq),
itr_(seq.begin())
{
}
bool hasNext() { return seq_ && itr_ != seq_->end(); }
OBJ_TYPE next() { return *itr_++; }
protected:
const VECTOR_TYPE *seq_;
VECTOR_TYPE::const_iterator itr_;
};
template <typename MAP_TYPE, typename OBJ_TYPE>
class MapIterator : public Iterator<OBJ_TYPE>
{
public:
MapIterator(const MAP_TYPE *map) :
map_(map)
{
if (map)
itr_ = map->begin();
}
MapIterator(const MAP_TYPE &map) :
map_(&map),
itr_(map.begin())
{
}
bool hasNext() { return map_ && itr_ != map_->end(); }
OBJ_TYPE next() {
OBJ_TYPE next = itr_->second;
itr_++;
return next;
}
protected:
const MAP_TYPE *map_;
MAP_TYPE::const_iterator itr_;
};
template <typename SET_TYPE, typename OBJ_TYPE>
class SetIterator : public Iterator<OBJ_TYPE>
{
public:
SetIterator(const SET_TYPE *set) :
set_(set)
{
if (set)
itr_ = set->begin();
}
SetIterator(const SET_TYPE &set) :
set_(&set),
itr_(set.begin())
{
}
bool hasNext() { return set_ && itr_ != set_->end(); }
OBJ_TYPE next() { return *itr_++; }
protected:
const SET_TYPE *set_;
SET_TYPE::const_iterator itr_;
};
} // namespace

View File

@ -36,6 +36,7 @@ public:
LibertyPort *related_pg_port,
FuncExpr *when,
float power);
LeakagePower(LeakagePower &&other) noexcept;
~LeakagePower();
LibertyCell *libertyCell() const { return cell_; }
LibertyPort *relatedPgPort() const { return related_pg_port_; }

View File

@ -24,10 +24,16 @@
#pragma once
#include <memory>
#include <mutex>
#include <atomic>
#include <functional>
#include <set>
#include <map>
#include <string>
#include <vector>
#include "ContainerHelpers.hh"
#include "MinMax.hh"
#include "RiseFallMinMax.hh"
#include "ConcreteLibrary.hh"
@ -35,6 +41,8 @@
#include "MinMaxValues.hh"
#include "Transition.hh"
#include "Delay.hh"
#include "InternalPower.hh"
#include "LeakagePower.hh"
#include "LibertyClass.hh"
namespace sta {
@ -44,52 +52,97 @@ class LibertyCellIterator;
class LibertyCellPortIterator;
class LibertyCellPortBitIterator;
class LibertyPortMemberIterator;
class ModeValueDef;
class TestCell;
class PatternMatch;
class LatchEnable;
class Report;
class Debug;
class LibertyBuilder;
class LibertyReader;
class OcvDerate;
class TimingArcAttrs;
class InternalPowerAttrs;
class StaState;
class Corner;
class Corners;
class DcalcAnalysisPt;
class Scene;
class DriverWaveform;
typedef Map<const char*, TableTemplate*, CharPtrLess> TableTemplateMap;
typedef Vector<TableTemplate*> TableTemplateSeq;
typedef Map<const char*, BusDcl *, CharPtrLess> BusDclMap;
typedef Vector<BusDcl *> BusDclSeq;
typedef Map<const char*, ScaleFactors*, CharPtrLess> ScaleFactorsMap;
typedef Map<const char*, Wireload*, CharPtrLess> WireloadMap;
typedef Map<const char*, WireloadSelection*, CharPtrLess> WireloadSelectionMap;
typedef Map<const char*, OperatingConditions*,
CharPtrLess> OperatingConditionsMap;
typedef Map<LibertyPort*, Sequential*> PortToSequentialMap;
typedef Vector<TimingArcSet*> TimingArcSetSeq;
typedef Set<TimingArcSet*, TimingArcSetLess> TimingArcSetMap;
typedef Map<LibertyPortPair, TimingArcSetSeq*,
LibertyPortPairLess> LibertyPortPairTimingArcMap;
typedef Vector<InternalPower*> InternalPowerSeq;
typedef Map<const LibertyPort *, InternalPowerSeq> PortInternalPowerSeq;
typedef Vector<LeakagePower*> LeakagePowerSeq;
typedef Map<const LibertyPort*, TimingArcSetSeq*> LibertyPortTimingArcMap;
typedef Map<const OperatingConditions*, LibertyCell*> ScaledCellMap;
typedef Map<const OperatingConditions*, LibertyPort*> ScaledPortMap;
typedef Map<const char *, ModeDef*, CharPtrLess> ModeDefMap;
typedef Map<const char *, ModeValueDef*, CharPtrLess> ModeValueMap;
typedef Map<const TimingArcSet*, LatchEnable*> LatchEnableMap;
typedef Vector<LatchEnable*> LatchEnableSeq;
typedef Map<const char *, OcvDerate*, CharPtrLess> OcvDerateMap;
typedef Vector<InternalPowerAttrs*> InternalPowerAttrsSeq;
typedef Map<std::string, float> SupplyVoltageMap;
typedef Map<std::string, DriverWaveform*> DriverWaveformMap;
typedef Vector<DcalcAnalysisPt*> DcalcAnalysisPtSeq;
// Mode definition mode_value group (defined before ModeValueMap / ModeDef).
class ModeValueDef
{
public:
ModeValueDef(std::string value, FuncExpr *cond, std::string sdf_cond);
ModeValueDef(ModeValueDef &&other) noexcept;
~ModeValueDef();
const std::string &value() const { return value_; }
FuncExpr *cond() const { return cond_; }
void setCond(FuncExpr *cond);
const std::string &sdfCond() const { return sdf_cond_; }
void setSdfCond(std::string sdf_cond);
private:
std::string value_;
FuncExpr *cond_;
std::string sdf_cond_;
};
// Latch enable port/function for a latch D->Q timing arc set.
class LatchEnable
{
public:
LatchEnable(LibertyPort *data,
LibertyPort *enable,
const RiseFall *enable_edge,
FuncExpr *enable_func,
LibertyPort *output,
TimingArcSet *d_to_q,
TimingArcSet *en_to_q,
TimingArcSet *setup_check);
LibertyPort *data() const { return data_; }
LibertyPort *output() const { return output_; }
LibertyPort *enable() const { return enable_; }
FuncExpr *enableFunc() const { return enable_func_; }
const RiseFall *enableEdge() const { return enable_edge_; }
TimingArcSet *dToQ() const { return d_to_q_; }
TimingArcSet *enToQ() const { return en_to_q_; }
TimingArcSet *setupCheck() const { return setup_check_; }
private:
LibertyPort *data_;
LibertyPort *enable_;
const RiseFall *enable_edge_;
FuncExpr *enable_func_;
LibertyPort *output_;
TimingArcSet *d_to_q_;
TimingArcSet *en_to_q_;
TimingArcSet *setup_check_;
};
using TableTemplateMap = std::map<std::string, TableTemplate>;
using TableTemplateSeq = std::vector<TableTemplate*>;
using BusDclMap = std::map<std::string, BusDcl>;
using BusDclSeq = std::vector<BusDcl*>;
using ScaleFactorsMap = std::map<std::string, ScaleFactors>;
using WireloadMap = std::map<std::string, Wireload>;
using WireloadSelectionMap = std::map<std::string, WireloadSelection>;
using OperatingConditionsMap = std::map<std::string, OperatingConditions>;
using PortToSequentialMap = std::map<LibertyPort*, size_t>;
using TimingArcSetSeq = std::vector<TimingArcSet*>;
using TimingArcSetSet = std::set<TimingArcSet*, TimingArcSetLess>;
using LibertyPortPairTimingArcMap = std::map<LibertyPortPair, TimingArcSetSeq,
LibertyPortPairLess>;
using InternalPowerSeq = std::vector<InternalPower>;
using InternalPowerPtrSeq = std::vector<const InternalPower*>;
using InternalPowerIndexSeq = std::vector<size_t>;
using PortInternalPowerMap = std::map<const LibertyPort *, InternalPowerIndexSeq>;
using LeakagePowerSeq = std::vector<LeakagePower>;
using ScaledCellMap = std::map<const OperatingConditions*, LibertyCell*>;
using ScaledPortMap = std::map<const OperatingConditions*, LibertyPort*>;
using ModeDefMap = std::map<std::string, ModeDef>;
using ModeValueMap = std::map<std::string, ModeValueDef>;
using LatchEnableIndexMap = std::map<const TimingArcSet*, size_t>;
using LatchEnableSeq = std::vector<LatchEnable>;
using OcvDerateMap = std::map<std::string, OcvDerate>;
using SupplyVoltageMap = std::map<std::string, float>;
using DriverWaveformMap = std::map<std::string, DriverWaveform>;
using SceneSeq = std::vector<Scene*>;
enum class ClockGateType { none, latch_posedge, latch_negedge, other };
@ -161,14 +214,15 @@ public:
DelayModelType delayModelType() const { return delay_model_type_; }
void setDelayModelType(DelayModelType type);
void addBusDcl(BusDcl *bus_dcl);
BusDcl *makeBusDcl(std::string name, int from, int to);
BusDcl *findBusDcl(const char *name) const;
BusDclSeq busDcls() const;
void addTableTemplate(TableTemplate *tbl_template,
TableTemplate *makeTableTemplate(std::string name,
TableTemplateType type);
TableTemplate *findTableTemplate(const char *name,
TableTemplateType type);
TableTemplateSeq tableTemplates() const;
TableTemplateSeq tableTemplates(TableTemplateType type) const;
float nominalProcess() const { return nominal_process_; }
void setNominalProcess(float process);
float nominalVoltage() const { return nominal_voltage_; }
@ -177,8 +231,8 @@ public:
void setNominalTemperature(float temperature);
void setScaleFactors(ScaleFactors *scales);
// Add named scale factor group.
void addScaleFactors(ScaleFactors *scales);
// Make named scale factor group. Returns pointer to the inserted element.
ScaleFactors *makeScaleFactors(const char *name);
ScaleFactors *findScaleFactors(const char *name);
ScaleFactors *scaleFactors() const { return scale_factors_; }
float scaleFactor(ScaleFactorType type,
@ -279,20 +333,20 @@ public:
Units *units() { return units_; }
const Units *units() const { return units_; }
Wireload *findWireload(const char *name) const;
void setDefaultWireload(Wireload *wireload);
Wireload *defaultWireload() const;
WireloadSelection *findWireloadSelection(const char *name) const;
WireloadSelection *defaultWireloadSelection() const;
void addWireload(Wireload *wireload);
Wireload *makeWireload(std::string name);
const Wireload *findWireload(const char *name) const;
void setDefaultWireload(const Wireload *wireload);
const Wireload *defaultWireload() const;
WireloadSelection *makeWireloadSelection(std::string name);
const WireloadSelection *findWireloadSelection(const char *name) const;
const WireloadSelection *defaultWireloadSelection() const;
WireloadMode defaultWireloadMode() const;
void setDefaultWireloadMode(WireloadMode mode);
void addWireloadSelection(WireloadSelection *selection);
void setDefaultWireloadSelection(WireloadSelection *selection);
void setDefaultWireloadSelection(const WireloadSelection *selection);
OperatingConditions *makeOperatingConditions(std::string name);
OperatingConditions *findOperatingConditions(const char *name);
OperatingConditions *defaultOperatingConditions() const;
void addOperatingConditions(OperatingConditions *op_cond);
void setDefaultOperatingConditions(OperatingConditions *op_cond);
// AOCV
@ -301,8 +355,8 @@ public:
void setOcvArcDepth(float depth);
OcvDerate *defaultOcvDerate() const;
void setDefaultOcvDerate(OcvDerate *derate);
OcvDerate *makeOcvDerate(std::string name);
OcvDerate *findOcvDerate(const char *derate_name);
void addOcvDerate(OcvDerate *derate);
void addSupplyVoltage(const char *suppy_name,
float voltage);
bool supplyExists(const char *suppy_name) const;
@ -316,29 +370,30 @@ public:
const char *filename);
static void
makeCornerMap(LibertyLibrary *lib,
makeSceneMap(LibertyLibrary *lib,
int ap_index,
Network *network,
Report *report);
static void
makeCornerMap(LibertyCell *link_cell,
makeSceneMap(LibertyCell *link_cell,
LibertyCell *map_cell,
int ap_index,
Report *report);
static void
makeCornerMap(LibertyCell *cell1,
makeSceneMap(LibertyCell *cell1,
LibertyCell *cell2,
bool link,
int ap_index,
Report *report);
static void
checkCorners(LibertyCell *cell,
Corners *corners,
checkScenes(LibertyCell *cell,
const SceneSeq &scenes,
Report *report);
DriverWaveform *findDriverWaveform(const char *name);
DriverWaveform *driverWaveformDefault() { return driver_waveform_default_; }
void addDriverWaveform(DriverWaveform *driver_waveform);
DriverWaveform *driverWaveformDefault() { return findDriverWaveform(""); }
DriverWaveform *makeDriverWaveform(const std::string &name,
TablePtr waveforms);
protected:
float degradeWireSlew(const TableModel *model,
@ -375,9 +430,9 @@ protected:
float slew_upper_threshold_[RiseFall::index_count];
float slew_derate_from_library_;
WireloadMap wireloads_;
Wireload *default_wire_load_;
const Wireload *default_wire_load_;
WireloadMode default_wire_load_mode_;
WireloadSelection *default_wire_load_selection_;
const WireloadSelection *default_wire_load_selection_;
WireloadSelectionMap wire_load_selections_;
OperatingConditionsMap operating_conditions_;
OperatingConditions *default_operating_conditions_;
@ -388,8 +443,6 @@ protected:
LibertyCellSeq *buffers_;
LibertyCellSeq *inverters_;
DriverWaveformMap driver_waveform_map_;
// Unnamed driver waveform.
DriverWaveform *driver_waveform_default_;
static constexpr float input_threshold_default_ = .5;
static constexpr float output_threshold_default_ = .5;
@ -404,12 +457,12 @@ private:
class LibertyCellIterator : public Iterator<LibertyCell*>
{
public:
explicit LibertyCellIterator(const LibertyLibrary *library);
LibertyCellIterator(const LibertyLibrary *library);
bool hasNext();
LibertyCell *next();
private:
ConcreteCellMap::ConstIterator iter_;
ConcreteLibraryCellIterator iter_;
};
////////////////////////////////////////////////////////////////
@ -428,8 +481,8 @@ public:
bool hasInternalPorts() const { return has_internal_ports_; }
ScaleFactors *scaleFactors() const { return scale_factors_; }
void setScaleFactors(ScaleFactors *scale_factors);
ModeDef *makeModeDef(const char *name);
ModeDef *findModeDef(const char *name);
ModeDef *makeModeDef(std::string name);
const ModeDef *findModeDef(const char *name) const;
float area() const { return area_; }
void setArea(float area);
@ -461,18 +514,20 @@ public:
bool isClockGate() const;
void setClockGateType(ClockGateType type);
const TimingArcSetSeq &timingArcSets() const { return timing_arc_sets_; }
const TimingArcSetSeq &timingArcSetsFrom(const LibertyPort *from) const;
const TimingArcSetSeq &timingArcSetsTo(const LibertyPort *to) const;
// from or to may be nullptr to wildcard.
const TimingArcSetSeq &timingArcSets(const LibertyPort *from,
const LibertyPort *to) const;
size_t timingArcSetCount() const;
// Find a timing arc set equivalent to key.
TimingArcSet *findTimingArcSet(TimingArcSet *key) const;
TimingArcSet *findTimingArcSet(unsigned arc_set_index) const;
TimingArcSet *findTimingArcSet(size_t index) const;
bool hasTimingArcs(LibertyPort *port) const;
const InternalPowerSeq &internalPowers() const { return internal_powers_; }
const InternalPowerSeq &internalPowers(const LibertyPort *port);
LeakagePowerSeq *leakagePowers() { return &leakage_powers_; }
InternalPowerPtrSeq internalPowers(const LibertyPort *port) const;
const LeakagePowerSeq &leakagePowers() const { return leakage_powers_; }
void leakagePower(// Return values.
float &leakage,
bool &exists) const;
@ -486,6 +541,7 @@ public:
const Statetable *statetable() const { return statetable_; }
// Find bus declaration local to this cell.
BusDcl *makeBusDcl(std::string name, int from, int to);
BusDcl *findBusDcl(const char *name) const;
// True when TimingArcSetBuilder::makeRegLatchArcs infers register
// timing arcs.
@ -497,15 +553,14 @@ public:
const FuncExpr *&enable_func,
const RiseFall *&enable_rf) const;
const RiseFall *latchCheckEnableEdge(TimingArcSet *check_set);
bool isDisabledConstraint() const { return is_disabled_constraint_; }
LibertyCell *cornerCell(const Corner *corner,
LibertyCell *sceneCell(const Scene *scene,
const MinMax *min_max);
LibertyCell *cornerCell(const DcalcAnalysisPt *dcalc_ap);
LibertyCell *cornerCell(int ap_index);
LibertyCell *sceneCell(int ap_index);
// AOCV
float ocvArcDepth() const;
OcvDerate *ocvDerate() const;
OcvDerate *makeOcvDerate(std::string name);
OcvDerate *findOcvDerate(const char *derate_name);
// Build helpers.
@ -522,22 +577,28 @@ public:
void makeStatetable(LibertyPortSeq &input_ports,
LibertyPortSeq &internal_ports,
StatetableRows &table);
void addBusDcl(BusDcl *bus_dcl);
// Add scaled cell after it is complete.
void addScaledCell(OperatingConditions *op_cond,
LibertyCell *scaled_cell);
unsigned addTimingArcSet(TimingArcSet *set);
void addInternalPower(InternalPower *power);
void addInternalPowerAttrs(InternalPowerAttrs *attrs);
void addLeakagePower(LeakagePower *power);
TimingArcSet *makeTimingArcSet(LibertyPort *from,
LibertyPort *to,
LibertyPort *related_out,
const TimingRole *role,
TimingArcAttrsPtr attrs);
void makeInternalPower(LibertyPort *port,
LibertyPort *related_port,
LibertyPort *related_pg_pin,
const std::shared_ptr<FuncExpr> &when,
InternalPowerModels &models);
void makeLeakagePower(LibertyPort *related_pg_port,
FuncExpr *when,
float power);
void setLeakagePower(float leakage);
void setOcvArcDepth(float depth);
void setOcvDerate(OcvDerate *derate);
void addOcvDerate(OcvDerate *derate);
void setTestCell(TestCell *test);
void setHasInferedRegTimingArcs(bool infered);
void setIsDisabledConstraint(bool is_disabled);
void setCornerCell(LibertyCell *corner_cell,
void setSceneCell(LibertyCell *scene_cell,
int ap_index);
// Call after cell is finished being constructed.
void finish(bool infer_latches,
@ -550,9 +611,9 @@ public:
LibertyPort *&input,
LibertyPort *&output) const;
// Check all liberty cells to make sure they exist
// for all the defined corners.
static void checkLibertyCorners();
void ensureVoltageWaveforms(const DcalcAnalysisPtSeq &dcalc_aps);
// for all the defined scenes.
static void checkLibertyScenes();
void ensureVoltageWaveforms(const SceneSeq &scenes);
const char *footprint() const;
void setFootprint(const char *footprint);
const char *userFunctionClass() const;
@ -587,14 +648,12 @@ protected:
void translatePresetClrCheckRoles();
void inferLatchRoles(Report *report,
Debug *debug);
void deleteInternalPowerAttrs();
void makeTimingArcMap(Report *report);
void makeTimingArcPortMaps();
bool hasBufferFunc(const LibertyPort *input,
const LibertyPort *output) const;
bool hasInverterFunc(const LibertyPort *input,
const LibertyPort *output) const;
bool checkCornerCell(const Corner *corner,
bool checkSceneCell(const Scene *scene,
const MinMax *min_max) const;
LibertyLibrary *liberty_library_;
@ -612,14 +671,11 @@ protected:
bool interface_timing_;
ClockGateType clock_gate_type_;
TimingArcSetSeq timing_arc_sets_;
TimingArcSetMap timing_arc_set_map_;
TimingArcSetSet timing_arc_set_set_;
LibertyPortPairTimingArcMap port_timing_arc_set_map_;
LibertyPortTimingArcMap timing_arc_set_from_map_;
LibertyPortTimingArcMap timing_arc_set_to_map_;
bool has_infered_reg_timing_arcs_;
InternalPowerSeq internal_powers_;
PortInternalPowerSeq port_internal_powers_;
InternalPowerAttrsSeq internal_power_attrs_;
PortInternalPowerMap port_internal_powers_;
LeakagePowerSeq leakage_powers_;
SequentialSeq sequentials_;
PortToSequentialMap port_to_seq_map_;
@ -629,18 +685,17 @@ protected:
ScaleFactors *scale_factors_;
ScaledCellMap scaled_cells_;
TestCell *test_cell_;
// Latch D->Q to LatchEnable.
LatchEnableMap latch_d_to_q_map_;
// Latch EN->D setup to LatchEnable.
LatchEnableMap latch_check_map_;
// Latch D->Q to LatchEnable index.
LatchEnableIndexMap latch_d_to_q_map_;
// Latch EN->D setup to LatchEnable index.
LatchEnableIndexMap latch_check_map_;
LatchEnableSeq latch_enables_;
// Ports that have latch D->Q timing arc sets from them.
LibertyPortSet latch_data_ports_;
float ocv_arc_depth_;
OcvDerate *ocv_derate_;
OcvDerateMap ocv_derate_map_;
bool is_disabled_constraint_;
Vector<LibertyCell*> corner_cells_;
std::vector<LibertyCell*> scene_cells_;
float leakage_power_;
bool leakage_power_exists_;
bool has_internal_ports_;
@ -659,18 +714,18 @@ private:
class LibertyCellPortIterator : public Iterator<LibertyPort*>
{
public:
explicit LibertyCellPortIterator(const LibertyCell *cell);
LibertyCellPortIterator(const LibertyCell *cell);
bool hasNext();
LibertyPort *next();
private:
ConcretePortSeq::ConstIterator iter_;
ConcreteCellPortIterator iter_;
};
class LibertyCellPortBitIterator : public Iterator<LibertyPort*>
{
public:
explicit LibertyCellPortBitIterator(const LibertyCell *cell);
LibertyCellPortBitIterator(const LibertyCell *cell);
virtual ~LibertyCellPortBitIterator();
bool hasNext();
LibertyPort *next();
@ -814,17 +869,12 @@ public:
const RiseFall *pulseClkSense() const { return pulse_clk_sense_; }
void setPulseClk(const RiseFall *rfigger,
const RiseFall *sense);
bool isDisabledConstraint() const { return is_disabled_constraint_; }
void setIsDisabledConstraint(bool is_disabled);
LibertyPort *cornerPort(const Corner *corner,
LibertyPort *scenePort(const Scene *scene,
const MinMax *min_max);
const LibertyPort *cornerPort(const Corner *corner,
const LibertyPort *scenePort(const Scene *scene,
const MinMax *min_max) const;
LibertyPort *cornerPort(const DcalcAnalysisPt *dcalc_ap);
const LibertyPort *cornerPort(const DcalcAnalysisPt *dcalc_ap) const;
LibertyPort *cornerPort(int ap_index);
const LibertyPort *cornerPort(int ap_index) const;
void setCornerPort(LibertyPort *corner_port,
const LibertyPort *scenePort(int ap_index) const;
void setScenePort(LibertyPort *scene_port,
int ap_index);
const char *relatedGroundPin() const;
void setRelatedGroundPin(const char *related_ground_pin);
@ -842,10 +892,6 @@ public:
float clkTreeDelay(float in_slew,
const RiseFall *from_rf,
const MinMax *min_max) const;
void setClkTreeDelay(const TableModel *model,
const RiseFall *from_rf,
const RiseFall *to_rf,
const MinMax *min_max);
// deprecated 2024-06-22
RiseFallMinMax clkTreeDelays() const __attribute__ ((deprecated));
// deprecated 2024-02-27
@ -881,6 +927,7 @@ protected:
float,
const MinMax *)> &setter);
LibertyPort *scenePort(int ap_index);
LibertyCell *liberty_cell_;
BusDcl *bus_dcl_;
@ -902,11 +949,9 @@ protected:
const RiseFall *pulse_clk_sense_;
std::string related_ground_pin_;
std::string related_power_pin_;
Vector<LibertyPort*> corner_ports_;
std::vector<LibertyPort*> scene_ports_;
ReceiverModelPtr receiver_model_;
DriverWaveform *driver_waveform_[RiseFall::index_count];
// Redundant with clock_tree_path_delay timing arcs but faster to access.
const TableModel *clk_tree_delay_[RiseFall::index_count][RiseFall::index_count][MinMax::index_count];
unsigned int min_pulse_width_exists_:RiseFall::index_count;
bool min_period_exists_:1;
@ -923,7 +968,6 @@ protected:
bool isolation_cell_enable_:1;
bool level_shifter_data_:1;
bool is_switch_:1;
bool is_disabled_constraint_:1;
bool is_pad_:1;
private:
@ -939,7 +983,7 @@ sortByName(const LibertyPortSet *set);
class LibertyPortMemberIterator : public Iterator<LibertyPort*>
{
public:
explicit LibertyPortMemberIterator(const LibertyPort *port);
LibertyPortMemberIterator(const LibertyPort *port);
virtual ~LibertyPortMemberIterator();
virtual bool hasNext();
virtual LibertyPort *next();
@ -990,7 +1034,7 @@ protected:
class ScaleFactors
{
public:
explicit ScaleFactors(const char *name);
ScaleFactors(const char *name);
const char *name() const { return name_.c_str(); }
float scale(ScaleFactorType type,
ScaleFactorPvt pvt,
@ -1017,10 +1061,10 @@ protected:
class BusDcl
{
public:
BusDcl(const char *name,
BusDcl(std::string name,
int from,
int to);
const char *name() const { return name_.c_str(); }
const std::string &name() const { return name_; }
int from() const { return from_; }
int to() const { return to_; }
@ -1034,18 +1078,16 @@ protected:
class ModeDef
{
public:
~ModeDef();
const char *name() const { return name_.c_str(); }
const std::string &name() const { return name_; }
ModeValueDef *defineValue(const char *value,
FuncExpr *cond,
const char *sdf_cond);
ModeValueDef *findValueDef(const char *value);
ModeValueMap *values() { return &values_; }
const ModeValueDef *findValueDef(const char *value) const;
const ModeValueMap *values() const { return &values_; }
explicit ModeDef(std::string name);
protected:
// Private to LibertyCell::makeModeDef.
ModeDef(const char *name);
std::string name_;
ModeValueMap values_;
@ -1053,41 +1095,19 @@ private:
friend class LibertyCell;
};
// Mode definition mode_value group.
class ModeValueDef
{
public:
~ModeValueDef();
const char *value() const { return value_.c_str(); }
FuncExpr *cond() const { return cond_; }
void setCond(FuncExpr *cond);
const char *sdfCond() const { return sdf_cond_.c_str(); }
void setSdfCond(const char *sdf_cond);
protected:
// Private to ModeDef::defineValue.
ModeValueDef(const char *value,
FuncExpr *cond,
const char *sdf_cond);
std::string value_;
FuncExpr *cond_;
std::string sdf_cond_;
private:
friend class ModeDef;
};
class TableTemplate
{
public:
TableTemplate(const char *name);
TableTemplate(const char *name,
TableTemplate(std::string name);
TableTemplate(std::string name,
TableTemplateType type);
TableTemplate(std::string name,
TableAxisPtr axis1,
TableAxisPtr axis2,
TableAxisPtr axis3);
const char *name() const { return name_.c_str(); }
void setName(const char *name);
const std::string &name() const { return name_; }
void setName(std::string name);
TableTemplateType type() const { return type_; }
const TableAxis *axis1() const { return axis1_.get(); }
TableAxisPtr axis1ptr() const { return axis1_; }
void setAxis1(TableAxisPtr axis);
@ -1100,6 +1120,7 @@ public:
protected:
std::string name_;
TableTemplateType type_;
TableAxisPtr axis1_;
TableAxisPtr axis2_;
TableAxisPtr axis3_;
@ -1109,8 +1130,8 @@ class TestCell : public LibertyCell
{
public:
TestCell(LibertyLibrary *library,
const char *name,
const char *filename);
std::string name,
std::string filename);
protected:
};
@ -1118,9 +1139,9 @@ protected:
class OcvDerate
{
public:
OcvDerate(const char *name);
OcvDerate(std::string name);
~OcvDerate();
const char *name() const { return name_; }
const std::string &name() const { return name_; }
const Table *derateTable(const RiseFall *rf,
const EarlyLate *early_late,
PathType path_type);
@ -1130,7 +1151,7 @@ public:
TablePtr derate);
private:
const char *name_;
std::string name_;
// [rf_type][derate_type][path_type]
TablePtr derate_[RiseFall::index_count][EarlyLate::index_count][path_type_count];
};

View File

@ -25,10 +25,9 @@
#pragma once
#include <memory>
#include "Vector.hh"
#include "Map.hh"
#include "Set.hh"
#include <vector>
#include <map>
#include <set>
namespace sta {
@ -67,19 +66,19 @@ class ReceiverModel;
class Statetable;
class StatetableRow;
typedef Vector<LibertyLibrary*> LibertyLibrarySeq;
typedef Vector<LibertyCell*> LibertyCellSeq;
typedef Vector<Sequential*> SequentialSeq;
typedef Map<LibertyCell*, LibertyCellSeq*> LibertyCellEquivMap;
typedef Vector<LibertyPort*> LibertyPortSeq;
typedef Set<LibertyPort*> LibertyPortSet;
typedef std::pair<const LibertyPort*,const LibertyPort*> LibertyPortPair;
typedef Set<LibertyCell*> LibertyCellSet;
typedef std::shared_ptr<Table> TablePtr;
typedef std::shared_ptr<TimingArcAttrs> TimingArcAttrsPtr;
typedef std::shared_ptr<TableAxis> TableAxisPtr;
typedef std::shared_ptr<ReceiverModel> ReceiverModelPtr;
typedef std::vector<StatetableRow> StatetableRows;
using LibertyLibrarySeq = std::vector<LibertyLibrary*>;
using LibertyCellSeq = std::vector<LibertyCell*>;
using SequentialSeq = std::vector<Sequential>;
using LibertyCellEquivMap = std::map<LibertyCell*, LibertyCellSeq*>;
using LibertyPortSeq = std::vector<LibertyPort*>;
using LibertyPortSet = std::set<LibertyPort*>;
using LibertyPortPair = std::pair<const LibertyPort*,const LibertyPort*>;
using LibertyCellSet = std::set<LibertyCell*>;
using TablePtr = std::shared_ptr<Table>;
using TimingArcAttrsPtr = std::shared_ptr<TimingArcAttrs>;
using TableAxisPtr = std::shared_ptr<TableAxis>;
using ReceiverModelPtr = std::shared_ptr<ReceiverModel>;
using StatetableRows = std::vector<StatetableRow>;
enum class ScaleFactorType : unsigned {
pin_cap,

View File

@ -58,7 +58,7 @@ protected:
class CheckLinearModel : public CheckTimingModel
{
public:
explicit CheckLinearModel(LibertyCell *cell,
CheckLinearModel(LibertyCell *cell,
float intrinsic);
ArcDelay checkDelay(const Pvt *pvt,
float from_slew,

View File

@ -1,191 +0,0 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software.
//
// Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// This notice may not be removed or altered from any source distribution.
#pragma once
#include <map>
#include <algorithm>
namespace sta {
// Add convenience functions around STL container.
template <class KEY, class VALUE, class CMP = std::less<KEY>>
class Map : public std::map<KEY, VALUE, CMP>
{
public:
Map() :
std::map<KEY, VALUE, CMP>()
{
}
explicit Map(const CMP &cmp) :
std::map<KEY, VALUE, CMP>(cmp)
{
}
// Find out if key is in the set.
bool
hasKey(const KEY key) const
{
return this->find(key) != this->end();
}
// Find the value corresponding to key.
VALUE
findKey(const KEY key) const
{
auto find_iter = this->find(key);
if (find_iter != this->end())
return find_iter->second;
else
return nullptr;
}
void
findKey(const KEY key,
// Return Values.
VALUE &value,
bool &exists) const
{
auto find_iter = this->find(key);
if (find_iter != this->end()) {
value = find_iter->second;
exists = true;
}
else
exists = false;
}
void
findKey(const KEY &key,
// Return Values.
KEY &map_key,
VALUE &value,
bool &exists) const
{
auto find_iter = this->find(key);
if (find_iter != this->end()) {
map_key = find_iter->first;
value = find_iter->second;
exists = true;
}
else
exists = false;
}
void
insert(const KEY &key,
VALUE value)
{
this->operator[](key) = value;
}
void
deleteContents()
{
Iterator iter(this);
while (iter.hasNext())
delete iter.next();
}
void
deleteKeysContents()
{
for (const auto [key, value] : this) {
delete key;
delete value;
}
}
void
deleteArrayContents()
{
Iterator iter(this);
while (iter.hasNext())
delete [] iter.next();
}
void
deleteContentsClear()
{
deleteContents();
std::map<KEY, VALUE, CMP>::clear();
}
// Java style container itererator
// Map::Iterator<string *, Value, stringLess> iter(map);
// while (iter.hasNext()) {
// Value *v = iter.next();
// }
class Iterator
{
public:
Iterator() : container_(nullptr) {}
explicit Iterator(std::map<KEY, VALUE, CMP> *container) :
container_(container)
{ if (container_ != nullptr) iter_ = container_->begin(); }
explicit Iterator(std::map<KEY, VALUE, CMP> &container) :
container_(&container)
{ if (container_ != nullptr) iter_ = container_->begin(); }
void init(std::map<KEY, VALUE, CMP> *container)
{ container_ = container; if (container_ != nullptr) iter_=container_->begin();}
void init(std::map<KEY, VALUE, CMP> &container)
{ container_ = &container; if (container_ != nullptr) iter_=container_->begin();}
bool hasNext() { return container_ != nullptr && iter_ != container_->end(); }
VALUE next() { return iter_++->second; }
void next(KEY &key,
VALUE &value)
{ key = iter_->first; value = iter_->second; iter_++; }
std::map<KEY, VALUE, CMP> *container() { return container_; }
private:
std::map<KEY, VALUE, CMP> *container_;
typename std::map<KEY, VALUE, CMP>::iterator iter_;
};
class ConstIterator
{
public:
ConstIterator() : container_(nullptr) {}
explicit ConstIterator(const std::map<KEY, VALUE, CMP> *container) :
container_(container)
{ if (container_ != nullptr) iter_ = container_->begin(); }
explicit ConstIterator(const std::map<KEY, VALUE, CMP> &container) :
container_(&container)
{ if (container_ != nullptr) iter_ = container_->begin(); }
void init(const std::map<KEY, VALUE, CMP> *container)
{ container_ = container; if (container_ != nullptr) iter_=container_->begin();}
void init(const std::map<KEY, VALUE, CMP> &container)
{ container_ = &container; if (container_ != nullptr) iter_=container_->begin();}
bool hasNext() { return container_ != nullptr && iter_ != container_->end(); }
VALUE next() { return iter_++->second; }
void next(KEY &key,
VALUE &value)
{ key = iter_->first; value = iter_->second; iter_++; }
const std::map<KEY, VALUE, CMP> *container() { return container_; }
private:
const std::map<KEY, VALUE, CMP> *container_;
typename std::map<KEY, VALUE, CMP>::const_iterator iter_;
};
};
} // namespace

View File

@ -36,8 +36,8 @@ class MinMax;
class MinMaxAll;
// Use typedefs to make early/late functional equivalents to min/max.
typedef MinMax EarlyLate;
typedef MinMaxAll EarlyLateAll;
using EarlyLate = MinMax;
using EarlyLateAll = MinMaxAll;
// Large value used for min/max initial values.
extern const float INF;
@ -112,6 +112,7 @@ public:
static const MinMaxAll *max() { return &max_; }
static const MinMaxAll *late() { return &max_; }
static const MinMaxAll *all() { return &all_; }
static const MinMaxAll *minMax() { return &all_; }
const std::string &to_string() const { return name_; }
int index() const { return index_; }
const MinMax *asMinMax() const;

Some files were not shown because too many files have changed in this diff Show More