Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • How to Use This Course
  • Reading Path
  • STA Glossary
  • STA Metrics Reference
  • STA Mastery Cheatsheet
  • Timing Paths and Checks16
  • Constraints & SDC Fundamentals20
  • Delay Graph & Path Analysis16
  • Beyond Setup and Hold16
  • Multi-Corner Multi-Mode Signoff16
  • OCV, AOCV, POCV and Variation16
  • Crosstalk and Noise16
  • ECO and Closure16
  • STA Debug Playbook16
  • STA Interview Prep26
  • Capstone Timing Signoff Lab4
    • Capstone Brief
    • Audit the Constraints
    • Classify and Fix
    • Signoff
Loading lesson

‹Capstone Timing Signoff Lab
  1. Topics
  2. Static Timing Analysis
  3. Capstone Timing Signoff Lab
  4. Signoff

Part 11 · Capstone Timing Signoff Lab · All levels

Signoff

The final slack table, the weighted checklist, the before-and-after dashboard and a signoff statement that a reviewer can check.

On this page

    The last step assembles the evidence. The final table comes from rerunning the engine with all fixes applied; the checklist uses the blocker and major weights from the debug playbook; the dashboard compares the state at handover with the state now; and the statement says exactly what is claimed and what it depends on.

    The final table

    example.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    BUDGET = {("clk", "clk"): 1.0, ("clk", "clk_div2"): 1.0, ("clk_div2", "clk"): 1.0,
              ("clk", "clk_b"): 0.3, ("clk_b", "clk"): 0.3}    # capture-edge budget per clock pair, ns (async pairs: arbitrary pessimistic placeholder, not the closest-edge gap)
    def path(l, c, mx, mn, sk=0.0):
        return {"l": l, "c": c, "mx": mx, "mn": mn, "su": 0.06, "ho": 0.05, "sk": sk}
    PATHS = {"E1": path("clk", "clk", 0.82, 0.20, 0.02), "E2": path("clk", "clk", 0.91, 0.16),
             "E3": path("clk", "clk", 0.90, 0.12, -0.03), "E4": path("clk", "clk_div2", 0.75, 0.30),
             "E5": path("clk_div2", "clk", 1.02, 0.30), "E6": path("clk", "clk_b", 0.40, 0.10),
             "E7": path("clk_b", "clk", 0.55, 0.10), "E8": path("clk", "clk", 0.90, 0.06, 0.05)}
    FP_ASYNC = {("clk", "clk_b"), ("clk_b", "clk")}              # false paths between the truly asynchronous clocks
    FP_DIV = {("clk_div2", "clk"), ("clk", "clk_div2")}          # false paths between the divided clock and its source
    def analyse(paths, clocks, exceptions):
        out = {}
        for name, p in paths.items():
            if p["l"] not in clocks or p["c"] not in clocks:
                out[name] = "unconstrained"
            elif any((p["l"], p["c"]) in ex for ex in exceptions):
                out[name] = "excepted"
            else:
                setup = BUDGET[(p["l"], p["c"])] + p["sk"] - p["su"] - p["mx"]
                hold = p["mn"] - (p["ho"] + p["sk"])
                out[name] = (round(setup, 3), round(hold, 3))
        return out
    def summary(res):
        nums = {k: v for k, v in res.items() if isinstance(v, tuple)}
        kinds = [v if isinstance(v, str) else "checked" for v in res.values()]
        return {"checked": kinds.count("checked"), "excepted": kinds.count("excepted"), "unconstrained": kinds.count("unconstrained"),
                "wns_setup": min(v[0] for v in nums.values()), "wns_hold": min(v[1] for v in nums.values())}
    clocks = {"clk", "clk_b", "clk_div2"}
    PATHS["E5"] = dict(PATHS["E5"], mx=1.02 - 0.10, mn=0.30 - 0.05)       # shared-cell sizing: 0.10 ns faster
    PATHS["E8"] = dict(PATHS["E8"], mx=0.90 + 0.05, mn=0.06 + 0.05)       # 0.05 ns of delay at the endpoint
    res = analyse(PATHS, clocks, [FP_ASYNC])
    s = summary(res)
    margin = 0.005
    assert res == {"E1": (0.14, 0.13), "E2": (0.03, 0.11), "E3": (0.01, 0.1), "E4": (0.19, 0.25), "E5": (0.02, 0.2),
                   "E6": "excepted", "E7": "excepted", "E8": (0.04, 0.01)}
    assert s == {"checked": 6, "excepted": 2, "unconstrained": 0, "wns_setup": 0.01, "wns_hold": 0.01}
    assert all(v[0] >= margin and v[1] >= margin for v in res.values() if isinstance(v, tuple))
    print("PASS: final", s)

    Endpoint

    Setup (ns)

    Hold (ns)

    Note

    E1

    +0.140

    +0.130

    E2

    +0.030

    +0.110

    E3

    +0.010

    +0.100

    Smallest setup slack: watch after any change

    E4

    +0.190

    +0.250

    Newly constrained

    E5

    +0.020

    +0.200

    Fixed by sizing a shared cell

    E6, E7

    excepted

    excepted

    Asynchronous crossings, owned by the CDC signoff

    E8

    +0.040

    +0.010

    Fixed by a 0.05 ns delay inside the computed window

    Every checked endpoint now has at least the 5 ps margin on both checks: setup WNS +0.010 ns (E3) and hold WNS +0.010 ns (E8). The two excepted endpoints are covered by the CDC methodology, not by timing, and that dependency belongs in the statement.

    Dashboard: handover against now

    Measure

    At handover

    Final

    Endpoints actually checked

    4 of 8

    6 of 8 (the other 2 excepted with evidence)

    Unconstrained endpoints

    2

    0

    Exceptions

    4 commands (2 pairs; one pair wrong)

    2 commands (1 pair, covers exactly 2 crossings)

    Setup WNS

    +0.010 ns (misleading)

    +0.010 ns (all 6 checked endpoints)

    Hold WNS

    -0.040 ns

    +0.010 ns

    Real violations found and fixed

    1 known (E8 hold)

    2 fixed (E5 setup, newly exposed; E8 hold, known)

    The weighted checklist

    example.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    items = [
        ("no unclocked or unconstrained endpoints", "blocker", "closed"),
        ("every exception reviewed with its path count", "blocker", "closed"),
        ("setup and hold clean with margin in the analysed scenario", "blocker", "closed"),
        ("hold fixes fit inside their setup slack", "blocker", "closed"),
        ("analysed scenario only; other scenarios not run", "blocker", "open"),
        ("asynchronous crossings covered by the CDC signoff", "major", "waived"),
        ("run manifest recorded", "major", "closed"),
    ]
    blockers_open = [n for n, w, s in items if w == "blocker" and s != "closed"]
    majors_open = [n for n, w, s in items if w == "major" and s == "open"]
    waived = [n for n, w, s in items if s == "waived"]
    assert blockers_open == ["analysed scenario only; other scenarios not run"] and majors_open == [] and waived == ["asynchronous crossings covered by the CDC signoff"]
    ready = not blockers_open and not majors_open
    assert ready is False
    print("PASS: not ready; open blockers", blockers_open, "; waived", waived)

    The engine models a single scenario, so the other-scenarios item is honestly open: the capstone numbers are one corner. The crossings E6 and E7 are waived from timing on the strength of the CDC signoff, and the waiver is listed rather than counted as fixed. With a blocker still open, the result is not ready and the correct statement refuses the signoff.

    Signoff statement

    Timing is not signed off. The analysed scenario is clean: all six timed endpoints meet setup and hold with at least 5 ps of margin (setup WNS +0.010 ns at E3, hold WNS +0.010 ns at E8). This analysis uses one scenario and excludes clock uncertainty, derates, common path pessimism removal and SI; sign-off requires rerunning the slow and fast corners with those included. Constraints were audited: no unclocked endpoints, one exception remaining, which covers exactly the two asynchronous crossings E6 and E7 and depends on their CDC signoff. Two real violations were fixed: E5 by sizing a shared cell, E8 by a 0.05 ns delay inside its computed window. Any change to the clocks, exceptions, or the E5 and E8 fixes re-opens the affected rows.

    Common pitfall

    Omitting the condition. A statement that claims more than the evidence covers is the capstone's final trap.

    Interview

    Close a case study with the statement and its condition, the way you would to a reviewer.

    Check yourself Which three facts in the statement are checkable by someone who was not involved?

    The final table (the engine reproduces it), the exception audit (E6 and E7 are the only paths covered), and the fix windows (0.045 to 0.085 ns for E8, with 0.05 ns chosen).

    Exercise

    Extend it: raise the clk_div2 data delay at E4 to 0.95 ns and rerun. Which check fails, by how much, and which fix method fits? Then change E8's maximum delay to 0.96 ns and decide whether delay insertion can still fix it by computing the sum of its two slacks.

    Related topics

    • Back: Classify and Fix

    • Capstone Brief

    • Final Checklists

    Previous

    183 / 183

    Up next

    You reached the end of this course — nicely done.

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Capstone Brief
    • Audit the Constraints