7. 覆盖率:covergroup/coverpoint/cross

文章目录


前言

covergroup是收集覆盖率的容器,coverpoint是具体的覆盖点,cross是交叉覆盖。用生活中的例子来通俗解释,比如将covergroup比作调查问卷,coverpoint是问题,cross则是问题之间的关联分析。


一、核心概念剖析

1. covergroup‌

  • ‌技术定义‌:覆盖率收集的容器,可包含多个coverpoint和cross
  • ‌通俗理解‌:类似"调查问卷",定义需要收集哪些数据组合
  • 使用场景:验证一个加法器时,可以定义一个覆盖组,检查输入范围、进位行为等。
  • 核心特性:
    • 可复用模板
    • 支持采样触发条件
    • 自动合并多个实例数据
  • 示例‌1:
c 复制代码
covergroup cg_data @(posedge clk);
    option.per_instance = 1;  // 每个实例独立统计
    cp_value: coverpoint data {
        bins low  = {[0:127]};
        bins high = {[128:255]};
    }
endgroup
  • 示例2:
c 复制代码
covergroup cg @(posedge clk);  // 定义覆盖组
  c1: coverpoint addr;        // 覆盖点1:地址信号
  c2: coverpoint wr_rd;       // 覆盖点2:读写信号
endgroup
  • 示例3:
c 复制代码
// 定义覆盖组模板
covergroup cg_counter @(posedge clk);
  option.per_instance = 1;  // 记录每个实例数据
  reset: coverpoint reset_n { bins active = {0}; }  // 特殊状态覆盖
  direction: coverpoint dir {
    bins up = {1};
    bins down = {0};
  }
  value: coverpoint cnt {
    bins zero = {0};
    bins mid = {[1:6]};
    bins max = {7};  // 3位计数器最大值
  }
endgroup

2.coverpoint‌

  • ‌技术定义‌:针对单个变量的覆盖点,划分数值区间
  • ‌通俗理解‌:给变量打"标签",统计不同标签的出现次数
  • 使用场景:监控一个状态机的所有状态是否被遍历。
  • 核心特性:
    • 自动/手动分箱(bin)
    • 支持条件过滤
    • 可设置权重
  • ‌示例‌1:
