4. 信号查找与条件过滤

在复杂SoC验证中,一个中等规模设计的波形数据库往往包含数万到数十万条信号。如果只靠手动展开层次树逐层寻找,调试效率会急剧下降。Verdi 的 Signal Search / Filter 机制正是为解决这一问题而设计:它允许你按名称、类型、层次路径定位信号,用通配符和正则表达式批量匹配,再叠加 X/Z 状态、活动事件等条件,把真正需要观察的信号快速收敛到波形窗口中。

一、信号查找的三种入口

Verdi 中查找信号主要有三个入口,它们面向不同场景:

  • Get Signals(按名称/层次):在 nWave 或 nSchema 中通过 Signal > Get Signals 打开,输入完整或部分层次路径,例如 tb_top.u_dma.u_axi.arvalid,适合已知信号名或路径前缀的情况。
  • Signal Search(按类型/属性):通过 Signal > Search 或工具栏搜索框,可按信号类型(wire、reg、input、output、inout)、位宽、方向等属性筛选,适合“找出所有输出端口”这类需求。
  • Find in Hierarchy:在层次树中直接输入关键字,Verdi 会高亮匹配的实例名或信号名,适合在浏览层次时快速跳转。

三者的核心区别在于:Get Signals 以“路径”为索引,Signal Search 以“属性”为索引,Find in Hierarchy 以“当前视图”为索引。实际调试中通常组合使用——先用层次树定位到某个模块,再用 Get Signals 拉出该模块下的关键信号。

二、通配符与正则表达式

Verdi 的搜索框支持两种匹配模式,理解它们的差异是高效过滤的前提。

通配符模式使用 * 匹配任意字符序列,? 匹配单个字符。例如:

tb_top.u_dma.*.arvalid     // 匹配 u_dma 下任意子模块的 arvalid
tb_top.u_*.rdata           // 匹配 u_ 开头的模块下的 rdata
*_fifo_*                   // 匹配任意包含 _fifo_ 的信号名

正则表达式模式则提供更强的表达能力,Verdi 使用类似 Perl 的正则语法。例如要匹配所有以 r 或 w 开头、以 valid 结尾的信号:

^[rw].*valid$

要匹配 AXI 通道中所有 ar 或 aw 前缀且带 ready 的信号:

^(ar|aw).*ready$

需要注意:正则中的 . 默认匹配任意字符,若只想匹配层次分隔符,应转义为 \.。另外,Verdi 的正则匹配默认区分大小写,若信号命名风格不统一,可在搜索选项中关闭大小写敏感。

当不确定信号全名时,先用通配符做粗筛,再用正则做精筛。例如先搜 *valid* 看有哪些候选,再根据结果写 ^(ar|aw).*valid$ 精确锁定。

三、过滤 X/Z/未知态

X/Z 态是调试中最常见的异常信号。Verdi 提供了专门的过滤条件,可以在搜索或波形显示阶段只保留处于未知态的信号。

在 Signal Search 对话框中,展开 Value Filter 区域,可以看到 X、Z、X or Z 等选项。勾选后,Verdi 会扫描指定时间窗口内信号的值,只返回出现过对应状态的信号。例如:

  • 勾选 X:找出所有在仿真过程中出现过 X 的信号,常用于定位未初始化寄存器或总线冲突。
  • 勾选 Z:找出高阻态信号,常用于检查三态总线或未驱动端口。
  • 勾选 X or Z:合并筛选,适合快速排查“未知/高阻”类问题。

时间窗口的设置很关键。默认可能是整个仿真区间,但对于长仿真,建议先定位到异常发生的时间段(例如通过 nWave 中的 X 标记跳转),再把过滤窗口缩小到该区间,避免扫描全库导致响应缓慢。

四、按活动事件筛选信号

“活动事件”指信号在指定时间窗口内发生过跳变(0→1、1→0、X→0 等)。Verdi 的 Activity Filter 允许你只保留“有活动”或“无活动”的信号。

