3. 验证计划到覆盖率模型的映射

验证计划回答的是“要验什么”,覆盖率模型回答的是“仿真到底跑到了什么”。两者之间如果没有一条可追溯的映射链,就会出现两种典型失控:一是验证计划里的需求点根本没有对应的覆盖项,仿真跑得再多也无法证明需求被验过;二是覆盖率数字很高,但覆盖的都是一些无关紧要的角落,真正的边界条件从未被触发。本节要做的,就是把验证计划中的每一条需求,逐层翻译成可采集、可判定、可追溯的覆盖率结构。

从需求条目到覆盖点的提取

验证计划通常以需求条目(requirement)为最小单位,例如“当 FIFO 写指针追上读指针时应置满标志”“AXI 写响应必须在 16 个周期内返回”。这些句子是自然语言,不能直接采集,必须先提取出可观测的“覆盖点”。提取的核心动作是问三个问题:这个需求涉及哪些信号或事务字段?这些字段有哪些值得区分的取值或取值组合?在什么条件下这些取值才有意义?

以“FIFO 满标志”为例,涉及对象是写指针、读指针、深度参数和 full 信号;值得区分的取值是“指针差等于深度”“指针差等于深度减一”“指针差为零”;有意义的条件是复位释放之后、且写使能有效。把这三者合起来,就得到一个覆盖点:在写使能有效时,采样指针差与 full 的对应关系。这个过程不是一次性的,而是对每条需求重复执行,最终形成一张“需求—覆盖点”对照表。

提取覆盖点时,优先选择设计接口上真实存在、且仿真中可稳定采样的信号。如果某个需求只能通过内部信号判断,应确认该信号是否被层次化引用允许,否则需要改用可观测的等价条件。

covergroup 与 bins 的定义方式

覆盖点确定后,用 SystemVerilog 的 covergroup 承载。covergroup 是采集容器,coverpoint 是单个采样对象,bins 则把连续或离散的取值划分成若干可统计的区间。三者的关系是:一个 covergroup 可以包含多个 coverpoint,一个 coverpoint 可以包含多个 bins,bins 的命中情况最终汇总成覆盖率。

下面是一个与前述 FIFO 需求对应的示例,参数为合理假设,用于说明结构而非实测结果:

covergroup fifo_full_cg @(posedge clk);
  cp_ptr_diff: coverpoint (wr_ptr - rd_ptr) {
    bins empty   = {0};
    bins near    = {[1 : DEPTH-1]};
    bins full    = {DEPTH};
    bins illegal = default;   // 越界或负值,单独统计
  }
  cp_full: coverpoint full {
    bins asserted   = {1};
    bins deasserted = {0};
  }
  // 交叉覆盖:满标志与指针差必须同时成立
  x_full_diff: cross cp_ptr_diff, cp_full;
endgroup

这里有几个关键决策。第一,采样时机由 @(posedge clk) 决定,必须与设计实际更新 full 的节拍一致,否则会采到过渡态。第二,near 用区间表示,避免为深度 64 的 FIFO 写出 63 个独立 bins,但区间过粗会掩盖边界,所以通常把“深度减一”单独拆出来。第三,illegal 用 default 兜底,任何未显式列出的取值都会落入该 bin,一旦命中就说明出现了预期外的指针关系,这本身就是有价值的检查。第四,cross 用于表达组合需求,但交叉会产生 bins 数量相乘的膨胀,只对真正有业务含义的组合建立 cross。

建立需求与覆盖率项的可追溯关系

可追溯关系的本质是给每个覆盖点一个稳定的标识,并把它与需求编号绑定。推荐的做法是在验证计划中为每条需求分配唯一 ID,例如 REQ-FIFO-003,然后在 covergroup 的注释或独立的映射表中记录该 coverpoint 对应的需求 ID。这样覆盖率报告出来时,可以反向回答“REQ-FIFO-003 是否被覆盖”。

映射关系需要覆盖三种情况:一对一(一条需求对应一个 coverpoint)、一对多(一条需求需要多个 coverpoint 共同证明,如满标志既需要指针差也需要 full 信号)、多对一(多条需求共享同一个基础 coverpoint,例如多个功能都依赖复位后的初始状态)。一对多最容易遗漏,因为只覆盖其中一个 coverpoint 时,覆盖率报告会显示部分达标,但需求并未真正验证。

需求 ID需求描述覆盖点覆盖类型判定条件
REQ-FIFO-003写指针追上读指针时置满cp_ptr_diff.full + cp_full.asserted一对多两个 bin 均命中
REQ-FIFO-004读空后 full 必须撤销cp_full.deasserted一对一该 bin 命中
REQ-FIFO-005指针关系不得越界cp_ptr_diff.illegal一对一(反向)该 bin 命中即为失败

注意最后一行的特殊性:illegal bin 的命中不是达标,而是违例。这类“反向覆盖点”在映射表中必须显式标注判定方向,否则覆盖率工具会把它当作普通 bin 统计,导致违例被误读为覆盖成功。

映射链的完整视图

把上述过程串起来,可以看到一条从自然语言需求到可统计覆盖率的完整链路。下图展示了需求条目、覆盖点、covergroup 结构以及追溯标识之间的对应关系,其中一对多和多对一的分支是实际工程中最容易断裂的位置。

验证计划 → 覆盖率模型 映射链 验证计划(需求层) REQ-FIFO-003 写指针追上读指针置满 REQ-FIFO-004 读空后 full 撤销 REQ-FIFO-005 指针关系不得越界 REQ-FIFO-006 复位后初始状态正确 覆盖点(coverpoint) cp_ptr_diff empty / near / full / illegal cp_full asserted / deasserted x_full_diff cross 组合覆盖 cp_reset_state 初始指针与标志 covergroup 容器 fifo_full_cg @(posedge clk) 采样节拍与设计一致 含 3 个 coverpoint + 1 个 cross fifo_reset_cg @(posedge rst_n) 复位释放后采样 含 cp_reset_state 追溯标识:每个 coverpoint 注释中记录 REQ-ID 覆盖率报告可反查需求是否被验证 正向映射 需确认采样条件

图中左侧是需求层,中间是覆盖点层,右侧是 covergroup 容器层。实线箭头表示直接映射,虚线箭头表示该需求需要额外确认采样条件后才能建立覆盖点。底部标注了追溯标识的落点:它不改变覆盖率统计本身,但决定了覆盖率报告能否被用来回答“需求是否验过”这个问题。

映射过程中的常见断裂点

第一类断裂是需求有、覆盖点无。典型原因是需求描述的是时序行为(如“16 个周期内返回响应”),而覆盖点只采了信号值,没有采时间间隔。解决办法是把时间量也做成 coverpoint,例如用计数器采样响应延迟并划分 bins。

第二类断裂是覆盖点有、需求无。这通常来自验证工程师凭经验添加的额外覆盖,本身不是错误,但必须在映射表中标注为“补充覆盖”,否则覆盖率达标会被误认为需求全部验证完毕。

第三类断裂是 bins 划分与需求语义不符。例如需求要求验证“满标志在写指针追上读指针的同一周期置起”,但 bins 只统计了指针差等于深度,没有约束 full 必须同时为 1,此时即使 bin 命中也不能证明需求成立。这类问题只能通过 cross 或采样条件表达式来修复。

映射表不是一次性文档。每当验证计划新增或修改需求,必须同步检查对应 coverpoint 是否存在、bins 划分是否仍然匹配语义、追溯标识是否更新。覆盖率数字本身不会告诉你映射已经失效。