Skip to content

Sta variant corner - #394

Open
dsengupta0628 wants to merge 6 commits into
The-OpenROAD-Project:masterfrom
The-OpenROAD-Project-staging:sta_variant_corner
Open

Sta variant corner#394
dsengupta0628 wants to merge 6 commits into
The-OpenROAD-Project:masterfrom
The-OpenROAD-Project-staging:sta_variant_corner

Conversation

@dsengupta0628

Copy link
Copy Markdown
Contributor

Summary

Adds an analysis_corner object to the OpenROAD fork of OpenSTA: a named
bundle of per-corner setup data (liberty, parasitics, corner-scoped SDC)
that scenes reference. One logical mode can now be analyzed across N
corners with different derates, IO delays, clock uncertainty, and clock
latency — without defining one composed mode per (mode x corner) pair.

Scenes remain the only unit of analysis and results; the corner is a
setup-side object that computes nothing. The timing engine's data model
is unchanged.

Motivation

Per-corner data (derates, IO budgets from external blocks, uncertainty)
lives in SDC, but SDC state is per-mode. Without this feature, MCMM
flows must compose mode+corner SDC files into synthetic modes
(func_ss, func_ff, ...): each is a full Mode instance (own Sdc,
Sim, ClkNetwork, Genclks, PathGroups) duplicated per corner, and
the generated mode names surface in report_checks headers, get_modes,
write_sdc -mode, and every downstream script. This PR removes the need
for synthetic modes entirely: reports show the real mode, and the mode
list stays clean.

User-facing commands

  define_analysis_corner ss_cmax -liberty {ss.lib} -spef spef_ss \
    -sdc {derates_ss.sdc io_ss.sdc}
  read_sdc -mode func func.sdc
  define_scene func_ss -mode func -analysis_corner ss_cmax

  get_analysis_corners [pattern]
  get_scenes -filter {analysis_corner == ss_cmax}
  get_property [get_scenes func_ss] analysis_corner

  # corner-scoped SDC, file or interactive:
  read_sdc -mode func -analysis_corner ss_cmax extra_derates.sdc
  set_cmd_analysis_corner ss_cmax ... unset_cmd_analysis_corner

All existing commands and arguments are unchanged; flows that do not use
corners are unaffected.

Design

  • Corner-scoped SDC is stored in a sparse overlay Sdc instance per
    (mode, corner), lazily created. The overlay reuses the existing Sdc
    class unmodified; whitelisted SDC write commands target it when a
    corner scope is active, and engine read points consult it with the
    mode Sdc as fallback.
  • Whitelist (corner scope): set_timing_derate, set_input_delay /
    set_output_delay, set_clock_uncertainty (all forms),
    set_clock_latency / insertion, and their unset forms. Everything
    else — clocks, exceptions, case analysis, and all other mode-level SDC
    writes — errors out in corner scope, so structural constraints can
    never exist in two places.
  • No precedence scheme. A corner either defines a data family (and
    replaces the mode's wholesale for that family's key — whole derate
    table, per pin for IO delays, per clock for uncertainty, per lookup
    for latency) or it doesn't (mode value applies untouched). No merging.
    The only ordering is the pin-beats-clock specificity the code already
    has; a corner value wins only at equal specificity.
  • Clock-form set_clock_uncertainty is stored on the corner keyed by
    the mode's Clock* (upstream stores it on the Clock object, which is
    shared across corners); purged on remove_clock / sta::clear.
  • Property/filtering is registered in the C++ property registry — no
    Tcl-side filtering.

