4. PolarFire时钟树与时钟域规划
在PolarFire FPGA上做时序收敛,第一步往往不是改约束,而是把时钟树和时钟域关系画清楚。PolarFire的时钟资源分为全局时钟网络和区域时钟网络两大类,二者在扇出范围、偏斜、功耗和可用资源上差异明显。如果时钟域规划阶段把高速逻辑放到了区域时钟上,或者把跨时钟域路径误当成同步路径处理,后续无论怎么调布局布线都很难收敛。本节围绕时钟树结构、时钟切换、分频以及跨时钟域边界识别展开,目标是让读者能够独立完成一份可落地的时钟域规划。
全局时钟与区域时钟的物理差异
PolarFire器件内部提供多条全局时钟网络,它们可以驱动整个芯片范围内的时序单元,偏斜经过专门平衡,适合高扇出、跨象限的时钟,例如系统主时钟、DDR参考时钟、高速收发器相关时钟。全局时钟资源数量有限,通常每条全局网络对应特定的时钟输入引脚或内部时钟源,使用时需要关注器件手册中全局网络的编号与可用输入。
区域时钟网络则只覆盖芯片的某个区域或若干相邻区域,扇出较小、偏斜略大,但数量更多、功耗更低。它适合局部模块的采样时钟、低速外设时钟或仅在单个区域内使用的派生时钟。把只在局部使用的时钟放到全局网络上,会浪费宝贵的全局资源;反过来,把需要跨区域传递的时钟放到区域网络上,则可能因为无法到达目标区域而导致布线失败或时序不可预测。
规划时的基本判断是:先看时钟的扇出范围,再看它的频率和抖动要求。跨象限、高扇出、对偏斜敏感的时钟优先分配全局网络;单区域、低扇出、频率不高的时钟优先使用区域网络。Libero SoC的时钟资源报告中会列出每条时钟网络的使用情况,规划完成后应核对全局网络是否被局部时钟占用。
时钟切换与分频的实现要点
PolarFire的时钟切换通常通过时钟管理单元或专用glitch-free MUX实现。切换的核心要求是:在切换过程中不能产生毛刺,否则下游触发器可能采到窄脉冲而进入亚稳态。实现时,切换控制信号需要先同步到两个候选时钟域,再经过握手逻辑,确保当前时钟停止后另一路才接入。Libero中可以使用Clock Conditioning Circuit的切换模式,也可以例化专用的时钟MUX原语。
时钟分频有两种常见做法。第一种是在时钟管理单元内部直接配置输出分频比,这种方式产生的时钟抖动小、相位关系确定,适合作为主时钟使用。第二种是用计数器在逻辑中分频,这种方式灵活但输出时钟由普通触发器产生,偏斜和抖动较大,通常只用于低速、非关键的使能信号。一个实用的经验是:如果分频后的时钟要驱动超过几十个触发器,或者要跨区域传递,就应优先使用时钟管理单元的分频输出,而不是逻辑分频。
下面给出一个典型的时钟管理单元配置示例,用于从50 MHz输入产生200 MHz系统时钟和100 MHz区域时钟:
// 示例:PolarFire CCC 配置(参数为教学示例,非实测值)
// 输入时钟:50 MHz
// 输出0:200 MHz,全局网络,占空比50%
// 输出1:100 MHz,区域网络,占空比50%
// 输出2:50 MHz,区域网络,用于外设
PF_CCC #(
.IN_FREQ(50.0),
.OUT0_FREQ(200.0),
.OUT1_FREQ(100.0),
.OUT2_FREQ(50.0),
.OUT0_DIV(1),
.OUT1_DIV(2),
.OUT2_DIV(4)
) u_ccc (
.REF_CLK(ext_clk_50m),
.OUT0_CLK(sys_clk_200m),
.OUT1_CLK(region_clk_100m),
.OUT2_CLK(periph_clk_50m),
.LOCK(pll_lock)
);
配置完成后,需要在Libero的时钟报告中确认:200 MHz输出是否分配到了全局网络,100 MHz和50 MHz是否分配到了区域网络,以及PLL锁定信号是否被正确约束。如果发现高速时钟被分配到了区域网络,应检查时钟输入引脚是否支持全局网络,或者是否因为全局网络已被其他时钟占用。
跨时钟域边界的识别方法
跨时钟域边界识别是时序收敛中最容易被忽视的环节。很多时序违例并不是因为逻辑太慢,而是因为工具把异步路径当成了同步路径去分析,或者反过来,真正的同步路径被错误地设置了false path。识别CDC边界的基本方法是:列出设计中所有时钟域,然后逐一检查每个触发器时钟端所属的域,凡是数据从一个域传到另一个域且没有同步器或异步FIFO的路径,就是需要处理的CDC路径。
在PolarFire上,Libero的Timing Analyzer可以报告跨时钟域路径,但前提是约束中已经正确定义了时钟。如果时钟没有约束,工具会使用默认的估计值,CDC报告就不可信。因此,时钟约束是CDC识别的前提。建议在约束文件中为每个时钟域显式创建时钟,并标注它们之间的异步关系。
对于单比特控制信号跨时钟域,常用两级触发器同步器;对于多比特数据总线,应使用异步FIFO或握手协议,不能简单地对每一位分别打两拍,因为多位信号在跨域时可能因为到达时间不同而产生错误的中间组合。对于脉冲信号,可以使用脉冲同步器或展宽后再同步。识别出CDC路径后,应在约束中设置set_clock_groups或set_false_path,避免工具对异步路径做无意义的时序分析。
时钟域规划的实际操作流程
把上述内容整合成一个可执行的规划流程。第一步,列出所有时钟源,包括外部晶振、收发器参考时钟、内部派生时钟,标注频率、抖动要求和扇出范围。第二步,为每个时钟源分配网络类型:跨象限高扇出用全局,单区域低扇出用区域。第三步,确定分频和切换关系,优先使用时钟管理单元输出,逻辑分频只用于低速使能。第四步,识别所有跨时钟域路径,为每条路径选择同步方案,并在约束中标注异步关系。第五步,在Libero中运行时钟报告和时序报告,核对全局网络占用、区域网络分配和CDC路径处理情况。
以一个教学示例说明:设计包含200 MHz系统时钟、100 MHz图像处理时钟和50 MHz外设时钟。200 MHz需要驱动整个芯片的流水线,分配全局网络;100 MHz只在图像处理区域使用,分配区域网络;50 MHz用于UART和SPI,分配区域网络。200 MHz到100 MHz的数据通过异步FIFO传递,100 MHz到50 MHz的控制信号通过两级触发器同步。约束中为三个时钟分别创建create_clock,并用set_clock_groups将三者设为异步。这样处理后,时序分析只关注各时钟域内部的路径,跨域路径由同步器保证,收敛目标就变得清晰可控。
时钟树和时钟域规划是时序收敛的地基。全局与区域时钟的选择决定了布线和偏斜的上限,时钟切换和分频决定了时钟质量,CDC边界识别决定了异步路径是否被正确处理。这三者共同构成约束文件的基础。规划阶段多花时间核对时钟报告,后续布局布线阶段就能少走很多弯路。