典型用法:

  • 只显示有跳变的信号:在调试死锁时,把长时间无变化的信号过滤掉,剩下的就是仍在活动的控制/数据信号,能快速缩小怀疑范围。
  • 只显示无跳变的信号:反向排查“本该翻转却没翻转”的信号,例如时钟使能、握手 ready 等。
  • 按跳变次数筛选:部分版本支持设置最小/最大跳变次数,例如“跳变次数 > 0 且 < 5”,用于找出异常稀疏的活动。

活动过滤通常与时间游标配合:先把 nWave 的游标定位到感兴趣的时间段,再执行 Activity Filter,Verdi 会以当前可见时间窗口为基准进行统计。

五、组合过滤的典型工作流

实际调试中,单一条件往往不够。下面是一个组合过滤的典型流程,用于定位 AXI 写通道的异常:

  1. 在层次树中定位到 tb_top.u_dma.u_axi,确认 AXI 接口实例。
  2. 用 Get Signals 输入 tb_top.u_dma.u_axi.*w*,拉出所有写通道相关信号。
  3. 在 Signal Search 中叠加正则 ^(aw|w|b).*(valid|ready)$,精确匹配握手信号。
  4. 勾选 Value Filter 的 X,只保留出现过 X 的信号。
  5. 再叠加 Activity Filter 的“有跳变”,排除静态信号。
  6. 把结果 Add to Wave,在 nWave 中观察握手时序。

经过这六步,原本数百条 AXI 信号会被收敛到几条到十几条,波形窗口的可读性大幅提升。

Verdi 信号查找与条件过滤 — 组合过滤工作流 以 AXI 写通道异常定位为例 ① 层次定位 tb_top.u_dma.u_axi Find in Hierarchy ② 通配符粗筛 tb_top.u_dma.u_axi.*w* Get Signals ③ 正则精筛 ^(aw|w|b).*(valid|ready)$ Signal Search ④ X/Z 过滤 Value Filter 勾选 X ⑤ 活动过滤 Activity Filter 有跳变 ⑥ Add to Wave 收敛至 5~15 条信号 nWave 观察握手时序 过滤效果对比 原始 AXI 信号:约 200+ 条 过滤后:5~15 条关键握手信号 过滤条件速查 过滤维度 语法/选项 示例 适用场景 名称/层次 完整路径或前缀 tb_top.u_dma.u_axi 已知路径 通配符 * 匹配任意,? 匹配单字符 *_fifo_* 粗筛候选 正则表达式 ^ $ . * | () 等 ^(ar|aw).*ready$ 精确匹配 X/Z 状态 Value Filter 勾选 X / Z X or Z 未知态排查 活动事件 Activity Filter 有/无跳变 跳变次数 > 0 死锁/静态排查

六、实践中的注意事项

第一,正则表达式要转义层次分隔符。Verdi 的层次路径使用 . 分隔,而正则中 . 是通配符。如果写 tb_top.u_dma.*valid,其中的 . 会匹配任意字符,可能误匹配到 tb_topXu_dma 这类不存在的路径。正确写法是 tb_top\.u_dma\..*valid。

第二,过滤窗口不宜过大。X/Z 过滤和活动过滤都需要扫描波形数据,如果时间窗口覆盖整个仿真(例如 10ms 仿真、1ps 精度),扫描量会非常庞大。建议先用 nWave 的标记功能定位到异常时间段,再以该段为窗口执行过滤。

第三,组合条件有先后顺序。一般建议先用名称/层次缩小范围,再用正则精筛,最后叠加 X/Z 和活动过滤。如果先做活动过滤,可能会因为信号数量仍然很大而耗时较长。

第四,保存过滤结果。Verdi 支持把当前搜索条件保存为 .rc 或信号列表文件,下次调试同类问题时可直接加载,避免重复输入。对于团队协作,把常用的过滤条件写入脚本,可以统一调试入口。

使用正则表达式时,若信号名中包含特殊字符(如 [、]、$),需要先转义。例如总线信号 data[31:0] 在正则中应写为 data\[31:0\],否则方括号会被解释为字符集。

掌握信号查找与条件过滤,本质上是把“在波形里找信号”从手工劳动变成可复现的查询过程。名称、类型、层次是索引,通配符和正则是匹配语言,X/Z 与活动事件是状态条件,四者组合起来,才能在复杂波形中快速锁定真正值得观察的对象。