← Home Static Timing Analysis
8 Static Timing Analysis

Timing Exceptions

STA fundamentals — cell delay, interconnect, setup/hold, MCMM, OCV, noise, IR-drop and sign-off

Chapter 8 — Timing Exceptions

Why Exceptions Exist

A static timing analyzer (STA, the tool that checks chip timing) starts as a pessimist. It assumes one fixed rule. Every path between two registers must launch data on one clock edge. It must capture that data on the very next clock edge. This is the single-cycle assumption. That rule drives setup and hold checks. For most paths in a synchronous design, it is correct. But a real chip is not so uniform. Some paths are never actually used. Some are allowed to take several cycles. Some cross between unrelated clocks. Some pins are tied to a fixed value in silicon. The tool does not know any of this. So it applies its default rule everywhere. It then reports failures that can never happen. Worse, it pushes the build flow to fix timing that was never broken. Think of it like a strict gym coach. He times every lap with one stopwatch rule. He does not know some runners are warming up, not racing. He still yells at them for being slow. That over-fixing has a hidden cost. A false failure still burns effort. The tool adds buffers, makes cells bigger, and reroutes wires. It spends area and power closing a path that does not exist. A timing exception fixes this. It tells STA the functional truth about your design. The tool then stops checking things that are not real. It also stops over-designing for them. So an exception is not a trick to pass timing. It is a constraint. It carries design intent the netlist (the gate-level wiring list) cannot show on its own. There are four main exceptions. They are false paths,

multicycle paths, min/max delay overrides, and case analysis. Each one removes or reshapes a default check. Default single-cycle vs the exception types default single-cycle false path (excluded) multicycle (N cycles) min/max delay (bounded) case analysis (pruned)

Figure 8.1 Default single-cycle check vs. the four exception types reshaping launch/capture relationships

ExceptionWhat it meansCommandPrimary risk if misused
False pathPath exists in wiring but isset_false_path never used; do not check itHiding a path that is real, masking a true failure
MulticycleData is allowed N cycles to pathset_multicycle_path arrive; relax the captureForgetting the matching hold fix, creating a real hold failure

window

Max delayBound the path delayset_max_delayOver- or under-constraining a
overridedirectly to a chosen valuepath the tool would size

correctly

Min delaySet a lower bound on a pathset_min_delayConflicting with hold intent if
overridedelay directlyapplied carelessly
CaseTie a pin to a constant to analysisset_case_analysis pick a mode and prune logicDisabling paths valid in another mode you forgot to check

False Paths

A false path exists in the netlist but is never used. No legal input sequence sends a real, timingrelevant change down it. It cannot carry meaningful data in the check being run. So forcing it to meet setup or hold is pointless. Common sources of false paths include the following.

  • Mutually exclusive mux selects. Two muxes (multiplexers, which pick one input) have select signals that can never both pick the crossed inputs at once. The diagonal path through both is present but logically impossible.
  • Mode-isolated logic. A block used only in test mode shares wiring with functional logic. The two are never active together.
  • Quasi-static / configuration paths. Some signals change only at boot or reconfiguration. Then they hold steady. They do not need single-cycle timing.
  • Asynchronous clock-domain crossings. Paths between unrelated clocks have no real launch- capture link. These are often set as false paths. (You can also use set_clock_groups .) The tool then stops trying to line up edges that never align.

WORKED EXAMPLE: A MODE-ISOLATED PATH

Picture a register cfg_reg . Its output feeds a block read only while func_en is low. During that window, the launching flop data_reg is held by clock gating (the clock is paused). So the path data_reg -> ... -> cfg_capture_reg never sees a real change that must be caught in one cycle. The tool knows none of this. It flags a setup failure because the logic is deep. The honest fix is to mark the path false.

# standard (SDC)
set_false_path -from [get_pins data_reg/Q] \
-through [get_pins mode_mux/A] \
-to [get_pins cfg_capture_reg/D]

The -from , -through , and -to switches scope the exception. Be as exact as the case needs. A broad set_false_path -from [get_clocks clk_a] -to [get_clocks clk_b] fits a whole async boundary. But one sneaky diagonal mux path needs -through . Otherwise you may disable good sibling paths by accident. The danger of false paths is bluntness. Mark too much false and you blind the tool to real logic. Every false path should trace to a written reason. Ideally someone who knows the RTL intent reviews it. Do not add one just to silence a red number.

Multicycle Paths

