The netlist omits the clock speed, input arrival times and output requirements. The SDC file supplies them.
Here is the whole file for a tiny block: one clock clk, an input bus din with a valid bit, an output bus dout, and an active-low reset rst_n that goes to a reset synchroniser. Read it top to bottom; each numbered comment is one decision.
# 1. The clock: 500 MHz (2.0 ns), 50% duty cycle
create_clock -name clk -period 2.0 [get_ports clk]
# 2. Margin for jitter and skew that the tool does not know yet
set_clock_uncertainty -setup 0.15 [get_clocks clk]
set_clock_uncertainty -hold 0.05 [get_clocks clk]
# 3. Inputs arrive 40% into the cycle after the clock edge (outside logic uses the rest)
set_input_delay -clock clk -max 0.8 [get_ports {din[*] valid}]
set_input_delay -clock clk -min 0.2 [get_ports {din[*] valid}]
# 4. The next chip needs 0.6 ns of the cycle after our data leaves
set_output_delay -clock clk -max 0.6 [get_ports {dout[*]}]
set_output_delay -clock clk -min 0.0 [get_ports {dout[*]}]
# 5. Drive and load of the pins
set_driving_cell -lib_cell BUF_X2 [get_ports {din[*] valid}]
set_load 0.05 [get_ports {dout[*]}]
# 6. Reset is asynchronous: scope the exception to the reset synchroniser flops only
# Recovery/removal on the synchronised reset net stay checked against the destination clock.
# Never an unscoped false path from the reset port into the whole design.
set_false_path -from [get_ports rst_n] -to [get_pins {rst_sync_ff*/RST}]
# Confirm in the timing report what the exception covered: tools differ on whether a false path also removes recovery/removal checks.Constraint | What it means | If missing |
|---|---|---|
| Period and waveform at a port or pin | The register paths are not timed at all |
| Extra margin on every capture edge | Optimistic slack; fails after clock tree synthesis |
| When inputs change, relative to a clock edge | Input paths are unconstrained in STA (reported by |
| How much of the cycle the next block needs | Output paths unconstrained |
| Realistic input slew and output load | Over-optimistic port timing |
| Paths that are not single-cycle or never active | Over-constraining: the tool wastes effort or fails real timing |
The input and output delays decide how much of the cycle is left for your own logic. The outside world uses one part of the period, the uncertainty takes another, and you get the rest.
Read each bar from the launching edge on the left to the capturing edge on the right. The highlighted segment is the time your block owns.
Input bar: the outside logic uses the first 0.8 ns, so your logic plus setup gets 2.0 - 0.8 - 0.15 = 1.05 ns.
Output bar: the next chip needs the last 0.6 ns, so your clock-to-Q plus logic gets 2.0 - 0.6 - 0.15 = 1.25 ns.
Uncertainty sits just before the capturing edge in both bars. It is margin, so it shrinks your segment, not the outside one.
These budgets assume the ideal, zero-latency clocks above. Propagated clock latencies and external clock relationships must also be included when present.
No. Arrival plus setup and uncertainty is 0.80 + 1.10 + 0.15 = 2.05 ns, giving -0.05 ns setup slack. Omitting uncertainty would incorrectly predict +0.10 ns.
When both neighbouring blocks share an owner, split the cycle between them. Write the budget into both SDC files.
The starter file assumes one rising-edge clock, ns time units, pF capacitance units, synchronous external data referenced to that clock, a library containing BUF_X2, and a reset synchroniser whose asynchronous pins match rst_sync_ff*/RST. Confirm units from the loaded Liberty/tool report before using 2.0 or 0.05. Negative output -min values may be needed for a real receiver's hold budget; 0.0 above is only an assumed interface contract.
A pattern that matches nothing applies no constraint and gives no error. In OpenSTA, collections are Tcl lists. After linking the design and loading libraries, run these guards before applying the file (adapt collection-size APIs in other STA tools):
proc require_nonempty {label objects} {
if {[llength $objects] == 0} { error "Empty timing collection: $label" }
return $objects
}
require_nonempty clock_port [get_ports clk]
require_nonempty reset_port [get_ports rst_n]
require_nonempty data_bus [get_ports {din[*]}]
require_nonempty valid_port [get_ports valid]
require_nonempty output_bus [get_ports {dout[*]}]
require_nonempty reset_sync_pins [get_pins {rst_sync_ff*/RST}]
require_nonempty input_driver [get_lib_cells */BUF_X2]# OpenSTA examples: inspect warnings and both delay directions.
check_timing -verbose
report_checks -path_delay max
report_checks -path_delay minIllustrative audit result (not tool output) | Action |
|---|---|
din/valid -> input-register D: clock + max/min input delay present | Inspect setup AND hold slack |
Internal register Q -> register D: clk present | Check period, uncertainty and both delay directions |
Output-register Q -> dout: max/min output delay present | Check external receiver contract and output load |
status output has no output delay | Unconstrained: add its interface contract before claiming closure |
reset exception matches synchronizer async pins only | Audit exceptions and downstream recovery/removal; a nonempty match alone does not prove correct scope |
Also compare collection widths and full matched names against the intended interface; partial bus matches can pass a nonempty guard. Check the library cell identity, clock coverage and exception coverage in the actual tool. See OpenSTA examples and units and command reference.
set_input_delay -max 3.0. How much time is left for logic and setup between the input pin and the first register?4.0 − 3.0 = 1.0 ns. If the register's setup time is 0.1 ns, the logic and wiring must fit in 0.9 ns. Any setup uncertainty reduces that budget further.
The SDC is an adaptation template, not a validated SDC and netlist pair. The audit table is illustrative, not tool output. No SDC or physical timing result is established by it.