Beyond Synthesis: Verifying Your Design Actually Works

You've synthesized your design into gates, optimized for area and power, and analyzed the results. But there's one critical question remaining: Will it work at the target clock frequency? Synthesis tools provide estimates, but accurate timing verification requires dedicated static timing analysis (STA). This is where hope becomes certainty—or where you discover timing violations that must be fixed before tape-out.

Static timing analysis is the industry-standard method for verifying timing in digital designs. Unlike simulation (which only checks specific input vectors), STA mathematically analyzes all possible paths through your circuit, ensuring timing requirements are met across all operating conditions. Understanding STA fundamentals—setup and hold constraints, clock definitions, delays, and exceptions—is essential for any digital designer working on real hardware.

This module introduces the foundational concepts of timing analysis that apply across all STA tools, though we'll use OpenSTA for concrete examples.

Setup and Hold Constraints: The Fundamental Requirements

Understanding Setup Time

Setup time is the minimum time data must be stable before the clock edge captures it.

Physical Reason
Inside a flip-flop, data must propagate through internal transistors and gates to reach the master latch. If data changes too close to the clock edge, the internal circuitry doesn't have time to resolve the correct value, potentially capturing the wrong data or entering a metastable state.

Setup Time Specification

Data must be stable at least T_setup before the clock edge

From Liberty File

timing () {
    related_pin : "D";
    timing_type : setup_rising;
    rise_constraint (setup_template_5x5) {
        values (...);  // Setup time values
    }
}

Setup Check Equation

T_data_arrival + T_setup ≤ T_clock_arrival + T_period

Or equivalently:
T_data_arrival ≤ T_clock_arrival + T_period - T_setup

Where:
  T_data_arrival = Time when data arrives at capture flip-flop
  T_setup = Setup time requirement (from Liberty)
  T_clock_arrival = Time when clock arrives at capture flip-flop
  T_period = Clock period

Setup Slack

Slack = Required_time - Arrival_time
      = (T_clock + T_period - T_setup) - T_data_arrival

Positive slack: Timing met (data arrives early enough)
Negative slack: Timing violation (data arrives too late)
Zero slack: Exactly meeting timing (no margin)

Understanding Hold Time

Hold time is the minimum time data must remain stable after the clock edge.

Physical Reason
After the clock edge triggers capture, the flip-flop's internal master latch needs time to completely latch the data. If data changes too soon after the clock edge, the latch might not have fully captured the value, leading to incorrect operation.

Hold Time Specification

Data must remain stable for at least T_hold after the clock edge

Hold Check Equation

T_data_arrival ≥ T_clock_arrival + T_hold

Or equivalently:
T_data_arrival - T_clock_arrival ≥ T_hold

Where:
  T_data_arrival = Time when data arrives at capture flip-flop
  T_clock_arrival = Time when clock arrives at capture flip-flop
  T_hold = Hold time requirement (from Liberty)

Hold Slack

Slack = Arrival_time - Required_time
      = T_data_arrival - (T_clock + T_hold)

Positive slack: Hold timing met (data stays stable long enough)
Negative slack: Hold violation (data changes too soon)

Key Differences: Setup vs. Hold

Setup Timing:

  • Checks maximum delay (data arrives before deadline)
  • Related to clock period (higher frequency = harder to meet)
  • Fixed by: Speeding up logic, pipelining, lowering frequency
  • Analysis corner: Slow corner (SS - worst-case delays)