Implementation / merge hygiene

  • Logic lives in new files: include/sta/AnalysisCorner.hh,
    search/AnalysisCorner.cc, search/AnalysisCorner.i,
    tcl/AnalysisCorner.tcl.
  • Existing files receive small fenced hunks
    (// ---- OpenROAD fork: analysis_corner support ----) intended to be
    re-applied on upstream merges: read-point overrides in
    search/Search.cc, PathEnd.cc, VisitPathEnds.cc, CheckTiming.cc,
    ReportPath.cc, one-line cmdSdc() -> cmdCornerSdc() swaps in the
    whitelisted write commands in sdc/Sdc.i, and one inline accessor in
    Sdc.hh. Sdc.cc is untouched.
  • Zero overhead when the feature is unused: overlay lookups are gated on
    inline null/empty checks; no overlays are allocated unless a
    corner-scoped SDC command runs.

Testing

  • New regressions: search_analysis_corner (define/query/filter,
    liberty-spef bundles, composition), search_corner_sdc_derate
    (1 mode x N corners vs equivalent synthetic-mode setup — exact
    numeric equivalence asserted in-test), search_corner_sdc_bundle
    (full whitelist per corner vs manual composition — exact equivalence;
    corner isolation; guard errors; redefine semantics).
  • Full suite: 6087/6087 pass.

Known limitations (documented)

  • set_input_transition / set_load are not yet corner-scoped (error
    3711); per-corner RC is expected via per-corner SPEF.
  • Corner clock latency does not adjust generated-clock master-path
    computation or the clock arrival implied by corner IO delays'
    -clock reference (mode values used).
  • A corner cannot un-constrain a pin the mode constrains (override is
    wholesale per pin, no tombstones).
  • Scenes must be defined before timing queries (pre-existing issue
    found in upstream behavior, not introduced here).

Signed-off-by: dsengupta0628 <dsengupta@precisioninno.com>
Signed-off-by: dsengupta0628 <dsengupta@precisioninno.com>
Signed-off-by: dsengupta0628 <dsengupta@precisioninno.com>
…pt set_ip_trans and set_load

Signed-off-by: dsengupta0628 <dsengupta@precisioninno.com>
@dsengupta0628 dsengupta0628 self-assigned this Jul 27, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for analysis corners (PVT/RC corners) to group scenes sharing operating points across modes and manage corner-scoped SDC constraints like timing derates, IO delays, clock uncertainty, and clock latency. The feedback suggests optimizing string lookups in AnalysisCornerNameMap by accepting std::string_view in makeAnalysisCorner and findAnalysisCorner to avoid unnecessary allocations, and improving the time complexity of unique delay set collection in cornerDelaySets from O(N^2) to O(N log N) using std::set.

Comment thread include/sta/Sta.hh Outdated
Comment on lines +155 to +156
AnalysisCorner *makeAnalysisCorner(const std::string &name);
AnalysisCorner *findAnalysisCorner(const std::string &name) const;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

You're using std::less<> for AnalysisCornerNameMap in AnalysisCorner.hh, which enables heterogeneous lookups (e.g., with std::string_view) to avoid std::string allocations on lookups. To fully leverage this, consider changing the signatures of makeAnalysisCorner and findAnalysisCorner to accept std::string_view instead of const std::string &.

  AnalysisCorner *makeAnalysisCorner(std::string_view name);
  AnalysisCorner *findAnalysisCorner(std::string_view name) const;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied. makeAnalysisCorner/findAnalysisCorner now take std::string_view; find goes through findStringKey (the exact idiom upstream's Sta::findMode(std::string_view) uses

Comment thread search/AnalysisCorner.cc
Comment on lines +224 to +232
std::vector<DelaySet*> delay_sets;
for (const Scene *scene : mode->scenes()) {
DelaySet *delays = cornerDelaysLeafPin(scene, pin, delays_leaf_pin);
if (delays
&& std::find(delay_sets.begin(), delay_sets.end(), delays)
== delay_sets.end())
delay_sets.push_back(delays);
}
return delay_sets;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current implementation to find unique DelaySet* uses std::find within a loop over scenes, which has a time complexity of O(N^2) where N is the number of scenes. For better performance, especially if a mode could have a large number of scenes, consider using std::set to collect unique pointers, which would have a complexity of O(N log N).

  std::set<DelaySet*> unique_delay_sets;
  for (const Scene *scene : mode->scenes()) {
    if (auto* delays = cornerDelaysLeafPin(scene, pin, delays_leaf_pin)) {
      unique_delay_sets.insert(delays);
    }
  }
  return {unique_delay_sets.begin(), unique_delay_sets.end()};

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

declined: N <= scenes-per-mode (~10), distinct sets bounded by corner count, so linear dedup beats std::set's allocations at this scale, and std::set's pointer-order iteration would make enumeration order nondeterministic across runs, which we avoid in the timing engine.

@dsengupta0628

Copy link
Copy Markdown
Contributor Author

The following work currently:

  get_scenes -filter {analysis_corner == ss}      ;# works
  get_scenes -filter {analysis_corner =~ s*}      ;# works
  get_property [get_scenes func_ss] analysis_corner

The corner itself isn't in the property dispatch: no PropertyRegistry<const AnalysisCorner*>, so the following don't work yet:

  get_analysis_corners -filter {name =~ ss*}     ;# NOT supported (pattern arg only)
  get_property $corner liberty_files             ;# errors
  define_property -object_type analysis_corner   ;# error 2209
  set_property $corner temperature 125           ;# error 2214

Signed-off-by: dsengupta0628 <dsengupta@precisioninno.com>
@dsengupta0628
dsengupta0628 requested a review from jhkim-pii July 27, 2026 14:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant