2. Versal时钟生成与分配网络
Versal 的时钟体系不是“一个 PLL 带全芯片”的树状结构,而是由多个独立时钟域通过 NoC 与可编程逻辑互连构成的网状分配系统。理解它的关键,是先分清“时钟从哪来、经过谁、送到哪、在哪里换域”这四个问题。本节围绕 PS、PL、NoC、AI Engine 四类时钟源,以及 MMCM/PLL、BUFG/BUFGCE 等分配资源,梳理时钟生成与分配的完整路径,并给出时钟域交叉点的识别方法。
一、四类时钟源的来源与边界
Versal 中可用的时钟源大致分为四类。第一类是 PS 时钟:由 PS 内部的 PLL(如 APLL、RPLL、DPLL)产生,主要服务 Cortex-A72、Cortex-R5F、DDR 控制器和外设,也可通过 PL 时钟输出端口把部分时钟引到 PL 侧。第二类是 PL 时钟:来自外部时钟引脚(如 GC 引脚)、PS 输出或 NoC 输出,进入 PL 后由 MMCM/PLL 做倍频、分频和相位调整。第三类是 NoC 时钟:NoC 有独立的参考时钟输入,用于驱动 NoC 主从端口和 DDRMC,其频率通常与 PL 时钟解耦。第四类是 AI Engine 时钟:AI Engine 阵列有专门的时钟输入,AI Engine 内部还有自己的时钟分频与门控逻辑,与 PL 时钟域相互独立。
这四类时钟源的边界非常重要:它们默认不同源,因此跨域时必然存在相位和频率关系不确定的问题。即使频率数值相同,也不能假设它们同相。
二、MMCM/PLL 与 BUFG/BUFGCE 的分工
在 PL 侧,MMCM 和 PLL 负责“生成”:把输入参考时钟倍频到目标频率,并通过多个输出通道提供不同频率和相位的时钟。MMCM 相比 PLL 多了精细相位调整和占空比调整能力,适合需要多相位或精确相移的场景。PLL 则更适合对抖动和面积敏感、只需频率倍频的场合。
BUFG 和 BUFGCE 负责“分配”。BUFG 是全局时钟缓冲,把时钟送到全局时钟网络,保证到达各触发器的偏斜可控;BUFGCE 是带时钟使能的全局缓冲,可以在运行时关断某路时钟,用于低功耗或动态切换。需要注意的是,BUFGCE 关断时输出为固定电平,下游逻辑会停止翻转,因此它常被用作时钟门控,而不是简单的“开关”。
一个典型的 PL 时钟链是:外部晶振 → GC 引脚 → IBUF → MMCM → BUFG/BUFGCE → 目标寄存器。如果中间插入 BUFGCE,则使能信号本身必须与目标时钟域同步,否则会产生毛刺或亚稳态。
三、时钟域交叉点的识别方法
CDC 识别不能只看“频率是否相同”,而要看“是否同源、是否同相、是否经过同一分配路径”。具体可按以下顺序排查:
- 追源:从目标寄存器的时钟引脚反向追踪,确认它最终来自哪个时钟源。如果两个寄存器追到不同的源(例如一个来自 PS APLL,一个来自 PL MMCM),则它们之间是异步 CDC。
- 看分配路径:即使同源,如果经过不同的 BUFG 分支,或者其中一路经过 BUFGCE 门控,到达时间可能不同,应按 CDC 处理。
- 查跨边界信号:重点检查 PS 与 PL 之间的 AXI 接口、PL 与 NoC 之间的 AXI 通道、PL 与 AI Engine 之间的 AXI4-Stream 或共享内存接口。这些接口两侧通常属于不同时钟域。
- 看约束:在 XDC 中,跨时钟域路径如果没有被 set_clock_groups 或 set_false_path 正确约束,时序报告会报出无法满足的路径,这本身就是 CDC 存在的信号。
四、一个可执行的 CDC 检查清单
下面给出一份可直接用于工程检查的 CDC 识别清单,字段和判断依据均围绕 Versal 时钟网络设计:
| 检查项 | 判断依据 | 处理方式 |
|---|---|---|
| PS→PL 信号 | PS 侧时钟来自 APLL/RPLL,PL 侧来自 MMCM | 使用 AXI 寄存器或双触发器同步 |
| PL→NoC 信号 | NoC 参考时钟与 PL 时钟不同源 | 通过 NoC AXI 接口,使用异步 FIFO |
| PL→AI Engine | AIE 时钟独立于 PL 时钟 | 使用 AXI4-Stream 或共享内存加同步 |
| 同源不同 BUFG | 两路时钟来自同一 MMCM 但不同输出 | 按 CDC 处理,或约束为同步但需验证偏斜 |
| BUFGCE 门控路径 | 使能信号与目标时钟不同步 | 使能信号先同步到目标时钟域 |
五、实际配置中的关键参数
以 PL 侧一个典型 MMCM 配置为例:输入参考时钟 100 MHz,目标输出 200 MHz 和 50 MHz。MMCM 的 VCO 频率需落在器件规定范围内(例如 800–1600 MHz),因此可设 M=10、D=1,使 VCO=1000 MHz;再设 O0=5 得到 200 MHz,O1=20 得到 50 MHz。配置完成后,需在 XDC 中为输入时钟和生成时钟分别创建约束:
create_clock -name clk_in -period 10.000 [get_ports clk_in_p]
create_generated_clock -name clk_200 -source [get_pins mmcm_i/CLKIN1] \
-divide_by 5 -multiply_by 10 [get_pins mmcm_i/CLKOUT0]
create_generated_clock -name clk_50 -source [get_pins mmcm_i/CLKIN1] \
-divide_by 20 -multiply_by 10 [get_pins mmcm_i/CLKOUT1]
set_clock_groups -asynchronous -group {clk_200} -group {clk_50}
注意最后一行:如果 200 MHz 和 50 MHz 虽然同源但被当作异步处理,工具会跳过它们之间的时序检查。是否应该这样做,取决于设计是否真的在这两个域之间传递信号。如果存在传递,应改用同步约束并插入同步器,而不是简单设为异步。
总结来说,Versal 时钟网络的核心是“源—生成—分配—目标域”四层结构。掌握 PS、PL、NoC、AI Engine 四类时钟源的边界,理解 MMCM/PLL 与 BUFG/BUFGCE 的分工,再按“追源、看路径、查边界、看约束”四步识别 CDC,就能在工程中快速定位跨时钟域路径,并为后续的同步设计和时序约束打下基础。