Input and output delays are the contract between a block and its neighbours. Wrong values, or a wrong min/max choice, give a block that looks clean alone and fails when integrated. Two rules matter: the values come from the outside logic's timing, and setup and hold use different values.
# not-run: SDC is not executable here
set_input_delay -clock sys_clk -max 4.0 [get_ports din] ;# data can arrive up to 4.0 ns after the clock edge
set_input_delay -clock sys_clk -min 1.0 [get_ports din] ;# and as early as 1.0 ns (for hold)
set_output_delay -clock sys_clk -max 3.0 [get_ports dout] ;# outside logic + external setup need 3.0 ns
set_output_delay -clock sys_clk -min -0.5 [get_ports dout] ;# external hold minus its min path delayMax (setup) | Min (hold) | |
|---|---|---|
Input delay | External clock-to-Q max + external logic max + board delay max | The same terms at their minimum |
Output delay | External logic max delay + external setup time (+ skew) | External hold time - external logic min delay (can be negative) |
# Input path budget: period 10 ns, input delay max 4.0, the internal path from port to flop
T = 10.0
input_delay_max = 4.0
internal_path = 3.5 # buffer + logic from the port to the capture flop D
setup = 0.1
arrival = input_delay_max + internal_path # relative to the launching clock edge
required = T - setup
slack = required - arrival
assert abs(slack - 2.4) < 1e-9
# Output side: period 10, internal clk-to-Q + path to the port 5.0, output delay max 3.0
out_arrival = 5.0
out_required = T - 3.0
assert abs((out_required - out_arrival) - 2.0) < 1e-9
print("PASS: input slack", round(slack, 2), "ns; output slack", round(out_required - out_arrival, 2), "ns")The input arrives 4.0 ns into the cycle and the block uses 3.5 ns of it, leaving 2.4 ns of margin against 9.9 ns required. The output side has 10 - 3 = 7 ns available to get from the clock edge to the port, of which 5 ns is used, leaving 2.0 ns. The input delay shrinks the time the block has; the output delay shrinks it from the other end.
Every non-clock input has -max and -min input delays against a named clock; every output has -max and -min output delays.
Values trace to the neighbour's timing (their clock-to-Q and logic) or to an interface specification, not to a default.
The reference clock of each delay matches the interface's clock, with source latency set for the external path; the internal tree latency belongs only to the capturing flops.
A second set_input_delay (or set_output_delay) on the same port for a different clock replaces the first unless -add_delay is used.
1.5 + 0.2 = 1.7 ns, the outside delay plus the external setup time (plus any skew allowance).