一、随机激励基础:什么是随机激励、为什么需要随机激励、随机激励在验证中的角色

1.1 随机激励到底是什么?

先说说我的理解。随机激励,说白了就是让测试平台自己“动脑子”产生输入信号,而不是我们一条条手写。

举个例子。你写了一个加法器,想验证它对不对。传统做法是:

  • 写 testcase:输入 1+1,检查输出是不是 2
  • 再写一条:输入 2+3,检查输出是不是 5
  • 再写一条:输入 100+200……

你想想看,这得写到什么时候?而且你永远不知道,会不会漏掉某个边界情况。

随机激励的做法是:告诉验证平台“给我生成两个 0 到 255 之间的随机数,加到 DUT 上,然后自动比对结果”。平台就会自动生成成千上万条测试,覆盖各种组合。

核心定义:随机激励 = 由约束驱动的、自动生成的、可重复的输入序列。

1.2 为什么我们需要随机激励?

这个问题我当年也问过。说实话,刚开始做验证时,我觉得手写 testcase 也挺好的,至少心里有底。直到我在一个项目中栽了跟头。

那是一个总线仲裁器的验证。我手写了大概 200 条 testcase,自认为覆盖得很全面了。结果仿真一跑,RTL 设计人员跑过来说:“你试过同时三个 master 发起请求,并且优先级相同的情况吗?”

我愣住了。我没写这个场景。因为我觉得“不太可能发生”。

嗯,这就是问题所在——人的思维是有盲区的。

随机激励能解决三个核心痛点:

  1. 覆盖更广:随机可以产生你没想到的组合。我习惯的做法是,让随机跑 10 万次,然后看覆盖率报告——经常能发现一些“我根本没想到”的 corner case。
  2. 节省人力:写一条带约束的随机测试,顶得上手写几百条定向测试。这个账很好算。
  3. 发现隐藏 bug:有些 bug 只在特定时序、特定数据组合下才会触发。手写很难精准命中,但随机跑着跑着就撞上了。

我的经验:随机激励不是“乱来”,而是“有方向的随机”。约束写得好,随机就是你的得力助手;约束写得差,随机就是浪费时间。

1.3 随机激励在验证中的角色

随机激励在整个验证流程中,到底扮演什么角色?我用一张图来说明。

随机激励在验证流程中的角色 测试平台(Testbench) 包含:驱动器、监视器、计分板、覆盖率收集器 随机激励生成器 约束求解器 + 随机数发生器 待测设计(DUT) 接收随机输入,产生输出 覆盖率驱动 → 调整约束 → 再随机 形成“随机 → 覆盖 → 反馈 → 再随机”闭环 反馈调整约束

从这张图可以看到,随机激励不是孤立存在的。它处于测试平台的核心位置,连接着约束生成和覆盖率反馈。

具体来说,随机激励在验证中扮演三个角色:

角色 说明 我的体会
输入生成器 自动产生符合约束的输入序列 省去了大量手写 testcase 的时间
覆盖率驱动者 通过随机覆盖各种功能点 我习惯先跑一轮随机,再看哪些点没覆盖到
bug 探测器 发现定向测试难以触发的隐藏问题 曾经有个 bug 跑了 50 万次才出现……

注意:随机激励不是万能的。它不能替代定向测试,也不能替代形式化验证。我见过有人过度依赖随机,结果覆盖率一直上不去——后来发现是约束写得太死了,随机根本没自由度。

1.4 一个简单的随机激励示例

光说不练假把式。我写一段 SystemVerilog 的随机激励代码,你看看就明白了。

class Packet;
  rand bit [7:0] addr;
  rand bit [7:0] data;
  rand bit       wr_en;

  // 约束:地址范围限制在 0x00-0x7F
  constraint addr_range {
    addr inside {[0:127]};
  }

  // 约束:写操作时数据不能为 0
  constraint data_valid {
    if (wr_en) data != 8'h00;
  }
endclass

module testbench;
  Packet pkt;

  initial begin
    pkt = new();
    repeat (1000) begin
      assert(pkt.randomize());
      // 将随机产生的 pkt 驱动到 DUT
      drive_to_dut(pkt);
    end
  end
endmodule

这段代码做了三件事:

  • 定义了三个随机变量:地址、数据、读写使能
  • 加了两个约束:地址范围限制、写数据不能为零
  • 循环 1000 次,每次随机化后驱动到 DUT

你看,就这么几行,就能产生 1000 条不同的测试。要是手写,得写到什么时候?

小技巧:我刚开始写约束时,总喜欢把约束写得特别紧,生怕产生非法输入。后来发现,适当放宽约束,让随机有更多“发挥空间”,反而更容易发现 bug。当然,前提是 DUT 的边界处理要正确。

1.5 随机激励的常见误区

最后说说我踩过的坑。随机激励虽然好,但用不对就是灾难。

  • 误区一:随机 = 完全随机
    我曾经犯过这个错。完全随机产生的输入,大部分都是“正常情况”,边界条件反而很难覆盖到。正确的做法是加约束,引导随机往边界走。
  • 误区二:随机次数越多越好
    不一定。我见过有人跑 100 万次随机,覆盖率还是 60%。为什么?因为约束没写好,一直在重复同样的场景。关键不是次数,而是多样性。
  • 误区三:随机可以替代所有测试
    不行。随机适合做“广度覆盖”,但有些深度场景(比如特定状态机的跳转路径),还是得靠定向测试来精准打击。

嗯,关于随机激励的基础,就先聊这么多。记住一句话:随机激励是你的工具,不是你的主人。用好它,它能帮你省下大量时间;用不好,它只会给你一堆没用的仿真波形。