A multicycle path truly gets more than one cycle. The hardware allows data to take several cycles to arrive and settle before capture. This is real design, not a workaround. Maybe the source register updates only every fifth cycle. Maybe an enable on the destination flop opens its window once every N cycles. The path then has N cycles of real time. Forcing it into one cycle would over-constrain it badly. You tell the tool with set_multicycle_path . You give a multiplier. You say if it applies to setup or hold. The setup multiplier moves the capture edge later. The hold check must then be fixed too, or it gets wrongly strict. This hold interaction is the most common multicycle mistake, in interviews and in real work.

THE HOLD-EDGE GOTCHA

By default, the hold check is tied to the setup check. Hold is checked one launch edge before the setup capture edge. When you push the setup capture edge out by N cycles, the default hold edge moves out too. It lands N−1 cycles from the launch edge.

That is almost never what you want. It would demand data launched at edge 0 still be stable many cycles later. No logic can meet that without huge delay padding. The fix is a hold multiplier. It snaps the hold check back to the launch edge (position 0). The rule for a path with setup multiplier N is a hold multiplier of N−1. This pulls the hold edge back next to the launch. The normal hold relationship returns.

Setup capture Hold check edge Hold edge after correct

edge(default)fix
Single-cycle (default)Edge 1Edge 0Edge 0
Multicycle, setup = 4, no holdEdge 4Edge 3(wrong — too strict)

fix

Multicycle, setup = 4, hold = 3 Edge 4 Edge 0 Edge 0 (correct)

Setup checkHold check
launchcapture (T)same edge
data must arrive before T −Tsudata must NOT arrive before Thold

Figure 8.2 Timeline of launch edge and capture edges showing setup moved to edge 3 and hold pulled back to

edge 0

WORKED EXAMPLE: A 4-CYCLE DATAPATH

Suppose mult_src feeds a deep multiplier. Its result is used by mult_dst . The control logic makes sure mult_dst enables its capture only every fourth clock. So the path has four full cycles to settle. The constraint pair is below.

# standard (SDC)
# Setup: allow 4 cycles instead of 1
set_multicycle_path 4 -setup \
-from [get_pins mult_src/Q] -to [get_pins mult_dst/D]
# Hold: pull the hold edge back so it checks against the launch edge
set_multicycle_path 3 -hold \
-from [get_pins mult_src/Q] -to [get_pins mult_dst/D]

Always write the hold line with the setup line. A setup multicycle with no hold multicycle is a hidden hold bug. Layout will expose it later. When source and destination use different clocks, be clear about which clock the multiplier counts. The -start and -end qualifiers exist for this. Pick based on which clock defines the N-cycle relationship.

Min/Max Delay Overrides

Sometimes you do not want to relax a check by edges. You want to bound the delay to a number directly. set_max_delay and set_min_delay do this. They override the clock-based requirement with an absolute value. These fit when there is no clean clock relationship. Common uses follow. Timing a pure combinational path from an input port to an output port. There is no register on either end, so no edges to multiply. Bounding an async interface to a maximum propagation. Putting a tight ceiling on a feedback or resetrelease path.

# standard (SDC)
# Bound a combinational in-to-out path to 6 ns
set_max_delay 6.0 -from [get_ports cfg_in] -to [get_ports status_out]
# Hold a minimum on a fast bypass path
set_min_delay 0.8 -from [get_pins bypass_reg/Q] -to [get_pins out_reg/D]

Use these surgically. A set_max_delay replaces the normal setup requirement on the affected paths. Scope it too broadly and you may loosen or tighten many paths the tool already handled fine. These are precision tools, not blanket policy.

Case Analysis

Case analysis tells STA a pin is held at a constant value. With set_case_analysis you fix a modeselect or scan-enable pin to 0 or 1. The tool then sends that constant through the logic. Two things happen. It prunes paths that become unreachable. A mux side the constant can never pick is effectively cut off. It also selects a mode. So you check the chip as it will really run in that setting.

# standard (SDC)
# Analyze the design in functional mode (scan disabled)
set_case_analysis 0 [get_ports scan_enable]
# Force a configuration mux to its default selection
set_case_analysis 1 [get_ports clk_sel]

The key with case analysis is completeness across modes. Say your chip has functional, test, and low-power configurations. Each is a separate case-analysis setting. Each ideally gets its own analysis run. Setting scan_enable to 0 removes scan paths from the functional run. That is correct. But you also need a test-mode run where it is 1. Otherwise the scan-shift timing is never checked. The risk of case analysis is silent under-checking. Paths valid in a mode you never ran simply vanish from the report. Case analysis is also often used to disable an unused clock at a clock-mux input. This can prune huge amounts of logic. It cleans up reports a lot. But you must also analyze the other clock selection.

