验证方法论

第 13 章 · 共 15 章

读懂失败的特征

在做深入的诊断工作之前,一个失败呈现出来的样子,本身就已经是它属于第 1 章四个类别里哪一个的线索——是立刻、确定性地出错,还是跟顺序有关,还是压根没跑到仿真那一步就失败了,还是恰好对上了 spec 定义好的某个结果——全部立足于 axil_regfile 那三个真实事件当初实际呈现出来的样子。

第 1 章把每一个失败分进了四个结构性类别。这一章是深入排查之前的那一遍快速扫描:一个失败呈现出来的样子,在第 3 章那套隔离-插桩-假设-确认的流程真正开始之前,本身就已经是它更可能属于哪个类别的证据。是一条线索,不是定论——但值得在花真正的诊断力气之前先读一读。

四种特征,各对应一个类别

DUT bug 往往是立刻、确定性地出错。 早期版本 s_axi_awready/s_axi_wready 里的那个组合逻辑环(uvm-advanced 第 1 章)不是有时候失败、有时候通过——一个真正的组合逻辑环根本没有稳定解,所以受影响的信号从它第一次被用到的那个周期开始就是错的(或者会引来仿真器自己对这个结构的抱怨),而且每一次跑都一模一样。RTL 里的一个结构性缺陷不需要靠调度运气才会显现;它是结构上注定错的,每次都一样。

Testbench 竞争往往跟顺序有关。 一个由竞争驱动的失败会不会出现,取决于两个独立进程之间的相对时序——跟 DUT 有没有做错任何事完全没关系。这个项目自己的那个事件(BVALIDirq 落在完全相同的时钟边沿,uvm-advanced 第 4 章)到底是怎么被抓到的,值得说精确:不是靠等一次跑仿真的时候恰好碰上一次偶发失败,而是直接给两个信号都装上打印 $timealways 块,确认它们落在同一个时间戳上——直接对相对事件顺序进行推理,而不是指望一个间歇性的症状总有一天自己冒出来。这往往才是抓住这种特征更快、更可靠的办法:不要等硬币抛错了才发现,直接去查一查这里到底有没有在抛硬币。

环境不匹配往往在仿真逻辑还没真正介入之前就已经失败了。 Icarus Verilog 完全没有实现 clocking block(SV 第 13 章)不会表现成某个信号上的一个错误值——它表现成一次解析失败,是靠直接试最简单的独立用例、然后眼看着它连编译都过不去来确认的。这时候 DUT 的逻辑或者 testbench 的时序都还完全没有介入;同样的代码要么在别的地方能编译通过,要么不能,这一点本身就是特征。

"不是 bug"往往恰好对上 spec 里一个有名字的结果。 一个真正错误的值通常就是单纯错了——是噪声,跟 spec 描述的任何东西都对不上号。写 STATUS 得到 SLVERR,一旦这个测试真的存在,情况正好相反:"意外"的结果是 spec 专门给这个场景分配的一个具体的、有文档记载、有名字的响应码,不是一个随意的错误值。当一处不匹配恰好精准地落在一条已定义的错误路径上,而不是落在什么地方都对不上号的空处时,这正是那个值得先拿去对照 spec 核实、再假设有什么东西坏了的特征。

是线索,不是定论

读懂一个特征,能缩小排查范围;它完成不了整个工作。一个只在某种具体、罕见的输入组合下才会显现的 DUT bug,完全可能表现得跟竞争一样间歇性;而一个竞争,也完全可能在某一个具体仿真器的调度实现里表现得很确定,哪怕底层协议其实根本没有保证过那个顺序。读特征是这一章对一次调试过程的贡献——一个快速、低成本的初步假设,关于该先去哪里看——不是第 3 章那套真正的确认流程的替代品,把一个假设变成一个经过验证的根因,靠的是那套流程。

小结

  • DUT bug 往往立刻、确定性地呈现出来——从受影响的逻辑第一次被用到开始就是错的(或者引来抱怨),每次跑都一样,就像一个组合逻辑环这样的结构性缺陷,压根就没有稳定解一样。
  • Testbench 竞争往往表现得跟顺序有关——会不会失败,取决于独立进程之间的调度,跟 DUT 的逻辑没关系。像 uvm-advanced 第 4 章那样直接插桩去检查相对事件顺序,比等一个间歇性失败自己冒出来更快抓住这种特征。
  • 环境不匹配往往在任何仿真逻辑真正介入之前就已经失败了——一次解析或者编译失败,或者同样的代码在不同工具上表现不一样,靠隔离出最小的用例来确认。
  • "不是 bug"往往看起来像一处恰好精准落在一个有名字、spec 定义好的结果上的不匹配,而不是一个随意的错误值——值得先拿去对照 spec 核实,再假设有什么东西坏了。
  • 一个特征是一个快速的初步假设,不是一个已确认的诊断——缩小该先去哪里看的范围是这一章的工作;真正确认它,靠的是第 3 章的诊断方法。

一个信号从它第一次被用到的那个周期开始就显示错误的值(或者 X),而且每一次跑都一模一样。这个特征最强烈地指向第 1 章里的哪个类别?

uvm-advanced 第 4 章的 BVALID/irq 竞争,是靠给两个信号都装上打印 $time 的 always 块、确认它们落在同一个时间戳上抓到的——不是靠在一次真实的测试运行里观察到一次间歇性失败。这一章主张这说明了什么?

Icarus Verilog 连一个裸的 clocking block 都解析不了(SV 第 13 章),这被归类在环境不匹配的特征下。是什么让这个特征跟 DUT bug 或者 testbench bug 的特征区分开来?

读完一个失败的特征、对它属于第 1 章四个类别里的哪一个形成了一个假设之后,这个假设算是确认了吗?