⏱️ SDC 2.1 Standard • Timing Intent & Signoff Constraints Reference

SDC & Timing Constraints Complete Cheat Sheet

The authoritative reference for timing intent in silicon: clock definitions, generated clocks, I/O delay budgeting, clock domain crossing (CDC), false paths, multicycle paths, MMMC, and signoff timing closure across Synopsys, Cadence, AMD Vivado, and OpenSTA.

🧠 SDC Mental Model

Timing intent vs implementation, the 5 core pillars, and minimal ASIC SDC template.

⏰ Clocks & Waveforms

create_clock, duty cycles, virtual clocks, and multi-clock port budgeting.

🌐 I/O Environment Delays

Modeling the external world: set_input_delay, set_output_delay, and -add_delay.

🚫 Timing Exceptions & CDC

False paths, multicycle setup/hold edge movement, and set_clock_groups.

Filter: Showing 68 Topics
M1

SDC Mental Model & Timing Intent

§1

Timing Intent in Silicon

SDC Core Concept
▼

SDC (Synopsys Design Constraints) is a standardized language that communicates the intended timing behavior of a digital chip to synthesis, static timing analysis (STA), and physical design (P&R) engines. SDC does not dictate how logic gates are wired; instead, it defines when electrical signals are required to arrive and become stable.

💡 The Core SDC Principle
SDC represents the contract between the chip and the outside world. Without complete and accurate constraints, EDA optimization algorithms cannot distinguish between critical nanosecond datapath speed requirements and harmless asynchronous reset signals.
[SDC] HIERARCHY OF TIMING SPECIFICATION
# Canonical Order of Constraints:
# 1. Define Clocks (create_clock, create_generated_clock)
# 2. Define External World I/O Delays (set_input_delay, set_output_delay)
# 3. Define Clock Margins (set_clock_uncertainty, set_clock_latency)
# 4. Define Clock Relationships (set_clock_groups -asynchronous)
# 5. Define Specific Timing Exceptions (set_false_path, set_multicycle_path)
§2

SDC Implementation Pipeline

Flow RTL-to-GDSII
▼

The identical SDC timing intent guides every phase of implementation, but as the chip progresses from logical synthesis to tapeout, the accuracy of wire RC parasitics and clock trees increases dramatically.

[FLOW] PHYSICAL DESIGN PROGRESSION
RTL Synthesis (Wire Load Models / Pre-layout STA)
       │  Ideal clocks, estimated interconnect wire models
       ▼
Floorplan & Power Planning
       │  Die boundary, macro placement, power grid IR bounds
       ▼
Standard Cell Placement (place_opt / optDesign)
       │  Global routing estimations, cell buffering for slew
       ▼
Clock Tree Synthesis (CTS - ccopt_design / clock_tree_synthesis)
       │  Clocks transition from IDEAL to PROPAGATED (real clock skew & insertion delay)
       ▼
Detailed Routing (route_design / detailed_route)
       │  Actual metal layers, vias, crosstalk coupling capacitances
       ▼
Signoff STA & Extraction (PrimeTime / Tempus / OpenSTA with SPEF parasitics)
       └── Final timing signoff across all MMMC PVT corners
§3

The 5 Core SDC Pillars

Taxonomy Architecture
▼

Every timing constraint in production ASIC and FPGA designs fits into five foundational categories:

  1. Clock Definition: What clocks exist, their periods, waveforms, and origin pins.
  2. I/O Timing: Arrival and required times of off-chip signals relative to reference clocks.
  3. Clock Uncertainty & Latency: Margins for jitter, PVT variation, and clock insertion delays.
  4. Clock Domain Relationships: Declaring whether clock pairs are synchronous, asynchronous, or exclusive.
  5. Timing Exceptions: Overriding the default single-cycle setup/hold rules for multi-cycle paths and false paths.
§4

Minimal ASIC SDC Template

Golden Template ASIC
▼

A clean, minimal, synthesizable SDC file for a single-clock digital block running at 100 MHz (10 ns period):

[SDC] MINIMAL_SYNCHRONOUS_BLOCK.SDC
# 1. Primary Clock (100 MHz, 50% duty cycle)
create_clock -name sys_clk -period 10.000 -waveform {0.000 5.000} [get_ports clk]

# 2. I/O Constraints (Assuming external device uses 2ns for launch & requires 2ns setup)
set_input_delay  -clock sys_clk -max 2.000 [get_ports data_in*]
set_input_delay  -clock sys_clk -min 0.500 [get_ports data_in*]
set_output_delay -clock sys_clk -max 2.000 [get_ports data_out*]
set_output_delay -clock sys_clk -min 0.500 [get_ports data_out*]

# 3. Margins: Setup Uncertainty (Jitter + Margin = 200ps), Hold Uncertainty (100ps)
set_clock_uncertainty -setup 0.200 [get_clocks sys_clk]
set_clock_uncertainty -hold  0.100 [get_clocks sys_clk]

# 4. Design Rules
set_max_transition 0.250 [current_design]
set_load 0.050 [all_outputs]
M2

Primary Clocks & Waveforms

§5

Primary Clock Definition (create_clock)

create_clock Universal
▼

create_clock defines a master timing reference on a physical port or pin. All downstream register setups and holds are computed relative to edges originating from this definition.

[SDC] CREATE_CLOCK SYNTAX
# Standard 200 MHz Clock on Primary Port 'clk_200m'
create_clock -name core_clk -period 5.000 [get_ports clk_200m]

# Tool Notes:
# [SYNOPSYS] dc_shell / pt_shell: Applied to ports or internal pins
# [VIVADO]   UG835: Automatically creates a propagated clock object
# [CADENCE]  Innovus: Automatically sets up the CTS target root
§6

Period to Frequency Conversion

Math Formulas
▼

SDC periods are strictly specified in time units (typically nanoseconds ns or picoseconds ps as defined in the library header).

$$F\,(\text{MHz}) = \frac{1000}{T\,(\text{ns})} \quad\Longleftrightarrow\quad T\,(\text{ns}) = \frac{1000}{F\,(\text{MHz})}$$
  • 10.0 ns = 100 MHz
  • 5.0 ns = 200 MHz
  • 3.333 ns = 300 MHz
  • 2.0 ns = 500 MHz
  • 1.0 ns = 1.0 GHz
  • 0.5 ns = 2.0 GHz