Exception Priority and the Over-Constraint Trap

Several exceptions may apply to one path. The tool does not combine them. It picks one by a fixed order. Here it is, highest priority first.

PriorityExceptionNotes
1set_false_path (highest)Removing a check always beats relaxing or bounding it
2set_max_delay /Explicit numeric bounds beat edge-based relaxation
set_min_delay
3set_multicycle_pathRelaxes the default edge relationship
4 (lowest)Default single-cycle checkApplies when no exception matches

Within the same type, more specific scoping usually wins. A -from/-through/-to exception beats a broad -from -only one when both could match. The tool favors the tighter spec. Case analysis sits apart. It changes which paths exist before priority is even checked. So a path pruned by

set_case_analysis  never reaches this contest.

Priority matters because it explains surprising reports. Say you add a multicycle path. But a broader false path already covers the same endpoints. The multicycle then does nothing. The false path has higher priority, so the path is not checked. Engineers waste hours debugging multicycle constraints that were simply outranked. The big hazard across all exceptions is over-constraining. That means piling on exceptions until the report turns green. Each false path is a check you turned off. Each broad multicycle is a window you widened. Do this carelessly and you tape out a chip with real failures hidden by your own constraints. The professional standard is simple. Every exception must be justified, scoped, and reviewed. It should trace to a written reason. It should be scoped as narrowly as that reason allows. Someone who knows the intent should sign off. A clean report bought with sloppy exceptions is not a clean chip. It is a silicon bug with good paperwork. Default single-cycle vs the exception types default single-cycle false path (excluded) multicycle (N cycles) min/max delay (bounded) case analysis (pruned)

Figure 8.3 Decision flowchart — is the path real? does it need >1 cycle? is there a clock relationship? pick the

exception

Interview Q&A

Q
Why is the matching hold constraint so important when you set a multicycle setup path,

and what multiplier do you use? Relaxing the setup edge by N cycles also pushes the default holdcheck edge out to N−1 cycles. That demands the data hold stable far longer than real logic can promise. The result is a false hold failure or massive padding. You apply a hold multicycle of N−1. This pulls the hold check back to the launch-adjacent edge (position 0). The normal hold relationship returns. Setup multicycle with no hold multicycle is a hidden hold bug.

Q
A multicycle path you added seems to be ignored. What is the most likely cause? Exception

precedence. A set_false_path or a set_max_delay covering the same endpoints outranks the multicycle. So the path is removed or bounded before the multicycle is even considered. Check for a broader, higher-priority exception on those pins. A scoping mismatch is the other common cause. Your -through may not be on the real sensitized path.

Q
When would you reach for set_max_delay instead of set_multicycle_path ? When there is

no clean clock-edge relationship to multiply. Most often this is a pure combinational input-to-output path with no register on either end. Or an async interface that just needs a hard ceiling.

set_max_delay  bounds the delay to an absolute number. Multicycle only makes sense when clock

launch and capture edges define the relationship.

Q
What is the danger of using set_case_analysis to clean up a report? Silent under-checking

across modes. Fixing a mode pin to a constant prunes the paths unreachable in that mode. That is correct for that mode. But any path valid only in the other setting vanishes from the analysis. If you never run the complementary case, like test mode with scan on, that logic is never timed. Case analysis must be complete. Run one scenario per operating mode.

Key Takeaways

  • Exceptions tell STA the functional truth the netlist cannot express. They remove false failures and prevent wasteful over-design.
  • False paths delete checks on paths that exist but are never used. Sources include mutually exclusive muxes, mode isolation, and async crossings. Scope them tightly.
  • Multicycle paths truly grant N cycles. Always pair the setup multicycle (N) with the hold multicycle (N−1). This avoids a false or real hold problem.
  • Min/max delay overrides bound a path to an absolute number. They fit combinational and async interfaces with no clock relationship.
  • Case analysis fixes a pin to a constant to prune logic and pick a mode. It demands a complete set of mode runs, or it silently under-checks.
  • Precedence is false path, then min/max delay, then multicycle, then default single-cycle. More specific scoping wins within a type.
  • Every exception is a check you weaken or remove. Justify it, scope it, review it. A green report built on sloppy exceptions hides real violations.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

Replying to