Clock Distribution Network
Master the FPGA clock network — BUFG, BUFH, BUFR, BUFIO, MMCM, and PLL — and learn how to design robust multi-clock systems with proper CDC handling.
Why Clocks Need Dedicated Networks
A clock signal is the most demanding signal in any synchronous digital system. It must arrive at every flip-flop simultaneously — or as close to simultaneously as possible. The difference in clock arrival time between two flip-flops is called clock skew. Even a few hundred picoseconds of skew between the source and destination registers of a timing path can cause setup or hold violations.
If you were to route a clock through general routing fabric (SL1/SL2/SL6 segments), the clock would experience 3–5 ns of skew across a large FPGA — completely unacceptable at any frequency above a few hundred MHz. Even at 100 MHz (10 ns period), 3–5 ns of skew would consume half the entire timing budget just for clock distribution.
Xilinx FPGAs solve this with a dedicated H-tree clock distribution network — a symmetric, balanced tree of metal wires specifically designed to deliver the clock to all flip-flops with <100 ps of skew across the entire device. This network is separate from general routing fabric and cannot be used for data signals — it is exclusively for clocks. Knowing how to properly use this network is non-negotiable for correct FPGA design.
Clock Network Hierarchy (7-Series)
Xilinx 7-series FPGAs provide five types of clock buffers, each serving a different scope and purpose:
| Buffer Type | Scope | Drive Capability | Use Case |
|---|---|---|---|
| BUFG | Global (full chip) | All FFs, BRAM, DSP, IO | Primary system clocks — highest fanout, symmetric H-tree delivery |
| BUFH | Half chip (one clock region) | All FFs in one half-chip region | Regional high-fanout signals, saves power vs BUFG for localized clocks |
| BUFR | One clock region | FFs + ISERDES/OSERDES in region | Regional clocks derived from MMCM for serial interface logic |
| BUFIO | IO bank only | ISERDES/OSERDES only | Source-synchronous interface clocks — ultra-low skew to IO primitives |
| BUFMR | Multi-region | Multiple BUFRs across 2 regions | Cascading BUFR across adjacent IO clock regions |
BUFG — Global Clock Buffer
The BUFG is the most important clock resource for the majority of designs. Key facts:
- 7-series devices have 32 BUFG resources per device — this limits how many independent global clocks a design can have
- BUFG drives a dedicated H-tree with symmetric layout — achieves approximately 50–100 ps skew across the entire chip
- Must be used for: primary system clocks, DDR memory clocks, MGT (transceiver) reference clocks, any clock driving the entire FPGA
- A clock signal from an FPGA input pin must pass through IBUF first, then BUFG — the tools insert IBUF automatically for top-level clock ports
- Cannot be driven directly by LUT outputs without a timing closure violation — the tools will warn about "Clock signal ... not reaching a dedicated clock buffer"
MMCM — Mixed-Mode Clock Manager
The MMCM is Xilinx's advanced clock synthesis and conditioning primitive. It is a phase-locked loop (PLL) with additional features beyond basic frequency multiplication/division:
| Capability | 7-Series Specification |
|---|---|
| Input frequency range | 10 – 933 MHz |
| VCO frequency range | 600 – 1200 MHz (must be in range) |
| Output frequency | User-defined: F_OUT = F_IN × M / (D × O) |
| Clock outputs | 7 independent outputs (CLKOUT0–CLKOUT6) |
| Phase adjustment | 0–360° in steps of 1/8 VCO period |
| Duty cycle adjustment | 1%–99% on CLKOUT0 only |
| Spread spectrum clocking | Supported (for EMI reduction) |
| Jitter | Device-dependent; typically 50–150 ps RMS |
The frequency formula: F_OUT = F_IN × M / (D × O) where M is the feedback multiplier, D is the input divider, and O is the output divider for that specific output. For example, to generate 500 MHz from a 200 MHz input: F_VCO = 200 × 5 / 1 = 1000 MHz (in range), F_OUT = 1000 / 2 = 500 MHz — so M=5, D=1, O=2.
The VCO frequency must stay within 600–1200 MHz for 7-series. If your M/D combination produces a VCO frequency outside this range, the MMCM will not lock. Vivado's Clocking Wizard IP automatically validates this constraint and finds valid M/D/O combinations for your target frequencies.
PLL — Phase-Locked Loop
The PLL is a simpler version of the MMCM. Both generate synthesized clocks from a reference, but they differ in feature set:
Use MMCM When...
- You need phase shifting (0–360°) on output clocks
- You need fractional frequency division (non-integer M/O)
- You need spread-spectrum clocking (EMI reduction)
- You need more than 6 clock outputs
- You need fine duty-cycle control on CLKOUT0
Use PLL When...
- You need maximum frequency with minimum jitter
- You don't need phase shifting or fractional dividers
- 6 clock outputs are sufficient
- Power consumption matters and MMCM is overkill
- The application is a simple frequency multiplier
Clock Domain Crossing (CDC)
Any design with more than one clock domain must carefully handle signals that cross from one domain to another. When a signal generated in clock domain A is sampled by a flip-flop in clock domain B, the signal may not be stable when the B clock edge arrives — this is the metastability problem. A metastable flip-flop may produce an output that is neither a valid 0 nor a valid 1, and may oscillate for an unpredictable time before settling.
The standard solutions:
| CDC Scenario | Recommended Solution | Notes |
|---|---|---|
| Single-bit control signal | Two-FF synchronizer | Gold standard — two FFs in the destination domain, back-to-back |
| Multi-bit data bus | Asynchronous FIFO | Use Xilinx FIFO IP with independent read/write clocks |
| Slow-changing configuration | Gray-code encoding + 2FF sync | Only adjacent bits change — ensures valid intermediate state |
| Pulse transfer | Pulse synchronizer (toggle FF) | Converts pulse to toggle, synchronizes toggle, re-pulses |
Vivado includes a dedicated CDC analysis command:
report_cdc. Run this after implementation to identify all clock domain crossings in your
design. Each crossing is categorized by severity — missing synchronizers appear as
"CRITICAL" and will cause functional failures in silicon.
XDC Clock Constraints
Correct XDC timing constraints are essential for the MMCM/PLL setup to be analyzed correctly by Vivado's static timing analysis engine. Without proper constraints, timing analysis either over-constrains or under-constrains your design.
Common Clock Mistakes
These are the most common clock-related errors seen in FPGA designs:
| Mistake | Consequence | Correct Approach |
|---|---|---|
Gated clock: clk_g = clk AND en |
Glitches on the gated clock edge → metastability, incorrect FF behavior | Use clock enables: always @(posedge clk) if(en) q <= d; |
| Clock from LUT output | Massive skew through general routing — setup/hold violations everywhere | All clocks must come from BUFG, BUFH, or MMCM/PLL output → BUFG |
Missing set_clock_groups for async domains |
Timing analysis reports false failures — impossible to close timing |
Use set_clock_groups -asynchronous between unrelated clock
domains
|
| Exceeding 32 BUFG limit | Vivado error: cannot place all BUFG — design fails to route | Reuse clocks, use BUFH for regional clocks, reduce clock domain count |
| Direct combinational paths across CDC | Metastability — data corruption in silicon even if simulation passes | Always use 2-FF synchronizer, async FIFO, or Xilinx CDC IP |
assign clk_gated = clk AND enable; creates glitches
whenever enable changes while clk is high — this produces
spurious clock edges that corrupt flip-flop state. Instead, use a clock enable
signal on the flip-flop itself:
always @(posedge clk) if(enable) q <= d; — the flip-flop ignores
data when enable is low but always clocks cleanly on the rising clock edge.
A: BUFG (Global Clock Buffer) drives the full-chip H-tree clock network, delivering the clock to all flip-flops, BRAM, DSP, and IO primitives across the entire device with <100 ps skew. It consumes more power because it drives the entire chip. BUFH (Half-chip Clock Buffer) drives only one half of the device — one clock region — making it more power-efficient for clocks that only need to reach logic in a specific area. BUFH is typically used for derived clocks from MMCM that feed only a local region of the design, while BUFG is used for the primary system clock that all logic shares.
Knowledge Check
1. How many BUFG (Global Clock Buffer) resources does a Xilinx 7-series FPGA provide?
- A 8
- B 16
- C 32
- D 64
2. What does MMCM stand for?
- A Multi-Mode Clock Multiplexer
- B Mixed-Mode Clock Manager
- C Master Module Clock Multiplier
- D Multi-Channel Clock Monitor
3. Which clock buffer type is specifically designed for IO source-synchronous interfaces, driving ISERDES and OSERDES primitives only?
- A BUFG
- B BUFH
- C BUFR
- C BUFIO
4. Which Vivado Tcl command checks your design for clock domain crossing (CDC) issues and missing synchronizers?
-
A
check_timing -
B
report_timing -
C
report_cdc -
D
report_clock_interaction
report_cdc is Vivado's dedicated clock domain crossing
analysis command. It identifies every point in your design where a signal crosses
from one clock domain to another, categorizes each crossing by severity (Critical
/ Warning / Info), and flags missing synchronizers. Run it after implementation to
catch CDC bugs before they cause intermittent failures in hardware.
5. The standard two-flip-flop CDC synchronizer uses how many flip-flops in the destination clock domain?
- A 1
- B 2
- C 3
- D 4
6. Which XDC constraint defines a clock that is derived from (generated by) an MMCM or PLL output?
-
A
create_clock -
B
create_generated_clock -
C
set_output_delay -
D
set_clock_groups
create_generated_clock defines a clock that is derived from
a primary source clock through a divider, multiplier, or MMCM/PLL. It tells the
timing engine the relationship between the parent clock and the derived clock,
enabling correct setup/hold analysis across the design. The Clocking Wizard IP
generates these constraints automatically — one of the key reasons to always use
it.
7. Why should you never use a gated clock (e.g.,
assign clk_g = clk AND enable;) in an FPGA design?
- A It uses too many LUT resources
- B BUFG cannot buffer a gated clock signal
- C The AND gate creates glitches on the clock edge when enable changes, corrupting FF state
- D Gated clocks cannot be analyzed by the static timing tool
enable transitions while clk is high, the
expression clk AND enable produces a spurious glitch — a short pulse
on the gated clock output. Flip-flops sensitive to that glitch will capture
incorrect data, causing functional failures that are extremely difficult to debug.
The FPGA solution is always to use clock enable inputs on the flip-flops
themselves: always @(posedge clk) if(enable) q <= d;
Practical Exercise
Then manually write the XDC constraints for this MMCM setup. Create a file
clocks.xdc with: (1) a create_clock for the 100 MHz input;
(2) a create_generated_clock for the 250 MHz output; (3) a
create_generated_clock for the 50 MHz output. Compare your XDC to the
one generated automatically by the Clocking Wizard IP — identify any differences and
understand why the wizard may add additional constraints you didn't write.
Summary
- Clocks must use dedicated H-tree networks to achieve <100 ps skew — routing clocks through general fabric introduces 3–5 ns skew and is never acceptable
- BUFG (32 per 7-series device) drives the full-chip clock network — use for all primary system clocks
- BUFH drives one half of the chip (one clock region) — power-efficient for regional clocks
- BUFIO drives ISERDES/OSERDES only — used exclusively for source-synchronous IO interfaces
- MMCM (Mixed-Mode Clock Manager) provides frequency synthesis, phase adjustment, and 7 output clocks — always instantiate via Clocking Wizard IP
- PLL is simpler than MMCM — use for minimum-jitter frequency multiplication without phase shift requirements
- Clock Domain Crossing (CDC) requires synchronizers: 2-FF synchronizer for single bits, async FIFO for data buses
-
Run
report_cdcafter implementation to identify all CDC crossings and missing synchronizers -
XDC constraints:
create_clockfor primary clocks,create_generated_clockfor derived clocks,set_clock_groups -asynchronousfor unrelated domains - Never use gated clocks in FPGA — use clock enables on flip-flops instead