§7

Clock Waveform & Duty Cycles

-waveform Waveform
▼

By default, create_clock assumes a 50% duty cycle with the rising edge at $t = 0$ and falling edge at $t = T/2$. The -waveform {rise fall} option overrides this for asymmetrical or phase-shifted clocks.

[SDC] NON-50% AND PHASE-SHIFTED WAVEFORMS
# 10 ns Period, 25% Duty Cycle (High for 2.5ns, Low for 7.5ns)
create_clock -name clk_25duty -period 10.000 -waveform {0.000 2.500} [get_ports clk_a]

# 10 ns Period, Phase Shifted by 90 Degrees (2.5ns delay before rise, falling at 7.5ns)
create_clock -name clk_90deg -period 10.000 -waveform {2.500 7.500} [get_ports clk_b]
§8

Virtual Clocks in Real Designs

Virtual Clock I/O Reference
▼

A Virtual Clock has a period and waveform but no physical port or pin target in the design netlist. It represents an external clock generator located outside the chip packaging.

[SDC] VIRTUAL CLOCK SPECIFICATION
# Define virtual clock (notice no [get_ports] argument!)
create_clock -name virt_ext_clk -period 8.000

# Use virtual clock to constrain chip inputs and outputs
set_input_delay  -clock virt_ext_clk -max 1.800 [get_ports sensor_data*]
set_output_delay -clock virt_ext_clk -max 2.200 [get_ports dac_out*]

# Benefit: We can assign independent latency, jitter, and uncertainty to virt_ext_clk 
# without perturbing the chip's internal clock distribution network!
§9

Multiple Clocks on Single Port (-add)

-add Multi-Freq
▼

If a chip port can be driven by different oscillators in different modes (e.g. 100 MHz normal mode vs 10 MHz low-power mode), apply multiple clocks to the same port using -add.

[SDC] MULTI-CLOCK ASSIGNMENT
# Fast mode clock
create_clock -name clk_fast -period 5.000 [get_ports clk_in]

# Low-power mode clock on the SAME port (Must use -add!)
create_clock -name clk_slow -period 50.000 -add [get_ports clk_in]

# Declare them exclusive so STA does not analyze cross-frequency paths
set_clock_groups -physically_exclusive -group {clk_fast} -group {clk_slow}
CRITICAL TRAP: Omitting -add will cause the second create_clock command to silently overwrite the first clock definition in most EDA engines!
M3

Generated Clocks & Derivations

§10

Generated Clock Mechanics (create_generated_clock)

Generated Clock STA Master
▼

When a clock signal passes through an internal flip-flop divider, PLL, counter, or clock-gating latch, the output is a generated clock. STA tools maintain the phase and latency relationship back to the master clock source.

[SDC] CREATE_GENERATED_CLOCK ESSENTIALS
# Syntax:
# create_generated_clock -name <gen_clk_name> \
#   -source <master_clock_source_pin_or_port> \
#   [-divide_by <N> | -multiply_by <M> | -invert | -edges <list>] \
#   <target_pin_or_port>
§11

Frequency Dividers (-divide_by)

-divide_by RTL Dividers
▼

For a flip-flop whose inverted output feeds back to its D-input, the Q pin generates a divide-by-2 clock:

[SDC] DIVIDE-BY-2 AND DIVIDE-BY-4 CONSTRAINTS
# Master clock on port 'clk' (10ns = 100MHz)
create_clock -name clk_master -period 10.000 [get_ports clk]

# Divide by 2 clock (20ns = 50MHz) generated at flop U_DIV2/Q
create_generated_clock -name clk_div2 \
  -source [get_ports clk] \
  -divide_by 2 \
  [get_pins U_DIV2/Q]

# Divide by 4 clock (40ns = 25MHz) generated at flop U_DIV4/Q
create_generated_clock -name clk_div4 \
  -source [get_pins U_DIV2/Q] \
  -divide_by 2 \
  [get_pins U_DIV4/Q]
§12

Frequency Multipliers & PLLs (-multiply_by)

-multiply_by PLL Hard Macro
▼

On-chip Phase-Locked Loops (PLLs) and Frequency Synthesizers multiply the reference crystal oscillator:

[SDC] PLL MULTIPLIER CONSTRAINTS
# 25 MHz Reference Crystal
create_clock -name ref_25m -period 40.000 [get_ports osc_in]

# PLL multiplies by 16 to generate 400 MHz core clock (2.5ns period)
create_generated_clock -name core_400m \
  -source [get_ports osc_in] \
  -multiply_by 16 \
  [get_pins U_PLL/CLKOUT]
§13

Inverted Generated Clocks (-invert)

-invert Phase Shift
▼

When a clock passes through an inverter, the rising edge of the source clock causes the falling edge of the inverted clock.

[SDC] INVERTED CLOCK CONSTRAINT
create_generated_clock -name clk_inverted \
  -source [get_ports clk] \
  -invert \
  [get_pins U_CLK_INV/Y]
§14

Complex Edge Derivations (-edges)

-edges DDR / Asymmetric
▼

The -edges {r1 f1 r2} option maps specific source edges (1 = 1st rise, 2 = 1st fall, 3 = 2nd rise, 4 = 2nd fall) to the generated clock's 1st rise, 1st fall, and 2nd rise.

[SDC] EDGE MAPPING EXAMPLE
# Master clock: 10ns period (edges: 1@0ns, 2@5ns, 3@10ns, 4@15ns, 5@20ns)
# Generate divide-by-2 clock with rising edge at master edge 1, falling edge at master edge 3, 
# and next rising edge at master edge 5:
create_generated_clock -name clk_div2_edges \
  -source [get_ports clk] \
  -edges {1 3 5} \
  [get_pins U_DIV/Q]
§15

CTS Network Topology Traps

Trap Cadence / Synopsys
▼

During Clock Tree Synthesis (CTS), Innovus and ICC2 trace the physical clock network backward from the generated clock target to the specified -source pin.

