ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

FPGA时序分析:零周期检查与set_data_check实战指南

FPGA时序分析:零周期检查与set_data_check实战指南 1. 从一个真实翻车案例说起为什么零周期检查让人头疼去年帮一个朋友看他的FPGA时序报告他做的是一个高速ADC数据采集项目DDR接口跑在800Mbps。综合实现都过了时序报告里setup和hold的WNS都是正的看起来一切正常。结果板子回来跑起来数据误码率居高不下偶尔还会出现整段数据错位。他反复检查了时钟约束、IO约束甚至换了PCB走线问题依旧。后来我让他把时序报告里所有路径都翻出来特别是那些没有出现在常规setup/hold分析里的路径。果然问题出在ADC数据和随路时钟之间的skew上——这两组信号在FPGA内部走的是不同的路径到达采样寄存器的延迟差异超过了半个数据周期。常规的setup/hold分析只检查时钟沿和数据到达时间的关系但这里数据是相对于另一个数据信号来采样的不是相对于时钟沿。这就是典型的Data to Data Check场景而它对应的约束周期是零周期。这个案例让我意识到很多工程师对STA的理解停留在setup和hold两个维度一旦遇到数据对数据的检查就懵了。零周期检查在高速接口、源同步协议、DDR类接口中非常常见但它的分析逻辑和常规时序检查有本质区别。这篇文章就把我这些年踩过的坑、总结的方法从头到尾捋一遍。2. 零周期检查的本质它到底在检查什么2.1 常规setup/hold和data to data check的根本差异先把这个概念说清楚。常规的setup检查本质上是问数据到达寄存器D端的时间是否比时钟沿提前了至少setup时间hold检查则是问数据在时钟沿之后是否还稳定了至少hold时间这两个检查的参考点都是时钟沿。但Data to Data Check不一样。它的参考点不是时钟沿而是另一个数据信号。换句话说它检查的是两个数据信号之间的到达时间关系。比如信号A是数据信号B是随路时钟或者选通信号那么Data to Data Check要保证的是A的跳变相对于B的跳变满足一定的建立和保持关系。为什么叫“零周期”因为在STA工具里当你用set_data_check命令去约束两个数据端口之间的关系时默认的检查周期是0。这个0不是说时间窗口是0而是说这两个信号之间没有周期性的时钟关系它们是在同一个时刻窗口内被比较的。工具不会自动推导出它们之间的周期关系需要你手动指定一个检查窗口。2.2 为什么工具默认不分析这类路径常规STA引擎的时序图是基于时钟树的。工具会先找到所有时钟然后沿着时钟路径传播计算每个寄存器的时钟到达时间再计算数据路径的延迟最后做setup和hold的比对。这个流程的前提是所有时序检查都挂靠在某个时钟上。但Data to Data Check的路径不挂靠任何时钟。比如一个源同步接口数据和选通信号都是从同一个源发出的它们之间没有经过任何时钟同步逻辑。工具在默认情况下根本不知道这两个信号之间需要做检查因为它们的时序关系不是由时钟定义的而是由协议定义的。这就导致一个很危险的情况工具不报错不代表没有问题。很多工程师看到时序报告全绿就以为万事大吉实际上那些没有被约束覆盖的路径工具压根就没分析。零周期检查就是典型的“你不约束工具就不管”的场景。2.3 零周期检查的典型应用场景我整理了一下零周期检查主要出现在这几类场景里源同步接口数据和随路时钟/选通信号同源接收端用选通信号去采样数据。比如RGMII、源同步DDR、一些自定义的高速并行接口。DDR类接口的DQS与DQ之间DQS是数据选通DQ是数据它们之间的时序关系需要用data check来约束。多路数据之间的偏斜检查比如总线上的多位数据需要保证它们之间的偏斜不超过某个值。异步接口的握手信号请求和应答信号之间的时序关系有时也需要用data check来约束。这些场景的共同特点是信号之间的时序关系不是由时钟周期定义的而是由协议或接口规范定义的。工具无法自动推导必须手动约束。3. set_data_check命令的实战用法3.1 命令语法与参数详解set_data_check是SDC标准命令主流STA工具都支持。基本语法是这样的set_data_check -from 相关信号 -to 被检查信号 [-setup 值] [-hold 值] [-clock 时钟]几个关键参数-from参考信号也就是“相对于谁”来做检查。-to被检查信号也就是“检查谁”。-setup建立检查值默认是0。-hold保持检查值默认是0。-clock可选指定关联的时钟。如果不指定工具会尝试自动推断。这里有个容易混淆的地方-from和-to的方向。我的记忆方法是-to是你关心的信号-from是它的参考。比如你要检查数据DQ相对于DQS的建立时间那么-from是DQS-to是DQ。3.2 一个完整的约束示例假设我们有一个源同步接口数据总线data[7:0]和选通信号strobe。接口规范要求数据在strobe上升沿之前至少0.5ns稳定在上升沿之后至少0.3ns保持。约束写法# 先定义相关时钟如果有 create_clock -name clk -period 10 [get_ports clk] # 设置data check set_data_check -from [get_ports strobe] -to [get_ports data*] -setup 0.5 -hold 0.3注意这里-to用了通配符data*可以一次性约束多位数据。工具会对每一位数据分别做检查。如果strobe是差分信号或者需要指定沿可以这样写set_data_check -from [get_ports strobe] -to [get_ports data*] -setup 0.5 -hold 0.3 -clock clk加上-clock后工具会把检查关联到指定时钟检查窗口会基于这个时钟的沿来计算。但要注意这里的时钟只是用来确定检查的时间窗口不是用来做常规setup/hold分析的。3.3 参数值的计算与选择setup和hold的值怎么定这不是拍脑袋决定的要从接口规范或者器件手册里推导。以DDR接口为例假设DDR颗粒的DQS和DQ之间的skew要求是DQ相对于DQS的建立时间至少0.25个UI保持时间至少0.25个UI。如果UI是1.25ns800Mbps那么setup和hold都是0.3125ns。但实际约束时不能直接用这个值还要考虑PCB走线延迟、FPGA内部延迟、时钟不确定性等因素。我的经验是先按规范值约束跑一遍时序看余量有多少再根据余量调整。如果余量很大可以适当放宽约束如果余量为负就要优化布局布线或者调整约束值。这里有个坑setup和hold的值不能随便设成0。设成0意味着你要求两个信号完全对齐这在物理上几乎不可能实现。正确的做法是根据接口规范设置合理的最小值。4. 零周期检查的时序分析原理4.1 工具内部是如何计算零周期路径的STA工具处理data check路径时流程和常规路径不同。常规路径是时钟源→时钟网络→寄存器时钟端→数据路径→寄存器数据端。data check路径是参考信号端口→参考信号路径→检查点被检查信号端口→被检查信号路径→检查点。工具会分别计算两条路径的延迟然后比较它们的到达时间差再和setup/hold值做比对。因为没有时钟周期作为参考工具实际上是在同一个时间窗口内比较两个信号的到达时间。具体来说工具会做这样的计算参考信号到达时间 参考信号路径延迟 参考信号源延迟被检查信号到达时间 被检查信号路径延迟 被检查信号源延迟建立检查被检查信号到达时间 - 参考信号到达时间 ≥ setup保持检查参考信号到达时间 - 被检查信号到达时间 ≥ hold注意这里的符号方向。建立检查要求被检查信号不能太晚到保持检查要求被检查信号不能太早到。两个检查合起来就是要求被检查信号在一个窗口内到达。4.2 零周期路径的时序图解读在时序报告里data check路径通常单独列出来不会混在常规setup/hold报告里。报告会显示参考信号路径的延迟明细被检查信号路径的延迟明细两者的到达时间差和setup/hold值的比对结果slack值我习惯先看slack如果是负的再去看是哪条路径延迟太大。常见的原因是参考信号走了全局时钟网络延迟很小被检查信号走了普通布线延迟很大。或者反过来。4.3 零周期检查与常规检查的交互一个信号可能同时参与常规setup/hold检查和data check。比如一个数据信号它既被时钟采样又需要相对于另一个数据信号做检查。这种情况下工具会分别做两套检查互不影响。但要注意约束之间可能会冲突。比如你给一个信号同时设了常规的input delay和data check工具可能会报冲突。这时候需要仔细分析看哪个约束是真正需要的。我的经验是如果信号是源同步接口的一部分通常只需要data check不需要常规input delay。如果信号是系统同步接口才需要input delay。5. 实操中常见的坑与排查方法5.1 约束写了但工具不分析这是最常见的问题。你写了set_data_check但时序报告里找不到相关路径。原因通常有几个信号名写错了get_ports没抓到正确的端口。用get_ports -regexp或者先report_ports确认一下。信号被优化掉了综合工具把相关逻辑优化了端口不存在了。检查综合报告看端口是否保留。约束顺序不对set_data_check必须在时钟定义之后。如果时钟还没定义工具可能无法正确关联。工具版本不支持老版本工具可能不支持某些参数。查一下工具文档。排查方法先用report_data_check命令如果工具支持看约束是否生效。如果没有这个命令可以用report_timing -to 被检查信号看路径是否被分析。5.2 slack为负但找不到原因slack为负说明时序不满足。常见原因和解决方法问题现象可能原因解决方法参考信号延迟太小参考信号走了全局时钟网络改用普通布线或调整约束被检查信号延迟太大被检查信号走了长路径优化布局加流水线setup/hold值设得太紧约束值超过了实际能力重新计算约束值时钟不确定性太大时钟抖动或偏斜大优化时钟树或放宽约束我遇到过一次slack负了0.8ns查了半天发现是参考信号被工具自动放到了全局时钟网络上延迟只有0.1ns而被检查信号走了普通布线延迟0.9ns。后来把参考信号也改成普通布线slack就正了。5.3 多位数据之间的偏斜检查有时候需要检查多位数据之间的偏斜比如data[7:0]之间任意两位的偏斜不能超过0.2ns。这种检查用set_data_check不太好写因为需要两两组合。我的做法是用set_max_skew或者set_data_check配合通配符。有些工具支持set_max_skew命令可以直接约束一组信号之间的最大偏斜。如果不支持就只能手动写多条约束或者用脚本生成。# 方法一用set_max_skew如果工具支持 set_max_skew -from [get_ports data*] -to [get_ports data*] 0.2 # 方法二手动写两两组合不推荐太繁琐 # 用脚本生成约束 foreach i {0 1 2 3 4 5 6 7} { foreach j {0 1 2 3 4 5 6 7} { if {$i ! $j} { set_data_check -from [get_ports data[$i]] -to [get_ports data[$j]] -setup 0.2 } } }5.4 跨时钟域的data check如果参考信号和被检查信号属于不同的时钟域data check会更复杂。工具需要知道用哪个时钟来做检查。这时候-clock参数就很重要。我的建议是尽量让参考信号和被检查信号在同一个时钟域。如果实在跨时钟域要仔细分析时钟关系确保约束值合理。跨时钟域的data check很容易出现假报错或漏报。6. 零周期检查的优化策略6.1 布局布线的优化方向零周期检查的slack主要取决于两条路径的延迟差。优化方向有两个减小参考信号延迟或者增大被检查信号延迟如果是hold问题则反过来。具体手段手动布局把参考信号和被检查信号的源寄存器放在相邻位置减少布线延迟差。复制寄存器如果参考信号驱动多个被检查信号可以考虑复制参考信号寄存器让每个被检查信号都有独立的参考源减少偏斜。调整布线层让两条路径走相同的布线层减少层间差异。加延迟单元如果被检查信号到得太早可以加缓冲器增加延迟。6.2 约束的合理设置约束值不是越紧越好。设得太紧工具会花大量时间优化甚至优化不出来设得太松又起不到检查作用。我的经验是先按接口规范设置约束值跑一遍时序看余量。如果余量在20%以上可以适当收紧约束给实际板级留更多余量。如果余量为负先优化布局布线再考虑放宽约束。另外setup和hold的值要分开考虑。有些接口对建立时间要求高对保持时间要求低反之亦然。不要一刀切。6.3 与常规时序约束的协同零周期检查不是孤立的。它和常规setup/hold检查、input/output delay约束、时钟约束都有关系。我的做法是先定义所有时钟。再设置常规的input/output delay。然后设置data check约束。最后跑时序看是否有冲突。如果发现冲突优先保证data check约束因为它是接口协议的直接体现。常规约束可以适当放宽。7. 几个真实案例的复盘7.1 案例一RGMII接口的data checkRGMII接口是典型的源同步接口TXC和TXD之间需要做data check。约束写法set_data_check -from [get_ports TXC] -to [get_ports TXD*] -setup 0.5 -hold 0.5这个案例的坑在于TXC是时钟信号工具默认会把它当时钟处理而不是数据信号。所以需要先用set_false_path或者set_clock_groups把TXC从时钟分析里排除再用data check约束。7.2 案例二DDR DQS与DQ的检查DDR接口的DQS和DQ之间需要做data check。约束写法set_data_check -from [get_ports DQS*] -to [get_ports DQ*] -setup 0.25 -hold 0.25这个案例的坑在于DQS是差分信号需要分别约束P端和N端。而且DQS的沿选择也很重要上升沿和下降沿的检查值可能不同。7.3 案例三多路数据偏斜检查一个自定义并行接口8位数据之间的偏斜不能超过0.15ns。约束写法set_max_skew -from [get_ports data*] -to [get_ports data*] 0.15这个案例的坑在于set_max_skew不是所有工具都支持。如果不支持只能用data check逐对约束非常繁琐。后来我写了个Tcl脚本自动生成约束效率高很多。8. 工具支持与版本差异不同STA工具对data check的支持程度不同。主流工具都支持set_data_check但参数和报告格式有差异。工具命令报告命令备注PrimeTimeset_data_checkreport_timing -to支持最完整Tempusset_data_checkreport_timing参数略有不同Vivadoset_data_checkreport_timing需要先set_false_pathQuartusset_data_checkreport_timing支持有限我的建议是先查工具文档确认支持的命令和参数。如果不确定先用一个小设计测试一下看约束是否生效。9. 写在最后的一些个人体会零周期检查这个事说难不难说简单也不简单。核心就一句话工具不会自动分析数据对数据的路径你必须手动约束。但实际操作中约束怎么写、值怎么定、slack怎么调每一步都有坑。我自己的习惯是拿到一个新接口先看协议规范把时序要求列出来然后写约束跑时序最后根据报告调整。整个过程可能要迭代好几轮。但一旦约束写对了后面就省心了。另外不要迷信工具的默认行为。工具不报错不代表没有问题。特别是源同步接口和DDR类接口一定要手动加data check约束。我见过太多项目因为漏了data check板子回来才发现问题那时候改成本就高了。最后分享一个小技巧如果slack一直调不正可以试试把参考信号和被检查信号都改成普通布线不要走全局时钟网络。全局时钟网络延迟小但偏斜也小普通布线延迟大但可控。有时候换个思路问题就解决了。
返回列表