Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
9afd41e
dbSta: add depth-based (AOCV-style) OCV derate report (first slice)
saurav-fermions Jul 9, 2026
d70d97b
AOCV: apply depth-based OCV derate during STA propagation (flag-gated)
saurav-fermions Jul 9, 2026
3899f5f
feat(dbSta,rcx): add coupling Miller-factor SI timing derate
saurav-fermions Jul 9, 2026
9f1c998
SI slice 2: timing-window aware coupling derate
saurav-fermions Jul 9, 2026
9236683
dbSta: add report_pba_slack PBA pessimism-recovery (setup, first slice)
saurav-fermions Jul 9, 2026
1245af1
[dbSta] CPPR: clock reconvergence pessimism removal (report-only)
saurav-fermions Jul 9, 2026
69f2ad5
[dbSta] crosstalk-aware delay: coupling-cap effective-C stage-delay a…
saurav-fermions Jul 9, 2026
c33ef7d
[dbSta] crosstalk slice 2: per-edge direction + bounded re-convergence
saurav-fermions Jul 9, 2026
1a91027
[dbSta] PBA hold-path recovery + endpoint closure decision
saurav-fermions Jul 9, 2026
eeff7e9
[dbSta] MCMM: multi-corner setup + cross-corner worst-slack report
saurav-fermions Jul 9, 2026
ac5bb71
[dbSta] CPPR slice 2: endpoint closure decision with CRPR credit
saurav-fermions Jul 9, 2026
b9e1339
[dbSta] incremental STA for ECO/repair path (additive, full-STA-equiv…
saurav-fermions Jul 9, 2026
61b6e4b
[dbSta] unified PBA+CPPR closure report
saurav-fermions Jul 9, 2026
beb21fb
[dbSta] crosstalk-aware delay on hold paths (flag-gated)
saurav-fermions Jul 9, 2026
aa492e4
[dbSta] test: crosstalk-aware delay on hold paths (si-hold)
saurav-fermions Jul 9, 2026
4ced81f
[dbSta] MCMM slice 2: mode dimension + per-mode worst-slack
saurav-fermions Jul 9, 2026
7bf9745
[dbSta] test: MCMM slice 2 by-mode (2 modes x 2 corners)
saurav-fermions Jul 9, 2026
27cc748
dbSta: drop references to internal investigation notes
saurav-fermions Jul 9, 2026
9bc49cc
feat(dbSta): add report_noise crosstalk glitch triage
saurav-fermions Jul 9, 2026
f5f3dbf
dbSta: optional noise-induced delay push (crosstalk noise -> timing)
saurav-fermions Jul 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/dbSta/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,18 @@ package(
cc_library(
name = "dbSta",
srcs = [
"src/PbaReport.cc",
"src/CpprReport.cc",
"src/McmmReport.cc",
"src/IncrementalStaReport.cc",
"src/dbSta.cc",
],
hdrs = [
"include/db_sta/DelayFmt.hh",
"include/db_sta/PbaReport.hh",
"include/db_sta/CpprReport.hh",
"include/db_sta/McmmReport.hh",
"include/db_sta/IncrementalStaReport.hh",
"include/db_sta/dbSta.hh",
],
includes = [
Expand Down Expand Up @@ -134,6 +142,10 @@ cc_library(
cc_library(
name = "ui",
srcs = [
"include/db_sta/PbaReport.hh",
"include/db_sta/CpprReport.hh",
"include/db_sta/McmmReport.hh",
"include/db_sta/IncrementalStaReport.hh",
"src/MakeDbSta.cc",
":swig",
":tcl",
Expand Down
76 changes: 76 additions & 0 deletions src/dbSta/include/db_sta/AocvDerate.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2019-2025, The OpenROAD Authors

// Depth-based (AOCV-style) on-chip-variation derate, first slice.
//
// This is an OpenROAD-side (dbSta) feature that re-uses public OpenSTA APIs to
// recompute a depth-adjusted setup slack on already-found critical paths. It
// does NOT modify the OpenSTA forward search.

#pragma once

#include <map>
#include <string>
#include <vector>

#include "sta/Search.hh" // OpenROAD-fork: AOCV -- AocvDepthDerate interface

namespace sta {

class Sta;
class PathEnd;

// A simple depth -> derate-multiplier table, with separate early and late
// columns. depth is the number of combinational logic stages along the data
// path. Lookup uses the entry with the largest tabulated depth that is <= the
// queried depth (i.e. step / hold-last-value), which matches how AOCV tables
// are typically interpreted. If empty, lookups return 1.0 (inactive).
//
// OpenROAD-fork: AOCV -- this table also implements the OpenSTA AocvDepthDerate
// hook so it can be installed on Search for propagation-time depth derating.
class AocvDerateTable : public AocvDepthDerate
{
public:
void clear();
bool empty() const { return late_.empty() && early_.empty(); }

void setLate(int depth, float derate) { late_[depth] = derate; }
void setEarly(int depth, float derate) { early_[depth] = derate; }

// Returns 1.0 when no late entries are present (inactive / default).
float lateDerate(int depth) const override;
float earlyDerate(int depth) const override;
// OpenROAD-fork: AOCV -- which sides have explicit table data.
bool lateActive() const override { return !late_.empty(); }
bool earlyActive() const override { return !early_.empty(); }

// Load a whitespace table file with lines of the form:
// depth late_derate [early_derate]
// '#' starts a comment. Returns false and sets error on a malformed line.
bool readFile(const std::string& filename, std::string& error);

private:
static float lookup(const std::map<int, float>& tbl, int depth);

std::map<int, float> late_;
std::map<int, float> early_;
};

// One row of the AOCV slack report for a single path end.
struct AocvPathResult
{
std::string endpoint;
int logic_depth = 0;
float flat_slack = 0.0f;
float aocv_slack = 0.0f;
float late_derate = 1.0f; // derate used for this depth
};

// Recompute depth-adjusted setup slack for one path end, applying the table's
// late derate (by logic depth) to the data path's combinational cell arcs in
// place of the flat late derate that OpenSTA actually applied.
AocvPathResult aocvAdjustPathEnd(Sta* sta,
PathEnd* path_end,
const AocvDerateTable& table);

} // namespace sta
148 changes: 148 additions & 0 deletions src/dbSta/include/db_sta/ClosureReport.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2026, The OpenROAD Authors

// Unified pessimism-recovery closure report (additive, report-only).
//
// This is an ADDITIVE, OpenROAD-side (dbSta) diagnostic. It does NOT change
// the default graph-based-analysis (GBA) results produced by report_checks,
// and it does NOT mutate the timing graph.
//
// Motivation
// ----------
// Two independent pessimism-recovery surfaces already exist in this fork:
// * PBA (PbaReport) -- path-based gate-slew pessimism recovery; recovers
// the gate-stage delay over-estimate the worst-case
// graph slew bakes into GBA.
// * CPPR (CpprReport) -- clock-reconvergence pessimism removal; credits
// back the double-counted derate on the shared
// launch/capture clock segment.
// Each classifies endpoints separately. A user closing a design wants ONE
// verdict: for every endpoint that is failing under the most pessimistic
// view, does it STILL fail after BOTH recoveries are applied (a GENUINE
// violation to fix), or does some recovery mechanism clear it (an ARTIFACT)?
//
// Composition (NOT reimplementation)
// ----------------------------------
// We COMPOSE the existing computePbaEndpoints() and computeCpprEndpoints()
// results, joined per endpoint. The pessimism stack, from most to least
// pessimistic, is:
//
// raw_slack = PathEnd::slackNoCrpr (CpprEndpointResult.raw_slack)
// + cppr_credit = CPPR common-path credit (>= 0)
// = gba_slack = PathEnd::slack = report_checks slack
// (== CpprEndpointResult.cppr_slack
// == PbaEndpointResult.gba_slack)
// + pba_recovered = PBA gate-slew pessimism recovery (>= 0)
// = recovered_slack = PbaEndpointResult.pba_slack
//
// So the fully-recovered slack is exactly the PBA slack (PBA already builds
// on the CPPR-adjusted GBA slack), and the combined recovery over the raw
// baseline is cppr_credit + pba_recovered. Both terms are >= 0 by the
// construction proved in the PBA and CPPR modules, so the recovery is
// monotone: recovered_slack >= raw_slack.
//
// Classification (keyed off the RAW pessimistic baseline)
// -------------------------------------------------------
// raw_violated : raw_slack < 0 (failing under the pessimistic view)
// genuine : recovered_slack < 0 (still failing after BOTH
// recoveries -- the real violation to fix)
// artifact : raw_violated && !genuine (cleared by some recovery),
// labeled with WHICH mechanism cleared it:
// CPPR -- CPPR credit alone lifts it to >= 0,
// PBA -- PBA recovery alone lifts it to >= 0,
// BOTH -- neither alone suffices but together they do.

#pragma once

#include <string>
#include <vector>

#include "sta/MinMax.hh"

namespace sta {

class dbSta;

// Which recovery mechanism cleared a raw-failing endpoint (for artifacts).
enum class ClearedBy
{
kNone, // not an artifact (either not raw-failing, or still genuine)
kCppr, // CPPR common-path credit alone lifts raw_slack to >= 0
kPba, // PBA gate-slew recovery alone lifts raw_slack to >= 0
kBoth // neither mechanism alone suffices; both together clear it
};

// Human-readable mechanism label for ClearedBy (stable, used in reports and
// the machine-readable test surface). "-" for kNone.
const char* clearedByLabel(ClearedBy cleared_by);

// Per-endpoint unified closure result. Times are in seconds (STA internal
// units). Composed from the PBA and CPPR endpoint results.
struct ClosureEndpointResult
{
std::string endpoint;
// Most pessimistic baseline: pre-CPPR, pre-PBA (PathEnd::slackNoCrpr).
float raw_slack = 0.0f;
// GBA slack as reported by report_checks (CPPR applied, no PBA):
// gba_slack = raw_slack + cppr_credit.
float gba_slack = 0.0f;
// Fully recovered slack after BOTH CPPR and PBA:
// recovered_slack = gba_slack + pba_recovered = raw_slack + total recovery.
float recovered_slack = 0.0f;
// CPPR common-path credit (>= 0).
float cppr_credit = 0.0f;
// PBA gate-slew pessimism recovery (>= 0).
float pba_recovered = 0.0f;
// Deepest shared clock pin the CPPR credit is attributed to (or "").
std::string common_pin;
// Failing under the raw pessimistic baseline (raw_slack < 0).
bool raw_violated = false;
// GENUINE violation: still failing after BOTH recoveries
// (recovered_slack < 0).
bool genuine = false;
// ARTIFACT: raw-failing but cleared by some recovery (raw_violated &&
// !genuine).
bool artifact = false;
// For artifacts, which mechanism cleared it. kNone otherwise.
ClearedBy cleared_by = ClearedBy::kNone;
};

// Summary counters for the unified closure verdict.
struct ClosureSummary
{
int endpoints = 0; // endpoints analyzed
int raw_failing = 0; // failing under the raw pessimistic baseline
int cleared_by_cppr = 0; // artifacts cleared by CPPR alone
int cleared_by_pba = 0; // artifacts cleared by PBA alone
int cleared_by_both = 0; // artifacts cleared only by CPPR+PBA together
int genuine = 0; // still failing after both recoveries
};

// Compute the unified per-endpoint closure classification by COMPOSING the
// existing PBA and CPPR endpoint computations (it calls computePbaEndpoints
// and computeCpprEndpoints internally and joins them by endpoint name).
// max_paths : number of endpoint groups to enumerate (top-N), forwarded to
// both underlying computations.
// min_max : MinMax::max() for setup, MinMax::min() for hold.
// Read-only: does not mutate the graph and does not change crpr_enabled.
std::vector<ClosureEndpointResult> computeClosure(dbSta* sta,
int max_paths,
const MinMax* min_max);

// Summarize endpoint results into the unified closure counters.
ClosureSummary summarizeClosure(
const std::vector<ClosureEndpointResult>& endpoints);

// Unified closure decision surface: classify every raw-failing endpoint into
// a CPPR/PBA/BOTH artifact (cleared by pessimism recovery) vs a genuine
// post-recovery violation, print the combined recovered slack per endpoint
// and a one-line verdict summary.
// only_violations : when true (default) list only the genuine violations;
// when false also list the cleared artifacts (with the
// mechanism label).
void reportClosure(dbSta* sta,
int max_paths,
const MinMax* min_max,
bool only_violations);

} // namespace sta
141 changes: 141 additions & 0 deletions src/dbSta/include/db_sta/CpprReport.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2026, The OpenROAD Authors

// CPPR / CRPR -- Clock Reconvergence Pessimism Removal reporting.
//
// This is an ADDITIVE, OpenROAD-side (dbSta) diagnostic. It does NOT change
// the default graph-based-analysis (GBA) results produced by report_checks,
// and it does NOT mutate the timing graph.
//
// Background
// ----------
// For a setup/hold check the launch and capture clock paths usually share a
// common clock-tree segment from the clock root down to a branch point. When
// on-chip-variation (OCV / AOCV / set_timing_derate) is applied, the derate
// is applied INDEPENDENTLY to the launch and the capture clock path -- but
// the shared segment is the SAME physical silicon, so deratng it on both
// sides DOUBLE-COUNTS the pessimism on the common path. CPPR (a.k.a. CRPR)
// credits that pessimism back.
//
// What OpenSTA already provides vs. what this adds
// ------------------------------------------------
// OpenSTA already implements CRPR end-to-end (search/Crpr.cc, CheckCrpr) and
// it is ON by default in OCV analysis (Variables::crpr_enabled_ == true). The
// authoritative credit for a check is therefore already available through the
// public PathEnd API:
// * PathEnd::slackNoCrpr(sta) -- slack WITHOUT the common-path credit (the
// pessimistic, double-counted number),
// * PathEnd::slack(sta) -- slack WITH the credit (the GBA result),
// * PathEnd::checkCrpr(sta) -- the signed CRPR delta folded into the
// required time.
// This module does NOT reimplement CRPR. It SURFACES the raw-vs-adjusted
// split per check in one auditable table, and -- using only the public
// Path / PathExpanded API -- independently identifies the deepest shared
// clock pin (the common point) so the credit is attributable to a concrete
// branch point. The reported credit is taken from OpenSTA (slack -
// slackNoCrpr), so it always matches the engine.

#pragma once

#include <string>
#include <vector>

#include "sta/MinMax.hh"

namespace sta {

class dbSta;

// Per-check CPPR result. Times are in seconds (STA internal units).
struct CpprPathResult
{
std::string endpoint;
// Raw slack with the common clock-path pessimism still double-counted
// (PathEnd::slackNoCrpr). This is the conservative / pessimistic slack.
float raw_slack = 0.0f;
// CPPR-adjusted slack with the common-path credit applied
// (PathEnd::slack -- the default GBA result).
float cppr_slack = 0.0f;
// Pessimism credited back on the common clock path:
// credit = cppr_slack - raw_slack, always >= 0 (CPPR only relaxes).
float credit = 0.0f;
// Name of the deepest shared clock pin between the launch and capture
// clock paths (the common point), or "" if none was identified.
std::string common_pin;
};

// Per-endpoint CPPR aggregation enriched with the closure-decision flags.
// For the slice we enumerate one check per endpoint, so this is a 1:1 view
// of CpprPathResult plus the raw->cppr transition flags. Mirrors the
// PbaEndpointResult closure surface for cross-command consistency.
struct CpprEndpointResult
{
std::string endpoint;
// Raw slack with the common clock-path pessimism still double-counted
// (PathEnd::slackNoCrpr) -- the conservative slack the user would close on
// if CRPR pessimism were not credited back.
float raw_slack = 0.0f;
// CPPR-adjusted slack with the common-path credit applied (PathEnd::slack,
// the default GBA result).
float cppr_slack = 0.0f;
// Pessimism credited back (cppr_slack - raw_slack), always >= 0.
float credit = 0.0f;
// Deepest shared clock pin (the branch point) the credit is attributed to.
std::string common_pin;
// Endpoint fails under RAW GBA slack (slackNoCrpr < 0): pessimistic view.
bool raw_violated = false;
// Endpoint still fails after the CPPR credit (slack < 0): a GENUINE
// post-CPPR violation, not a common-path-pessimism artifact.
bool cppr_violated = false;
// Raw-failing but CPPR-passing: the negative raw slack was double-counted
// clock-reconvergence pessimism (an artifact cleared by CPPR).
bool recovered_to_positive = false;
};

// Summary counters for the CPPR closure decision surface.
struct CpprClosureSummary
{
int endpoints = 0; // endpoints analyzed
int raw_violations = 0; // endpoints failing under RAW (no-CRPR) slack
int cppr_violations = 0; // endpoints still failing after CPPR (genuine)
int recovered_endpoints = 0; // raw-failing that CPPR recovered to passing
};

// Compute the CPPR raw-vs-adjusted slack split for the top-N critical checks.
// max_paths : number of endpoint groups to enumerate (top-N).
// min_max : MinMax::max() for setup, MinMax::min() for hold.
// Ordering follows the GBA slack ordering. Read-only: does not mutate the
// graph and does not change crpr_enabled.
std::vector<CpprPathResult> computeCpprSlack(dbSta* sta,
int max_paths,
const MinMax* min_max);

// Per-endpoint aggregation (setup or hold) with closure flags populated.
std::vector<CpprEndpointResult> computeCpprEndpoints(dbSta* sta,
int max_paths,
const MinMax* min_max);

// Summarize endpoint results into closure counters.
CpprClosureSummary summarizeCpprClosure(
const std::vector<CpprEndpointResult>& endpoints);

// Compute + print a per-check report table to the STA report stream.
void reportCppr(dbSta* sta, int max_paths, const MinMax* min_max);

// Per-endpoint CPPR-adjusted slack aggregation: for each endpoint print the
// raw slack, the CPPR credit applied, the adjusted slack and the post-CPPR
// closure status, plus a one-line raw->cppr recovery summary.
void reportCpprEndpoints(dbSta* sta, int max_paths, const MinMax* min_max);

// CPPR closure decision surface: classify endpoints failing under raw GBA
// into (a) common-path-pessimism artifacts that pass once CPPR is applied vs
// (b) genuine post-CPPR violations. Mirrors reportPbaClosure.
// only_violations : when true (default) list only the genuine (post-CPPR)
// violations; when false also list the recovered
// (artifact) endpoints CPPR cleared.
void reportCpprClosure(dbSta* sta,
int max_paths,
const MinMax* min_max,
bool only_violations);

} // namespace sta
Loading
Loading