Writing XDC Clock Constraints for Vivado

2025/09/01

Writing XDC Clock Constraints for Vivado

This guide explains how to properly constrain a digital design with multiple clocks in an XDC (Xilinx Design Constraints) file, specifically for use in Vivado batch mode. We’ll cover primary clocks, generated clocks, and the relationships between them.

The Foundation: Primary Clocks

A primary clock is a clock that enters the FPGA from an external source. It’s the root of a clock tree. You must define all primary clocks first.

Differential Clock Input:

For an external differential clock, you only need to constrain one of the pins (usually the positive ‘P’ side). The create_clock command defines its period, waveform, and attaches it to a port on your design.

Internally Generated Clocks

FPGAs commonly use clock management resources like MMCMs (Mixed-Mode Clock Manager) or PLLs (Phase-Locked Loop) to generate new clocks from a primary clock. These are called generated clocks.

You should not use create_clock for these. Instead, use create_generated_clock. Vivado’s timing engine needs to understand the phase and frequency relationship between the primary clock and the generated clocks. The create_generated_clock command does this automatically by tracing the clock path from a source.

Asynchronous Clock Domains

If your design has clocks that are truly unrelated (e.g., two different oscillators), the timing analyzer will try to find paths between them by default. This leads to timing failures that are impossible to fix because there is no synchronous relationship.

You must tell Vivado to ignore timing analysis between these domains.

Note: Vivado automatically considers clocks generated from the same MMCM/PLL to be in the same synchronous group. The above example is for illustration; often, you just need to group the primary clocks.

A simpler form for the above would be:

set_clock_groups -asynchronous \
  -group [get_clocks sys_clk] \
  -group [get_clocks adc_clk]  

This command is powerful because it tells the tool that sys_clk and any clocks generated from it are one group, and adc_clk (and any clocks generated from it) are another. The tool will not time any paths that cross from one group to the other. You must handle these crossings with proper synchronizer circuits (e.g., multi-flop synchronizers).

Clock Uncertainty

Clock jitter (from the oscillator) and internal FPGA jitter affect the timing budget. The set_clock_uncertainty command models this.

Often, the default system jitter calculated by Vivado is sufficient, but for high-speed designs, you might need to specify it.

Summary for Vivado Batch Mode

When running Vivado in batch mode (e.g., with a Tcl script), you will source your XDC file. A typical flow is:

  1. Read in your HDL files.
  2. Synthesize the design (synth_design).
  3. Read in your XDC file (read_xdc).
  4. Implement the design (place_design, route_design).
  5. Generate timing reports (report_timing_summary).

The constraints are critical for the place and route steps, as the tools work to meet the timing you have defined.