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:
commit
8adbcc0d6d
|
|
@ -10,7 +10,7 @@ AllowAllParametersOfDeclarationOnNextLine: false
|
|||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterReturnType: TopLevel
|
||||
BinPackArguments: false
|
||||
BinPackArguments: true
|
||||
# fails
|
||||
BinPackParameters: AlwaysOnePerLine
|
||||
BraceWrapping:
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
@ -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);
|
||||
```
|
||||
|
|
@ -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 }}
|
||||
|
|
@ -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 }}
|
||||
|
|
@ -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
|
||||
|
|
@ -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 }}
|
||||
|
|
@ -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")
|
||||
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
17
app/Main.cc
17
app/Main.cc
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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 "";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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
|
||||
------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
6688
doc/OpenSTA.fodt
6688
doc/OpenSTA.fodt
File diff suppressed because it is too large
Load Diff
BIN
doc/OpenSTA.pdf
BIN
doc/OpenSTA.pdf
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,2 @@
|
|||
create_clock -name m1_clk -period 1000 {clk1 clk2 clk3}
|
||||
set_input_delay -clock m1_clk 100 {in1 in2}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
create_clock -name m2_clk -period 500 {clk1 clk3}
|
||||
set_output_delay -clock m2_clk 100 out
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
204
graph/Graph.cc
204
graph/Graph.cc
|
|
@ -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
|
||||
|
|
|
|||
233
graph/Graph.i
233
graph/Graph.i
|
|
@ -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 *
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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 ¶siticAnalysisPts();
|
||||
|
||||
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
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ®ClkVertices() { 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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ namespace sta {
|
|||
class VertexNameLess
|
||||
{
|
||||
public:
|
||||
explicit VertexNameLess(Network *network);
|
||||
VertexNameLess(Network *network);
|
||||
bool operator()(const Vertex *vertex1,
|
||||
const Vertex *vertex2);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 *¶sitic) 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.
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "Set.hh"
|
||||
#include "NetworkClass.hh"
|
||||
|
||||
namespace sta {
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ class InputDriveCell;
|
|||
class InputDrive
|
||||
{
|
||||
public:
|
||||
explicit InputDrive();
|
||||
InputDrive();
|
||||
~InputDrive();
|
||||
void setSlew(const RiseFallBoth *rf,
|
||||
const MinMaxAll *min_max,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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_; }
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
Loading…
Reference in New Issue