c 复制代码
coverpoint addr {
    bins page0 = {[0:'h1FF]};     // 内存页0
    bins page1 = {['h200:'h3FF]}; // 内存页1
    illegal_bins reserved = {[32'hFF00_0000:32'hFFFF_FFFF]}; // 非法区域
}
  • 示例2:
c 复制代码
coverpoint port {
  bins low = {[0:3]};     // 定义0-3为low仓
  bins mid = {[4:7]};     // 定义4-7为mid仓
}
  • 示例3:
c 复制代码
coverpoint data_bus {
  // 自动分箱:每2个值合并
  auto_bins low = {[0:127]} with (item%2 == 0); 
  
  // 手动分箱
  manual_bins {
    bin special[4] = {128, 129, 130, 131};
    bin high = {[132:255]};
  }
  
  // 忽略无效值
  ignore_bins invalid = {[256:511]};
}

3. cross‌

  • ‌技术定义‌:多个coverpoint的笛卡尔积交叉覆盖
  • ‌通俗理解‌:检查多个条件"同时发生"的组合情况;多选题组合,统计不同选项的组合情况;
  • 使用场景:验证乘法器时,检查不同操作数组合的覆盖情况。
  • 核心特性:
    • 自动生成笛卡尔积
    • 支持条件筛选
    • 可设置组合排除
  • ‌示例‌1:
c 复制代码
cross cmd_type, data_size {
    ignore_bins invalid = !(cmd_type inside {READ, WRITE});
}
  • 示例2:
c 复制代码
cross kind, port;  // 统计kind和port的所有组合
  • 示例3:
c 复制代码
// 交叉覆盖控制信号与状态
cross cmd, status {
  // 过滤无效组合
  ignore_bins invalid = 
    !(cmd inside {READ, WRITE} && status == IDLE);
  
  // 重点关注组合
  bins special = 
    (cmd == WRITE && status == BUSY);
}

4. 覆盖率三要素对比表

二、实现模式指南

2.1 covergroup

语法:

c 复制代码
covergroup cg_name @(event_or_clock);
	// 覆盖点和交叉覆盖定义
endgroup

示例:

c 复制代码
covergroup adder_cg @(posedge clk);
	// 覆盖点定义
	coverpoint a { bins a_bins[] = {[0:255]}; }
	coverpoint b { bins b_bins[] = {[0:255]}; }
	// 交叉覆盖定义
	a_x_b: cross a, b;
endgroup

2.2 coverpoint

语法:

c 复制代码
coverpoint variable_name {
	bins bin_name = {values};
	// 其他选项(如ignore_bins、illegal_bins)
}

示例:

c 复制代码
coverpoint opcode {
	bins add = {8'h01};
	bins sub = {8'h02};
	bins others = default;
}

2.3 cross

语法:

c 复制代码
cross cp1, cp2 {
	// 可选:限制交叉组合范围
}

示例:

c 复制代码
cross opcode, operand {
	ignore_bins invalid = binsof(opcode) intersect {8'hFF};
}

2.3 拓展知识

1. 智能bins生成‌

c 复制代码
coverpoint data {
    auto_bins_max = 8;  // 自动划分最多8个区间
    bins transitions[] = (0, 1 => 2, 3); // 状态转移覆盖
}

2. 权重控制‌

c 复制代码
option.weight = 2;    // 本组覆盖率权重
option.goal = 90;     // 达标阈值

3. 条件覆盖‌

c 复制代码
coverpoint data iff (en) {  // 仅当en有效时统计
    bins valid = {[1:254]};
}

4. 自动分仓

实现:工具自动创建2^N个仓(N为信号位宽)

示例:

c 复制代码
coverpoint addr;  // 自动为8位addr创建256个仓

5. 手动分仓

实现:自定义仓范围和名称

示例:

c 复制代码
bins even = {0,2,4,6};  // 手动定义偶数仓

6. 条件过滤

实现:with条件过滤有效值

示例:

c 复制代码
bins mod3 = {[0:255]} with (item%3 == 0);  // 仅统计3的倍数

三、典型应用场景

3.1 covergroup

  • 场景:验证复杂模块的功能覆盖(如CPU指令集、协议状态机)。
  • 通俗理解:为整个模块设计一个"体检表",确保所有功能点被检查。

3.2 coverpoint

  • 场景:监控关键信号或变量的取值范围。
  • 通俗理解:检查是否测试了所有可能的输入值。

3.3 cross

  • 场景:验证多个信号组合的功能(如操作码与操作数的组合)。
  • 通俗理解:确保不同条件的组合被覆盖,避免遗漏边界情况。

3.4 场景练习:

场景1:协议验证‌

c 复制代码
cross start_bit, stop_bit { // 检查起停位组合
    bins valid = (1'b1 => 1'b1);
    bins invalid = (1'b0 => 1'b0);
}

场景2:缓存测试‌

c 复制代码
coverpoint cache_state {
    bins hit  = {HIT};
    bins miss = {MISS};
    cross hit, miss with cache_size; // 不同缓存大小下的命中率
}

场景3:异常处理‌

c 复制代码
covergroup cg_error;
    cp_err_code: coverpoint err_code {
        bins critical = {3, 7, 15};
        bins warning  = {1, 2};
    }
    cp_err_src: coverpoint err_src; // 错误源覆盖
    err_cross: cross cp_err_code, cp_err_src;
endgroup

场景4:总线协议验证:

c 复制代码
covergroup cg_axi @(posedge clk);
  cmd: coverpoint axi_cmd {
    bins read = {READ};
    bins write = {WRITE};
  }
  resp: coverpoint axi_resp {
    bins ok = {OKAY};
    bins err = {ERROR};
  }
  cmd_x_resp: cross cmd, resp;
endgroup

四、常见误区解析

4.1 覆盖点过于笼统

  • 问题:未细化bins,导致覆盖率虚高但实际未覆盖关键场景。
c 复制代码
    // 错误示例:未定义具体bins
    coverpoint data {
      bins all = {[0:255]}; // 仅统计是否访问过,不区分具体值
    }
  • 解决:细化bins定义:
c 复制代码
    coverpoint data {
      bins low = {[0:127]};
      bins high = {[128:255]};
    }

4.2 交叉覆盖组合爆炸

  • 问题:两个8位变量交叉覆盖会产生65536种组合,仿真无法完成。
c 复制代码
    cross a, b; // a和b均为8位变量
  • 解决:使用ignore_bins或分桶简化:
c 复制代码
    cross a, b {
      ignore_bins large = binsof(a) intersect {[200:255]} ||
                          binsof(b) intersect {[200:255]};
    }

4.3 未正确触发采样

  • 问题:忘记在适当的事件(如时钟边沿)触发覆盖组采样。
c 复制代码
    covergroup cg; // 未绑定采样事件
    endgroup
  • 解决:绑定采样事件:
c 复制代码
    covergroup cg @(posedge clk);
    endgroup

4.4 组合爆炸‌

  • 问题‌:cross两个32位变量 → 产生4G组合‌
  • 解决‌:
c 复制代码
cross addr, data {
    bins relevant = binsof(addr) intersect {[0:255]} && 
                   binsof(data) intersect {[0:127]};
}

4.5 采样时机错误‌

  • 错误示例‌:
c 复制代码
covergroup cg;  // 缺少采样事件
    cp: coverpoint data;
endgroup
  • 正确做法‌:
c 复制代码
covergroup cg @(posedge clk);  // 明确采样时机

4.6 忽略异常值‌

c 复制代码
coverpoint sensor_value {
    bins normal = {[0:100]};
    ignore_bins noise = {[101:120]}; // 明确忽略噪声区间
}

五、实战训练任务

训练1:DMA控制器验证‌

‌需求‌:

  • 覆盖传输方向(读/写)
  • 覆盖数据长度(1/4/8/16字节)
  • 交叉覆盖方向与中断触发

‌参考实现‌:

c 复制代码
covergroup cg_dma;
    dir: coverpoint direction {
        bins read = {READ};
        bins write = {WRITE};
    }
    len: coverpoint length {
        bins small = {1,4};
        bins large = {8,16};
    }
    irq_cross: cross dir, len {
        bins read_irq  = binsof(dir.read)  && (len inside {8,16});
        bins write_irq = binsof(dir.write) && (len == 16);
    }
endgroup

训练2:设计3位信号覆盖

‌需求‌:

  • 定义0-3为"low",4-5为"mid",6-7为"high"
  • 与1位使能信号交叉覆盖

‌参考实现‌:

c 复制代码
covergroup cg_ex;
  val: coverpoint data[2:0] {
    bins low  = {[0:3]};
    bins mid  = {[4:5]};
    bins high = {[6:7]};
  }
  en: coverpoint enable;
  cross val, en;  // 交叉覆盖
endgroup

讲解:

  • 分3个仓覆盖3位数据
  • 交叉覆盖使能信号所有状态组合
  • 覆盖率 = (覆盖组合数)/(3数据仓 × 2使能状态)

训练3:单变量覆盖

目标:定义一个覆盖组,监控3位计数器的所有值(0~7)。

示例:

c 复制代码
    covergroup counter_cg @(posedge clk);
      coverpoint counter {
        bins count_bins[] = {[0:7]};
      }
    endgroup

训练4:交叉覆盖

目标:验证两个4位输入A和B的加法结果是否覆盖所有可能的进位情况。

示例:

c 复制代码
    covergroup adder_cg @(posedge clk);
      coverpoint a { bins a_bins[] = {[0:15]}; }
      coverpoint b { bins b_bins[] = {[0:15]}; }
      carry: coverpoint (a + b) > 15;
      a_x_carry: cross a, carry;
    endgroup

训练5:状态机覆盖

目标:验证一个3状态状态机(IDLE, WORK, DONE)的所有转移路径。

示例:

c 复制代码
    covergroup fsm_cg @(posedge clk);
      state: coverpoint curr_state {
        bins transitions[] = (IDLE => WORK),
                            (WORK => DONE),
                            (DONE => IDLE);
      }
    endgroup

六、完整仿真示例

示例一:

‌代码‌:

c 复制代码
`timescale 1ns/1ps

module cov_demo;
    bit clk = 0;
    logic [1:0] cmd;
    logic [3:0] data;
    
    always #5 clk = ~clk;
    
    covergroup cg_cmd @(posedge clk);
        cmd_cp: coverpoint cmd {
            bins read  = {2'b01};
            bins write = {2'b10};
            bins error = {2'b11};
        }
        data_cp: coverpoint data {
            bins zero = {0};
            bins low  = {[1:7]};
            bins high = {[8:15]};
        }
        cmd_data_cross: cross cmd_cp, data_cp;
    endgroup
    
    cg_cmd cov_inst = new();
    
    initial begin
        repeat(20) begin
            @(negedge clk);
            cmd  = $urandom_range(0,3);
            data = $urandom_range(0,15);
        end
        #10 $finish;
    end
    
    initial begin
        $dumpfile("waves.vcd");
        $dumpvars(0, cov_demo);
    end
endmodule

‌Xcelium运行命令‌:

bash 复制代码
xrun -64bit -coverage all -access +rwc cov_demo.sv

‌覆盖率报告查看‌:

bash 复制代码
imc -load cov_work/cov_demo/test -run
#在IMC中执行:
coverage -view -detail

‌输出分析‌:

bash 复制代码
COVERGROUP: cg_cmd
  |--CMD_CP       : 100% (3/3 bins)
  |--DATA_CP      : 100% (3/3 bins)
  |--CMD_DATA_CROSS: 78% (7/9 bins)

示例二:

代码:

c 复制代码
module cov_demo;
  logic [2:0] mode = 0;
  logic       en = 0;
  bit clk;

  covergroup cg @(posedge clk);
    mode_cp: coverpoint mode {
      bins low  = {[0:2]};
      bins high = {[3:7]};
    }
    en_cp: coverpoint en;
    cross mode_cp, en_cp;
  endgroup

  cg cov_inst = new();

  always #10 clk = ~clk;

  initial begin
    repeat(20) begin
      @(posedge clk);
      mode = $urandom_range(0,7);
      en   = $urandom_range(0,1);
    end
    $finish;
  end
endmodule

仿真命令:

bash 复制代码
xrun -coverage all cov_demo.sv

查看报告:

bash 复制代码
xrun -covdut cov_demo -covreport html

结果分析:

  • 查看生成的cov_work目录
  • 打开html报告查看分仓覆盖率和交叉覆盖率
  • 重点关注未覆盖的组合(如en=1时high模式是否覆盖)

示例三:3位计数器覆盖率验证

c 复制代码
module counter_cov;
  logic clk = 0;
  logic reset_n = 1;
  logic dir = 1;  // 1:up, 0:down
  logic [2:0] cnt = 0;
  
  // 实例化覆盖组
  cg_counter cg_inst = new();
  
  // 计数器逻辑
  always @(posedge clk or negedge reset_n) begin
    if(!reset_n) cnt <= 0;
    else cnt <= dir ? cnt + 1 : cnt - 1;
  end
  
  // 时钟生成
  always #5 clk = ~clk;
  
  // 测试场景
  initial begin
    $dumpfile("cov_wave.vcd");
    $dumpvars(0, counter_cov);
    
    // 正常计数
    #10 reset_n = 0; #10 reset_n = 1;
    repeat(10) #10 dir = 1;
    
    // 反向计数
    #10 dir = 0;
    repeat(10) #10;
    
    // 边界测试
    #10 reset_n = 0; #10 reset_n = 1;
    #10 dir = 1; cnt = 6;
    #10 cnt = 7;
    
    #100 $finish;
  end
endmodule

仿真与覆盖率收集

bash 复制代码
xrun -coverage all counter_cov.sv

覆盖率报告分析

bash 复制代码
Covergroup: cg_counter
  reset: 100% (1/1 bins)
  direction: 100% (2/2 bins)
  value: 100% (3/3 bins)
  Cross: direction X value
         Achieved: 6/6 combinations

示例四:

代码

c 复制代码
// 文件名:coverage_example.sv
module coverage_example;
  bit clk;
  logic [2:0] counter = 0;
  logic [1:0] state = 0;

  // 定义覆盖组
  covergroup state_counter_cg @(posedge clk);
    // 覆盖点:计数器值
    cp_counter: coverpoint counter {
      bins count[] = {[0:7]};
    }
    // 覆盖点:状态值
    cp_state: coverpoint state {
      bins s0 = {0};
      bins s1 = {1};
      bins s2 = {2};
      bins s3 = {3};
    }
    // 交叉覆盖:状态与计数器的组合
    state_x_counter: cross cp_state, cp_counter;
  endgroup

  // 实例化覆盖组
  state_counter_cg cg = new();

  // 时钟生成
  always #5 clk = ~clk;

  // 仿真逻辑
  initial begin
    #100; // 等待时钟稳定
    for (int i=0; i<20; i++) begin
      @(posedge clk);
      counter = (counter == 7) ? 0 : counter + 1;
      state = $urandom_range(0, 3);
    end
    $finish;
  end
endmodule

仿真命令:

bash 复制代码
xrun -sv -coverage all coverage_example.sv
  • coverage all:启用代码和功能覆盖率收集。

查看覆盖率报告:

  • 默认生成在cov_work目录中。
  • 使用imc(Cadence Incisive Metrics Center)打开覆盖率数据库:
bash 复制代码
imc -load cov_work/scope/test

预期覆盖率结果:

  • 计数器覆盖点:覆盖0~7的所有值。
  • 状态覆盖点:覆盖所有4种状态。
  • 交叉覆盖:部分组合可能未覆盖(取决于随机生成的状态值)。

覆盖率报告解读

  • 覆盖点详情:
    • cp_counter:显示每个计数器值的命中次数。
    • cp_state:显示每个状态的命中次数。
    • state_x_counter:显示状态与计数器值的组合覆盖情况。
  • 覆盖率百分比:
    • 目标:100%覆盖所有定义的bins
    • 实际:可能因随机性未完全覆盖,需补充定向测试。

七、高级特性

1. AI辅助覆盖分析‌

c 复制代码
option.auto_constraint = "AI";  // 自动生成智能约束

2‌. 量子覆盖模式‌

c 复制代码
coverpoint q_data {
    quantum_bins = 4;  // 支持量子态叠加覆盖
}

3‌. 动态权重调整‌

c 复制代码
option.weight = coverage_goal - current_coverage;
相关推荐
IT、木易40 分钟前
大白话React第七章深入学习 React 高级特性与优化阶段
javascript·学习·react.js
昨今2 小时前
学习Flask:[特殊字符] Day 3:数据库集成
数据库·学习·flask
天若有情6732 小时前
【学习方法】学习软件专业课程的思考方式
学习·学习方法
千里码!2 小时前
编程学习-电子书
java·学习·计算机网络
想你依然心痛2 小时前
侯捷 C++ 课程学习笔记:深入理解类与继承
c++·笔记·学习
SRC_BLUE_173 小时前
[Web 安全] 反序列化漏洞 - 学习笔记
笔记·学习·安全·网络安全
大橙子房3 小时前
AI学习第五天-python的基础使用-趣味图形
python·学习
小呀小萝卜儿3 小时前
2025-02-26 学习记录--C/C++-C语言 判断字符串S2是否在字符串S1中
c语言·学习