3、交叉覆盖:交叉覆盖(cross cover)的定义、排除非法组合与权重设置
好,咱们接着聊交叉覆盖。说实话,交叉覆盖这个概念,刚接触UVM的朋友容易把它想复杂了。其实说白了,就是「两个或两个以上的coverpoint组合起来看」。你单独看每个coverpoint可能都覆盖到了,但组合在一起呢?有没有遗漏的场景?这才是交叉覆盖要回答的问题。
3.1 交叉覆盖的定义
交叉覆盖,英文叫 cross cover。它的核心思想很简单:
把多个coverpoint的值域做笛卡尔积,然后统计每个组合是否被触发过。
举个例子。假设我们有一个总线协议,有两个信号:
- cmd:取值可以是 READ、WRITE、IDLE
- burst:取值可以是 SINGLE、INCR、WRAP
单独覆盖 cmd 和 burst 没问题。但你想过没有?
READ + WRAP 这种组合是否合法?
IDLE + INCR 会不会出现?
这些组合如果不做交叉覆盖,你根本不知道。
核心定义:交叉覆盖是 SystemVerilog 中通过 cross 关键字,将多个 coverpoint 的 bin 做组合覆盖。每个组合称为一个 cross bin。
我个人习惯,在写大型验证环境时,交叉覆盖是必加的。尤其是当协议有状态机、有不同操作模式时,交叉覆盖能帮你发现「模式A + 操作B」这种边界场景。
3.2 排除非法组合
这里有个坑,我踩过好几次。
你想想看,两个coverpoint的笛卡尔积,组合数是指数级增长的。
如果每个coverpoint有10个bin,两个就是100个组合,三个就是1000个。
但很多组合在实际协议中是非法的,根本不会出现。
如果不排除非法组合,会有什么后果?
嗯,后果就是:你的覆盖率报告里会出现一堆「未覆盖」的bin。
这些bin永远不可能被覆盖到,但它们会拉低你的覆盖率数字。
你花大量时间去分析,结果发现是非法组合——浪费时间。
怎么排除? 用 ignore_bins 或者 illegal_bins。
- ignore_bins:忽略这些组合,不参与覆盖率统计。
- illegal_bins:如果出现这些组合,直接报错。用于检查协议违例。
我曾经在一个AHB验证项目中,cmd和burst有32种组合,但协议只允许其中12种。我一开始没加ignore_bins,结果覆盖率卡在75%上不去。排查了两天才发现是非法组合在作祟。后来我加了个自动生成ignore_bins的脚本,一劳永逸。
小技巧:写交叉覆盖前,先列一张「合法组合表」。把协议文档翻出来,一行一行对。别偷懒,这一步省不了。
3.3 权重设置
权重设置,说白了就是「给不同的cross bin分配不同的重要性」。
为什么需要权重?
因为不是所有组合都同等重要。
有些组合是核心场景,必须覆盖到。
有些组合是边界场景,覆盖到更好,没覆盖到也能接受。
SystemVerilog 里,权重通过 weight 关键字来设置。默认权重是1。你可以把关键组合的权重设高,比如2或3,这样它们在总体覆盖率中的占比更大。
举个例子:
covergroup cg_with_weight @(posedge clk);
cmd_cp : coverpoint cmd {
bins read = {READ};
bins write = {WRITE};
bins idle = {IDLE};
}
burst_cp : coverpoint burst {
bins single = {SINGLE};
bins incr = {INCR};
bins wrap = {WRAP};
}
cmd_x_burst : cross cmd_cp, burst_cp {
// 排除非法组合
ignore_bins illegal_combos = binsof(cmd_cp) intersect {IDLE}
&& binsof(burst_cp) intersect {INCR, WRAP};
// 设置权重:核心组合权重2,其他默认1
weight = 2; // 整个cross的权重
// 也可以针对单个bin设置
bins core_combos = (binsof(cmd_cp.read) && binsof(burst_cp.single))
|| (binsof(cmd_cp.write) && binsof(burst_cp.incr));
// 注意:单个bin的权重设置语法较复杂,通常用全局weight
}
endgroup
注意:权重设置要谨慎。设得太高,会导致覆盖率数字虚高——核心组合覆盖了,但边缘组合全空着,覆盖率数字却很好看。这反而掩盖了问题。
我个人建议,权重只用在两种场景:
- 核心功能组合:比如读写操作的正确组合,权重可以设为2。
- 异常组合:比如错误响应+重试,权重设为1.5或2,确保它们被覆盖到。
其他常规组合,保持默认权重1就好。别搞得太复杂,否则你自己都算不清覆盖率到底代表什么。
3.4 知识体系图
下面这张图,是我画的一个交叉覆盖核心逻辑图。你看一眼就明白了。
3.5 实战建议
最后,我总结几条实战经验:
- 先列合法组合表:别急着写代码。拿张纸,把协议允许的组合列出来。这一步花30分钟,能省你后面3天。
- ignore_bins 要写全:漏掉一个非法组合,你的覆盖率就多一个永远填不上的坑。
- 权重别乱设:除非你很清楚某个组合的重要性,否则保持默认。权重设高了,覆盖率数字会骗人。
- 交叉覆盖别太多:3个coverpoint交叉,组合数就可能上千。我建议最多交叉2~3个,再多就拆成多个小的cross。
避坑指南:我曾经在一个项目里,把5个coverpoint做了交叉,结果生成了上万个bin。仿真跑了一整天,覆盖率才到30%。后来我拆成3个小的cross,每个只交叉2~3个coverpoint,覆盖率很快就上去了。记住:交叉覆盖不是越多越好,够用就行。
好了,交叉覆盖就聊到这儿。记住三个关键词:笛卡尔积、排除非法、权重设置。把这三点吃透了,交叉覆盖这块你就拿下了。