1. 覆盖率基础概念:什么是覆盖率?为什么重要?功能覆盖率与代码覆盖率的区别

各位同学好,我是老张。做芯片验证十几年了,今天咱们聊聊覆盖率这个绕不开的话题。

说实话,我刚入行那会儿,对覆盖率也是一知半解。领导让我跑覆盖率,我就跑;让我看报告,我就看。但到底什么是覆盖率?为什么它这么重要?功能覆盖率和代码覆盖率有啥区别?这些问题,我当时也说不清楚。

直到有一次,我负责的一个消费电子芯片项目,功能仿真都过了,代码覆盖率也到了95%以上。结果流片回来,有个场景死活跑不通。查了三天,才发现是一个很偏的输入组合没覆盖到。嗯,从那以后,我再也不敢小看覆盖率了。

1.1 什么是覆盖率?

覆盖率,说白了就是衡量你的验证工作做得有多「全」的一个指标。

你想想看,一个芯片有几百万、几千万个门。你写的测试用例,到底跑了多少?哪些电路被激活了?哪些状态被访问了?哪些条件被触发了?覆盖率就是回答这些问题的。

我个人习惯把覆盖率比作「探照灯」。你的验证环境是一盏灯,覆盖率就是这盏灯照亮的区域。照到的地方,你心里有底;没照到的地方,就是风险区。

核心定义:覆盖率 = (已覆盖的验证点数量 / 总验证点数量) × 100%

这里要注意,覆盖率不是越高越好,但太低肯定不行。我见过有些团队把覆盖率做到99.9%还不敢流片,也见过80%就敢 tapeout 的。关键看你覆盖的是什么,以及你的产品风险容忍度。

1.2 为什么覆盖率重要?

这个问题,我换个角度回答你:没有覆盖率的验证,就是盲人摸象。

具体来说,覆盖率的重要性体现在三个方面:

  • 衡量验证完整性:你跑了1000个用例,但可能只覆盖了20%的代码。没有覆盖率数据,你根本不知道。
  • 发现验证盲区:覆盖率报告会告诉你哪些地方没跑到。我曾经在一个项目中,通过覆盖率发现了一个从未被触发的状态机状态,那个状态正好对应一个硬件bug。
  • 指导测试用例编写:覆盖率低了,你就知道该往哪个方向补充用例。而不是盲目地加随机测试。

我的经验:覆盖率不是用来「交差」的,而是用来「找漏洞」的。每次看到覆盖率报告,我第一反应不是「达标了没」,而是「哪些地方还没跑到,为什么没跑到」。

1.3 功能覆盖率 vs 代码覆盖率

这两个概念,很多新手容易搞混。我当年也犯过这个错。

简单来说:代码覆盖率看「代码跑没跑」,功能覆盖率看「功能测没测」。

下面这张图,是我自己画的,帮你理清两者的关系:

覆盖率分类与关系图 覆盖率 代码覆盖率 功能覆盖率 行覆盖率 分支覆盖率 条件覆盖率 状态机覆盖率 输入组合 协议序列 边界条件 交叉覆盖 代码覆盖率:自动收集,反映「代码执行程度」 功能覆盖率:手动定义,反映「功能验证深度」

代码覆盖率

代码覆盖率是工具自动帮你收集的。你跑仿真,工具就记录哪些代码行被执行了,哪些分支被走过了。

常见的代码覆盖率类型包括:

类型 含义 我的经验
行覆盖率 每行代码是否被执行 最基础,但容易「虚高」
分支覆盖率 if-else、case 的每个分支是否走到 我遇到过分支覆盖100%,但条件组合漏了的情况
条件覆盖率 每个子条件的 true/false 是否都覆盖 这个容易被忽略,但很重要
状态机覆盖率 状态机的每个状态和跳转是否覆盖 我曾经靠这个抓到一个死循环bug

注意:代码覆盖率100% ≠ 验证完备。代码覆盖率只能告诉你「代码跑了」,但不能告诉你「功能对了」。我见过代码覆盖率95%以上的模块,功能覆盖率只有30%。

功能覆盖率

功能覆盖率就不一样了。它不是工具自动生成的,而是你根据设计规格书,手动定义出来的。

说白了,代码覆盖率是「被动」的——工具帮你统计。功能覆盖率是「主动」的——你自己定义要测什么。

举个例子:

// 代码覆盖率:工具自动统计
always @(posedge clk) begin
  if (data_valid & fifo_not_full) begin
    fifo_write <= 1'b1;  // 这行被执行了吗?
  end
end

// 功能覆盖率:手动定义
covergroup fifo_cg;
  option.per_instance = 1;
  coverpoint data_valid;
  coverpoint fifo_not_full;
  cross data_valid, fifo_not_full;  // 我要确保四种组合都测到
endgroup

你看,代码覆盖率只关心那行代码有没有被执行。但功能覆盖率关心的是:data_valid 和 fifo_not_full 的四种组合,是不是都测到了。

1.4 两者的关系:互补而非替代

很多团队有个误区:代码覆盖率达标了,就觉得验证够了。或者反过来,功能覆盖率做好了,就不管代码覆盖率了。

这两种想法都不对。

  • 代码覆盖率是「底线」:它告诉你有没有代码是「死代码」或者没跑到。我一般要求代码覆盖率至少90%以上,关键模块95%以上。
  • 功能覆盖率是「天花板」:它告诉你功能验证的深度够不够。这个没有固定标准,取决于你的产品规格和风险要求。

我的建议:先跑代码覆盖率,确保所有代码都被执行过。然后重点做功能覆盖率,把设计规格书里的每个功能点都转化成覆盖组。两者结合,才是完整的验证策略。

最后说一句:覆盖率是工具,不是目的。我们的目的是找到bug,确保芯片功能正确。覆盖率只是帮我们衡量「找得够不够」的一把尺子。

好了,这一章就到这里。下一章我们聊聊如何搭建覆盖率驱动的验证环境。


专注资料整理