ARTICLE DETAIL

资讯详情

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

sgdc约束文件编写实战:提升SpyGlass CDC检查准确率的关键方法

sgdc约束文件编写实战:提升SpyGlass CDC检查准确率的关键方法 刚接触SpyGlass CDC检查的同学十有八九会遇到这个场景拿到的RTL本身是精心设计过的每个异步接口都加了同步器可一跑spyglass cdc界面里密密麻麻全是violation点开detail一看很多时候工具根本没识别出你设想的时钟关系甚至把已经同步过的信号当成普通数据跨域来报。SpyGlass确实是个很严格的工具而它严格的前提是它根本不知道你的设计意图。它不认识哪根时钟是主时钟、哪根是分频得到的也不清楚某个寄存器复位是异步复位还是同步复位。它唯一能依赖的就是你给它的sgdc约束文件。sgdcSpyGlass Design Constraints这个文件可以说是做CDC检查之前比RTL本身更早要动手写的东西。如果你还没体会到它的作用那说明之前的CDC检查大概率还没把问题逼到真正需要深挖的阶段。这篇文章我会从实际项目中总结的经验出发讲清楚sgdc怎么组织、怎么用以及拿到一屏报错以后如何反推约束文件什么地方写得不全或者写得不对。适合前端设计工程师、验证工程师还有被CDC问题折腾得头大的集成人员一起看看。1. CDC检查的成败一半取决于sgdc约束怎么写1.1 sgdc与SDC的差别不是换个名字那么简单很多从普通时序约束转过来的人一开始会把sgdc和综合用的SDC混淆。两者从作用上说确实有相通之处但差异非常明显。SDC是给综合工具用的它描述的是某个时钟的频率、某个约束路径的时序余量、输入输出的延迟信息本质上回答的是“我这个电路的时序跑不跑得过”这个问题。而sgdc更偏向描述设计者的意图它回答的是“哪些时钟原本是异步的”“哪些信号本质上和哪个时钟同源”“哪条路径不需要做跨时钟域检查”。SDC描述的是物理和时序事实sgdc描述的是架构和同步策略。这个区别在SpyGlass CDC检查中的作用尤其明显。比如你在DC综合里定义了create_clock对某根时钟管脚推算频率SpyGlass虽然也能读入部分SDC信息但它更希望你在sgdc里把“哪个寄存器是同步器”这种结构信息显式表达出来。一个完整的sgdc至少需要包含时钟定义、复位定义、异步接口的合理性声明、不许检查的路径以及某些特殊管脚的抽象行为描述。你可以把sgdc想象成给一个极其较真的检查员提前交底哪些地方是故意这么设计的哪些东西不用查哪些东西只是样子上与普通跨域相似但实际是安全的。没有这份交底SpyGlass只会按最严格的方式去报这个严格程度远超任何一个工程师手动能把控的检查范围。1.2 不写sgdc直接跑CDC你会看到什么我第一次跑SpyGlass时其实没充分意识到sgdc的重要性直接用默认工程跑了一遍。结果生成的violation数量多的吓人几千条而且大量报错集中在同一个区域看起来像时钟树套了十层环。把detail打开发现很多violation的关键原因是“unconstrained clock”或者“no valid clock information for pin”。这种现象的本质是SpyGlass在没有约束文件的情况下会把所有它怀疑是时钟网络的信号都按自己的猜测去传播遇到两个不知道频率的时钟网络直接跨域那肯定全部列出来。因为工具不知道谁同源、谁异步、谁经过同步处理检查自然没底线。那次之后我的工作习惯就改了任何新项目或新单元的CDC检查第一件事不是编译RTL而是把时钟拓扑图、复位架构图、异步接口清单拿到手先写第一版sgdc再启动SpyGlass。这个顺序反了后面所有分析都会建立在大量冗余噪声之上时间和精力浪费得非常不值。1.3 什么样的人最需要认真掌握sgdc如果你只是用SpyGlass跑一下回归、大概看看有没有明显的问题那sgdc写不写也许一时看不出差别。但如果你想在cdc检查里真正找到有价值的bug或者需要在签核时对一长串violation逐一作出裁决那sgdc的准确度就是检查质量的底线。具体来说三类人最需要重视sgdc的编写质量。第一类是SoC集成工程师他们面对的IP时钟来源五花八门外部PLL、内部DLL、分频器、门控时钟不一而足稍有遗漏就会在后续检查中引发连环误报。第二类是前端设计工程师他们最清楚某个同步器的结构到底是什么样的——双寄存器同步、三寄存器同步、还是握手加格雷码如果不把这些信息写进约束文件SpyGlass就只能看到两个寄存器串在一起却不知道那是刻意设计的同步结构。第三类是验证工程师尤其是专注CDC验证的他们需要根据sgdc的内容去批量评估报错如果sgdc本身不准确那评估工作就是在垃圾数据上做判断。对于第三种场景我个人还有个体会sgdc并不仅仅是给SpyGlass用的它同时也是团队内部沟通同步方案的重要载体。它把设计者对异步接口的理解以机器可读的格式沉淀下来这对后续其他工具、其他项目的复用都很有价值。2. sgdc文件的基础构成从时钟定义到异步断点2.1 ast_clock先把时钟描述清楚sgdc里最基础的命令就是时钟定义不同版本SpyGlass支持的关键字会有差异但总的方向是一致且稳定的。新版本里常见的是ast_clock系列命令老版本里可能用set_clock或者define_clock不管哪种核心要描述的都是时钟的名字、频率或周期、占空比、所属域、以及这个时钟在模块中被驱动的管脚或网络名。我的习惯是先画一张手写时钟拓扑把每个时钟的源头是谁、分频系数是多少、经过了哪些时钟门控都标清楚。然后按这张图写约束先写最顶层的primary clock再写由它产生的衍生时钟。严格来说SpyGlass对于分频时钟、门控时钟有自己的自动推断能力如果你不写工具也能猜出来一部分但这种自动推断在复杂的时钟逻辑面前经常猜错尤其是多级分频和动态门控混在一起的情况手动定义能省掉后面一大轮排查。举个实际例子ast_clock -clk clk_a -period 10 -edge {0 5} -domain d1 -group g1 -module soc_top -method func ast_clock -clk clk_b -period 5 -edge {0 2.5} -domain d2 -group g2 -module soc_top -method func这里-period单位是ns-edge写的是时钟跳变沿在周期内的绝对时间点-domain指定这个时钟属于哪个时钟域-group用来定义同源时钟组。同源时钟组这个概念非常关键因为SpyGlass默认将不同名字的时钟视为异步时钟但如果你声明它们属于同一个group工具就知道它们之间其实是同步关系不必再彼此做CDC检查。2.2 ast_reset异步复位要交代清楚spyglass cdc还需要知道每个异步复位的具体行为尤其是复位信号的有效电平、是异步复位还是同步复位以及复位的异步断点如何被同步释放。这个信息直接影响到对寄存器复位端路径的分析。比如ast_reset -reset rst_n -value 0 -async -module soc_top这条命令告诉SpyGlassrst_n是一个低电平有效的异步复位信号。如果你不写-async工具可能会把复位树上的所有逻辑当普通数据路径来分析产生大量和复位相关的伪报。更麻烦的是异步复位释放那一瞬间如果与时钟跳变沿过于接近工具会报出潜在复位亚稳态问题但这个问题需要结合deassertion同步结构才能判断单纯从RTL结构上自动识别依赖条件很多只能靠约束辅助判断。另外复位信号常常不是单根而是一棵复位树。需要把复位树的根节点在sgdc里声明好有些项目甚至会在恢复/移除时间检查中专门用reset约束去约束复位树上的时钟关系。2.3 false_path与异步安全的真实断点光定义时钟和复位还不够CDC检查中最关键的一步是告诉SpyGlass哪些路径虽然跨越了时钟域但却是设计上已经被同步过的或者根本不需要检查。最常见的两条命令是false_path和abstract_port边界约束。false_path适合那种操作非常简单、物理上不可能有问题的路径。比如在测试模式下某些时钟被旁路掉或者某个信号只是一个静态配置pin经过同步后在一定时间窗口内保持不变那就可以直接约束掉。false_path -from clk_a -to clk_b -module soc_top false_path -from test_mode -to clk_b -module soc_topabstract_port则适合那种真正经过异步握手、双时钟异步FIFO、多bit握手加格雷码转换的接口。它通过声明接口的类型把黑盒或者连通单元内部的跨域行为抽象出来比单纯false_path更准确。一个简单例子abstract_port -port wr_req -clock clk_a -domain d1 -type handshake -method sync2 abstract_port -port rd_ack -clock clk_b -domain d2 -type handshake -method sync2这种方式告诉SpyGlass这个端口上的信号确实从一个时钟域跨越到了另一个时钟域但跨越的方式已经通过两边同步器结构处理中间的CDC路径不需要再作为问题报告。相对于一刀切false_pathabstract_port保留了接口方向信息后续约束检查也更容易维护。2.4 interface模块把同步器结构显式“表白”出来实际设计里同步器的形态并不总是经典的双寄存器接法。有的同步器会多打一拍有的中间还有电平转换器有的为了降低亚稳态失效率会把第一级寄存器复制成两份。这些结构一旦超出工具默认识别的模板SpyGlass就认不出来了会老老实实把它当作跨域路径报出来。一个更稳妥的实践是把设计里的同步器结构单独提取成一个module然后在sgdc里对这类module定义其接口行为。比如定义一个模块cdc_sync2内部是两级寄存器但在sgdc中你可以通过abstract_port描述该模块的输入输出端口让SpyGlass将整个模块当成一个功能透明的同步通道。这样即使内部结构超出了SpyGlass默认模板工具也不会产生误报。module cdc_sync2 ( input wire clk_dst, input wire rst_n, input wire data_in, output wire data_out );在sgdc里写上对齐的abstract_port声明把data_in视作异步输入、data_out视作本域输出工具就清楚这个模块的职责了。3. 实战案例sgdc解决常见跨时钟域报错的核心操作3.1 案例A握手信号的跨域一直被误报前一阵处理过一个小型视频处理芯片的CDC检查里面有一段跨时钟域逻辑写控制寄存器的clk_a域需要给clk_b域发一个启动脉冲标准的4-phase handshake结构。RTL里握手逻辑写得很规整但SpyGlass在默认约束下直接把req和ack都当作数据跨域路径报了。为什么会这样后来查了一下工具把req信号从clk_a域传到clk_b域时虽然在clk_b域内有同步器打拍但SpyGlass对同步器的识别依赖条件的某些前提没有被满足——同步器前的MUX选通逻辑被工具认定为组合逻辑环从而破坏了模板匹配。解决办法是在sgdc里将req、ack所在的接口声明为握手类型。我把两边的信号分别用abstract_port描述同时把控制寄存器相关路径定义成false_path最终这条握手通道的误报消失剩余真正需要关注的CDC violation也清晰了许多。值得一提的是如果接口特别多逐个abstract_port会显得比较繁琐。可以先在RTL中把这类接口统一成同一命名规则比如都叫xxx_req、xxx_ack然后通过sgdc的-auto结合脚本批量生成约束条目效率会高很多。3.2 案例B多bit总线信号跨域的灰码报错另一类高频报错是多bit总线信号跨域。比如一个计数器值要从clk_a域送往clk_b域设计上用的是格雷码转换。这本身是一个成熟的异步处理方式但SpyGlass如果不认识格雷码结构就会对多个bit之间的skew产生怀疑报出潜在的灰色路径问题。这类问题的sgdc处理比较复杂单纯false_path会让整个总线失去跨域检查意义。更合理的做法是将格雷码转换模块单独抽出然后在sgdc中用抽象接口来描述让工具对总线的每条bit都按照独立、已经过安全同步处理的单bit路径来理解。我在一个具体案例里是通过在两个域之间定义bus_sync抽象接口来解决的。SpyGlass对这个接口的每条bit可单独做CDC分析又不会因为bit间skew误报。在实际操作时我习惯在该模块内部保留一个断言逻辑实时监测多条bit是否在同一拍内跳变这样既安抚了工具硬件上也真的能捕获异常。3.3 一次完整的sgdc编写与SpyGlass运行流程为了更直观我把自己通常的运行流程写出来。这不是命令大全只是一个可以参考的操作顺序具体版本可能有细微差异但总体思路是通用的。第一步整理时钟拓扑。把设计里所有时钟信号的名字、频率、同源关系列成表格同时确认哪些是primary clock、哪些是generated clock、哪些时钟在某种模式下会被旁路。第二步整理复位结构。把所有异步复位信号、复位释放同步的结构、以及复位与时钟的关系标出来。第三步整理异步接口清单。逐条列出哪个模块的哪个信号从哪个时钟域到哪个时钟域、采用什么同步方式双寄存器、三寄存器、握手、异步FIFO、格雷码等。第四步写sgdc文件并启动SpyGlass编译。第五步如果violation仍然铺天盖地不要急着逐条分析先回看sgdc是不是少了一条时钟、少了一个接口抽象、复位方向是否写反。这一步做完违规数量通常会大幅下降。我自己的经验是前三步的整理工作看起来不容易量化产出但恰恰是它们决定了第四步之后的工作效率。等哪一天你能在开会时不看树形图就能准确说出“这个接口是异步FIFO那几个pin需要false_path”那sgdc的功底就算真的上身了。4. 常见问题排查实录从一堆violation里“捞”出真问题4.1 问题一时钟没有定义报错数量爆炸如果你打开SpyGlass看到几千条CDCM-001之类与时钟无关的违法报告其中大量都是“clock information missing”之类提示优先检查sgdc中主时钟定义是不是没写全。尤其是当设计里有时钟MUX或者时钟门控时工具从命名上无法自动选择正确的主时钟必须先手动指定。验证方法很简单在SpyGlass的时钟报告里搜索Unconstrained clocks或者Unconstrained pins的条目看列表中是否有明显应该是时钟网络的信号。如果某个模块的时钟确实来自顶层PLL分频但该模块内部没有打主时钟约束工具就会把这些网络当普通逻辑去分析。还有一种隐蔽的情况是某个时钟的-domain参数写错了导致本该是同域的寄存器被拆成两个不同域。这种情况下工具不会报缺时钟而是会多出大量奇怪的跨域报告规律是集中在两块由同一个PLL驱动的局部区域。4.2 问题二异步复位约束缺失寄存器复位路径被乱报很多新手在处理CDC报错时大量时间花在分析复位相关路径上但问题的根源往往只是sgdc里少了一条ast_reset声明。SpyGlass默认情况下对复位端与时钟之间的关系是高度敏感的如果没有显式声明某个复位是异步复位它会在所有寄存器复位端与时钟沿之间做的时序检查中用最悲观模型去计算。这里的排查技巧是打开reset report看SpyGlass识别出来的复位树与你的设计复位架构是否一致。如果识别出的复位树残缺不全比如某个子系统的复位头到不了那先补全ast_reset再配合-async或-sync声明。补全之后你会发现大量疑似亚稳态的问题消失了因为它们本来就不该通过复位路径产生。4.3 问题三invert clock被误判报出奇怪的同步器mismatch当设计里某个时钟域内部有一部分寄存器使用反相时钟沿采样时SpyGlass在默认情况下不太擅长理解反相时钟与同步器组合时的真实时序关系。它可能会把原本安全的同步器报告为unsafe因为两个寄存器的采样沿在工具看来变成了不同时钟沿导致skew分析出现偏差。这种问题的处理方式有两种优先推荐在写时钟约束时就规范地生成反相时钟节点的定义把反相时钟的时间沿单独描述清楚而不是让工具自动传播。另一方式是如果确实没有实际风险可以在约束里声明这是一条安全的路径。但我更建议前一种做法因为直接把问题根源描述正确后续回归中不会反复出现模糊不清的警告。4.4 问题四约束文件写错scope明明加了约束却没生效sgdc里几乎每个命令都支持-module或者-apply来限定作用范围。一旦作用域写错约束看起来是加上了实际检查时SpyGlass根本不会用到它。最典型的场景是在顶层module下写了一个针对子模块内部信号的约束但该信号在子模块内部不叫这个名字于是约束对不上路径被SpyGlass默默忽略。排查这类问题可以通过SpyGlass的约束报告来验证工具一般会显示每条约束的匹配情况如果在某条约束里看到0 matching pins/net/registers那基本就是作用域或者对象名写错了。我常用的办法是在写每一条关键约束前先在SpyGlass的GUI或者RTL browser里找到该信号的完整层次路径再复制进sgdc可大幅减少低级错误。4.5 常见错误速查表为了便于你后续快速定位问题我把上面提到的现象、原因、对策整理成一个速查表实际检查时可以先对照它做一轮过滤。表面现象可能原因排查对策violation数量爆炸广泛报CDCM-001类主时钟或生成时钟约束缺失检查Unconstrained clocks列表补齐ast_clock两个同PLL的模块互相报跨域-domain或-group参数设置错误核对时钟拓扑合并正确的同源时钟域复位相关路径异常增多异步复位未声明或复位树识别错误补建ast_reset确认异步复位有效电平同步器被报为不安全同步器结构超出默认模板、反相时钟沿抽出同步器模块并加abstract_port声明约束未生效一直有0 match提示模块作用域或信号层次路径写错用RTL browser复制完整路径再写约束握手信号跨域误报接口方向未被工具识别使用abstract_port定义握手类型接口4.6 一条避坑心得不要用false_path处理所有跨域信号看到报错不要总想着用false_path一把清干净。如果跨域信号本质上是一个真实的数据总线你直接false_path掉等于告诉SpyGlass不用检查这个信号那后续如果总线宽度变化、同步逻辑改变隐患就漏过去了。我建议的划分方式是以真实同步结构为界能通过结构被工具明确识别的用abstract_port处理实在无法通过结构识别的、设计上又确实认为是安全的路径才用false_path。而且false_path只做最小范围声明宁可多花点时间在abstract_port上也不要把false_path写得越来越宽。这个习惯一次养成了后面项目维护会轻松很多。5. 从sgdc到体系化CDC检查几个收尾建议5.1 sgdc文件本身也要纳入版本管理与评审在我接触过的项目里sgdc大多只有设计工程师一个人维护偶尔加上验证人员补充。但CDC约束文件和RTL同样重要它应该和RTL一起提交评审一起入版本管理。任何一个和时序或跨域相关的RTL改动都应当触发一次sgdc的适用性检查。实际项目里出现过这种情况RTL里把一个异步接口从双寄存器同步改成了握手同步但sgdc里的约束描述没跟着更新导致新结构明明已经安全了却还在按照旧结构被错误分析。这种问题很隐蔽因为报错是偶发的、不稳定的要让工具和人都能对上“现在到底用的什么结构”约束的版本管理就是唯一的锚点。5.2 尽量让sgdc有自动化的影子如果你的设计里存在大量规律性接口比如AHB总线各模块之间的跨域接口、或同种类型外设的异步寄存器那么sgdc完全可以由脚本生成。我见过有人用python脚本读一份接口清单Excel自动生成对应的abstract_port与false_path条目效果很好。脚本只需要维护接口类型、时钟域名、端口名三列就能覆盖80%的常规接口。这样还有一个额外好处接口登记表本身就变成了设计与验证之间的契约文档sgdc只是这个契约的产物。维护更新版本的时候只要改表格再重新生成约束就行远比手工逐条更新可靠。5.3 最后分享一个我自己的小习惯每次我在sgdc里增删修改任何一条与时钟或接口相关的约束时都会在文件里用注释记录日期、修改人和修改原因。等到项目到了后期面对一大堆CDC报告需要解释时这些注释常常能帮我回忆起当时设计的初衷。毕竟一个准确的sgdc不仅能让SpyGlass少报错更重要的是它能帮你讲清楚每个跨域设计到底是怎么想的。想要把CDC验证做好约束文件的“可叙事性”和我上面讲到的“正确性”一样重要。
返回列表