Hold Timing:

  • Checks minimum delay (data doesn't arrive too soon)
  • Independent of clock period (same requirement at any frequency)
  • Fixed by: Adding delay (buffers, routing detours)
  • Analysis corner: Fast corner (FF - minimum delays)

Critical Insight
Setup violations can be fixed by reducing clock frequency. Hold violations cannot be fixed by changing frequency—they require physical design changes (adding delay). This makes hold violations more serious in many ways.

Example: Timing Analysis of a Simple Path

Circuit

Launch_FF → INV → AND → NAND → Capture_FF

Setup Analysis (Slow Corner, 2.0ns clock period)

Launch FF clock-to-Q:     0.180ns
INV delay:                0.065ns
AND delay:                0.078ns
NAND delay:               0.082ns
Wire delays:              0.045ns
────────────────────────────────
Data arrival time:        0.450ns

Clock period:             2.000ns
Capture FF setup time:   -0.095ns
────────────────────────────────
Required time:            1.905ns

Setup slack = 1.905 - 0.450 = 1.455ns (PASS)

Hold Analysis (Fast Corner, same path)

Launch FF clock-to-Q:     0.095ns
INV delay:                0.032ns
AND delay:                0.038ns
NAND delay:               0.040ns
Wire delays:              0.020ns
────────────────────────────────
Data arrival time:        0.225ns

Capture FF hold time:     0.045ns
────────────────────────────────
Required time:            0.045ns

Hold slack = 0.225 - 0.045 = 0.180ns (PASS)

Both setup and hold are satisfied with positive slack.

Clock Definitions and Specifications

Why Clock Definition Matters

Clocks are the reference for all timing checks. Every setup and hold calculation depends on accurate clock definition. Incorrect clock specifications lead to incorrect timing analysis—potentially passing bad designs or failing good ones.

Basic Clock Definition (SDC Format)

Simple Clock

create_clock -name sys_clk -period 10.0 [get_ports clk]

This defines:

  • Clock name: sys_clk
  • Period: 10.0ns (100 MHz)
  • Source: Port named clk

Equivalent Specifications

# Using frequency instead of period
create_clock -name sys_clk -period 10.0 -waveform {0 5} [get_ports clk]

Where waveform:
  First edge (rise) at 0ns
  Second edge (fall) at 5ns
  Creates 50% duty cycle

Non-50% Duty Cycle

# 40% duty cycle (4ns high, 6ns low)
create_clock -name sys_clk -period 10.0 -waveform {0 4} [get_ports clk]

Multiple Clocks

Independent Clocks

create_clock -name fast_clk -period 5.0  [get_ports clk_fast]
create_clock -name slow_clk -period 20.0 [get_ports clk_slow]

# Declare them unrelated (asynchronous)
set_clock_groups -asynchronous -group {fast_clk} -group {slow_clk}

Related Clocks

create_clock -name main_clk -period 10.0 [get_ports clk]

# Derived clock (divided by 2)
create_generated_clock -name div2_clk \
    -source [get_ports clk] \
    -divide_by 2 \
    [get_pins div/Q]

The STA tool understands div2_clk is synchronous to main_clk and analyzes paths between them correctly.

Clock Characteristics

Clock Period
Defines the fundamental timing window:

create_clock -period 5.0 ...
# Launch edge at 0ns, capture edge at 5ns

Clock Latency
Time for clock to reach sequential elements:

# Source latency (before clock tree)
set_clock_latency -source 0.5 [get_clocks sys_clk]

# Network latency (clock tree delay)
set_clock_latency 1.2 [get_clocks sys_clk]

# Total clock arrival time = source + network latency

Clock Transition
Clock edge slew rate:

set_clock_transition 0.1 [get_clocks sys_clk]

Affects flip-flop setup/hold times (from Liberty characterization).

Virtual Clocks

Purpose: For I/O timing when external clock isn't visible in design

# External system clock (not in design)
create_clock -name ext_clk -period 10.0

# Reference for input/output delays
set_input_delay -clock ext_clk -max 2.0 [get_ports data_in]
set_output_delay -clock ext_clk -max 1.5 [get_ports data_out]

Virtual clocks define timing relationships without an actual clock signal in the design.

Input and Output Delays

Why I/O Delays Matter

Your design doesn't exist in isolation—it interfaces with external devices (other chips, memories, sensors). I/O delays model the timing relationship between your internal clock and external signals.

Input Delays

Concept: External device launches data relative to its clock; your chip captures it relative to your clock.

Input Delay Specification

set_input_delay -clock sys_clk -max 3.0 [get_ports data_in]
set_input_delay -clock sys_clk -min 1.0 [get_ports data_in]

Interpretation:

  • -max 3.0: In worst case, data arrives 3.0ns after the clock edge
  • -min 1.0: In best case, data arrives 1.0ns after the clock edge

Setup Check with Input Delay

Available time = Clock_period - Input_delay_max - Setup_time

Example:
  Period: 10.0ns
  Input delay max: 3.0ns
  Setup time: 0.1ns
  Available for internal logic: 10.0 - 3.0 - 0.1 = 6.9ns

Hold Check with Input Delay

Required delay = Input_delay_min + Hold_time

Example:
  Input delay min: 1.0ns
  Hold time: 0.05ns
  Internal path must be at least: 1.0 + 0.05 = 1.05ns

Output Delays

Concept: Your chip launches data; external device must capture it within its timing budget.

Output Delay Specification

set_output_delay -clock sys_clk -max 2.5 [get_ports data_out]
set_output_delay -clock sys_clk -min 0.5 [get_ports data_out]

Interpretation:

  • -max 2.5: External device needs data stable 2.5ns before its clock edge
  • -min 0.5: External device needs data stable 0.5ns after its clock edge

Setup Check with Output Delay

Available time = Clock_period - Output_delay_max

Example:
  Period: 10.0ns
  Output delay max: 2.5ns
  Internal logic budget: 10.0 - 2.5 = 7.5ns

Practical I/O Timing Example

System Architecture

External Chip → [data_in] → Your Chip → [data_out] → External Memory
    (Tco=2ns)                              (Tsu=1.5ns)

Constraints

# Input from external chip
# Worst case: External Tco = 2ns, board trace = 1ns
set_input_delay -clock sys_clk -max 3.0 [get_ports data_in]
# Best case: Tco = 1ns, trace = 0.5ns
set_input_delay -clock sys_clk -min 1.5 [get_ports data_in]

# Output to external memory
# Memory setup requirement = 1.5ns, board trace = 1ns
set_output_delay -clock sys_clk -max 2.5 [get_ports data_out]
# Memory hold requirement = 0.5ns, trace = 0.2ns
set_output_delay -clock sys_clk -min 0.7 [get_ports data_out]

This ensures your chip's internal timing accounts for external system requirements.

False Paths: Intentionally Ignoring Timing

What Are False Paths?

False paths are signal paths that exist structurally but will never actually propagate data in real operation. Analyzing them wastes time and creates false timing violations.

Common False Path Scenarios

Scenario 1: Asynchronous Clock Domain Crossing

// Data crosses from clk_a domain to clk_b domain
always @(posedge clk_a) begin
    data_a <= input_signal;
end

// Synchronizer in clk_b domain
always @(posedge clk_b) begin
    sync1 <= data_a;  // Metastable
    sync2 <= sync1;   // Stable
end

Path from clk_a domain to clk_b domain is asynchronous—timing doesn't matter (synchronizer handles metastability).

False Path Declaration

set_false_path -from [get_clocks clk_a] -to [get_clocks clk_b]

Scenario 2: Configuration Registers

// Configuration written once at startup, never during operation
always @(posedge cfg_clk) begin
    config_reg <= config_data;
end

// Design uses config_reg, but it's static during operation
always @(posedge sys_clk) begin
    result <= data & config_reg;
end

Path from cfg_clk domain to sys_clk domain is false (config_reg doesn't change).

False Path Declaration

set_false_path -from [get_clocks cfg_clk] -to [get_clocks sys_clk]

Scenario 3: Test/Debug Paths

// Debug multiplexer
assign output = debug_mode ? debug_data : normal_data;

If debug_mode is never high in production, the path through debug_data is false.

False Path Declaration

set_false_path -through [get_pins debug_mux/debug_data]

False Path Cautions

Warning: False paths eliminate timing analysis. Use carefully:

  • Document why each false path is truly false
  • Verify the path won't be used in operation
  • Reconsider if design changes might enable the path

Common Mistake: Using false paths to "fix" real timing violations

# BAD: Hiding real timing problem
set_false_path -from launch_ff -to capture_ff

If the path is functionally real, this creates a chip that won't work!

Multicycle Paths: Relaxing Timing Requirements

What Are Multicycle Paths?

Multicycle paths are paths where data intentionally takes multiple clock cycles to propagate. The default single-cycle setup check is too pessimistic.

Multicycle Path Scenarios

Scenario 1: Slow Divider

// 32-bit divider takes 32 cycles
always @(posedge clk) begin
    if (start)
        busy <= 1;
    
    if (busy) begin
        // Division logic (many cycles)
        counter <= counter + 1;
        if (counter == 31) begin
            busy <= 0;
            result <= quotient;
        end
    end
end

always @(posedge clk) begin
    if (!busy)
        output_reg <= result;  // Only captured after 32 cycles
end

Path from divider to output_reg can take 32 cycles.

Multicycle Constraint

set_multicycle_path 32 -setup -from [get_pins divider/*] -to [get_pins output_reg]
set_multicycle_path 31 -hold  -from [get_pins divider/*] -to [get_pins output_reg]

Why hold is 31?
Setup checks at cycle N+32, hold checks at cycle N+31 (one cycle before).

Scenario 2: Pipelined Multiplier with Enable

// 3-stage multiplier, only updates every 3 cycles
always @(posedge clk) begin
    if (enable) begin
        stage1 <= a * b;
        stage2 <= stage1;
        stage3 <= stage2;
    end
end

If enable pulses every 3 cycles, paths can be multicycle.

Multicycle Path Equations

Setup Check

Default: Check at N+1 cycles
Multicycle K: Check at N+K cycles

Available time = K × T_period - T_setup

Hold Check

Default: Check at same edge (N cycles)
Multicycle K: Check at N+(K-1) cycles

This prevents hold check from being too relaxed

Multicycle Path Cautions

Verify Functionality
Ensure the design truly operates over multiple cycles:

  • Control logic enforces multicycle operation
  • Data stability guaranteed
  • No glitches or intermediate updates

Document Thoroughly
Multicycle paths are non-obvious; document:

  • Why the path is multicycle
  • What control logic enforces it
  • Cycle count and reasoning

Clock Uncertainty and Skew

Clock Uncertainty

Clock uncertainty accounts for variations in clock arrival time:

  • Jitter: Random cycle-to-cycle variation
  • Duty cycle distortion: Non-50% duty cycle errors
  • Modeling inaccuracy: Pessimism in clock tree analysis

Specification

set_clock_uncertainty -setup 0.5 [get_clocks sys_clk]
set_clock_uncertainty -hold 0.2 [get_clocks sys_clk]

Impact on Timing

Setup check: Tightens requirement by uncertainty amount
  Available time = T_period - T_setup - T_uncertainty

Hold check: Tightens requirement by uncertainty amount
  Required time = T_hold + T_uncertainty

Typical Values:

  • Low-quality oscillator: 100-500ps uncertainty
  • High-quality PLL: 20-100ps uncertainty
  • On-chip generated clock: 50-200ps uncertainty

Clock Skew

Clock skew is the difference in clock arrival time between launch and capture flip-flops.

Positive Skew (capture clock arrives later):

Launch FF clock arrives at 1.0ns
Capture FF clock arrives at 1.2ns
Skew = +0.2ns (positive)

Impact:

  • Setup: Helps (more time for data)
  • Hold: Hurts (less time before next edge)

Negative Skew (capture clock arrives earlier):

Launch FF clock arrives at 1.0ns
Capture FF clock arrives at 0.8ns
Skew = -0.2ns (negative)

Impact:

  • Setup: Hurts (less time for data)
  • Hold: Helps (more time before next edge)

Common-Path Pessimism Removal (CPPR)

Modern STA tools remove pessimism from using worst-case delays for both launch and capture paths when they share common clock tree segments.

Without CPPR (overly pessimistic):

Launch path: Worst-case delay
Capture path: Worst-case delay
Total pessimism: Sum of two worst cases

With CPPR (realistic):

Common path: Use same delay for both
Unique paths: Use appropriate corner
Result: Less pessimistic, more accurate

Most modern tools enable CPPR by default.

Practical Uncertainty Guidelines

Conservative Approach

# External clock (board-level)
set_clock_uncertainty -setup 0.5 [get_clocks ext_clk]
set_clock_uncertainty -hold 0.3 [get_clocks ext_clk]

# On-chip PLL
set_clock_uncertainty -setup 0.2 [get_clocks pll_clk]
set_clock_uncertainty -hold 0.1 [get_clocks pll_clk]

# Internal generated (divider)
set_clock_uncertainty -setup 0.1 [get_clocks div_clk]
set_clock_uncertainty -hold 0.05 [get_clocks div_clk]

Uncertainty vs. Margin:

  • Uncertainty models real variation
  • Design margin is separate (target slack)
  • Both contribute to robust design

Summary

Static timing analysis fundamentals provide the foundation for timing closure:

  • Setup constraints verify data arrives before the clock edge deadline
  • Hold constraints ensure data remains stable after the clock edge
  • Clock definitions establish the reference for all timing checks
  • Input/output delays model external system timing requirements
  • False paths eliminate analysis of structurally impossible paths
  • Multicycle paths relax timing for intentionally slow operations
  • Clock uncertainty and skew account for real-world clock variations

Key concepts you've mastered:

  • Setup checks maximum delay (slow corner)
  • Hold checks minimum delay (fast corner)
  • Setup violations can be fixed by slowing clock; hold violations cannot
  • Proper clock definition is critical for accurate analysis
  • I/O delays bridge your chip to the external system
  • Timing exceptions (false paths, multicycle) must be used carefully

With these fundamentals, you're ready to perform actual timing analysis using OpenSTA in the next module. Understanding these concepts deeply—not just the commands—enables effective timing closure, intelligent optimization, and confident tape-out. Every timing check you'll encounter builds on these foundations.

Did you find what you were looking for?

Quiz

No quiz questions available for this article.