Sometimes no clock relationship describes a path's requirement, for example a crossing between unrelated clocks where you want a bounded delay without a full check. set_max_delay and set_min_delay set a direct limit on the path delay. They override the default requirement, so they must be precise.
# not-run: SDC is not executable here
set_max_delay 2.5 -from [get_pins a_reg/CK] -to [get_pins sync1/D] ;# arrival must be <= 2.5 ns
set_max_delay 2.5 -ignore_clock_latency -from [get_clocks clk_a] -to [get_clocks clk_b] ;# ignore clock latencies and skew
set_min_delay 0.2 -from [get_pins a_reg/CK] -to [get_pins b_reg/D] ;# arrival must be >= 0.2 nsset_max_delay | set_min_delay | |
|---|---|---|
Replaces | The setup requirement of the covered paths | The hold requirement of the covered paths |
Checks | Data path delay (launch clock to endpoint arrival) against the number | The same delay against a lower bound |
-ignore_clock_latency | Excludes clock latency so only the data path counts (clock latency is excluded only with that standard option) | n/a in the same way; used with care |
Typical use | Bounded delay on crossings and bus skew control | Guarantee a minimum delay |
# Bounded-delay check: path delays on a bus must stay within the limit
# the 0.7 ns spread below is observed, not guaranteed: a max-only bound limits skew to (bound - minimum delay)
limit = 2.5
bus_delays = {"d0": 1.9, "d1": 2.2, "d2": 2.6, "d3": 2.4}
violations = {k: round(v - limit, 2) for k, v in bus_delays.items() if v > limit}
assert violations == {"d2": 0.1}
spread = max(bus_delays.values()) - min(bus_delays.values())
assert abs(spread - 0.7) < 1e-9
print("PASS: violations", violations, "skew spread", round(spread, 2), "ns")One bit exceeds the limit by 0.10 ns and the observed bus delay spread is 0.7 ns. For crossings such as Gray-coded pointers, a max-only bound on every bit limits the skew to (bound - minimum delay); a skew requirement needs a minimum bound too, or a bound tight relative to the destination period. The CDC course explains the protocol side.
Each max/min delay value is derived (a skew budget, a protocol requirement), not tuned to pass.
-ignore_clock_latency is used deliberately: it ignores clock latency, so check what that omits.
Exceptions order is understood: a false path overrides a delay exception on the same path; multicycle exceptions do not combine with a delay limit the way you might expect.
Because the clocks are unrelated, their latencies and skew are meaningless for the bound. -ignore_clock_latency checks the data path delay alone against the number.