How Constraints Work
Timing Path & Constraint Budget
Core Commands
Essential SDC Commands Reference
| Command | Purpose | Key Options |
|---|---|---|
create_clock | Define primary clock — period and waveform | -period, -waveform, -name |
create_generated_clock | Define derived clock from divider, PLL, mux | -source, -divide_by, -multiply_by, -edges |
set_clock_uncertainty | Model jitter, skew, OCV margin | -setup, -hold |
set_clock_transition | Set clock slew at source (before CTS) | -rise, -fall |
set_input_delay | Arrival time of data at input ports | -max (setup), -min (hold), -clock |
set_output_delay | Required time for data at output ports | -max (setup), -min (hold), -clock |
set_false_path | Exclude path from timing analysis entirely | -from, -to, -through, -setup, -hold |
set_multicycle_path | Allow path N cycles instead of 1 | -setup N, -hold N-1, -start, -end |
set_max_fanout | Max fanout limit per net | value, [get_designs] |
set_max_transition | Max slew (transition time) on nets/ports | value in ns |
set_max_capacitance | Max net capacitance limit | value in pF |
set_dont_touch | Prevent tool from modifying cell/net | cell or net object |
set_case_analysis | Force net to constant value for analysis | 0 or 1 |
set_load | Model output port capacitive load | value in pF |
set_driving_cell | Model drive strength at input ports | -lib_cell, -pin |
Real Example
Complete SDC File — 500 MHz ASIC
## ============================================================ ## Clock Definition ## ============================================================ create_clock -period 2.0 -waveform {0 1.0} [get_ports CLK] set_clock_uncertainty -setup 0.1 [get_clocks CLK] # 100ps setup margin set_clock_uncertainty -hold 0.05 [get_clocks CLK] # 50ps hold margin set_clock_transition 0.1 [get_clocks CLK] # 100ps slew pre-CTS ## Generated clock from /4 divider create_generated_clock -name CLK_DIV4 \ -source [get_ports CLK] \ -divide_by 4 \ [get_pins u_clkdiv/CLK_OUT] ## ============================================================ ## Input / Output Delays ## ============================================================ # Inputs: data arrives 0.6ns after rising CLK set_input_delay -max 0.6 -clock CLK [get_ports {DATA_IN[*] ADDR[*]}] set_input_delay -min 0.1 -clock CLK [get_ports {DATA_IN[*] ADDR[*]}] # Outputs: external logic needs data 0.4ns before next CLK set_output_delay -max 0.4 -clock CLK [get_ports {DATA_OUT[*]}] set_output_delay -min 0.0 -clock CLK [get_ports {DATA_OUT[*]}] # Async reset: no timing set_false_path -from [get_ports RST_N] ## ============================================================ ## Physical Constraints ## ============================================================ set_max_fanout 20 [get_designs TOP] set_max_transition 0.25 [get_designs TOP] set_max_capacitance 0.5 [get_designs TOP] ## Model output load (next stage input cap) set_load 0.05 [get_ports DATA_OUT] ## Model input driver set_driving_cell -lib_cell BUFX4 -pin Z [get_ports {DATA_IN[*]}] ## ============================================================ ## Timing Exceptions ## ============================================================ # 2-cycle multiplier path set_multicycle_path 2 -setup \ -from [get_cells u_mult/*] -to [get_cells u_acc/*] set_multicycle_path 1 -hold \ -from [get_cells u_mult/*] -to [get_cells u_acc/*] # Scan mode path (test): false path set_case_analysis 0 [get_ports SCAN_EN] set_false_path -through [get_pins */SE] # scan enable mux inputs
Exceptions
Timing Exceptions — false_path vs multicycle_path
## false_path examples set_false_path -from [get_clocks CLK_A] -to [get_clocks CLK_B] # CDC set_false_path -from [get_ports RST_N] # async reset set_false_path -through [get_cells u_test_mux] # test mode ## multicycle_path — ALWAYS set both -setup and -hold set_multicycle_path 2 -setup -from [get_cells u_mul/*] # 2 cycles for setup set_multicycle_path 1 -hold -from [get_cells u_mul/*] # move hold back 1 # Note: -hold value = setup_cycles - 1 (to maintain hold check correctness)
Common Mistakes
SDC Mistakes That Break Timing
| Mistake | Effect | Correct Practice |
|---|---|---|
| Forgetting -hold in MCP | Hold check uses cycle 0 reference — false hold violations on purpose-slow paths | Always pair set_multicycle_path N -setup with N-1 -hold |
| set_false_path on CDC path but no synchronizer | Metastability in silicon — false_path only removes timing check, not the metastability risk | Always add 2-FF synchronizer on CDC; false_path is just for STA exemption |
| create_clock on an internal net (not top-level port) | Clock network not propagated correctly — setup/hold paths may be incomplete | Create clock on the chip input port; use create_generated_clock for internal derived clocks |
| No set_driving_cell on inputs | Input transition defaults to 0 — overoptimistic; first-stage logic slew is wrong | set_driving_cell on all input ports using a realistic driving buffer |
| clock_uncertainty too tight (or zero) | Post-CTS hold violations appear because real skew > modeled uncertainty | Use ≥50 ps setup, ≥20 ps hold uncertainty before CTS; after CTS use propagated clocks |
| Missing set_clock_groups for async clocks | Tool checks CDC paths that should be false — fake timing violations | set_clock_groups -asynchronous -group {CLK_A} -group {CLK_B} |
Interview Q&A
Top SDC Interview Questions
What is create_clock and what does the -waveform option do?
create_clock -period T -waveform {rise fall} [get_ports CLK] defines a clock with period T ns. The waveform list specifies the rising and falling edge times within one period. E.g., -waveform {0 1.0} means rise at 0 ns, fall at 1.0 ns — 50% duty cycle for a 2 ns period clock. For a 40% duty cycle: -waveform {0 0.8} on a 2.0 ns period. The waveform affects slew-based cell characterization for rise/fall path analysis.
Why must you set both -setup and -hold in set_multicycle_path?
When you set MCP 2 -setup, the setup check moves to the 2nd clock edge (2T). But the hold check default stays relative to the launch edge — now checking hold at the 2nd cycle too, which is incorrectly lenient (allows data to be very late before the 2nd capture edge). To fix: set_multicycle_path 1 -hold moves the hold check back 1 cycle to the 1st capture edge (1T), maintaining the correct hold window. The rule: MCP hold = MCP setup − 1.
What is set_clock_groups and when do you use it?
set_clock_groups -asynchronous -group {CLK_A CLK_B} -group {CLK_C} tells the STA tool that clocks in different groups are asynchronous to each other — no timing relationship exists and cross-clock paths should not be checked. This is cleaner than multiple set_false_path commands for all cross-clock combinations. Use whenever two or more clock domains are not frequency-locked (no common PLL, different oscillators, or truly async interfaces).
What is the difference between -max and -min in set_input_delay?
set_input_delay -max models the latest possible arrival of data at an input port — used for setup analysis (the tool checks that data arrives and settles before the next clock edge). set_input_delay -min models the earliest possible arrival — used for hold analysis (the tool checks that data doesn't arrive so early that it violates hold time of the first flop). Both are needed for a complete constraint; if only -max is given, the tool assumes -min = 0 which may mask hold violations.
What is set_case_analysis and when is it used in DFT?
set_case_analysis forces a net to a constant logic value (0 or 1) for timing analysis purposes only — it doesn't change the netlist. In DFT: set_case_analysis 0 [get_ports SCAN_EN] tells STA to analyze the design in functional mode (SCAN_EN=0), so scan shift paths (when SCAN_EN=1) are naturally excluded from functional timing. Also used for mode pins (power-down mode, test mode) to focus timing analysis on the mode that matters.
How does set_clock_uncertainty relate to PLL jitter and CTS skew?
set_clock_uncertainty models all clock path uncertainties in one number: PLL output jitter (typically 50–100 ps), clock skew between launch and capture flops (before CTS: estimated 100–200 ps; after CTS: actual measured skew), and OCV variation. Pre-synthesis: use a pessimistic estimate (150–200 ps setup, 50 ps hold) because CTS hasn't been built yet. Post-CTS: replace with -propagated_clock and measured skew — this gives the most accurate STA.