
简介SpyGlass® LintRules Reference GuideQ-2020.03-SP1版是Synopsys官方发布的静态分析规则参考手册面向IC设计验证工程师、数字前端设计者及Verilog/VHDL开发者用于在设计早期定位语法错误、编码规范偏离、时序与功耗隐患等问题。资源包为单一PDF文件大小约2.04MB内容按规则ID逐条组织每条规则均给出描述、示例代码、解决方案与严重性等级并覆盖设计风格、时序分析、功耗优化、设计约束、接口检查等类别同时说明规则参数配置与自定义规则集的方法。文档还包含版权许可、出口控制声明及FOSS许可提示等合规信息。目前已有4460人学习下载适合需要系统查阅lint规则、对照示例修改代码或搭建团队检查规范的读者作为案头工具书使用。1. 从一份 2020 版规则手册说起SpyGlass lint 到底在查什么如果你手里有一份SpyGlass_LintRules_Reference.pdf版本号 Q-2020.03-SP1发布日期 2020 年 6 月那它大概率不是给你从头读到尾的。我见过太多人把它当小说翻翻了两章就扔在一边然后在跑 lint 的时候被一堆 W 开头、ST 开头的告警砸得晕头转向。这份文档的真实用法是当字典查——你被哪条规则卡住了就去查哪条规则的参数、示例和推荐改法。它覆盖的是 SpyGlass lint 产品里所有可配置的规则参数从allow_clk_in_condition到use_carry_bit按字母序排下来每一条都告诉你这个参数控制什么行为、默认值是什么、怎么影响检查结果。SpyGlass lint 本身是 IC 设计前端静态检查里绕不开的一环专门吃 Verilog 和 VHDL在综合之前就把编码风格、位宽不匹配、 latch 推断、组合环、跨时钟域这些脏东西翻出来。它不跑仿真不依赖 testbench纯靠语法树和语义分析给你出报告。适合谁RTL 设计工程师、验证工程师、以及那些被后端反馈“你这代码综合出来面积爆炸”的人。这份参考手册的价值在于它把每条规则的“开关”和“旋钮”都列清楚了你不需要猜为什么这条告警消不掉翻到对应参数页看它默认值、看它示例、看它建议基本能定位到是代码问题还是配置问题。2. 规则参数怎么读从allow_clk_in_condition到check_latch的配置逻辑2.1 参数命名规律与作用域这份手册里的参数名不是随便起的基本遵循“动词_对象_条件”或“check_对象”的结构。比如allow_clk_in_condition一看就是控制“是否允许时钟信号出现在条件表达式里”check_latch就是“是否检查 latch 推断”。你拿到一条告警先看告警里带的规则 ID再去手册里找对应的参数名然后看它的默认值是 0 还是 1。大部分 check 类参数默认是开启的但有些激进检查默认关闭比如check_counter_assignment_turbo它比普通版更严格默认不开因为误报率会上去。参数的作用域分三层全局、模块级、实例级。全局就是在 SpyGlass 工程配置文件里写一行set_option param value模块级是在sgdc约束文件里针对某个 module 写实例级更细可以只对某个 instance 生效。手册里每条参数都会标注它支持哪几个作用域但不会画成表格你得自己从描述里抠。我一般会先跑一遍默认配置看哪些告警量最大再决定是改代码还是调参数。2.2 用set_option改参数一个 latch 检查的实操假设你跑完 lint报告里一堆check_latch的告警但你确认某些 latch 是故意设计的比如低功耗门控单元里的锁存器。这时候你有两个选择改代码加// spyglass disable注释或者改参数把整个模块的 latch 检查关掉。后者更粗暴但更快适合赶节点的时候用。# 在 sgdc 约束文件里针对特定模块关闭 latch 检查 current_design top_module set_option check_latch 0 -module sub_module_a这段配置的意思是在top_module这个设计下对sub_module_a这个模块把check_latch参数设为 0也就是不检查 latch。注意-module这个开关手册里写的是-module或-inst前者按模块名匹配后者按实例名匹配。如果你写-inst u_sub_a那就只对那个实例生效模块里其他实例照查不误。逻辑说明set_option是 SpyGlass 里最常用的参数覆盖命令它会在当前current_design作用域内生效。参数值 0 表示关闭1 表示开启有些参数还接受字符串或数字阈值比如latch_effort_level可以设 low/medium/high。改完参数后必须重新跑spyglass -project才会生效光改文件不重跑等于没改。2.3 参数之间的依赖与冲突手册里有些参数是互斥的比如strict和no_strict。strict开启后会把很多 warning 升级成 errorno_strict则相反把一些 error 降级成 warning。你不能同时设两个否则后设的会覆盖先设的但具体哪个生效取决于工具读配置的顺序。我一般会在工程配置文件里把strict放在最后确保它压过前面的宽松设置。还有一组容易搞混的是check_counter_assignment和check_counter_assignment_turbo。前者是基础版检查计数器赋值是否规范后者是加强版会额外检查计数器位宽是否足够、是否有可能溢出。如果你两个都开turbo 会覆盖普通版的检查逻辑但普通版的告警不会消失只是被 turbo 的告警淹没了。手册里建议只开一个我实测下来也是只开 turbo 就够了普通版可以关掉省跑的时间。提示改参数之前先备份原始 sgdc 文件SpyGlass 不会自动回滚配置改错了只能手动恢复。3. 把规则手册变成可执行的 lint 流程从工程搭建到报告解读3.1 工程目录结构与最小配置文件SpyGlass 工程不需要复杂的目录树但有几个文件是必须的.prj工程文件、.sgdc约束文件、以及 RTL 文件列表。我一般会这样组织lint_work/ ├── project.prj ├── constraints.sgdc ├── rtl_files.f └── reports/project.prj里写的是读哪些文件、用哪个规则集、输出报告到哪。constraints.sgdc里写参数覆盖和时钟定义。rtl_files.f就是一行一个 RTL 文件路径。reports/放生成的报告方便后续 diff。一个最小的project.prj长这样# project.prj read_file -type verilog rtl_files.f set_option top top_module set_option enableSV yes set_option language_mode mixed set_option projectwdir ./lint_work set_option report {moresimple} current_goal lint/lint_rtl run_goal逻辑说明read_file读入文件列表set_option top指定顶层模块名enableSV开启 SystemVerilog 支持language_mode mixed允许 Verilog 和 VHDL 混编。current_goal lint/lint_rtl是选择 lint 规则集run_goal触发运行。report {moresimple}是报告格式比默认的simple多几列信息比如规则 ID 和文件行号。参数说明projectwdir是工作目录SpyGlass 会在里面生成中间文件和数据库。如果你跑多个项目这个目录一定要分开否则会互相覆盖。report的格式选项手册里有五六个moresimple是我用得最顺手的信息够全又不至于太啰嗦。3.2 规则集选择lint_rtl 与 lint_functional 的差别SpyGlass lint 有几个预置规则集最常用的是lint/lint_rtl和lint/lint_functional。前者偏重 RTL 可综合性检查比如 latch 推断、组合环、位宽不匹配后者偏重功能检查比如未初始化寄存器、死代码、条件表达式覆盖不全。手册里没有明确说哪个规则集包含哪些参数但你可以通过current_goal后面的名字去反查。我一般会先跑lint_rtl把可综合性问题清干净再跑lint_functional查功能隐患。两个规则集有重叠的参数比如check_latch在两个里都有但lint_functional会额外开check_initialization_assignment和check_temporary_flop。如果你时间紧只跑lint_rtl也能覆盖八成常见问题。# 跑 lint_rtl 规则集 spyglass -project project.prj -goal lint/lint_rtl -batch # 跑 lint_functional 规则集 spyglass -project project.prj -goal lint/lint_functional -batch-batch是批处理模式不弹 GUI。如果你要交互式看报告去掉-batch会启动图形界面但服务器上一般没 X11所以还是 batch 靠谱。跑完之后报告在reports/下文件名类似lint_rtl_moresimple.rpt。3.3 报告解读从告警 ID 反查手册参数报告里每条告警都带一个规则 ID比如W123或ST_1。这个 ID 和手册里的参数名不是一一对应的但有关联。比如check_latch参数对应的告警 ID 通常是LATCH开头check_counter_assignment对应CNT开头。手册的目录是按参数名字母序排的不是按告警 ID 排的所以你得先知道告警 ID 对应哪个参数。一个笨但有效的办法在手册 PDF 里搜告警 ID 的关键词比如搜latch会跳到check_latch那一页。那一页会告诉你这个参数控制哪些告警、默认值是什么、怎么关。我一般会把常用告警 ID 和参数名的对应关系记在一个小本子上比如告警 ID 前缀对应参数典型问题LATCHcheck_latch锁存器推断CNTcheck_counter_assignment计数器赋值不规范WIDTHcheck_natural_width位宽不匹配CLKallow_clk_in_condition时钟出现在条件里INITcheck_initialization_assignment寄存器未初始化这个表不是手册里抄的是我自己跑多了总结出来的。手册里每条参数页会列“Affected Rules”或类似的小节但排版比较散不如自己整理一张表来得快。注意不同版本的 SpyGlass 告警 ID 可能有变化Q-2020.03-SP1 里的 ID 和更新版本不一定完全一致跨版本迁移时要以实际报告为准。4. 避坑与排查lint 跑不通、告警消不掉、参数不生效的常见问题4.1 现象跑 lint 直接报 “Unable to resolve module”原因RTL 文件列表里缺文件或者顶层模块名写错了。SpyGlass 在read_file阶段不会报错但到了run_goal阶段发现某个模块找不到定义就会中断。解决先检查rtl_files.f里是否包含了所有.v和.sv文件包括那些被include的文件。如果用了include要在project.prj里加set_option include_path指向头文件目录。顶层模块名要和 RTL 里的module声明完全一致大小写敏感。4.2 现象set_option改了参数但告警没变化原因参数作用域不对或者配置文件没被读到。SpyGlass 读配置的顺序是命令行 工程文件 sgdc 文件。如果你在 sgdc 里改了参数但工程文件里又设了同样的参数工程文件的会覆盖 sgdc。解决用-verbose模式跑一遍看工具实际加载了哪些配置。或者在报告开头找 “Options used” 那段里面会列出所有生效的参数值。如果发现参数没生效检查 sgdc 文件是否被read_file读进去了很多人忘了在project.prj里加read_file -type sgdc constraints.sgdc。4.3 现象告警数量爆炸几千条 W 开头原因默认规则集太激进或者代码风格和规则集不匹配。比如你写的是低功耗设计大量使用门控时钟allow_clk_in_condition默认是 0就会把每个门控单元都报一遍。解决先按告警 ID 分组统计看哪类告警最多。如果是allow_clk_in_condition相关把它设成 1如果是check_latch相关确认哪些是故意的用// spyglass disable注释逐条豁免而不是全局关掉。全局关掉会漏掉真正的 latch 问题。4.4 现象报告里全是 “Info” 级别找不到重点原因set_message_severity参数没调默认把很多检查结果标成 Info。手册里set_message_severity那一页写了怎么把特定规则 ID 的严重级别改成 Warning 或 Error。解决在 sgdc 里加一行set_message_severity -rule W123 -severity error把关键告警升级。但别把所有 Info 都升成 Error否则报告没法看。我一般只升那些会导致综合失败或后仿失败的规则。4.5 现象跑完 lint 没有报告生成原因report参数没设或者projectwdir指向了一个不存在的目录。SpyGlass 不会自动创建多级目录如果projectwdir写的是./lint_work/reports但reports目录不存在报告就写不出来。解决跑之前先mkdir -p把目录建好或者把projectwdir设成已存在的目录。另外检查current_goal后面有没有跟run_goal只写current_goal不写run_goal是不会跑的。5. 进阶技巧用new_flow_width和handle_large_bus处理宽位宽设计5.1 宽位宽设计的 lint 痛点现在很多设计动辄几百位的数据总线SpyGlass 默认的位宽检查参数在遇到[511:0]这种信号时会变得很慢甚至误报。手册里有两个参数专门对付这种情况new_flow_width和handle_large_bus。前者控制位宽传播算法的版本后者控制大总线是否单独处理。new_flow_width默认是关闭的手册里说它用了新的位宽推断引擎对复杂表达式更准但跑得慢。我实测下来对于位宽超过 256 的设计开new_flow_width反而更快因为旧引擎在宽位宽上会做很多无用回溯。handle_large_bus默认阈值是 64 位超过这个位宽的总线会被特殊处理不再逐位追踪。# 在 sgdc 里开启新位宽引擎并调整大总线阈值 set_option new_flow_width 1 set_option handle_large_bus 128 set_option check_natural_width 1 set_option check_natural_width_of_multiplication 1逻辑说明new_flow_width 1启用新引擎handle_large_bus 128把大总线阈值提到 128 位意味着 128 位以下的总线还是逐位追踪超过的才走特殊路径。check_natural_width和check_natural_width_of_multiplication是配套的位宽检查前者查一般表达式后者专门查乘法器位宽。参数说明handle_large_bus的值不是越大越好。设成 256 会让 128 到 256 位之间的总线也走逐位追踪跑得慢但报得准。设成 64 则跑得快但可能漏掉一些位宽问题。我一般会根据设计里最宽的总线来定比最宽总线大一点就行。5.2 用ignore_*系列参数做精准豁免手册里有一大批ignore_开头的参数比如ignore_forloop_indexes、ignore_genvar、ignore_local_variables。这些参数的作用是让 lint 跳过某些特定语法结构不报相关告警。比// spyglass disable注释更高效因为注释是逐行加的参数是一次性全局生效。我常用的组合是set_option ignore_forloop_indexes 1 set_option ignore_genvar 1 set_option ignore_local_variables 1 set_option ignore_auto_function_return 1这四行下去for 循环索引、generate 变量、局部变量、自动函数返回值相关的告警基本就没了。这些告警在大多数设计里都是噪音因为它们的位宽和生命周期是确定的不需要 lint 操心。但ignore_*参数不能滥用比如ignore_signed_expressions关掉后有符号数运算的位宽问题就查不出来了那个我从来不关。5.3 验证参数改动是否有效改完参数后不能只看告警数量少了就完事得确认少的是该少的。我一般会做一次 diff改参数前跑一遍报告改参数后再跑一遍用diff对比两个报告看哪些告警消失了、哪些新出现了。# 跑两次 lint分别保存报告 spyglass -project project.prj -goal lint/lint_rtl -batch mv reports/lint_rtl_moresimple.rpt reports/before.rpt # 改完 sgdc 后再跑 spyglass -project project.prj -goal lint/lint_rtl -batch mv reports/lint_rtl_moresimple.rpt reports/after.rpt # 对比 diff reports/before.rpt reports/after.rpt | grep ^[] | head -50diff输出里开头的是改之前有的告警开头的是改之后新出现的。如果里出现了你没预料到的告警说明参数改过头了把不该关的检查也关了。这时候就得回退换更精准的ignore_参数或者用注释逐条豁免。提示每次改参数都保留一份 sgdc 备份命名带上日期和改动内容比如constraints_20200601_ignore_forloop.sgdc方便回滚。从那以后我每次动 lint 参数都强制走一遍 diff 流程哪怕只改了一个ignore_开关。因为 SpyGlass 的参数之间有隐式依赖关掉 A 可能导致 B 的检查逻辑也变了光看告警总数会骗人。希望帮到你。本文还有配套的精品资源点击获取