Logic Synthesis · Step 2

SDC Timing Constraints

Complete reference for Synopsys Design Constraints: clocks, I/O delays, exceptions, physical constraints — what every VLSI engineer must know for synthesis and STA.

Timing Path & Constraint Budget

Clock Period = T (e.g. 2.0 ns for 500 MHz) set_input_delay time before data arrives e.g. 0.6 ns Internal Logic Delay Budget = T − input_delay − output_delay − setup_time e.g. 2.0 − 0.6 − 0.4 − 0.15 = 0.85 ns set_output_delay time for data to reach dest e.g. 0.4 ns IN port OUT port Setup slack = Required time − Arrival time ≥ 0 ps (must be positive at tapeout)
SDC constraints define the timing budget: input_delay + internal logic delay + output_delay must fit within one clock period (minus setup margin).

Essential SDC Commands Reference

CommandPurposeKey Options
create_clockDefine primary clock — period and waveform-period, -waveform, -name
create_generated_clockDefine derived clock from divider, PLL, mux-source, -divide_by, -multiply_by, -edges
set_clock_uncertaintyModel jitter, skew, OCV margin-setup, -hold
set_clock_transitionSet clock slew at source (before CTS)-rise, -fall
set_input_delayArrival time of data at input ports-max (setup), -min (hold), -clock
set_output_delayRequired time for data at output ports-max (setup), -min (hold), -clock
set_false_pathExclude path from timing analysis entirely-from, -to, -through, -setup, -hold
set_multicycle_pathAllow path N cycles instead of 1-setup N, -hold N-1, -start, -end
set_max_fanoutMax fanout limit per netvalue, [get_designs]
set_max_transitionMax slew (transition time) on nets/portsvalue in ns
set_max_capacitanceMax net capacitance limitvalue in pF
set_dont_touchPrevent tool from modifying cell/netcell or net object
set_case_analysisForce net to constant value for analysis0 or 1
set_loadModel output port capacitive loadvalue in pF
set_driving_cellModel drive strength at input ports-lib_cell, -pin

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

Timing Exceptions — false_path vs multicycle_path

set_false_path CLK_A CLK_B CDC crossing: asynchronous clocks — path is NOT timed by static timing analysis Use: CDC paths, test mux, scan mode, reset paths set_multicycle_path 2 -setup 0 T 2T 2-cycle path allowed 1-cycle too tight ✗ Use: DSP pipelines, slow MUX paths, multi-cycle operations
false_path disables timing check entirely (for CDC/scan). multicycle_path extends the check window to N cycles (for deliberately slow paths).
## 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)

SDC Mistakes That Break Timing

MistakeEffectCorrect Practice
Forgetting -hold in MCPHold check uses cycle 0 reference — false hold violations on purpose-slow pathsAlways pair set_multicycle_path N -setup with N-1 -hold
set_false_path on CDC path but no synchronizerMetastability in silicon — false_path only removes timing check, not the metastability riskAlways 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 incompleteCreate clock on the chip input port; use create_generated_clock for internal derived clocks
No set_driving_cell on inputsInput transition defaults to 0 — overoptimistic; first-stage logic slew is wrongset_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 uncertaintyUse ≥50 ps setup, ≥20 ps hold uncertainty before CTS; after CTS use propagated clocks
Missing set_clock_groups for async clocksTool checks CDC paths that should be false — fake timing violationsset_clock_groups -asynchronous -group {CLK_A} -group {CLK_B}

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.