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

AboutRoadmapCareersInternshipsFAQContactPrivacyTerms
Skip to lesson

Course contents

  • Logic Synthesis Glossary
  • Logic Synthesis Cheatsheet
  • Synthesis Foundations14
  • Logic Optimisation and Mapping20
  • Constraints and Timing15
    • SDC for Synthesis
    • Delay Models and Slack
    • Timing-Driven Synthesis
      • Critical-Path Focus
      • Restructuring and Duplication
      • Sizing and Path Groups
      • Reading WNS and TNS
      • Margin and When to Stop
  • Sequential, FSM and Memory19
  • Datapath Synthesis14
  • Area, Power and Test14
  • Verification, ECO and Handoff15
  • Flows and Debugging15
  • Interview and Judgment11
Loading lesson

←Timing-Driven Synthesis
  1. Topics
  2. Logic Synthesis
  3. Constraints and Timing
  4. Timing-Driven Synthesis
  5. Reading WNS and TNS
On this page

    Part 3 of 9, lesson 14 of 15Part 3 of 9/Constraints and Timing/Lesson 14 of 15Intermediate

    Reading WNS and TNS

    Worst and total negative slack: what each measures and how to read them.

    Summing every failing path overcounts: one endpoint with six bad paths is one failing endpoint, not six. Reading TNS per endpoint keeps the total honest and the fix aimed at the right place.

    After this lesson you can: compute WNS and per-endpoint TNS from a sample report, show why the all-paths sum differs, and read the four WNS/TNS trend patterns.

    One slack per path, one verdict per endpoint

    Every timing path has a slack: required time minus arrival time, negative when the path misses. But a timing report does not hand you one line per path. It hands you one line per endpoint: each endpoint keeps only its worst path, the smallest slack among all paths that end there. Two totals summarise those endpoint lines. Worst negative slack, WNS, is the smallest endpoint slack in the design: how bad the single worst endpoint is. Total negative slack, TNS, is the sum of the negative endpoint slacks only: how much failure exists across the design. Positive endpoints contribute nothing to TNS, and when nothing violates, WNS is the smallest positive slack here (many tools clamp that case to WNS 0; the convention in this lesson keeps the headroom visible).

    Metric (standard timing-report semantics)

    Definition

    Answers

    WNS

    Minimum endpoint slack over the design

    How bad is the single worst endpoint.

    TNS

    Sum of the negative endpoint slacks

    How much failure exists across the design.

    The per-endpoint part is the correction that matters. Summing every failing path overcounts: one endpoint with six failing paths is one failing endpoint, not six. The program further down proves the gap with numbers: the same sample report gives -52 ps counted per endpoint, and -187 ps counted per path.

    A netlist with two endpoints

    The script below maps a two-output design: a five-stage AND-XOR chain behind y_deep next to a single AND gate behind y_side, the same shape as the critical-path lesson in miniature. Both runs use a very loose target so the reports show each cone's natural arrival: 5 cells at area 19 and a worst arrival of 432 ps under the typical 0.05 pF load. The assertions prove the generic gates are gone. The figure draws the recorded netlist both endpoints share, so the sample report below has a shape you can point at.

    yosys
    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
    read_verilog <<EOV
    module twoep(input [5:0] a, input b, output y_deep, output y_side);
    wire d0 = a[0] & a[1];
    wire d1 = d0 & a[2];
    wire d2 = d1 & a[3];
    wire d3 = d2 ^ b;
    assign y_deep = d3 ^ a[4];
    assign y_side = a[4] & a[5];
    endmodule
    EOV
    synth -top twoep -flatten
    design -save twoep
    tee -o ep_typ.txt abc -liberty sized.lib -constr typical.constr -D 100000
    tee -o ep_typ_stat.txt stat -liberty sized.lib
    write_json ep_net.json
    select -assert-none t:$and t:$or t:$xor t:$xnor t:$mux t:$not
    select -assert-none t:$_AND_ t:$_OR_ t:$_XOR_ t:$_XNOR_ t:$_MUX_ t:$_NOT_ t:$_NAND_ t:$_NOR_
    check
    design -load twoep
    tee -o ep_heavy.txt abc -liberty sized.lib -constr heavy.constr -D 100000
    tee -o ep_heavy_stat.txt stat -liberty sized.lib
    write_json ep_heavy_net.json
    select -assert-none t:$and t:$or t:$xor t:$xnor t:$mux t:$not
    select -assert-none t:$_AND_ t:$_OR_ t:$_XOR_ t:$_XNOR_ t:$_MUX_ t:$_NOT_ t:$_NAND_ t:$_NOR_
    check
    log PASS: two endpoints map once per load
    The recorded two-endpoint netlist: 5 cells, area 19, worst arrival 432 ps.

    A sample report in the shape of this netlist

    No open tool here prints per-endpoint slack: OpenSTA is not installed and ABC reports only the worst arrival, 432 ps above. So the report below is hand-written, labelled sample, with slacks in the shape of this netlist at a sample required time of 380 ps: six failing paths into y_deep, two comfortable paths into y_side. The 380 ps is chosen, not recorded: minus the recorded 432 ps arrival it gives the sample's -52 ps worst slack. Read it as the report a timer would print for these two endpoints, then watch the program recompute both totals from it.

    Diagram
    SAMPLE endpoint report (ps), required time 380 ps
    endpoint y_deep path slacks: -52, -47, -39, -28, -15, -6 (worst -52)
    endpoint y_side path slacks: +180, +195 (worst +180)
    WNS = minimum over endpoints = min(-52, +180) = -52
    TNS = worst per endpoint, negatives only = -52 + 0 = -52
    all-paths sum = -52 + -47 + -39 + -28 + -15 + -6 = -187 (wrong: counts paths, not endpoints)
    Predict first You fix only the worst path into y_deep, moving its slack from -52 to +5. What happens to WNS and to TNS?

    WNS jumps to +5: the worst endpoint is fixed. TNS moves to 0 for the same reason. Fix the endpoint, not the path.

    Two totals from one report

    The program below holds the sample report and computes all three figures: WNS, per-endpoint TNS, and the all-paths sum a per-path reading would give. Its checks pin each one and pin that the wrong total differs from the right one; if any figure drifts, the run goes red. The AFTER case replays the prediction: with y_deep's worst path at +5, WNS reads +5, the smallest positive slack in this lesson's convention, and TNS reads 0 because no endpoint is negative. Zero failing endpoints is the only TNS that signs anything off.

    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
    39
    40
    41
    42
    43
    44
    45
    46
    import sys
    
    # SAMPLE endpoint report (ps), in the shape of the two-endpoint netlist above.
    # Hand-written path slacks at a sample required time of 350 ps.
    BEFORE = {
        "y_deep": [-52, -47, -39, -28, -15, -6],
        "y_side": [180, 195],
    }
    AFTER = {
        "y_deep": [5, 12, 24],
        "y_side": [180, 195],
    }
    
    def wns(endpoints):
        return min(min(paths) for paths in endpoints.values())
    
    def tns(endpoints):
        total = 0
        for paths in endpoints.values():
            worst = min(paths)
            if worst < 0:
                total += worst
        return total
    
    def tns_all_paths(endpoints):
        return sum(s for paths in endpoints.values() for s in paths if s < 0)
    
    if wns(BEFORE) != -52:
        print("FAIL: WNS " + str(wns(BEFORE)) + " want -52")
        sys.exit(1)
    if tns(BEFORE) != -52:
        print("FAIL: TNS " + str(tns(BEFORE)) + " want -52")
        sys.exit(1)
    if tns_all_paths(BEFORE) != -187:
        print("FAIL: all-paths sum " + str(tns_all_paths(BEFORE)) + " want -187")
        sys.exit(1)
    if tns_all_paths(BEFORE) == tns(BEFORE):
        print("FAIL: all-paths sum should differ from per-endpoint TNS here")
        sys.exit(1)
    if wns(AFTER) != 5:
        print("FAIL: fixed WNS " + str(wns(AFTER)) + " want 5")
        sys.exit(1)
    if tns(AFTER) != 0:
        print("FAIL: fixed TNS " + str(tns(AFTER)) + " want 0")
        sys.exit(1)
    print("PASS: WNS -52 ps and TNS -52 ps; summing all paths gives -187 ps instead")
    Sample arrival against a 380 ps required time: 432 ps arrives 52 ps late (illustrative stage split).

    How to read each trend

    WNS and TNS move for different reasons, so read them as a pair. The table below covers the four common patterns; each row is a reading rule, not a measurement.

    WNS

    TNS

    Reading

    Improving

    Improving

    Effort works across the failing endpoints.

    Improving

    Flat

    One endpoint is fixed while many still fail; broaden the effort.

    Flat

    Improving

    Shared logic helps many endpoints but the worst one resists; attack it directly.

    Flat

    Flat

    Effort is spent out; restructure or stop.

    Break it: quadruple the load

    The script's second run replays the same design under heavy.constr at 0.2 pF per output. The recorded worst arrival rises from 432 ps to 572 ps at area 23: the same logic, later everywhere, because every endpoint now drives four times the capacitance. Against the sample required time of 380 ps the worst slack falls by exactly that rise, hand-derived below from the two recorded arrivals. A fixed target plus a heavier load is a tighter constraint wearing a disguise, and the endpoint totals are where the disguise shows.

    Diagram
    worst slack at required 380 ps, hand-derived from the recorded worst arrivals
    typical load: 380 - 432 = -52 ps
    heavy load: 380 - 572 = -192 ps
    shift = 140 ps worse on the worst endpoint

    Common mistakes

    Celebrating a better WNS while TNS stays flat misses the spread of failure. The design still fails on many endpoints, and signoff needs both totals at zero.

    WNS improves from -52 to -10 while TNS stays near -400. What does that say?

    • Weak answer: the design is almost fixed; keep polishing the worst path.

    • Strong answer: one endpoint improved from -52 to -10 while many endpoints still fail, so broaden the effort instead of polishing one path. And TNS sums endpoints, not paths: the sample's correct total is -52 ps, while summing every failing path gives -187 ps.

    • Follow-up: WNS is positive but TNS is nonzero, is that possible? No: a nonzero TNS means a negative endpoint exists, so WNS is negative too.

    Check yourself The sample gives WNS -52 and TNS -52. Which endpoints fail, and by how much in total?

    Only y_deep fails, with a worst slack of -52 ps. y_side is positive and contributes nothing, so the design's total shortfall is 52 ps across one endpoint.

    Check yourself After the fix WNS reads +5 while y_deep's other paths read +12 and +24. Why is TNS 0?

    TNS sums worst slacks per endpoint, not paths: y_deep's worst is now +5 and y_side's is +180, and neither is negative. One fixed endpoint zeroes the total.

    • WNS is the minimum endpoint slack; TNS sums only the negative endpoint slacks, worst path per endpoint.

    • Positive endpoints contribute nothing; with nothing failing, WNS is the smallest positive slack here (some tools clamp it to 0).

    • WNS up with TNS flat means one endpoint fixed among many failures.

    Rule of thumb: count endpoints, not paths: one worst slack per endpoint, negatives only.

    How this was checked

    Cell counts, areas, worst arrivals and the netlist picture on this page come from one Yosys 0.70 run of the script shown, recorded by the course checker (scripts/tools/run-rtl-testbenches.mjs with COURSE=synth): ABC maps a two-endpoint design against sized.lib with typical and heavy loads. Endpoint slacks are a hand-written labelled sample, because no open tool here prints per-endpoint slack; the program computes WNS, per-endpoint TNS and the all-paths counter-example from that sample with asserts. The library is fictional, so absolute figures are teaching units.

    • Interview: run a mock interview on this topic

    Related topics

    • Up: Timing-Driven Synthesis

    • Next: Margin and When to Stop

    • Debugging QoR

    Previous

    50 / 139

    Next: Margin and When to Stop

    Up next

    Up nextMargin and When to Stop

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error

    See also

    • Critical-Path Focus
    • Restructuring and Duplication