4、基础仿真验证:手动激励编写、波形观察、状态跳转检查、覆盖率概念引入

各位同学,咱们今天聊点实在的。

仿真验证,说白了就是给设计“喂”信号,看它怎么动。很多新手一上来就想着自动化、UVM,其实没必要。我做了十几年验证,最深的体会是:手动激励是基本功,波形观察是眼睛,状态跳转是灵魂。这三样玩不转,后面再高级的工具也是白搭。

4.1 手动激励编写——别小看这“笨办法”

手动激励,就是直接在testbench里用initial块或者task,一条条地给信号赋值。听起来很原始对吧?但我在项目中遇到过好几次,自动生成的激励死活复现不了某个bug,最后用手动写了几行就抓到了。

举个例子,一个简单的状态机,有IDLE、READ、WRITE三个状态。手动激励可以这样写:

initial begin
    // 复位
    rst_n = 0;
    #100 rst_n = 1;
    #20;
    
    // 发起一次读操作
    req = 1;
    rw = 0;  // 读
    #10;
    req = 0;
    
    // 等待状态跳转
    #50;
    
    // 发起一次写操作
    req = 1;
    rw = 1;  // 写
    #10;
    req = 0;
    
    #100;
    $finish;
end

嗯,这里要注意:时序一定要对齐。我见过太多人写激励时,时钟沿和赋值时机没配合好,结果仿真波形看起来对,实际逻辑根本没跑到。

我的小习惯:手动激励里,每个操作之间留足“观察窗口”。比如读操作后等50ns,专门看状态机是不是按预期跳到了READ状态。这样波形一眼就能看出问题。

4.2 波形观察——你的第二双眼睛

波形是验证工程师的“X光片”。你不会看波形,就等于医生不会看片子。

我个人习惯,打开波形后先做三件事:

  1. 看时钟和复位——这是基础,乱了就全乱
  2. 看状态机当前状态——用radix设为enum或symbolic,别盯着二进制数猜
  3. 看关键控制信号——比如req、ack、done这些握手信号

为什么会这样?因为状态机出问题,十有八九是状态跳转条件没满足,或者跳到了不该去的状态。波形上一眼就能看出来。

避坑指南:我曾经花了一整天查一个bug,最后发现是波形里把状态信号的radix设成了十进制,导致我看错了状态值。从那以后,我所有状态信号一律用enum显示。

4.3 状态跳转检查——验证的核心

状态机验证,说白了就是检查它能不能按设计意图跳转。我一般分三步走:

  • 第一步:列出所有合法跳转路径。比如IDLE可以到READ,READ可以到DONE,DONE回到IDLE。
  • 第二步:手动激励覆盖每条路径。别偷懒,每条路径至少跑一次。
  • 第三步:检查非法跳转。比如从IDLE能不能直接跳到DONE?如果能,那就是bug。

你想想看,如果状态机有5个状态,合法跳转可能有10条。手动写10个激励场景,花不了多少时间,但能发现80%的bug。

// 检查状态跳转的简单方法
always @(posedge clk) begin
    if (!rst_n) begin
        // 复位后必须在IDLE
        assert (state == IDLE);
    end else begin
        case (state)
            IDLE: begin
                if (req && !rw) assert (next_state == READ);
                if (req && rw)  assert (next_state == WRITE);
            end
            READ: begin
                if (done) assert (next_state == IDLE);
            end
            // ... 其他状态
        endcase
    end
end
注意:手动检查状态跳转时,别忘了检查“保持条件”。比如某个状态在条件不满足时,应该保持当前状态。很多bug就出在这里——状态机在条件没变时自己乱跳了。

4.4 覆盖率概念引入——从“跑没跑过”到“跑没跑全”

手动激励写完了,波形也看了,状态跳转也检查了。然后呢?你怎么知道你的激励够不够?

这就是覆盖率要解决的问题。

覆盖率说白了就两件事:

  • 代码覆盖率:你的激励让RTL代码里的每一行、每一个分支都执行过吗?
  • 功能覆盖率:你的激励覆盖了所有你想测的场景吗?

我记得刚入行时,领导问我:“你测了哪些场景?”我答:“都测了。”领导又问:“你怎么证明?”我哑口无言。后来才知道,覆盖率就是用来“证明”的。

对于状态机,最常用的覆盖率是:

覆盖率类型 检查什么 手动激励能覆盖吗
状态覆盖率 每个状态是否都进入过 可以,手动跑一遍就行
状态跳转覆盖率 每条跳转路径是否都走过 可以,但路径多了就累
条件覆盖率 每个跳转条件是否都测过 手动写比较麻烦
我的建议:刚开始学验证,先别管什么自动化覆盖率收集。你用手动激励跑一遍,然后自己画个表格,打勾确认每条路径都跑过了。这叫“手动覆盖率”,虽然土,但有效。

等你把状态机的所有跳转都手动跑了一遍,再去看工具自动收集的覆盖率报告,你会发现:原来我漏了这么多边角情况。这时候,你就真正理解覆盖率的意义了。

嗯,今天就先聊到这儿。手动激励、波形观察、状态跳转检查、覆盖率概念——这四个东西是基础中的基础。别急着学UVM,先把这些基本功练扎实了,后面学什么都快。

基础仿真验证知识体系 手动激励编写 波形观察 状态跳转检查 覆盖率概念 initial块 / task编写 时序对齐 / 时钟沿配合 时钟复位检查 状态信号enum显示 握手信号观察 合法跳转路径覆盖 非法跳转检查 保持条件验证 代码覆盖率 功能覆盖率 状态/跳转覆盖率 手动激励 → 波形观察 → 状态检查 → 覆盖率分析

可可精品资料库