COMMON CTS WARNING: If the -source pin is placed on a pin that does NOT have an unbroken physical combinational path to the generated clock pin (e.g. referencing an input port instead of the driving PLL/register output), CTS tools will report: **WARN: (ENCSYC-103): Cannot find clock latency path from master clock to generated clock. Treating as independent root!
M4

I/O Delay Budgeting & External World Modeling

§16

External World Modeling Concept

Concept I/O Budget
▼

A common misconception is that set_input_delay 2.0 adds 2 ns of internal chip delay. In reality, it models the external PCB trace delay plus external device clock-to-Q delay.

📐 The I/O Timing Equations
$$\text{Internal Time Available for Chip Input} = T_{\text{period}} - T_{\text{input\_delay(max)}} - T_{\text{setup}}$$ $$\text{Internal Time Available for Chip Output} = T_{\text{period}} - T_{\text{output\_delay(max)}} - T_{\text{clock\_to\_Q}}$$
§17

Input Delay: Setup (-max) Budget

-max set_input_delay
▼

The -max input delay represents the worst-case (latest) time the external signal will arrive at the package pin after the reference clock edge.

[SDC] MAX INPUT DELAY
# External chip takes up to 3.2ns to output data on PCB
set_input_delay -clock [get_clocks clk_sys] -max 3.200 [get_ports spi_miso]
§18

Input Delay: Hold (-min) Budget

-min Hold Check
▼

The -min input delay represents the best-case (earliest) time the external data will change. This is essential for preventing hold violations on chip input registers.

[SDC] MIN INPUT DELAY (HOLD)
# External chip data changes as early as 0.8ns after clock edge
set_input_delay -clock [get_clocks clk_sys] -min 0.800 [get_ports spi_miso]
§19

Output Delay Budgeting (set_output_delay)

set_output_delay External Setup/Hold
▼

set_output_delay describes the setup and hold requirements of the external receiver device connected to the chip's output pin.

[SDC] OUTPUT DELAY CONSTRAINTS
# External receiver requires 2.0ns setup before next clock edge:
set_output_delay -clock [get_clocks clk_sys] -max 2.000 [get_ports ddr_dq*]

# External receiver requires 0.5ns hold after clock edge:
set_output_delay -clock [get_clocks clk_sys] -min -0.500 [get_ports ddr_dq*]
HOLD SIGN CONVENTION: Notice that minimum output delay is often negative when the external receiver requires data to remain stable for a hold window $T_h$ after the clock edge: $\text{delay}_{\min} = -T_h$.
§20

Multi-Clock I/O & -add_delay

-add_delay Multi-Clock
▼

When a bidirectional or multiplexed bus is sampled by different clock domains in different system modes, apply delays with -add_delay:

[SDC] MULTI-CLOCK I/O CONSTRAINING
set_input_delay -clock clk_100 -max 2.500 [get_ports rx_bus*]
set_input_delay -clock clk_200 -max 1.200 -add_delay [get_ports rx_bus*]
§21

Separate Rise & Fall Delay Bounds

-rise / -fall Asymmetry
▼

Physical pads and PCB transmission lines have asymmetric rise and fall times due to PMOS vs NMOS driver pull-up and pull-down variations.

[SDC] SEPARATE RISE AND FALL BOUNDS
set_input_delay -clock clk_sys -rise -max 2.100 [get_ports bus_in*]
set_input_delay -clock clk_sys -fall -max 2.400 [get_ports bus_in*]
M5

Clock Margins: Uncertainty, Latency & Transition

§22

Clock Uncertainty (Jitter vs Skew vs Margin)

Uncertainty set_clock_uncertainty
▼

set_clock_uncertainty reduces the effective clock period during STA to reserve margin for clock jitter, phase noise, power supply ripple, and unmodeled silicon variations.

🔍 The 3 Physical Components of Uncertainty
$$\text{Total Uncertainty} = \text{Clock Jitter} + \text{Clock Skew Margin} + \text{Additional Guardband}$$
  • Jitter: Temporal variation of clock edges from the PLL or oscillator over cycles.
  • Skew: Spatial difference in clock arrival times between launch and capture registers.
  • Margin: Extra safety buffer for voltage drops, temperature hotspots, and aging.
[SDC] CLOCK UNCERTAINTY
# 200 ps uncertainty across all paths clocked by 'core_clk'
set_clock_uncertainty 0.200 [get_clocks core_clk]
§23

Setup vs Hold Uncertainty (-setup / -hold)

-setup / -hold Margins
▼

Setup and hold checks require different margins. Setup compares edges separated by a full clock cycle (accumulating cycle-to-cycle PLL jitter), whereas hold compares the same clock edge arriving at launch and capture flops (unaffected by cycle-to-cycle jitter).

[SDC] ASYMMETRIC SETUP & HOLD UNCERTAINTY
# Setup includes cycle-to-cycle jitter + OCV margin:
set_clock_uncertainty -setup 0.200 [get_clocks core_clk]

# Hold is within the same cycle; only accounts for local clock skew variation:
set_clock_uncertainty -hold  0.080 [get_clocks core_clk]
§24

Inter-Clock Domain Uncertainty (-from / -to)

-from / -to Cross-Domain
▼

When paths cross between two synchronous clocks derived from the same root (e.g. 200 MHz core clock and 100 MHz peripheral clock), define inter-clock uncertainty to model phase drift between tree branches.

[SDC] INTER-CLOCK UNCERTAINTY
set_clock_uncertainty -from [get_clocks clk_200] -to [get_clocks clk_100] -setup 0.350
set_clock_uncertainty -from [get_clocks clk_200] -to [get_clocks clk_100] -hold  0.150
§25

Clock Latency (Source vs Network Latency)

set_clock_latency Insertion Delay
▼

Clock Latency (insertion delay) is the time required for a clock edge to propagate from its origin to register clock pins.

  • Source Latency (-source): Delay from the actual clock oscillator/crystal outside the chip to the chip input port.
  • Network Latency: Delay from the chip clock input port through internal clock buffers to the leaf flip-flops.
