4、波形调试技巧:Verdi/QuestaSim波形查看、信号追踪、波形比较
波形调试,说白了就是数字验证的「照妖镜」。
代码写得再漂亮,仿真跑得再欢,最后还是要看波形说话。我见过太多工程师,代码写得飞起,一到看波形就抓瞎——信号太多不知道怎么加,波形太长不知道怎么定位,两个版本比对全靠肉眼硬看。嗯,这些坑我都踩过。
今天我就把压箱底的波形调试技巧掏出来,从查看、追踪到比较,一条龙讲清楚。
4.1 波形查看:别只会点「Add Wave」
很多人加信号的习惯是:选中所有信号,右键「Add to Waveform」。然后看着密密麻麻的波形图发呆。
我个人习惯是分层加、按需加。
- 先加顶层接口信号——看整体行为对不对
- 再加关键控制信号——状态机、计数器、握手信号
- 最后加数据通路信号——怀疑哪里有问题再加哪里
在Verdi里,我常用这几个快捷键:
| 操作 | Verdi快捷键 | QuestaSim快捷键 |
|---|---|---|
| 添加信号到波形 | Ctrl+W | Add Wave (菜单) |
| 放大/缩小 | Z / Shift+Z | Ctrl+滚轮 |
| 测量时间差 | 鼠标左键拖拽 | Ctrl+左键拖拽 |
| 查找信号跳变 | n / N (搜索) | Ctrl+F |
| 设置标记 | M | Mark (菜单) |
这里有个小技巧:在Verdi里,你可以把信号拖成「分组」。比如把所有AXI接口信号放一组,所有控制信号放一组。这样波形看起来清爽多了。
4.2 信号追踪:从波形反推RTL
波形调试的核心能力是什么?是「反推」。
看到波形上某个信号在某个时刻跳变了,你得能快速找到:这个跳变是哪个RTL语句产生的?
Verdi的「nTrace」功能就是干这个的。具体操作:
- 在波形窗口选中一个信号
- 右键选择「Show Source」或按快捷键
Ctrl+S - Verdi会自动跳转到RTL代码中该信号的驱动位置
更狠的是「nSchema」——它能画出信号的驱动链。比如你看到一个输出信号异常,点一下nSchema,所有相关的组合逻辑、时序逻辑一目了然。
- 先看驱动源(assign还是always块)
- 再看条件(if/else、case分支)
- 最后看时序(posedge还是negedge)
三步走完,90%的问题都能定位。
在QuestaSim里,虽然没有Verdi那么直观的图形化追踪,但可以用 add wave -r * 递归添加所有子模块信号,然后用 searchlog 命令查找特定值的变化。
4.3 波形比较:别再肉眼看了
说实话,我最怕的就是「两个版本波形比对」。以前我都是把两个波形截图,然后左右分屏,肉眼找差异。那叫一个痛苦。
后来我发现,Verdi和QuestaSim都有自动波形比较功能。
Verdi的波形比较
- 打开两个波形文件:
File -> Open Database - 选择
Tools -> Waveform Compare - Verdi会自动标记出所有差异点,用红色高亮显示
QuestaSim的波形比较
- 使用
vcompare命令 - 语法:
vcompare wave1.ewf wave2.ewf -report diff.txt - 差异会输出到文本文件,也可以图形化显示
4.4 核心知识体系
下面这张图是我自己总结的波形调试知识体系,你品品:
4.5 实战案例:一个AXI总线超时问题
讲个真实案例。有一次我调试一个AXI Slave,发现Master发起的读请求总是超时。
我按以下步骤排查:
- 加顶层信号:arvalid、arready、rvalid、rready、rdata
- 看波形:arvalid拉高后,arready一直没拉高
- 追踪:用nTrace找到arready的驱动逻辑——是一个状态机
- 看状态机:发现状态机卡在「WAIT_DATA」状态,因为内部fifo的empty信号一直为高
- 再追踪:fifo的empty信号来自写通道,发现写通道的wready也没拉高
- 最终定位:Slave的写地址通道和写数据通道的握手顺序反了
整个过程,从加信号到定位问题,不到10分钟。如果没有波形调试技巧,光靠读代码,可能得花半天。
嗯,今天就聊到这儿。这些技巧你多练几次,慢慢就形成肌肉记忆了。