SV 报告严重级:$info/$warning/$error/$fatal 分级与断言动作
更新时间:2026-09-28。SVA 断言的写法在 SystemVerilog 断言实战:并发断言与时序检查 里已经铺开;那一篇关心「断言怎么写」,这一篇只关心「断言(以及任何报告点)失败之后仿真器做什么」——也就是 SV 报告严重级这一层。UVM 环境里对应的
uvm_info/uvm_warning/uvm_error/uvm_fatal与过滤控制,见 UVM 报告机制与 verbosity 控制,两篇对照看能把「裸 SV」和「UVM」两条报告链路对齐。
本文要回答的问题
$info、$warning、$error、$fatal这四个系统任务除了打印文字不同,行为上到底差在哪?- 断言失败默认报什么级别?
elseaction block 和assert ... else $error(...)的写法怎么选? $fatal的第一参数是什么?仿真退出码、错误计数和回归脚本怎么配合?- 裸 SV 的严重级和 UVM 的
uvm_error/uvm_fatal是什么对应关系?
一、四个严重级的语义与默认动作
SystemVerilog 用一组严重级系统任务(severity system task)统一报告通道,从轻到重依次是 $info、$warning、$error、$fatal。它们长得像 $display,但每一条都附带一个严重级,仿真器据此决定「打印之后还做什么」。
| 系统任务 | 语义定位 | 默认动作 | 错误计数 |
|---|---|---|---|
$info | 正常进展提示(测试开始、配置打印) | 仅打印,仿真继续 | 不计 |
$warning | 可疑但不致命(FIFO 接近满、时序余量小) | 打印并标记警告,仿真继续 | 计入 warning 数 |
$error | 确认的功能错误(协议违例、数据比对失败) | 打印,仿真继续,错误计数加一 | 计入 error 数 |
$fatal | 环境已无法继续(虚接口为 null、内存耗尽) | 打印后立即结束仿真 | 计入 fatal,仿真退出 |
这张表是整篇的核心。两个最容易被低估的点:一是 $error 不停仿真——它只是记账,仿真接着跑,这正是回归场景想要的:一个用例里尽量多暴露几处错误,而不是第一处就中断;二是 $fatal 是四者中唯一会主动终结仿真的,适合「继续跑下去所有结果都不可信」的情形,比如 build 阶段发现虚接口没接到。

