ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

FPGA时钟资源全解析:从PLL到BUFG,搞定时序收敛

FPGA时钟资源全解析:从PLL到BUFG,搞定时序收敛 做FPGA设计的人总有一天会被“时钟资源”这四个字卡住。尤其是当你把工程从仿真搬到板子上发现时序收敛不了、采样老出错、PLL怎么都锁不上翻来覆去排查半天根子往往就在时钟资源的规划和使用上。这篇文章想围绕FPGA时钟资源这个主题把时钟网络、时钟管理模块、时钟约束、时序质量这些事从头到尾捋一遍聊清楚它们是什么、为什么重要、怎么用、怎么避坑。适合正准备开始做时序收敛的FPGA开发者也适合被“时钟偏斜”“BUFG不够用”“时钟域乱跳”折磨过但没时间翻手册的工程师。1. 先把时钟资源家族认全FPGA里面负责时钟的硬件资源不是一个东西而是一整套体系。很多人只听说过“PLL”以为时钟资源就是PLL其实PLL只是其中一个环节。真正重要的是后面那棵“时钟树”以及连接时钟进入FPGA的专用引脚。这套体系可以粗略分成三大类全局时钟网络、区域时钟与IO时钟、时钟管理模块。每一类管的事不一样用错了后面的时序报告就会给你颜色看。1.1 全局时钟网络芯片里的“城市主干道”全局时钟网络也就是常说的长线时钟资源是FPGA里最稳定、覆盖范围最大、偏斜最小的时钟通路。你可以把它理解成一座城市的环形主干道所有关键街区都能快速到达而且红绿灯设置得很均匀。普通逻辑互连资源则是小巷子走通能通但每条巷子的长度、弯道都不一样信号到达时间自然千差万别。时钟信号如果走在普通互连上每个寄存器收到的时钟边沿会有明显差异这就是偏斜。全局时钟网络从专门的时钟引脚进入FPGA后会经由全局缓冲器再分往整个芯片。这个缓冲器就是BUFG——GA缓冲器。BUFG的延迟通常是固定的而且网络内部做了负载均衡所以芯片左上角寄存器和右下角寄存器收到同一个时钟边沿的时间差可以压得很低只有几百皮秒甚至更低。它对全局的高扇出信号特别友好所以不只是时钟复位信号、高扇出的控制使能信号也经常借用全局时钟网络来驱动。我见过不少刚上手的工程师FPGA里明明有全局时钟网络因为不熟悉直接把内部逻辑产生的一个信号当“时钟”接到寄存器时钟端结果工具也不吭声最后就是时序报告一堆违例跑起来偶发出错。记住一个原则真正决定系统节拍的时钟特别是外部引脚进来的参考时钟一定要想办法接到BUFG让工具把它放到全局时钟布线上。1.2 区域时钟与IO时钟特定范围内的专用通道不是所有信号都需要满芯片范围内都拉一条低偏斜时钟线。器件大了以后全局时钟网络覆盖的路径更长占用资源也多。为了兼顾灵活和效率FPGA内部还会划分为多个时钟区域每个区域有独立的区域时钟缓冲器一般叫BUFH之类。区域时钟只能驱动本区域的逻辑延迟更短、资源开销更小适用于那些只影响一小片局部的同步逻辑。还有一类是专门为输入输出寄存器准备的IO时钟它有着更强的驱动能力和特殊的加速路径用来做高速源同步接口的采集时钟。比如你接一块外部ADC数据线带一个随路时钟DCODCO进来后通常不应该直接送全局时钟网络绕一圈而是就近接到区域时钟或者IO时钟链路这样数据引脚和时钟引脚之间的走线延迟关系更容易控制采样窗口更好。这里需要特别留意区域时钟不是“随便一个普通IO都能进”的你得用器件手册上标明的专用时钟引脚区域。换句话说外部时钟信号进入FPGA的位置是有讲究的。如果你的PCB原理图上时钟信号接到了普通数据引脚上就算逻辑上能功能仿真通过实际时序也大概率做不好甚至工具直接提示这条路径没有足够的时钟布线资源。1.3 时钟管理模块给时钟做“整形”和变频接下来是大家最熟悉的时钟管理模块PLL是锁相环MMCM是混合模式时钟管理器很多中高端FPGA上配的是MMCM早期器件则常用DCM这类延迟锁定环。功能上它们差不多对外部输入时钟做倍频、分频、相移、占空比调整有的还能把输入的差分时钟转成单端时钟顺便过滤一部分抖动。PLL内部的VCO压控振荡器工作范围是有讲究的。比如一个输入时钟是50MHz逻辑需要200MHz看起来倍频系数是4就够了。但很多器件PLL要求VCO频率在某个范围内比如400MHz到800MHz那你不能在200MHz频率点直接让VCO停住而是要让VCO先跑到中段频率比如600MHz再分频三次得到200MHz。配置工具通常会自动算但理解这个机制很重要否则你换一颗器件PLL配置评估就会报“频率超出范围”或者“找不到合适的VCO频率”。PLL输出的时钟如果是要发给全芯片逻辑用的一般还需要再过一级BUFG才能真正到全局网络。很多工程软件会自动帮你插入这级缓冲但如果你的工程里手动例化了PLL又没合理设置时钟资源属性就可能会出现“PLL输出时钟没有到全局布线资源上”这种隐蔽问题表现为时序分析里局部路径偏斜特别大。所以看资源报告时不光要看PLL锁没锁上还要看它的输出到底走了哪一类时钟布线。2. 时钟方案怎么选不是越“高级”越好拿到一个项目需求外部时钟频率多少、需要产生几路内部时钟、每路时钟要用在哪里这些信息直接决定你选哪类资源。别看到一个“全局时钟网络”就觉得什么都往上放也别觉得PLL万能。合理的方案往往是把不同种类的资源组合起来用。2.1 从使用场景倒推资源选择我习惯把FPGA里的时钟需求分成四类每类对应一种默认资源主时钟也就是系统同步逻辑的节拍通常来自外部晶振或参考时钟频率比较高扇出非常大所有寄存器都用它。这种一定要走全局时钟网络。如果主时钟频率由PLL产生那PLL输出再配一级全局缓冲就是最常见的标准结构。局部功能模块的时钟比如某个接口模块内部用到的同步时钟只影响模块内几百个寄存器用一个区域时钟就够了。区域时钟延迟更短而且不占用宝贵的主时钟通路。高速源同步接口的采集时钟比如DDR接口或者高速ADC/DAC数据流带随路时钟这种时钟往往直接送到IO时钟入口让数据和时钟在IO寄存器处保持精确相位关系。把这种慢速使用的时钟绕进全局网络反而会增加采样不确定性。特殊用途的时钟比如调试时用的触发器信号、外部输入中断脉冲扇出不大对偏斜不那么敏感如果直接拿普通互连资源驱动也不算致命。但需要注意任何作为“异步事件”的信号本来就不应该出现在时钟路径上更合适的是当成普通数据做同步。为方便对比我把常见资源、覆盖范围和典型用途整理成了下面这张表资源类型覆盖范围延迟与偏斜特点最典型用途全局时钟网络整个芯片延迟固定偏斜极低系统主时钟、全局复位区域时钟单个或相邻时钟区域延迟短局部偏斜低局部模块时钟IO时钟IO寄存器周边与数据引脚时序紧密对齐DDR接口、源同步采集PLL/MMCM频率变换与相位调整锁定后输出稳定倍频、分频、相移这里有一点要注意区域时钟和IO时钟的可用数量、连接关系与具体器件强相关同一个工程换器件型号时钟方案很可能要重新审核。2.2 时钟树规划的提前量画板前就要想时钟方案的规划最忌讳在PCB画完、甚至贴片完才做。外部时钟信号进入FPGA用的是专用时钟引脚不同位置的引脚对应到不同的全局时钟入口、区域时钟区域。如果你把外部时钟随便接了一个普通引脚后期就算内部逻辑想给它接BUFG也很难布线因为你绕不开管脚本身的位置约束。我自己吃过一次亏。某个小项目里原理图把外部时钟接到了一个全能IO功能是可以的但布局布线跑到全局时钟网络延迟偏大区域时钟资源又进不去。当时改了一版PCB多花了两周。所以现在做方案我一定会提前确认外部时钟引脚是否可直达全局缓冲差分时钟是否走了专用差分对复位按键信号要不要上全局网络这些在FPGA管脚分配阶段就要定好。另一个提前量是PLL输入和输出的数量。FPGA的时钟管理模块不是很多每个PLL能接的参考时钟也有限。如果一个模块接了多个PLL而每个PLL又都在做不同频率变换那么规划时就要核对功耗和资源余量。尤其是多路视频或通信项目动辄需要五六组内部时钟可能要做PLL级联先用一路主PLL产生基频再分配给第二级PLL或分频器。2.3 别轻易使用门控时钟写RTL时很容易图省事把某个使能信号和时钟做一个与门得到一个“只在使能时跳变的时钟”然后把门控时钟接到寄存器上。这种糊口式写法在仿真阶段完全没问题甚至看起来功耗还低因为不工作时时钟不翻转。但在FPGA实现阶段门控时钟会带来两类非常麻烦的问题。第一是毛刺风险。与门的两个输入如果存在竞争冒险输出时钟上可能蹦出窄脉冲如果这个窄脉冲正好被寄存器采到数据就可能写坏。第二是静时序分析困难。工具默认把时钟当作周期信号来推导约束你的门控时钟让时序分析器很难定义时钟边沿要么你得写复杂的约束要么干脆标记成虚假路径收敛质量大打折扣。推荐的做法是保留时钟一直翻转用时钟使能信号配合寄存器。比如一个计数器只有在数据有效的周期才计数就让使能信号进到时钟域内同步后再控制计数器而不是在时钟路径上插入门控。这几乎可以省掉一大类“偶发数据错误”。除非你有极强的低功耗设计需求且对毛刺做过专门分析否则尽量不要直接门控时钟。3. 实操把时钟资源真正用起来讲完理论说说在工程里怎么把时钟资源配置出来。我以一个真实的工程片段为例外部提供50MHz晶振系统逻辑需要200MHz的主时钟另外一路接口需要75MHz参考时钟还有一路外部ADC需要50MHz、相位滞后90度的采样时钟。3.1 从50MHz晶振到三组输出时钟先算频率方案。主流FPGA里配置PLL时输入50MHz要得到200MHz单纯倍频系数是4。但许多PLL的VCO范围有下限比如最低400MHz那VCO就不能直接锁在200MHz点。这时要让VCO在600MHz附近工作再通过分频器得到200MHz。75MHz可以由600MHz除以8得到50MHz带90度相移则是在600MHz分频配相移后得到。整个配置界面里会要求你填入输入时钟、输出时钟频率、相移数值工具自动给出M、D、O乘数分频关系。实操时我一般会先把VCO频率挑在器件标称范围的中段附近这样留有余量对温度变化更稳。配置完成后工具会生成一个时钟模块的IP核接口大致长这样clk_gen u_clk_gen ( .clk_in (clk_in_50m), .clk_out_200m (clk_200m), .clk_out_75m (clk_75m), .clk_out_50m_90(clk_50m_90), .locked (pll_locked) );这里clk_in_50m是从专用时钟引脚进来的外部时钟信号locked是PLL锁定指示复位逻辑一定要等它拉高后再释放不然早期时钟还没稳定寄存器可能被写入未知状态。有一点值得提醒如果只是借用某个厂商工程向导生成的IP接口名可能略有差异但关键信号基本都长这样。真正需要关心的是例化后综合的资源报告看你生成了几个PLL、几个全局缓冲。如果工具报了“全局时钟缓冲不足”往往不是真的不够用而是你把这个IP例化了很多份每份都带一个全局缓冲。3.2 时钟约束书写让时序分析器知道你的时钟长什么样有了时钟网络还要在时序约束里把你“希望工具认为的时钟”告诉它。常见工具支持SDC约束最基础的就是创建时钟。以外部100MHz输入为例create_clock -name sys_clk -period 10.000 [get_ports clk_in_100m]period 10.000表示时钟周期10纳秒也就是100MHz。这条约束告诉时序分析器从clk_in_100m引脚进来的信号是系统主时钟周期10ns。PLL内部生成的时钟工具会根据IP配置自动往后推衍不需要你手动再定义只要时钟源被正确约束了就行。实际项目里我通常还会跟上时钟不确定度约束set_clock_uncertainty -setup 0.150 -hold 0.050 [get_clocks sys_clk]setup不确定度设得比hold大是因为它要包含时钟抖动、板级噪声、PLL相位噪声等影响而hold相对更偏静态。不确定度设置需要根据硬件质量来别拍脑袋设太大余量太大容易把自己逼进“时序永远收敛不了”的死胡同设太小又会让工具盲乐观板子上跑起来就可能翻车。另外要提到跨时钟域约束。如果你有多个主时钟而且彼此之间没有确定相位关系就要用时钟分组把它们设为“异步”的set_clock_groups -asynchronous \ -group [get_clocks sys_clk] \ -group [get_clocks pcie_refclk]这段约束的意思是两个时钟域之间的路径时序分析器不需要检查因为设计里已经有跨时钟域同步策略了。没有这条约束工具默认去约束两个异步时钟之间的路径会产生大量假违例。3.3 手动插入BUFG的时机与方法多数情况下工具会在综合和布局布线阶段自动插入全局缓冲不需要你手动干预。但有几类场景需要手动指定比如复位的同步释放逻辑你想确保复位释放沿在全芯片内基本同时到达又比如某个内部生成的时钟你想强制它上全局网络再比如从GTP/Serdes恢复出来的时钟跨时钟域之前希望先走一遍全局缓冲整形。手动指定的一般方法是设置网络属性。以复位网络为例可以在综合工具里把复位网络指定为全局缓冲set_property CLOCK_BUFFER_TYPE BUFG [get_nets rst_sync]注意这里的属性名只是示意不同工具可能叫法不同但思路一致命名一个高扇出的网把它分配到全局时钟缓冲器。手动指定时我会先查一下网络扇出如果扇出不到几百个触发器根本没必要上BUFG用了反而浪费全局时钟资源。某些低端FPGA上全局缓冲数量少一个核心模块用一个别每个复位都搞一个全局缓冲否则后续工程扩展时资源会卡脖子。4. 时钟质量与时序收敛的关系时钟资源选好、配好之后接下来的问题就是怎么去衡量这套时钟系统到底好不好。很多工程师觉得PLL能锁定、输出频率够了就行直到时序分析报告里出现“clock skew”特别大的路径才醒悟。时序收敛这件事本质上就是和时钟的偏斜、抖动、延迟赛跑。4.1 偏斜、抖动和延迟一个一个算明白延迟latency好理解时钟从源头到寄存器时钟端的传输时间。偏斜skew是同一个时钟到达两个不同寄存器时钟端的时间差。抖动jitter是时钟边沿在时间轴上的不确定性PLL的抖动通常比外部晶振直接进来要小但也不是零。假设一条数据路径时钟周期10ns寄存器输出延迟Tco是2ns组合逻辑延迟5ns建立时间0.5ns。如果不考虑偏斜时序余量是10-2-5-0.5等于2.5ns还挺宽裕。但如果这时时钟偏斜是1.5ns余量直接被吃掉大半变成1ns偏斜到2.5ns余量只剩0超过2.5ns时序就violate了。这就是为什么全局时钟网络如此重要。普通逻辑绕线传时钟不同位置的走线长度差异可能是3纳秒级别这足以让一个本可以收时序的设计彻底崩溃。而全局时钟网络把偏斜压到几百皮秒反而让数据路径有了足够的设计空间。jitter的影响则体现在时序余量计算里通常归到时钟不确定度里。一个非常脏的参考时钟哪怕FPGA内部PLL尝试去过滤输出jitter也可能达到几百个皮秒如果通信接口本来就只有0.5ns的建立余量那必然是偶发错误不断。这种问题单纯加大约束余量没有意义要从源头换晶振或者加一个干净的时钟缓冲器。4.2 同源时钟与异步时钟域先识别再处理做多时钟设计时最大的坑不是“有多个时钟”而是“不知道哪些时钟是相关的”。两个时钟如果来自同一个PLL它们的相位关系是确定的工具可以推导出它们之间的路径时序这种叫同步相关时钟。比如PLL输出的200MHz和75MHz如果都锁定在同一个VCO上它们边沿之间是有固定相位关系的。跨时钟域时可以直接用打拍同步来处理。但如果是两个完全独立的外部时钟源比如一路来自板载晶振另一路来自PCIe参考时钟源二者之间频率和相位都没有确定性关系这两个时钟域之间就必须用异步FIFO、握手同步再加回环测试等手段。这类时钟之间要记得在约束里做异步分组否则时序分析器会去分析一堆不存在的路径产生好几千条假违例你修三天三夜也修不完。我遇到过最隐蔽的情况设计里两个PLL的输入来自同一个50MHz晶振但由于每个PLL内部VCO相噪特性不同两个PLL输出之间并不严格同相它们不是完全同步的时钟。从名字上看一个叫clk_pll_a一个叫clk_pll_b低级工程师可能想当然认为它们相关。处理这类问题我会直接打开时钟树报告看两个时钟的根节点是否同源、是否经过同一个PLL共用的VCO而不是看名字长不长得像。4.3 复位与时钟的配合细节时钟资源的问题是“时钟本身”但复位和时钟的配合也经常出幺蛾子。最常见的错误是把复位信号直接接到寄存器异步复位端而复位释放时刻没有和时钟对齐。举个例子PLL锁定后locked信号拉高你把这个信号直接拿来作为寄存器异步复位释放时候看起来没问题但locked信号本身既不是同步信号也未必和主时钟边沿对齐。如果恰好某个寄存器在复位释放的瞬间时钟边沿到来它可能被写入一个半稳定状态后面所有逻辑全乱。解决方式是用同步复位释放电路reg rst_n_meta, rst_n_sync; always (posedge clk_200m or negedge global_rst_n) begin if (!global_rst_n) begin rst_n_meta 1b0; rst_n_sync 1b0; end else begin rst_n_meta pll_locked; rst_n_sync rst_n_meta; end end assign rst_n rst_n_sync;这样就把PLL锁定信号同步到主时钟域再释放复位。这类电路看起来简单但很多人不做导致上板后偶发启动失败。经验是任何标记为“异步复位同步释放”的电路都要放在主时钟域里仔细验证并且不要让复位信号走普通逻辑资源到处漂必要时加一级BUFG。5. 常见问题排查时钟相关的坑我基本都踩过最后聊几个我在实际项目里反复见过的问题每个都伴随过不少调试工时。整理成可检索的形式希望对你有直接帮助。5.1 “BUFG不够用”到底该怎么解报错信息可能是“全局时钟缓冲资源不足”或者“无法分配时钟网络资源”。遇到这个先别急着删PLL或换器件我通常按以下顺序排查。先检查是不是同一个时钟被例化成了多个网络尤其是多个PLL输出同一频率同一相位时工具可能给它们各分配了一个全局缓冲。正确的做法是让它们合并或者主动指定其中一个作为主时钟网络其他模块直接借用。再检查是不是复位网络占了太多BUFG很多组件各自综合一套复位同步逻辑每套都会尝试用BUFG。可以把所有子模块的复位逻辑收敛到一个总复位模块全系统共用一条全局复位网络。最后检查有没有超大扇出的低优先级信号也被自动全局化了可以通过综合选项里把全局缓冲插入阈值调大让工具只在扇出超过一定数量时才使用全局缓冲。如果这三步都做完还缺缓冲那才需要考虑改用区域时钟把不影响全局时序的局部时钟挪到区域时钟网络。大部分情况下“不够用”不是真不够用而是资源分配不合理。5.2 PLL锁不住或输出时钟不稳PLL锁定失败首先要确认参考输入时钟确实到了PLL引脚。示波器钩不到FPGA内部就看PLL的配置寄存器有没有读到locked信号拉高。如果locked一直拉不高看硬件输入晶振是否起振、电平幅度是否满足VMIN/VMAX、是不是误把差分输入接成了单端。再看配置输入频率是否在PLL允许范围里输出频率计算是否超出了VCO范围。有一种比较隐蔽的原因PLL的输入参考时钟本身不稳定。比如时钟信号经过了普通IO引脚再绕到PLL或者前端有没做好的分频器导致时钟边沿抖动特别大PLL反复处于锁定和失锁状态。排查时可以用一个已知干净的外部信号做替换验证。如果换了干净时钟就能锁定问题就在前端硬件而不是PLL配置。输出时钟不稳还有一种表现是锁定时序报告里显示PLL输出jitter很大。这个要么是参考源不干净要么是配置里选的带宽模式不对。低带宽模式对输入jitter过滤更好但锁定时间更长高带宽模式锁定快但对输入噪声敏感。温度变化剧烈的环境中调试优先考虑低带宽模式。5.3 时序报告里偏斜大得离谱布局布线后如果某一组时序路径slack很紧打开时序报告看到clock skew那一列数值特别夸张多半是时钟路径走了“歪路”。常见原因有时钟源没进专用时钟引脚PLL输出没有接到全局缓冲局部逻辑处于一个离全局时钟入口很远的区域时钟绕了大半个芯片才到达。修复思路就是回到第2章讲的资源规划第一条是确认触发器阵列都放在离各自时钟源较近的时钟区域不要让PLL在芯片左下角而一百个关键触发器在右上角。第二条是确认路径上的时钟有没有真正使用全局网络可以打开时钟布线报告看一下时钟网络用的布线类型。第三条就是加约束在综合阶段把关键时钟明确指定到某个全局缓冲不要完全依赖工具自动选择。5.4 现场避坑清单速查现象可能原因优先排查动作时钟上出现毛刺门控时钟或组合逻辑时钟改成时钟使能禁止组合逻辑输出直接驱动时钟端仿真通过上电偶发错乱复位释放太早locked未同步增加异步复位同步释放电路等locked稳定后再释放BUFG资源不足高扇出信号各自上全局缓冲合并同频同相时钟复位网络收敛到一条全局网络PLL锁定失败输入频率范围越界或参考时钟抖动核对输入频率可达性换干净时钟源时序报告出现大量违例时钟域两个异步时钟域没做时钟分组增加set_clock_groups -asynchronous约束温度一高就出错时钟不确定度余量过小增加setup/hold不确定度检查晶振温度漂移这份清单不是万能的但能覆盖多数时钟资源相关的低频但麻烦的故障。排查时钟问题最重要的是保持“先看时钟再看逻辑”的顺序。一个信号出问题如果我确认它所在时钟域和时钟树质量没问题那多半是逻辑问题如果时钟树本身就偏斜大、抖动高那再怎么改逻辑都只是打补丁。最后自留地。我做时钟资源规划多年最大的体会是“规划永远比修补省钱”。画板之前花一天把时钟引脚、PLL资源、全局缓冲数量核对清楚比后期为了把一个时钟引到某个区域而重新布板要省几周时间。另一个习惯是每次改动时钟树或PLL配置后我不只跑增量实现而是从头跑一遍严格完整的时序分析因为时钟改动会影响全芯片的每一个寄存器的时序关系。希望这篇能帮你少踩几个坑把调试精力留给真正值得调的功能逻辑。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表