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. Margin and When to Stop
On this page

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

    Margin and When to Stop

    Over-constraining margin: how much helps, when it harms, and when to stop.

    Margin is insurance with a premium, and past the library floor the premium buys nothing. A recorded sweep with a visible knee turns stopping from a feeling into a reading.

    After this lesson you can: run a delay sweep, find the knee that reaches the delay floor, and state a stop rule with the sweep's own numbers.

    A little margin guards the handoff

    Synthesis models differ slightly from what later stages see: extraction, routing delay, and crosstalk all move arrival times after the netlist leaves synthesis. Closing exactly at zero in synthesis can therefore reopen downstream. The guard is margin: constrain synthesis to a target tighter than the real one, so a small model gap still leaves the handoff positive. The program below works the sign-off example from the sweep in picoseconds: a 700 ps period with 40 ps of margin means a 660 ps synthesis target, and the knee run arrives at 589 ps, leaving 71 ps at the tool and 111 ps at handoff. Its checks pin all three numbers, reading the arrival back from the recorded 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
    import sys
    
    # Margin arithmetic (ps) on the recorded sweep: a 700 ps sign-off with 40 ps
    # of margin means a 660 ps synthesis target; the arrival below is read back
    # from the recorded knee row, so a new recording moves every check with it.
    PERIOD = 700
    MARGIN = 40
    ARRIVAL = 589
    
    def close(got, want):
        return abs(got - want) < 1e-9
    
    target = PERIOD - MARGIN
    tool_slack = target - ARRIVAL
    handoff_slack = PERIOD - ARRIVAL
    if not close(target, 660):
        print("FAIL: synthesis target " + str(target) + " want 660")
        sys.exit(1)
    if not close(tool_slack, 71):
        print("FAIL: tool slack " + str(tool_slack) + " want 71")
        sys.exit(1)
    if not close(handoff_slack, 111):
        print("FAIL: handoff slack " + str(handoff_slack) + " want 111")
        sys.exit(1)
    print("PASS: margin 40 on 700 closes at 589 and leaves 111 at handoff")

    Margin is insurance with a premium: every picosecond of it is delay the tool must buy with area whether the gap materialises or not. The rest of this lesson measures that premium on a real sweep and states when to stop paying it.

    One design, seven targets

    The script below maps a parity-and-mux cone once, then replays the same generic gates against seven delay targets from -D 1000 down to -D 100. The design is new to this topic: parity trees on two nibbles feeding a mux, combined with a second mux term, so no lesson can borrow its numbers. The loose assertion pins the 1000 ps run to all-smallest cells; the 500 and 400 ps assertions pin at least one upsize each, proving the middle rows actually spent. Every number in the table that follows is read back from those recorded reports.

    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
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    read_verilog <<EOV
    module parity_mux(input [7:0] x, input s0, s1, output y);
    wire p0 = ^x[3:0];
    wire p1 = ^x[7:4];
    wire m0 = s0 ? p0 : p1;
    wire m1 = s1 ? (x[0] & x[7]) : (x[3] | x[4]);
    assign y = m0 ^ m1;
    endmodule
    EOV
    synth -top parity_mux -flatten
    design -save generic
    tee -o abc_1000.txt abc -liberty sized.lib -constr typical.constr -D 1000
    tee -o stat_1000.txt stat -liberty sized.lib
    write_json net_1000.json
    select -assert-none t:*_X2 t:*_X4
    design -load generic
    tee -o abc_700.txt abc -liberty sized.lib -constr typical.constr -D 700
    tee -o stat_700.txt stat -liberty sized.lib
    design -load generic
    tee -o abc_500.txt abc -liberty sized.lib -constr typical.constr -D 500
    tee -o stat_500.txt stat -liberty sized.lib
    select -assert-min 1 t:*_X2 t:*_X4 %u
    design -load generic
    tee -o abc_400.txt abc -liberty sized.lib -constr typical.constr -D 400
    tee -o stat_400.txt stat -liberty sized.lib
    write_json net_400.json
    select -assert-min 1 t:*_X2 t:*_X4 %u
    design -load generic
    tee -o abc_300.txt abc -liberty sized.lib -constr typical.constr -D 300
    tee -o stat_300.txt stat -liberty sized.lib
    design -load generic
    tee -o abc_200.txt abc -liberty sized.lib -constr typical.constr -D 200
    tee -o stat_200.txt stat -liberty sized.lib
    design -load generic
    tee -o abc_100.txt abc -liberty sized.lib -constr typical.constr -D 100
    tee -o stat_100.txt stat -liberty sized.lib
    design -load generic
    tee -o abc_course.txt abc -liberty course.lib -constr typical.constr -D 300
    tee -o stat_course.txt stat -liberty course.lib
    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: a margin sweep past the plateau on a new design
    Predict first The -D 500 run reaches the delay floor. What will the 400, 300, 200 and 100 ps runs report, and what does that cost?

    Exactly the same delay and area as the -D 500 run: the library has no faster cover to give, so the four tighter runs repeat the knee figures and buy nothing. The table proves it row by row.

    Target -D (recorded)

    Cells

    Area

    Delay reached

    1000 ps

    11

    48

    740 ps

    700 ps

    11

    56

    661 ps

    500 ps

    11

    64

    589 ps

    400 ps

    11

    64

    589 ps

    300 ps

    11

    64

    589 ps

    200 ps

    11

    64

    589 ps

    100 ps

    11

    64

    589 ps

    The staircase and the floor

    Read the table top to bottom. At 1000 ps the loose netlist already meets the target at area 48, arriving at 740 ps. At 700 ps the tool still meets, arriving at 661 ps for area 56: upsizing bought headroom while the target was still reachable. At 500 ps the run misses, reaching only 589 ps for area 64, and that 589 ps is the library floor: the 400, 300, 200 and 100 ps runs all repeat it at the same area 64. The chart draws the distinct points, delay reached against area, so the plateau reads as a flat end to the curve: faster costs more, until faster costs nothing because faster stops happening.

    Area against delay for the recorded sweep: 64 units at 589 ps, 56 units at 661 ps, 48 units at 740 ps. Faster costs more until the floor.

    The knee is the loosest target that reaches the floor: -D 500. That number is the whole stop rule for this design. Make it concrete with a sign-off example: a 700 ps period with 40 ps of margin means a 660 ps synthesis target. The loosest recorded target that clears 660 is -D 500, arriving at 589 ps for area 64: 8 more area units than the 700 row, which arrives at 661 ps and misses the 660 target. Tightening past the knee buys nothing at all: the 400 through 100 rows repeat 589 ps at area 64, so every unit of margin below the knee is premium with no insurance.

    The plateau netlist: 11 cells, area 64, the upsized cells in orange.

    Break it: take away the sizes

    The script's final run replays a tight target against course.lib, where each cell exists in one size only. At -D 300 the recorded result is 11 cells at area 48 and 740 ps, against 64 area units and 589 ps for the sized library at the -D 500 knee. A margin constraint can only steer the tool among choices the library offers: with no X2 or X4 to buy, the same pressure that upsized stages of the sized netlist changes nothing here. Margin without sizing choices is a wish, not a constraint.

    Rules for stopping

    Effort stops when the numbers and the budget agree. Each rule below is a separate reason to quit a failing path or a finished job, and each is readable off the sweep above.

    • WNS reaches zero at the synthesis target including margin: the job is done. Here that means clearing 660 ps, which the -D 500 row does at 589 ps.

    • TNS stays flat across two runs while area still grows: restructure instead of sizing further.

    • Each run moves the worst path somewhere new with no global gain, or the delay stops moving entirely: the 400 through 100 rows prove the structure is spent at 589 ps, so change the logic or accept the result.

    • Area or power hits its budget: further timing effort spends what the design cannot afford.

    Common mistakes

    Raising the margin to force a stubborn path usually backfires. The tool overworks easy paths and distorts the netlist while the true limiter stays untouched.

    Why constrain synthesis to 660 when sign-off is 700?

    • Weak answer: to be safe.

    • Strong answer: downstream stages move arrivals, so 40 ps of margin on 700 closes at 589 ps and still leaves 111 ps at handoff; without it a zero-slack handoff reopens.

    • Follow-up: when is margin too much? When it spends area on a fiction: the 700 row already meets at 661 ps for area 56, the -D 500 row pays 8 more to clear 660, and anything tighter pays the same 64 for nothing.

    Check yourself The 400, 300, 200 and 100 ps runs all report 589 ps at area 64. What is the right move at -D 300?

    Stop tightening: the library floor is 589 ps and every target past the -D 500 knee repeats it. Accept 589 ps, restructure the logic, or move on.

    Check yourself Against course.lib the -D 300 run reports area 48 and 740 ps. Why did margin buy nothing there?

    The single-size library offers no faster cell to buy: with no X2 or X4 available, the constraint has no choices to steer among. Margin needs a library with headroom to mean anything.

    • Margin means constraining synthesis tighter than sign-off; the handoff keeps what the models did not move.

    • The knee is the loosest target reaching the floor; tighter targets repeat it for the same area.

    • A library with one size per cell cannot buy speed at any margin.

    Rule of thumb: constrain at sign-off minus margin; if that is below the floor, change the logic.

    How this was checked

    Every number and picture on this page comes 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 parity-mux cone against sized.lib at seven delay targets with a 0.05 pF load, plus one run against the single-size course.lib. The margin program is a labelled example with its own time units. The library is fictional, so absolute areas and delays are teaching units; the staircase shape and the plateau are the point.

    • Interview: run a mock interview on this topic

    Related topics

    • Up: Timing-Driven Synthesis

    • Critical-Path Focus

    • Area, Power and Timing Tradeoffs

    Previous

    51 / 139

    Next: Sequential, FSM and Memory

    Up next

    Up nextSequential, FSM and Memory

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error

    See also

    • Critical-Path Focus
    • Restructuring and Duplication
    • Sizing and Path Groups