ARTICLE DETAIL

资讯详情

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

VC Spyglass CDC检查实战:跨时钟域验证的TCL脚本与SDC约束

VC Spyglass CDC检查实战:跨时钟域验证的TCL脚本与SDC约束 去年做一颗无线SoC的时候我在项目启动第一周就把VC Spyglass的CDC检查环境搭了起来。当时很多人不理解RTL还在天天改方案这么早跑CDC能查出什么结果第三周第一个完整block代码整合进来工具一口气报了四百多条跨时钟域问题其中有三条是真正能在芯片启动时把系统卡死的硬伤。从那以后我再也不敢把CDC检查拖到流片前才做。CDC是Clock Domain Crossing的缩写也就是跨时钟域。只要一个设计里存在两个以上异步时钟就一定有跨时钟域路径。这类路径上最经典的风险就是亚稳态而亚稳态不像功能bug那样可以通过仿真稳定复现它是概率性的、偶发的环境一变可能就消失到了现场才爆发。所以业内才专门有VC Spyglass这种静态工具在不跑仿真、不依赖测试向量的情况下用结构分析和形式化验证把跨时钟域风险全部摸一遍。这篇内容主要写给做数字前端设计、验证和集成的工程师尤其是要把SpyGlass从零搭起来、还要把TCL脚本和SDC约束写明白的团队参考。1. 为什么VC Spyglass的CDC检查越早跑越好1.1 亚稳态不是玄学是可以量化的风险先说亚稳态。一个寄存器如果没有满足建立时间和保持时间输出端就可能停在中间电平然后经过不确定的时间才稳定到0或1。这个“不确定时间”可能长达几十纳秒甚至在某些工艺角下更夸张。稳定的结果也是随机的可能是0也可能是1完全没法预测。更麻烦的是亚稳态会传播。如果第一级寄存器进入了亚稳态它输出端连接的组合逻辑会把中间电平继续往后推下一级寄存器采到的可能是错误数据。所以跨时钟域的第一条设计规则就是任何跨时钟域信号都要用同步器把它“挡一下”。最常见的同步器就是两级寄存器串接第一级采样原始信号第二级再采样第一级的输出给第一级留一个整拍的时间去恢复稳定。这里有一个工程上常用来评估风险的指标叫MTBF平均无故障时间。MTBF跟同步器的二级寄存器分辨率时间、时钟频率、数据翻转频率都有关系公式大概是MTBF exp(t_r / τ) / (T0 * f_clk * f_data)t_r是第二级寄存器允许的额外稳定时间τ是工艺相关的恢复时间常数。这个公式想说明的是同步器设计得越保守比如增加三级、增加t_r风险下降是呈指数级的。反过来如果只是简单地把信号接到目标时钟域的寄存器上没有任何同步器MTBF可能短到按小时甚至分钟计算这样的芯片根本没法量产。1.2 CDC检查、功能仿真和时序分析三者分工很多刚接触CDC的工程师会问我们已经有UVM环境在跑功能验证也有PT在做静态时序分析CDC检查是不是多余的其实三者解决的问题完全不一样。功能仿真靠的是你给的激励。跨时钟域的时序问题高度依赖信号到达寄存器时钟边沿的相对位置仿真器默认会假设所有寄存器采样都在理想时间点完成或者稍微带一点随机但不精确的延迟很难真实覆盖亚稳态窗口。你跑十万个测试用例可能也触发不了一次真正的冲突。静态时序分析也就是STA它主要查建立时间和保持时间关心的是“路径能不能在一个时钟周期内走完”。但对于两个异步时钟域之间的路径时序根本不可比两者之间没有一个确定的相移关系STA没办法给出严格约束所以通常在SDC里直接设成false path。这部分时序不吃紧但设计上必须要有同步机制这正是CDC检查的战场。VC SpyGlass在流程中更像是做“设计架构审查”。它从RTL结构上识别哪些信号跨了时钟域判断这些信号有没有经过同步器同步器结构合不合理多bit数据有没有用FIFO或者握手协议是否存在可能让不同bit被不同时刻采样的风险。它可以在前端就发现结构性问题而不是等到后仿真甚至测试阶段才暴露。2. 搭建CDC检查工程目录、TCL脚本和第一个run2.1 环境准备与推荐目录结构如果团队之前完全没用过SpyGlass第一步不是写脚本而是先把环境整理清楚。需要确认几件事工具的license是否支持CDC相关的goal比如CDC Verification和CDC FTD本机可用的临时磁盘空间够不够SpyGlass在elaborate大设计时会生成大量中间文件目录满了会非常痛苦以及RTL代码的编译顺序是否确定有没有依赖IP的库文件。我习惯在一个项目根目录下面维护这样一套结构.project_root/ rtl/ top.v sub_block.v sdc/ top.sdc top.cdc.sdc scripts/ run_cdc.tcl setup_env.tcl work/ spyglass_project/ reports/ cdc_report/scripts目录放所有流程脚本rtl只读不改sdc分两套一套是顶层常规约束另一套专门放CDC相关的异步约束。这样做的好处是后端起流程的时候可以直接复用这里整理好的时钟和时钟组关系不会出现前后端约束各写各的、对不上号的情况。2.2 TCL脚本骨架与关键命令解读VC SpyGlass本身支持命令行批处理和图形界面两种方式工程上我强烈建议用脚本驱动。下面是一份最简可运行的TCL脚本骨架基本流程是建工程、读RTL、指定顶层、读约束、选goal、运行。# run_cdc.tcl # 1. 创建工程 new_project -name cdc_check -directory ./work/spyglass_project -force # 2. 读入RTL文件列表 read_design -filelist ./rtl_filelist.f -top top # 3. 指定当前分析顶层 current_design top # 4. 读入SDC约束重点是时钟定义和时钟组 read_sdc ../sdc/top.sdc read_sdc ../sdc/top.cdc.sdc # 5. 设置目标goal并运行 set_option enable_gui no run_goal -goal cdc_verify先说明一点不同版本SpyGlass的命令参数会有差异比如read_design可能还需要指定语言类型run_goal的goal名称可能是{/top/cdc_verify}这种带路径的格式。以你手上版本的User Guide为准这里强调的是流程骨架。read_sdc这一步很多人会忽略觉得CDC检查不是只需要知道哪些时钟是异步的吗实际上SpyGlass需要SDC来获取时钟频率、端口约束、时钟组关系这些信息直接影响它对跨时钟域场景的判断。没有时钟组声明工具就会把两个实际异步的时钟当成同步关系来分析结果就是大面积假violation或者更糟该报的没报。2.3 编译和elaborate阶段最常翻车的三个原因第一次跑SpyGlass最容易挂在elaborate或者compile这一步。总结下来有三个高频原因。第一个是RTL文件编译顺序不对。SpyGlass底层还是要先把Verilog或者VHDL代码“读进去”再build成内部数据库。如果某个module被例化时还没编译工具会报找不到module有时候是warning有时候直接归档error。解决方法是维护一个干净的filelist按依赖顺序排列最好直接用工具支持的编写方式。第二个是缺少IP的仿真模型或者行为模型。现在SoC基本都会集成很多第三方IP、memory、PLLSpyGlass读RTL的时候需要对应的库单元描述。如果你只有门级网表没有行为模型工具可能无法完整理解IP内部逻辑导致自动同步器识别失败。我的经验是要么给SpyGlass提供可以elaborate的IP模型要么直接在约束里把这些IP设为黑盒然后用抽象模型代替。第三个是work目录的旧数据残留。SpyGlass的工程目录如果不清理第二次跑的时候容易出现工程状态错乱比如new_project报工程已存在或者读到的还是旧设计。所以在脚本开头用-force参数强制重建或者每次run之前手动删掉work目录都是避免这种低级问题的手段。3. TCL脚本和SDC约束怎么配合才算完整3.1 SDC在CDC检查里到底管什么SDC本身是给综合和STA用的约束格式但SpyGlass做CDC检查时也需要它而且需要比STA更细的时钟关系信息。常规SDC里必须包含两部分时钟定义和时钟组。时钟定义最简单比如create_clock -name clk_a -period 10.0 [get_ports clk_a] create_clock -name clk_b -period 6.0 [get_ports clk_b]时钟组描述的是时钟之间是同步还是异步关系set_clock_groups -asynchronous \ -group [get_clocks clk_a] \ -group [get_clocks clk_b]这里有一个特别容易犯的错很多人觉得既然STA里已经把异步时钟设成了false pathCDC检查里就不用再管了。其实false path和set_clock_groups是两回事。STA关心的是这条路径要不要做时序收敛而CDC检查关心的是这条路径上有没有同步机制。你在SDC里写false pathSpyGlass会认为这是一个异步跨时钟信号然后重点检查它有没有被正确同步。如果你不写false path也不写异步时钟组工具反而可能把它当成同步路径直接漏掉检查。所以正确的做法是在标准SDC里把异步关系用set_clock_groups声明清楚再用另一份CDC相关的约束文件告诉SpyGlass哪些路径是经过同步器的、哪些复位是异步复位的、哪些信号在特定模式下面是常数值。3.2 SpyGlass专用CDC约束同步器、复位和常量SpyGlass有一套自己的约束命令官方叫SGDC或者DCT语法用于补充标准SDC里表达不了的CDC信息。最常见的用途是手动标记同步器。SpyGlass定义了两级寄存器串接结构并且要求第一级采样时钟与第二级采样时钟不同它才会认为这是一个同步器。但实际设计里有各种变体比如同步器中间插了一个反相器或者第一级到第二级中间有一个选择器工具可能识别不出来。这种情况下就需要手动约束set_cdc_sync -from [get_cells u_sync/src_ff] \ -to [get_cells u_sync/dst_ff]不同版本语法不同也可能是set_sync_cell这类写法但思路是一致的明确告诉工具这条路径就是同步器让工具不要把它当成未保护路径报出来。另一个重要约束是异步复位的处理。芯片里大量复位信号是异步置位、同步释放的CDC检查如果不知道复位域可能把复位信号到普通寄存器的路径报警报错。一般需要在约束里声明异步复位相关信号或者用set_case_analysis把复位置成常数从而消除复位路径对CDC分析的干扰。还有test_mode。DFT模式的时钟和功能时钟完全可能是异步的scan链上会有大量跨时钟连接这些在功能CDC检查里都是假的。通常做法是给test_mode端口设置case analysis为0告诉工具在功能模式下这个信号是固定值这样Scan相关的路径就不会参与分析。set_case_analysis 0 [get_ports test_mode]这个操作虽然简单但能省下大量排查假violation的时间。3.3 约束书写的顺序问题TCL脚本是顺序执行的SDC和SGDC命令之间的顺序有时会影响结果。举一个实际场景如果你先set_clock_groups声明了两个时钟是异步的再在后面用set_false_path或者set_case_analysis这个false path会被正确理解。但如果顺序反过来某些版本的工具在内部解析时可能会因为false path的存在而把时钟组关系覆盖掉导致后续CDC分析认为它们还是同步的。为避免这类诡异问题我通常固定用一套顺序读设计、指定顶层先读基础SDC包含时钟定义和常规时序约束再读CDC专用约束包含set_clock_groups异步组、set_case_analysis、set_cdc_sync这些CDC语义最后再启动goal这样下来后加的CDC约束信息会覆盖在前面基础约束之上逻辑上比较清晰也方便在报告里回溯哪条规则在哪个阶段引入。4. Goal选择与运行策略结构检查、验证、FTD怎么串4.1 CDC_SETUP、DETECT、VERIFY、FTD逐级说明VC SpyGlass的CDC流程通常不是一个大goal一把梭而是分阶段的。不同版本叫法不完全一致但核心逻辑都类似先setup再detect再verify最后做formal等价性验证。CDC Setup阶段主要是把设计编译、elaborate好把时钟、复位、常量这些约束都加载进去并生成一个干净的数据库。这个阶段如果约束不全后面任何结论都不可靠。它更多是基础设施不是用来直接找CDC violation的。Detect CDC阶段做的是结构检测。工具会扫描所有寄存器确定每个寄存器的采样时钟找出所有跨时钟域的路径再分析这些路径上有没有同步结构。这个阶段输出的报告里有大量的“跨时钟域路径”列表其中包括已经受保护的、未受保护的以及不确定的。我一般先过这个报告把大规模结构问题比如某个模块完全没有同步器快速筛选出来。Verify CDC阶段就更深一层。它不只是看有没有同步器还会验证同步器是否有效、数据路径是否存在收敛性问题、多bit跨时钟域是否使用了匹配的协议、FIFO指针和格雷码是不是成对出现。很多复杂的CDC问题比如两个跨时钟信号汇聚到一个逻辑门上再被采样的reconvergence问题是在这个阶段被发现的。FTD也就是formal equivalent checking related to CDC? 更准确的说是Formal Testability DRC也有人叫CDC FTD一般是做一种更严格的formal分析来确认同步器和相关逻辑在某个抽象模型下是功能正确的。这个阶段对工具性能要求更高通常在大模块或者整个chip上跑。4.2 命令行批处理与图形化调试的配合我推荐的做法是平时回归全用命令行批处理跑detect和verify一旦报告里出现看不懂的violation再打开GUI加载已保存的工程用图形界面看电路结构。GUI的好处是可以直接把source、destination、同步器高亮出来还可以展开时钟路径看每个寄存器到底被哪个时钟采到。但GUI不适合做大工程运行太占内存太慢。所以工程做法是把重活放命令行把排查放GUI。还有一个细节保存工程后最好同时把当前约束和RTL快照一起归档。有时候你会遇到这种情况一份violation report是上周跑出来的但本周RTL已经改了三版回头想复现当时的电路结构没有快照根本做不了。我一般会在run命令前加一条记录当前git commit的操作或者把关键文件copy到report目录。5. Violation解读与调试实录5.1 常见Violation类别CDC报告里会按严重级别分类常见有Error、Warning、Info。Error不一定是真正的硬件bug但一定是需要人工review的Info多数是工具认为需要关注的跨时钟域情况但不一定有问题。从内容上我习惯把violation拆成几类类别典型表现通常原因无保护跨时钟路径source到destination之间没有任何同步器漏加同步器或约束没标同步器同步器识别问题明明有双触发器还被报成未保护同步器命名或结构不符合工具默认规则数据总线跨时钟多bit信号直接跨时钟域没有FIFO/握手设计结构不合理需要改架构复位域问题异步复位路径被当成普通跨时钟路径复位约束缺失收敛性问题多个跨时钟信号在目的逻辑汇聚需要检查汇聚后逻辑是否有逻辑竞争协议不匹配发送端用格雷码接收端却按普通数据同步FIFO设计不规范这些类别里最容易误报的是第二类同步器识别问题其次是第四类复位约束缺失。这两类问题的解决方式往往不是改RTL而是补约束。5.2 一个跨时钟域误报的排查经历有一次工具报了一条violation说某个控制信号从clk_a域到clk_b域没有经过同步器。我打开RTL一看明明有两级寄存器第一级由clk_a采样第二级由clk_b采样结构上就是典型同步器。为什么工具没认出来后来发现这个信号的路径上第一级寄存器输出没有直接接第二级寄存器输入中间隔了一个AND门。这个AND门在功能上不影响同步器效果因为另一个输入恒定是1但工具不会去分析常量传播默认把中间有组合逻辑的结构判为“非标准同步器”。解决办法有两个要么改RTL把AND门去掉要么在约束里显式声明这两级寄存器构成同步器。我选择的是先查这个AND门为什么会存在发现是上游代码风格问题一个冗余逻辑被保留了下来。清掉之后工具就识别了。这个案例说明工具误报有时候真的能暴露代码里不必要的逻辑及时清掉对后端也有好处。5.3 Waive和Review的正确姿势面对几百条violation逐条waive是很危险的但完全不waive也不行。关键是waive要有依据、可追溯。我建议团队内部建立一个review流程每一条waive都必须在report里写明原因、影响分析、处理时间、处理人。比如“该信号为测试模式下才跨时钟域功能模式已由test_mode0屏蔽”这种属于合理waive。但如果只写“与设计无关”这种话后面检查的人完全没法判断等于没waive。SpyGlass本身支持在report里标记waive状态也可以在TCL脚本里统一处理。但即便工具支持我仍然建议把waive清单维护到项目wiki或者bug系统里跟tool报告对起来。这是因为工具报告可能会在下次run时被覆盖而wiki记录可以长期保留。6. 避坑清单与项目复盘6.1 高频坑位整理这些年跑VC SpyGlass踩过不少重复的坑我整理了一份清单基本每次新项目都能用上。坑位现象避坑方式没建异步时钟组该异步的路径被当同步查漏报所有异步时钟必须显式set_clock_groups同步器中间有组合逻辑标准两级同步器报未保护要么改结构要么手动set_cdc_sync省略elaborate直接跑verify报出大量异常确保setup阶段无fataltest_mode未初始化扫描链跨时钟域全报成真实violation对test_mode端口set_case_analysis 0复位信号未设异步复位到数据路径产生大量虚报正确声明异步复位或设为常数IP无模型黑盒内部跨时钟域无法分析提供模型或使用abstract model只跑detect不跑verify结构同步器OK但协议错误漏掉最终必须跑到verify/FTD数据总线直接双触发器同步工具没报单bit风险但多bit数据容易错依赖工具的多bit协议检查并人工review其中最危险的是最后一条。很多人知道单bit信号要用双触发器但多bit总线直接把每个bit各接一个双触发器这种结构在CDC上是大问题。因为每个bit在源时钟域的变化时刻不同经过各自同步器后目标时钟域采样到的可能不是同一个时刻的值。对这种多bit跨时钟正确做法是异步FIFO、握手协议、格雷码编码或者保证所有bit都满足同一个稳定窗口并经过仔细验证。SpyGlass能帮你识别一部分但设计者在源头就要想清楚。6.2 把CDC检查纳入日常回归的建议最后一个建议把CDC检查放到每天自动回归里哪怕一天只跑一次detect和快速verify。原因很简单CDC问题有个特点它跟代码改动的关系很隐蔽。你可以连续两周每天只改一个小模块的接口最终某一天把两个改动叠加起来突然冒出一条新的跨时钟域路径。如果等到流片前统一检查发现一条严重的CDC问题改RTL可能牵动多个模块排期上非常被动。我现在的习惯是每天merge代码后自动触发一次SpyGlass batch run并把report diff发送到邮件或IM群里。只看新增的violation旧的处理掉就不要再刷屏。如果今天有人改动了同步器命名规则或者某个模块之间新增了握手信号第二天早上就能在report里看到变化。这种早期预警机制比任何一次集中式检查都更有效。再说回TCL脚本和SDC约束。这份东西不是写一次就完事的随着设计演进时钟结构、test_mode、复位方案都可能调整脚本里的约束、文件列表都要跟着维护。把它当成一份活文档每次改动设计后都要review一遍约束是否仍然匹配。只要约束不出大问题VC SpyGlass给出的CDC结论基本就能让你在流片前睡得着觉。
返回列表