[SDC] SOURCE AND NETWORK LATENCY
# External board/package clock delay:
set_clock_latency -source -max 1.500 [get_clocks pcie_clk]
set_clock_latency -source -min 1.000 [get_clocks pcie_clk]

# Pre-CTS estimated internal clock tree insertion delay:
set_clock_latency 0.800 [get_clocks pcie_clk]
§26

Pre-CTS vs Post-CTS Propagated Clocks

set_propagated_clock CTS Transition
▼

In pre-CTS synthesis, clock trees do not physically exist; registers receive ideal clocks with zero delay or user-specified estimated latency. Post-CTS, the design contains real physical buffer trees, and clocks must be marked as propagated.

[SDC] POST-CTS PROPAGATED CLOCK
# Post-CTS STA scripts (Innovus / PrimeTime / Tempus / OpenSTA):
set_propagated_clock [all_clocks]

# Tool Behavior:
# Pre-CTS:  STA calculates skew = 0 (or uses set_clock_uncertainty as proxy).
# Post-CTS: STA measures actual RC delays of physical buffers & routing wires!
§27

Clock Transition & Slew Margins (set_clock_transition)

set_clock_transition Slew
▼

Pre-CTS, set_clock_transition defines the rising and falling transition time (slew) on clock pins. Slower clock transitions increase register internal propagation delay ($T_{\text{cq}}$) and internal setup requirements.

[SDC] CLOCK SLEW SPECIFICATION
# Target 120ps rise and fall clock slew:
set_clock_transition 0.120 [get_clocks core_clk]

# Separate rise and fall slew:
set_clock_transition -rise 0.100 [get_clocks core_clk]
set_clock_transition -fall 0.130 [get_clocks core_clk]
M6

Clock Relationships, Domains & CDC

§28

Asynchronous Clock Groups (set_clock_groups)

-asynchronous CDC Uncoupling
▼

When two or more clocks originate from independent oscillators or crystals with unrelated frequencies and phases, they are asynchronous. Declaring them in asynchronous clock groups instructs STA to completely disable timing analysis between the domains.

[SDC] ASYNCHRONOUS CLOCK GROUPS
# System oscillator (100MHz) and PCIe Reference (100MHz from external board)
# Even though both are 100MHz, their phases drift independently!
create_clock -name sys_clk  -period 10.0 [get_ports clk_sys]
create_clock -name pcie_clk -period 10.0 [get_ports clk_pcie]

set_clock_groups -asynchronous \
  -group [get_clocks sys_clk] \
  -group [get_clocks pcie_clk]
§29

Clock Grouping vs CDC Silicon Safety

Warning Metastability
▼

An essential truth of semiconductor engineering:

CRITICAL HARDWARE WARNING: set_clock_groups -asynchronous tells the static timing engine: "Do not report timing errors on paths between these clocks."
It DOES NOT make the circuit safe in silicon! If the RTL designer omitted dual-flip-flop synchronizers, pulse stretchers, or Gray-coded asynchronous FIFOs, the physical silicon chip will suffer from metastability and catastrophic random crashes in the field!
§30

Physically Exclusive Clocks (-physically_exclusive)

-physically_exclusive Hardware Mux
▼

Clocks are physically exclusive if they physically cannot exist simultaneously on the design circuitry (for instance, sharing the same input pad via a board jumper or external hardware pin configuration).

[SDC] PHYSICALLY EXCLUSIVE CONSTRAINT
set_clock_groups -physically_exclusive \
  -group [get_clocks clk_crystal] \
  -group [get_clocks clk_test_bench_injector]
§31

Logically Exclusive Clocks (Muxes)

-logically_exclusive Clock Mux
▼

When two clocks feed the input data pins of a glitch-free clock multiplexer, both clocks physically exist on the chip, but downstream logic only receives one active clock at any given time depending on the select line.

[SDC] LOGICALLY EXCLUSIVE CLOCK MUX
create_clock -name clk_turbo -period 4.0 [get_ports osc_fast]
create_clock -name clk_eco   -period 10.0 [get_ports osc_slow]

# Output of clock mux feeds downstream registers:
set_clock_groups -logically_exclusive \
  -group [get_clocks clk_turbo] \
  -group [get_clocks clk_eco]
§32

False Paths vs Clock Groups

Comparison Best Practice
▼

Both commands can uncouple timing between clocks, but their architectural meaning and performance differ significantly:

Criteria set_clock_groups set_false_path -from clkA -to clkB
Scope Global domain relationship (bi-directional) Directional exception (A $\to$ B only)
Tool Runtime Fast (prunes path graphs before exploration) Slow (evaluates paths then discards them)
Intent Asynchronous domains Specific static control / quasi-static lines
M7

Timing Exceptions: False Paths

§33

set_false_path Semantics

set_false_path Exception
▼

set_false_path instructs the timing engine that specific paths cannot functionally occur or are explicitly synchronized in hardware, and should be excluded from setup and hold timing verification.

[SDC] FALSE PATH COMMAND
# Eliminate timing analysis on asynchronous reset pin:
set_false_path -from [get_ports rst_n]

# Eliminate timing on configuration register that never toggles during operation:
set_false_path -from [get_cells u_cfg/mode_reg[*]]
§34

Point-to-Point (-from / -to / -through)

-through Precision
▼

The -through argument is critical for pinpointing exact silicon pathways without over-constraining adjacent logic:

[SDC] THROUGH PIN CONSTRAINING
# False-path only paths passing through the test-mode multiplexer input pin:
set_false_path \
  -from [get_cells u_reg_bank/*] \
  -through [get_pins u_mux/test_in] \
  -to [get_cells u_alu/*]
§35

Asynchronous Reset Line Hazards

Reset Hazard Recovery/Removal
▼

While reset assertion is asynchronous, reset deassertion must be synchronous to avoid flip-flops waking up in undefined states (recovery and removal timing violations).

SENIOR STA INTERVIEW WARNING: Never write set_false_path -to [all_registers -pin CDN] blindly! If you false-path the reset pins of registers, STA will fail to check recovery and removal timing on the reset release edge! Instead, use reset synchronizer bridges and let STA check recovery/removal on the synchronized reset tree.
§36

False Path != Slow Path

Concept Design Mistake
▼

If a complex 64-bit floating point arithmetic unit takes 3 clock cycles to complete its computation, it is NOT a false path. It is a multicycle path. Declaring it as a false path tells the P&R router that the delay can be 100 nanoseconds, corrupting the operation!

§37

Blanket False-Path Blunders

Anti-Pattern Audit Warning
▼

Junior engineers under deadline pressure frequently commit this deadly anti-pattern to eliminate timing violations from reports:

[ANTI-PATTERN] DO NOT WRITE THIS!
# DISASTER: Hides all real I/O timing bugs across the entire chip!
set_false_path -from [all_inputs] -to [all_outputs]
M8

Timing Exceptions: Multicycle Paths

§38

Multicycle Setup Paths (set_multicycle_path)

Multicycle Setup Shift
▼

When digital architecture provides logic with multiple clock periods to settle (e.g. governed by a clock enable or state machine that only samples every $N$ cycles), use set_multicycle_path.

[SDC] 2-CYCLE SETUP EXCEPTION
# Allow 2 clock cycles for setup between source and destination:
set_multicycle_path 2 -setup -from [get_cells u_mult/src_reg*] -to [get_cells u_mult/dst_reg*]
§39

The Multicycle Hold Trap (N-1)

Classic Trap Hold Bug
▼

By default in SDC, setting a multicycle setup of $N$ moves the hold check forward to cycle $N-1$! This forces physical design tools to insert an enormous chain of delay buffers to delay data by an entire extra clock cycle, wasting area and routing resources!

⚠️ The Golden Multicycle Pair Formula
For same-clock multicycle paths enabled by a clock enable, you must ALWAYS pair the setup exception with an $(N-1)$ hold exception:
[SDC] MANDATORY SETUP & HOLD PAIR
# 2-Cycle Setup:
set_multicycle_path 2 -setup -from [get_cells u_alu/A*] -to [get_cells u_alu/RES*]

# MANDATORY: Hold check moved back to the launch clock edge (N - 1 = 1):
set_multicycle_path 1 -hold  -from [get_cells u_alu/A*] -to [get_cells u_alu/RES*]
§40

Edge Shifting: -start vs -end

-start / -end Phase Shift
▼

When source and destination clocks run at different frequencies, define whether the cycle multiplier moves relative to the launch clock (-start) or capture clock (-end):

  • -end (Default for setup): Multiplies the cycle period of the capture/destination clock.
  • -start (Default for hold): Multiplies the cycle period of the launch/source clock.
§41

Clock Enable Multipliers

Clock Enable RTL Pipelines
▼

Verifying that an RTL clock enable signal strictly toggles on alternate cycles allows physical implementation tools to relax combinational logic delays from 1 period to 2 periods without failing setup.

§42

Multicycle Edge Movement Diagrams

Diagram Visual Waveform
▼
[WAVEFORM] DEFAULT VS 2-CYCLE SETUP & HOLD
Default Single-Cycle:
Launch Clock:   |‾‾|_ (Edge 0)
Capture Clock:         |‾‾|_ (Edge 1: Setup Check)
                       |‾‾|_ (Edge 0: Hold Check)

Multicycle Setup = 2, WITHOUT Hold adjustment (THE TRAP):
Capture Clock:                |‾‾|_ (Edge 2: Setup Check)
                       |‾‾|_ (Edge 1: Hold Check -- BAD! Requires massive delay buffer!)

Multicycle Setup = 2, WITH set_multicycle_path 1 -hold:
Capture Clock:                |‾‾|_ (Edge 2: Setup Check)
                |‾‾|_ (Edge 0: Hold Check -- CORRECT! Normal hold margin at launch edge)
M9

Timing Exceptions: Max/Min Delay & Arc Disabling

§43

set_max_delay Path Overrides

set_max_delay Pure Delay
▼

set_max_delay overrides the default clock-period setup calculation with an explicit numerical upper bound. It is commonly used for asynchronous cross-domain channels, pulse widths, or pure combinational input-to-output feedthrough paths.

[SDC] MAX DELAY OVERRIDE
# Restrict feedthrough delay from primary input A to output Y to 4.5ns:
set_max_delay 4.500 -from [get_ports bypass_in] -to [get_ports bypass_out]

# Constrain CDC Gray-coded bus skew to less than half a clock cycle:
set_max_delay 2.500 -from [get_cells u_fifo/wptr_reg[*]] -to [get_cells u_fifo/rptr_sync_reg[*]]
§44

set_min_delay Hold Overrides

set_min_delay Min Bound
▼

set_min_delay specifies an absolute lower bound on data path propagation, preventing signals from racing through combinational logic and corrupting hold checks.

[SDC] MIN DELAY CONSTRAINT
set_min_delay 1.000 -from [get_ports bypass_in] -to [get_ports bypass_out]
§45

set_disable_timing Arc Cutting

set_disable_timing Arc Pruning
▼

Standard cell library definitions contain individual timing arcs between input and output pins. set_disable_timing breaks combinational loops or disables unused internal cell pathways.

[SDC] DISABLE SPECIFIC CELL TIMING ARC
# Disable combinational feedback loop through latch D-to-Q arc:
set_disable_timing -from D -to Q [get_cells u_latch_loop]
§46

set_data_check Pin Timing

set_data_check Custom Timing
▼

Enforces custom setup and hold timing relationships directly between two data pins (not reference clock pins), such as asynchronous handshakes or SPI chip-select to data setup windows.

[SDC] DATA-TO-DATA CHECK
# Ensure CS_N is asserted at least 1.5ns before DATA toggles:
set_data_check -from [get_pins u_spi/CS_N] -to [get_pins u_spi/MOSI] -setup 1.500
M10

Modes, Case Analysis & MMMC Integration

§47

Case Analysis & Static Constants (set_case_analysis)

set_case_analysis Mode Control
▼

set_case_analysis forces a static logic 0 or 1 onto a port or pin during STA. The timing engine propagates this constant through multiplexers and gates, pruning unreachable timing arcs without changing the underlying netlist.

[SDC] CASE ANALYSIS CONFIGURATION
# Constrain functional mode (Disable Scan Test and MBIST):
set_case_analysis 0 [get_ports test_mode]
set_case_analysis 0 [get_ports scan_enable]

# In a separate Scan Shift SDC file:
# set_case_analysis 1 [get_ports test_mode]
# set_case_analysis 1 [get_ports scan_enable]
§48

Functional vs Scan vs MBIST Modes

Modes DFT
▼

Modern microchips have distinct operational modes that require different SDC timing constraints:

  • Functional Mission Mode: High-frequency system clocks active, scan enable grounded at 0, full multi-gigahertz constraints.
  • Scan Shift Mode: Low-frequency slow test clock (e.g. 20–50 MHz), scan enable forced to 1, shift register chains checked for hold.
  • At-Speed Capture Mode: PLL burst pulse (launch and capture pulses) to verify transition delay faults.
  • Memory BIST (MBIST): Internal memory test controllers running at system frequency while functional core logic is idle.
§49

MMMC Constraint Modes

MMMC Constraint Modes
▼

In Multi-Mode Multi-Corner (MMMC) flows, each SDC file is packaged into a Constraint Mode.

[CADENCE / INVOVUS] MMMC CONSTRAINT MODE CREATION
create_constraint_mode -name mode_func -sdc_files {./constraints/func.sdc}
create_constraint_mode -name mode_scan -sdc_files {./constraints/scan.sdc}
§50

Analysis Views & Delay Corners

Analysis Views Signoff Matrix
▼

An Analysis View couples a Constraint Mode (SDC) with a Delay Corner (Library Set + RC Parasitic Corner). Innovus and Tempus optimize all active analysis views simultaneously during placement and routing.

[INNOVUS] ANALYSIS VIEW BINDING
create_analysis_view -name view_func_slow -constraint_mode mode_func -delay_corner corner_slow_max
create_analysis_view -name view_func_fast -constraint_mode mode_func -delay_corner corner_fast_min

# Activate setup and hold views:
set_analysis_view -setup {view_func_slow} -hold {view_func_fast}
M11

Design Rules & I/O Driving Environment

§51

Max Transition (DRC Slew Limits)

set_max_transition DRC Slew
▼

Limits the maximum voltage transition time (slew) allowed on any wire net in the design. Slow transitions increase power dissipation and susceptibility to crosstalk noise.

[SDC] MAX TRANSITION SPECIFICATION
# 250ps maximum slew allowed across all design nets:
set_max_transition 0.250 [current_design]

# Stricter requirement on clock trees (120ps max):
set_max_transition 0.120 [get_clocks core_clk]
§52

Max Capacitance Budgets (set_max_capacitance)

set_max_capacitance Cap Limit
▼

Prevents standard cell output driver pins from driving capacitive loads larger than characterized in their Liberty models:

[SDC] MAX CAPACITANCE
set_max_capacitance 0.150 [current_design]
§53

Max Fanout Limits (set_max_fanout)

set_max_fanout HFN Prevention
▼

Forces synthesis tools to insert buffer repeaters when an output net drives more than $N$ downstream logic gate inputs:

[SDC] MAX FANOUT
set_max_fanout 16 [current_design]
§54

set_driving_cell Library Modeling

set_driving_cell External Driver
▼

Rather than assuming ideal zero-resistance drivers on chip input ports, set_driving_cell models the actual library buffer driving the pin from off-chip:

[SDC] REALISTIC INPUT DRIVER MODELING
# Input pins are driven by a standard 4x drive inverter:
set_driving_cell -lib_cell INV_X4 -pin Y [all_inputs -no_clocks]
§55

Output Load Capacitance (set_load)

set_load External Cap
▼

Models the external PCB trace capacitance, receiver gate capacitance, and bond pad capacitance connected to chip output pins:

[SDC] OUTPUT CAPACITIVE LOAD
# 30 fF load on external GPIO outputs:
set_load 0.030 [get_ports gpio_out*]
M12

Validation, Timing Equations & Gold Templates

§56

check_timing Signoff Audit

check_timing Signoff Audit
▼

Running report_timing alone is never sufficient. You must run check_timing to audit for missing constraints, loops, and unconstrained registers:

[STA] CHECK_TIMING AUDIT
# OpenSTA / PrimeTime / Tempus Constraint Quality Check:
check_timing -verbose

# Key Diagnostic Flags Audited:
# - no_input_delay: Inputs lacking external world constraints
# - no_output_delay: Outputs lacking setup/hold budgets
# - no_clock: Registers lacking clock definitions (dead logic!)
# - unconstrained_endpoints: Flip-flops that never get timing checked
# - loops: Combinational feedback loops
§57

Unconstrained Endpoints Audit

Critical Check WNS Trap
▼

A design showing $WNS = 0.00\,\text{ns}$ with zero violations is NOT clean if it contains unconstrained endpoints! An unconstrained path is completely ignored by STA and can fail catastrophically in silicon.

§58

Setup Slack Equation & Fmax

Formulas Setup Math
▼
📐 The Setup Timing Formulation
$$T_{\text{arrival}} = T_{\text{launch\_clk}} + T_{\text{cq}} + T_{\text{logic}}$$ $$T_{\text{required}} = T_{\text{capture\_clk}} + T_{\text{period}} - T_{\text{setup}} - \text{Uncertainty}$$ $$\text{Slack}_{\text{setup}} = T_{\text{required}} - T_{\text{arrival}} \ge 0$$ $$F_{\max} = \frac{1}{T_{\text{cq}} + T_{\text{logic}} + T_{\text{setup}} + \text{Uncertainty} - \text{Skew}}$$
§59

Hold Slack Equation & Race Hazards

Formulas Hold Math
▼
📐 The Hold Timing Formulation
$$T_{\text{arrival(min)}} = T_{\text{launch\_clk(min)}} + T_{\text{cq(min)}} + T_{\text{logic(min)}}$$ $$T_{\text{required(min)}} = T_{\text{capture\_clk(max)}} + T_{\text{hold}} + \text{Uncertainty}$$ $$\text{Slack}_{\text{hold}} = T_{\text{arrival(min)}} - T_{\text{required(min)}} \ge 0$$ Fatal Silicon Race: Notice that clock period ($T_{\text{period}}$) does NOT appear in the hold equation! Lowering the clock frequency cannot fix a hold violation in silicon!
§60

Clock Skew Dynamics (Setup vs Hold)

Skew Physics Useful Skew
▼
$$\text{Skew} = T_{\text{capture\_clk}} - T_{\text{launch\_clk}}$$
  • Positive Skew ($T_{\text{capture}} > T_{\text{launch}}$): Clock arrives later at capture flip-flop. HELPS SETUP, HURTS HOLD!
  • Negative Skew ($T_{\text{capture}} < T_{\text{launch}}$): Clock arrives earlier at capture flip-flop. HURTS SETUP, HELPS HOLD!
§61

Complete ASIC Signoff SDC Template

Master Template Gold Reference
▼
[SDC] PRODUCTION_ASIC_SIGNOFF_TEMPLATE.SDC
#========================================================
# PRODUCTION ASIC TIMING CONSTRAINTS
#========================================================
current_design TOP

# 1. Primary Oscillators
create_clock -name sys_clk  -period 5.000 -waveform {0.000 2.500} [get_ports clk_sys]
create_clock -name pcie_clk -period 10.000 [get_ports clk_pcie]
create_clock -name virt_io_clk -period 5.000

# 2. Generated Clocks (Dividers & PLLs)
create_generated_clock -name clk_div2 \
  -source [get_ports clk_sys] \
  -divide_by 2 \
  [get_pins u_clock_gen/u_div2/Q]

# 3. Asynchronous Clock Domains (CDC)
set_clock_groups -asynchronous \
  -group [get_clocks {sys_clk clk_div2}] \
  -group [get_clocks pcie_clk] \
  -group [get_clocks virt_io_clk]

# 4. Clock Margins (Pre-CTS Setup: 150ps, Hold: 80ps)
set_clock_uncertainty -setup 0.150 [all_clocks]
set_clock_uncertainty -hold  0.080 [all_clocks]
set_clock_transition 0.120 [all_clocks]

# 5. External World I/O Delays
set_input_delay  -clock virt_io_clk -max 1.600 [get_ports data_in*]
set_input_delay  -clock virt_io_clk -min 0.400 [get_ports data_in*]
set_output_delay -clock virt_io_clk -max 1.500 [get_ports data_out*]
set_output_delay -clock virt_io_clk -min -0.300 [get_ports data_out*]

# 6. Electrical Environment Models
set_driving_cell -lib_cell BUF_X4 -pin Y [all_inputs -no_clocks]
set_load 0.040 [all_outputs]

# 7. Design Rule Constraints (DRC)
set_max_transition 0.220 [current_design]
set_max_fanout 20 [current_design]

# 8. Timing Exceptions
set_false_path -from [get_ports rst_n]
set_case_analysis 0 [get_ports test_mode]
set_case_analysis 0 [get_ports scan_enable]
§62

Complete Vivado XDC Constraints

Vivado XDC AMD FPGA
▼
[XDC] VIVADO_MASTER_CONSTRAINTS.XDC
# 1. Primary Clock Definition
create_clock -period 10.000 -name sys_clk_pin [get_ports sys_clk]

# 2. Physical FPGA Pin & IOSTANDARD Allocations
set_property PACKAGE_PIN E3 [get_ports sys_clk]
set_property IOSTANDARD LVCMOS33 [get_ports sys_clk]

set_property PACKAGE_PIN J15 [get_ports {switches[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {switches[0]}]

# 3. I/O Delays
set_input_delay -clock [get_clocks sys_clk_pin] -max 3.000 [get_ports {switches[*]}]
set_input_delay -clock [get_clocks sys_clk_pin] -min 1.000 [get_ports {switches[*]}]

# 4. Asynchronous Groups
set_clock_groups -asynchronous \
  -group [get_clocks -include_generated_clocks sys_clk_pin] \
  -group [get_clocks -include_generated_clocks clk_out1_clk_wiz_0]

# 5. False Paths on User Asynchronous Pushbuttons
set_false_path -from [get_ports btn_reset_n]
§63

SDC vs Vivado XDC Dialect Diff

Taxonomy Dialects
▼
Feature Standard ASIC SDC 2.1 AMD Vivado XDC
File Extension .sdc .xdc
Tcl Syntax Allowed Full Tcl scripts (in unmanaged flows) Constrained subset (only set, list, expr)
Physical Constraints Tool-specific DEF or Tcl commands Integrated: PACKAGE_PIN, Pblocks, IOSTANDARD
Propagated Clocks Requires set_propagated_clock post-CTS All clocks are propagated by default
§64

Top 10 SDC Blunder Hall of Fame

Hall of Fame Top Traps
▼
  1. Forgetting to pair multicycle setup with $(N-1)$ hold: Triggers thousands of catastrophic false hold buffers.
  2. Blanket false-pathing: set_false_path -from [all_inputs] hiding real silicon failures.
  3. False-pathing reset lines: Bypassing recovery and removal check verification.
  4. Missing generated clock declarations on dividers: Tools treat clocks as unconstrained or cross-domain.
  5. Ignoring unconstrained endpoints: Celebrating a $WNS = 0.00\,\text{ns}$ while 20% of registers are untimed.
  6. Applying input delays without specifying -min: Leaving input registers open to fatal hold race hazards.
  7. Overwriting clock definitions: Forgetting -add when multiple frequencies share an input pin.
  8. Mismatched generated clock source pins: Breaking CTS latency tracking trees.
  9. Assuming set_clock_groups fixes RTL metastability: Silicon crashes despite 100% clean STA.
  10. Treating multicycle paths as false paths: Router ignores routing delay entirely on slow math units.
§65

Senior STA Timing Interview Q&A

Interview Prep Senior Staff
▼
🎯 Q: Can a hold timing violation be fixed by slowing down the clock frequency?
A: NO, NEVER! Look at the hold equation: $$T_{\text{cq(min)}} + T_{\text{logic(min)}} \ge T_{\text{hold}} + \text{Skew} + \text{Uncertainty}$$ Clock period ($T_{\text{period}}$) does NOT appear in the equation because hold is evaluated on the same clock edge. Slowing down the clock leaves the data arrival and hold window completely unchanged! Hold violations must be resolved by inserting delay buffers, changing driver cell drive strength, or swapping to High-Vt (HVT) cells.
🎯 Q: What is the difference between set_clock_groups -asynchronous and set_false_path?
A: set_clock_groups establishes a bi-directional architectural relationship between clock domains, enabling the STA engine to prune timing graph search branches early. set_false_path is a directional exception applied to specific paths; the tool must still explore the timing graph before discarding them.
M13

Clock Gating, DDR Interfaces & CDC Buses

§66

Clock-Gating Checks (set_clock_gating_check)

Clock Gating Glitch Safety
▼

When a clock passes through a logic gate controlled by an enable, the enable must only change while the clock is at the gate's non-controlling level, the level where the gate's output ignores the enable. For an AND gate, the enable must change only while the clock is low. For an OR gate, it must change only while the clock is high. If the enable changes at any other time, the gated clock gets a clipped pulse or a glitch. That is a functional failure, not just lost slack. STA tools infer clock-gating setup and clock-gating hold checks on these gates, and set_clock_gating_check sets the margins for those checks.

{
  "title": "AND-type gating: EN rises while CLK is low, so GCLK starts with a full pulse",
  "ticks": false,
  "signals": [
    { "name": "CLK", "wave": "p.....", "period": 2 },
    { "name": "EN", "wave": "0..1........" },
    { "name": "GCLK = CLK AND EN", "wave": "0...hlhlhlhl" }
  ]
}
[SDC] CLOCK-GATING CHECK MARGINS
# Default margins for every inferred gating check (ns, illustrative)
set_clock_gating_check -setup 0.10 -hold 0.05 [current_design]

# Tighter setup margin on one hand-instantiated gate
set_clock_gating_check -setup 0.20 [get_cells u_cg/u_and_gate]

# Tell the tool which clock level to check when it cannot infer it
# (e.g. a mux or complex cell used as a gate)
set_clock_gating_check -high [get_cells u_clk_mux]   ;# AND-like behaviour
set_clock_gating_check -low  [get_cells u_or_gate]   ;# OR-like behaviour
Why synthesis inserts ICG cells
An integrated clock-gating (ICG) cell latches the enable while the clock is low, then ANDs it with the clock, so the enable is held stable by design. Its setup and hold requirements are characterised in the .lib (a cell marked with a clock_gating_integrated_cell attribute). The tool times those library arcs directly instead of inferring a check on discrete logic. Bare AND/OR gating is mainly found in hand-written or legacy RTL, and that is where the margins above matter most. Option names and report commands vary between tools, so check your tool's manual.
§67

Source-Synchronous DDR Input Constraints

DDR I/O -clock_fall -add_delay
▼

A double-data-rate (DDR) interface launches data on both edges of a clock that is forwarded alongside the data. Each edge needs its own input-delay window. Constrain the rising-edge data against the clock's rising edge. Constrain the falling-edge data with -clock_fall. Put -add_delay on the second pair so it adds to the first pair instead of replacing it. Tools differ on exactly what a second set_input_delay overwrites, so the standard DDR idiom always uses -add_delay.

[SDC] CENTRE-ALIGNED DDR RECEIVE (ILLUSTRATIVE VALUES)
# Forwarded 250 MHz clock: data toggles every 2 ns (both edges)
create_clock -name rx_clk -period 4.0 [get_ports rx_clk]

# Rising-edge data window
set_input_delay -clock rx_clk -max  0.4 [get_ports {rx_d[*]}]
set_input_delay -clock rx_clk -min -0.4 [get_ports {rx_d[*]}]

# Falling-edge data window: -clock_fall selects the edge,
# -add_delay keeps the rising-edge constraints above
set_input_delay -clock rx_clk -clock_fall -max  0.4 -add_delay [get_ports {rx_d[*]}]
set_input_delay -clock rx_clk -clock_fall -min -0.4 -add_delay [get_ports {rx_d[*]}]
Where the numbers come from
-max is the latest time the data can still be changing after the reference edge. -min is the earliest time it can start changing; a negative value means before the edge. Both come from the transmitter's datasheet (clock-to-data skew) plus your board-trace skew budget. The ±0.4 ns above is a placeholder. An edge-aligned interface has a different capture-edge relationship from a centre-aligned one (usually a phase-shifted capture clock), so start from your FPGA vendor's source-synchronous templates rather than adapting this snippet blindly.
§68

Multi-Bit CDC: Max Delay & Bus Skew

CDC Async FIFO
▼

set_clock_groups -asynchronous removes all timing between two domains. That is fine for a single-bit two-flop synchronizer. It is unsafe for Gray-coded async-FIFO pointers. Gray code guarantees that only one bit changes per increment. But if routing skew between the bits grows larger than roughly one source-clock period, two successive changes can be in flight at once. The destination can then sample a pointer value that never existed. For these crossings, bound the datapath delay and skew instead of cutting the paths completely.

[XDC] GRAY-POINTER CROSSING (VIVADO)
# Bound the crossing to about one period of the faster clock (4.0 ns, illustrative).
# -datapath_only ignores clock skew/latency, which are meaningless across async domains.
set_max_delay 4.0 -datapath_only \
    -from [get_cells {wr_ptr_gray_reg[*]}] \
    -to   [get_cells {wr_ptr_sync1_reg[*]}]

# Keep the bits of the bus arriving close together
set_bus_skew 4.0 \
    -from [get_cells {wr_ptr_gray_reg[*]}] \
    -to   [get_cells {wr_ptr_sync1_reg[*]}]

# Audit every crossing afterwards
report_cdc -details
Exception priority trap
set_clock_groups and set_false_path take priority over set_max_delay. If the two clocks are also in an asynchronous clock group, the max-delay constraint above has no effect. Constrain these crossings path by path instead of with a blanket group. In ASIC flows the closest equivalent is set_max_delay with -ignore_clock_latency on the same paths. Support for bus-skew checks varies by tool, so check your STA tool's documentation.