读这张图时抓两条主线:横向看,四个级别对「仿真是否继续」的回答不同——只有 $fatal 走到底部那条终止路径;纵向看,计数机制把 $error 变成了回归裁判的依据,仿真「跑完了」不等于「通过了」,批处理脚本看的从来都是 error/fatal 计数和日志里有没有 UVM_ERROR : 0 之外的数字。
二、断言失败与 action block
并发断言(concurrent assertion)自带默认报告:失败时按实现相关的方式打出一条错误级消息,等价于隐式调用了 $error。要控制级别和消息内容,用 action block——断言语句后面跟 pass 语句和 else 失败语句:
// 默认行为:失败报 error 级,消息是仿真器生成的
req_ack: assert property (@(posedge clk) req |=> ack);
// 显式 action block:自定义级别与消息
req_ack2: assert property (@(posedge clk) req |=> ack)
else $error("REQ_ACK", "req 后 %0t 未见 ack, req=%b", $time, req);
// 环境级致命问题可以直接上 $fatal
vld_stable: assert property (@(posedge clk) vld && !rst_n |-> $stable(data))
else $fatal(1, "DATA_STABLE", "vld 期间 data 跳变,采样必错");$fatal 的第一个参数是 finish 编号(0/1/2),语义对应 $finish(0/1/2):控制退出时打印多少诊断信息(统计量、实例位置等),回归脚本里通常约定用 1。后面跟着可选的标识字符串和 $sformatf 风格的参数。$error/$warning/$info 没有这个编号参数,第一个参数若有也是普通格式串的一部分——写顺手了把 $fatal(1, ...) 的格式套到 $error(1, ...) 上,打印出来的消息开头会多个莫名其妙的 1,这是一个真实常见的低级错。
选型经验:协议检查、数据比对用 $error,让仿真跑完收集更多违例;平台基础设施故障用 $fatal——config_db 取不到虚接口、memory 句柄为 null、激励文件打不开,这类问题下任何后续波形都是垃圾,越早停越省调试时间。$warning 留给「这次能跑但下次可能炸」的灰色地带,比如覆盖率配置缺失、可选功能未启用。
三、严重级与回归判定的配合
裸 SV 环境里,仿真器本身不会因为出现了 $error 就返回非零退出码——退出码表达的是「仿真器自己有没有崩」,不是「DUT 有没有错」。所以回归脚本必须解析日志:统计 Error / Fatal 关键字出现次数,或让 testbench 在 $finish 前打印一行汇总:
final begin
if ($getcoveerr != 0) ; // 各家 API 不同,思路一致:
// 自己维护计数器最稳妥
$display("TEST_DONE errors=%0d warnings=%0d", err_cnt, warn_cnt);
end实践中更稳的做法是在 environment 里包一层:所有 $error 调用点同时自增一个全局错误计数,final 块统一打印判定行,回归脚本只认这一行。这恰好就是 UVM report server 干的事——uvm_report_server 集中计数,run 阶段结束时 dump 出 UVM_ERROR : n / UVM_FATAL : n,UVM 报告机制与 verbosity 控制 对此有完整展开。对应关系也很直接:$info→uvm_info、$warning→uvm_warning、$error→uvm_error、$fatal→uvm_fatal,语义一一对齐,区别在 UVM 版本多了 id、verbosity 过滤和按组件的 action 控制(如 UVM_COUNT 把 error 攒到阈值再升级成 fatal)。
还有一个容易忽略的细节:$warning 在很多团队的回归里是「不算 fail 但要看趋势」的级别。warning 数从一个版本到下一个版本翻倍,往往预示着某个时序余量在缩小。建议回归报表里把 warning 计数单列一列,别和 info 混在一起淹没掉。
四、选型决策与常见误用
四个级别怎么选,落到日常判断上就是一张小表:
| 场景 | 选谁 | 理由 |
|---|---|---|
| 测试开始/结束、配置摘要打印 | $info | 纯进展,不影响判定 |
| 覆盖率配置缺失、可选功能未启用 | $warning | 能跑但偏离预期,值得留痕 |
| 协议违例、scoreboard 比对失败 | $error | 确认错误,但继续跑多暴露几处 |
| 虚接口 null、激励文件打不开、句柄为空 | $fatal | 环境不可信,继续跑全是垃圾波形 |
| 断言失败且属于数据稳定性硬约束 | $error 或 $fatal(1) | 看违例后波形是否还有诊断价值 |
误用方面排第一的是滥用 $fatal:有些团队图省事把 scoreboard 比对失败也报 fatal,结果一个回归里每个用例只暴露第一处错误,修一处冒一处,返工轮次翻倍。排第二的是把 $error 当打印工具——调试期的临时打印请用 $info 并配合开关变量,混进 $error 会污染回归计数,让真正的失败淹没在几百条「调试 error」里。第三条是 $display 绕开严重级体系:它不计数、不分级,回归脚本抓不到,任何与判定相关的信息都不该走 $display 裸打。
最后一个工程化建议:在 base test 里集中定义「哪些检查点用哪一级」,写进验证计划,而不是让每个写检查的人现场决定。级别口径不统一,回归报表就失去了横向可比性——同一个 bug 这周报 warning 下周报 error,趋势分析直接作废。
这一篇在知识体系里的位置
- 上游断言写法:SystemVerilog 断言实战:并发断言与时序检查 解决「检查什么」,本篇解决「查到之后怎么办」。
- UVM 对应链路:UVM 报告机制与 verbosity 控制 把同样的四级语义扩展成带 id、verbosity 与 action 控制的完整体系。
- 回归视角:错误计数如何驱动用例 PASS/FAIL 判定,与 回归管理与失败用例分诊 的分诊流程衔接。
总结
SV 报告严重级用 $info/$warning/$error/$fatal 四个系统任务把消息分成四档:前两者只打印,$error 记账但让仿真继续以暴露更多问题,$fatal 立即终结仿真以止损;断言用 action block 自定义级别与消息,协议违例选 $error、环境不可信选 $fatal,回归判定靠错误计数而非仿真是否跑完——裸 SV 的四级与 UVM 的 uvm_info/warning/error/fatal 一一对应,掌握一边即通两边。