FPGA 进阶 29:时钟网络与约束——多时钟、时钟组与时钟规划
本文是
fpga/进阶层第 33 篇。时钟是 FPGA 设计里最特殊的信号:走专用布线网络、由专用缓冲驱动,约束体系围绕它展开。单时钟的基本约束见 XDC 约束入门 与 约束实战,跨时钟域的硬件处理见 CDC 亚稳态 与异步 FIFO;这篇讲多时钟系统怎么规划、怎么约束。
本文要回答的问题
- FPGA 的时钟网络有哪几种缓冲(BUFG/BUFH/BUFR/BUFIO)?
- 主时钟、派生时钟怎么约束?哪些工具自动推、哪些要手写?
- 异步时钟域之间怎么声明?set_clock_groups vs set_false_path?
- 多时钟系统在架构上怎么规划?
一、时钟必须走专用网络
FPGA 内部布线分两类:普通 fabric 连线(给数据/使能用)和时钟专用网络(低偏斜、高扇出、树形分布、占 dedicated 资源)。时钟信号必须经专用缓冲驱动到专用网络:
| 缓冲 | 作用范围 | 典型用途 |
|---|---|---|
| BUFG | 全局(整个芯片) | 系统主时钟、MMCM 输出、复位释放同步 |
| BUFH | 单个水平时钟区域 | 局部高扇出、省全局资源 |
| BUFR | 单个区域(可带分频) | 源同步接口局部时钟、ISERDESE |
| BUFIO | IO 列(只能到 IO 逻辑) | SerDes/IDELAY 参考、IO 采样时钟 |
| MMCM/PLL | 时钟生成(频/相/占空比) | 晶振倍频分频、多相位、抖动滤波 |
铁律:
- 时钟不要从普通 fabric 连线进触发器 CK 端——综合会警告
using non-clock routing,偏斜不可控; - 需要低频动作优先用时钟使能(
always @(posedge clk) if (en)),不要用计数器分频出新时钟; - 真要新频率/相位,用 MMCM/PLL,输出自动上 BUFG;
- 外部进入 FPGA 的随路时钟(如 LVDS 源同步、RGMII)从时钟管脚进,工具自动放 BUFG/BUFIO,但要写约束。

二、时钟约束:主时钟与派生时钟
主时钟(晶振/外部输入管脚)必须手写:
# 板载 100MHz 差分/单端晶振
create_clock -name sys_clk -period 10.000 [get_ports clk100]
# 外部随路时钟(如 LVDS 接收侧)
create_clock -name rx_clk -period 8.000 [get_ports rx_clk_p]派生时钟:
- MMCM/PLL 输出:例化 Clocking Wizard 后,工具自动生成
create_generated_clock,不用手写(别重复写,否则冲突); - 手写分频寄存器输出:要手动声明:tcl
create_generated_clock -name clk_div -source [get_pins mmcm/clk_out1] \ -divide_by 2 [get_pins clk_div_reg/Q] - 收发器恢复时钟、SerDes 分频时钟:按 IP 手册约束,多数 IP 自带。
没被约束覆盖的时钟,时序报告里会出 "unsynthesizable/untimed" 或时钟缺失告警,等于那段逻辑没做时序签核。
三、异步时钟域:set_clock_groups
两个没有固定相位/频率关系的时钟域之间(如 100M 本地钟 vs 恢复时钟 vs 另一颗芯片来的钟),工具默认按"同源同步"去分析路径——要么报一堆永远收敛不了的假违例,要么你被迫加一堆错误例外。正确做法两步:
- RTL 里做 CDC:单 bit 用同步器/边沿检测,多 bit 用异步 FIFO/握手/Gray 码;
- 约束里声明无关:tcl组内仍正常分析,组间所有路径豁免时序检查。
set_clock_groups -asynchronous \ -group {sys_clk mmcm_clk0} \ -group {rx_clk} \ -group {rgmii_rx_clk}
set_clock_groups vs set_false_path:
| set_clock_groups | set_false_path | |
|---|---|---|
| 粒度 | 整组时钟之间全切断 | 单条/指定 from-to 路径 |
| 场景 | 异步时钟域之间 | 复位路径、静态配置、测试口 |
| 风险 | 组写错会漏分析真同步路径 | 漏写一条就漏一条 |
复位网络、上电只写一次的静态寄存器、JTAG/测试路径,用 set_false_path -from ... -to ... 精确豁免。例外约束只改变工具检查,不改变硬件——该做的同步器一个不能少(CDC 验证见进阶 RTL 质量检查篇)。
四、多时钟系统规划清单
- 列时钟表:每个时钟的频率、来源(晶振/MMCM/恢复/外部)、去向、与谁异步——一张表画清楚;
- 时钟树从简:一个 MMCM 集中生成所需频率,同频同相合并;低频动作优先 CE;
- 时钟域交叉显式化:所有跨域只许经过命名规范的同步器模块/异步 FIFO,禁止裸信号跨域;
- 复位随时钟域走:每个时钟域自己的同步释放复位;
- 约束配套:主时钟手写、派生时钟核对自动推导、异步组 set_clock_groups、例外路径逐条注释原因;
- 报告核对:实现后查 Clock Summary(时钟数量/频率/BUFG 占用)和 CDC/时序报告,确认没有 unconstrained clock。
常见坑对照
| 坑 | 后果 | 正确做法 |
|---|---|---|
| 寄存器分频直接当时钟 | 偏斜大、偶发亚稳 | CE 或 MMCM 生成 |
| 主时钟没写 create_clock | 整片无时序分析 | 晶振/输入钟必写 |
| MMCM 输出又手写约束 | 时钟冲突报错 | 用 IP 自动推导 |
| 异步域不做 CDC 只写 false_path | 硬件真出亚稳 | 先同步器/FIFO,再约束 |
| set_clock_groups 分组错 | 同步路径被漏分析 | 按真实时钟关系核对 |
| 时钟太多 BUFG 耗尽 | 实现失败 | 合并/CE/BUFR 分流 |
| 恢复时钟漏约束 | 接收侧无时序签核 | 按 IP 手册补 generated clock |
相关与延伸
前置:XDC 约束入门、约束实战、STA 静态时序分析。 硬件跨域:CDC 单 bit、异步 FIFO、复位策略。 多时钟架构设计见后续《多时钟系统设计》;例外路径深入见时序例外场景。
一句话总结
时钟是 FPGA 里唯一必须走专用网络的信号:晶振经 MMCM/PLL 生成所需频率、自动上 BUFG 全局树,局部 IO 用 BUFR/BUFIO;低频动作一律用时钟使能而不是寄存器分频造钟(偏斜/抖动不可控)。约束上分三层:晶振/外部输入钟手写 create_clock;MMCM 输出工具自动推 generated clock(手写分频/恢复钟才需补 create_generated_clock);异步时钟域之间先在 RTL 做同步器/异步 FIFO,再用 set_clock_groups -asynchronous 整组豁免——set_clock_groups 管整组、set_false_path 管单条(复位/静态寄存器)。约束只告诉工具"别查",不修复硬件。多时钟工程先列时钟表(频率/来源/异步关系)、集中生成、跨域显式化、复位分域,最后用 Clock Summary 和时序报告核对无遗漏。