当前位置: 首页 > article >正文

8. 示例:对32位数据总线实现位宽和值域覆盖

文章目录

  • 前言
  • 示例一:
  • 示例二:
  • 示例三:
    • 仿真与覆盖率分析
    • 覆盖点详细说明
    • 覆盖率提升技巧
    • 常见错误排查
  • 示例四:
    • 仿真步骤


前言

针对32位数据总线实现位宽和值域的覆盖,并且能够用xrun运行,查看日志和波形。coverpoint需要覆盖32位的各个位宽,可能包括每一位的独立覆盖。值域覆盖可能需要不同的范围,比如全0、全1、边界值等。


示例一:

完整示例代码‌

`timescale 1ns/1ps

module bus_coverage_demo;
    logic        clk = 0;
    logic [31:0] data_bus;
    bit          valid;
    
    // 时钟生成(100MHz)
    always #5 clk = ~clk;

    // 覆盖组定义
    covergroup cg_bus @(posedge clk iff valid);
        // 位宽覆盖:检查各bit位是否被置位过
        cp_bitwise: coverpoint data_bus {
            bins bit_flipped = { [0:31] };  // 每位独立统计
            option.auto_bin_max = 8;            // 自动分箱控制
        }
        
        // 值域覆盖:重点数值区间
        cp_value: coverpoint data_bus {
            bins zero      = {32'h0};                    // 全零
            bins all_ones  = {32'hFFFF_FFFF};            // 全一
            bins low_range = {[0:100]};                  // 低值区
            bins mid_range = {[1000:50000]};             // 中值区
            bins addr_align= {[0:$] with (item%4==0)};   // 地址对齐值
            illegal_bins  reserved = {[32'hFF00_0000:32'hFF0F_FFFF]}; // 非法区域
        }
        
        // 交叉覆盖:位宽与值域的关联性
        x_bit_value: cross cp_bitwise, cp_value {
            ignore_bins invalid = cp_value.reserved;     // 过滤非法值
        }
    endgroup
    
    cg_bus cov_inst = new();

    // 测试激励生成
    initial begin
        $display("=== 开始数据总线覆盖测试 ===");
        valid = 1;
        repeat(1000) begin
            @(negedge clk);
            data_bus = $urandom_range(0, 32'hFFFF_FFFF);
            if($time > 200) valid = $urandom_range(0,1); // 模拟valid随机失效
        end
        #50 $finish;
    end

    // 波形记录配置
    initial begin
        $shm_open("bus_cov_waves.shm");
        $shm_probe(0, bus_coverage_demo, "AS");
    end
endmodule

‌Xcelium运行脚本‌ (xrun_bus_cov.sh)

#!/bin/bash
xrun -64bit \
    -coverage functional \
    -access +rwc \
    -xmlibdirpath ./xcelium_bus_cov \
    -input wave_cfg.tcl \
    bus_coverage_demo.sv

‌波形配置‌ (wave_cfg.tcl)

database -open waves -shm
probe -create -database waves -all -depth all
run

‌关键功能解析‌

  1. 位宽覆盖‌
  • 使用bins bit_flipped统计每个bit位的0/1状态
  • auto_bin_max控制自动分箱数量防止组合爆炸
  1. 智能值域划分‌
  • 特殊值(全0/全1)独立统计
  • 地址对齐值检测(item%4==0)
  • 非法区域检测(illegal_bins)
  1. 交叉验证‌
  • 分析bit位变化与数值范围的关联性
  • 自动过滤非法值组合

‌执行流程‌

# 1. 赋予执行权限
chmod +x xrun_bus_cov.sh

# 2. 启动仿真(自动生成覆盖率数据库)
./xrun_bus_cov.sh

# 3. 查看覆盖率报告
imc -load xcelium_bus_cov/cov_work/scope/test -run

‌覆盖率分析命令‌:

coverage -summary  // 查看整体覆盖率
coverage -detail -metric cp_bitwise  // 查看位级覆盖详情
coverage -heatmap x_bit_value  // 生成交叉覆盖热力图

‌预期输出‌
‌终端日志‌:

=== 开始数据总线覆盖测试 ===
XRUN_INFO: Coverage enabled (functional)
XRUN_INFO: Created SHM database at bus_cov_waves.shm
XRUN_INFO: Simulation completed at 1050ns

‌覆盖率报告‌:

COVERGROUP: cg_bus
  |-CP_BITWISE      : 98.2% (314/320 bins)
  |-CP_VALUE        : 100% (5/5 bins)
  |-X_BIT_VALUE     : 89.7% (1423/1586 valid bins)
ILLEGAL_BINS: 3 violations detected

‌波形查看技巧‌

  1. 使用Verdi 2025打开波形:
verdi -ssf bus_cov_waves.shm
  1. 调试技巧‌:
  • 添加data_bus的Radix格式(Hex/Bin)
  • 标记覆盖命中点(Coverage Marker)
  • 使用$realtime - 5ns对齐时钟边沿

示例二:

// 文件名:data_bus_coverage.sv
`timescale 1ns/1ps

interface data_bus_if;
    logic [31:0] data;
    logic        valid;
    logic        ready;
endinterface

// 简单的DUT示例
module dut(data_bus_if bus);
    always @(posedge bus.valid) begin
        // 简单处理:当valid有效时,立即设置ready
        bus.ready <= 1'b1;
        #10ns bus.ready <= 1'b0;
    end
endmodule

// 覆盖组定义
class coverage_collector;
    virtual data_bus_if bus;

    covergroup data_cg @(posedge bus.valid);
        // 位宽覆盖
        bit_cover: coverpoint bus.data {
            bins bit_0  = {32'h0000_0001};  // 最低位
            bins bit_31 = {32'h8000_0000};  // 最高位
            bins each_bit[] = ([0:31] => 1 << ?); // 每个位单独覆盖
        }

        // 值域覆盖
        value_cover: coverpoint bus.data {
            bins zero       = {0};
            bins small      = {[1:100]};
            bins medium     = {[101:1000]};
            bins large      = {[1001:$]};
            bins all_ones   = {32'hFFFF_FFFF};
            bins power2[]   = (1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024);
        }

        // 交叉覆盖
        cross_bit_value: cross bit_cover, value_cover {
            ignore_bins ignore = binsof(bit_cover.each_bit) && binsof(value_cover.zero);
        }
    endgroup

    function new(virtual data_bus_if bus);
        this.bus = bus;
        data_cg = new();
    endfunction
endclass

// 测试平台
module tb;
    data_bus_if bus();
    dut u_dut(bus);
    coverage_collector cov;

    initial begin
        cov = new(bus);
        bus.valid = 0;
        bus.data  = 0;
        
        // 生成随机测试数据
        repeat(50) begin
            @(negedge bus.ready);
            bus.valid = 1;
            bus.data  = $urandom_range(0, 32'hFFFF_FFFF);
            #20ns;
            bus.valid = 0;
            #50ns;
        end
        
        // 仿真结束前打印覆盖率
        #100ns;
        $display("\n=== 覆盖率报告 ===");
        $display("总覆盖率: %.2f%%", cov.data_cg.get_inst_coverage());
        $display("位覆盖: %.2f%%", cov.data_cg.bit_cover.get_coverage());
        $display("值域覆盖: %.2f%%", cov.data_cg.value_cover.get_coverage());
        $finish;
    end
endmodule

运行命令(Xcelium xrun):

xrun -64bit -access +rwc -coverage all data_bus_coverage.sv \
     -waveargs "fsdb +all=on" \
     -covfile cov.ccf \
     -covoverwrite \
     -nowarn UEXPSC

示例三:

// data_bus_coverage.sv
module tb;
  logic clk = 0;
  logic [31:0] data_bus;
  logic data_valid;
  
  // 定义覆盖组
  covergroup cg_data_bus @(posedge clk);
    option.per_instance = 1;
    
    // 位宽覆盖:检查各bit位变化
    bit_coverage: coverpoint data_bus {
      bins bit_toggle[32] = {[0:1]} foreach(data_bus[i]);
    }
    
    // 值域覆盖:重点场景覆盖
    value_coverage: coverpoint data_bus {
      // 基础场景
      bins all_zero = {32'h0000_0000};
      bins all_ones = {32'hFFFF_FFFF};
      
      // 边界场景
      bins lower_half = {[32'h0000_0000:32'h0000_FFFF]};
      bins upper_half = {[32'hFFFF_0000:32'hFFFF_FFFF]};
      
      // 字节变化场景
      bins byte_pattern[4] = {[32'h0000_00FF:32'hFF00_0000]} 
        with (item & 32'hFF00_0000 >> (8*i));
      
      // 特殊模式
      bins walking_1 = (32'b1 << 31) =>>> (32'b1);
      bins walking_0 = (32'b0 << 31) =>>> (32'b0);
    }
    
    // 交叉覆盖:有效信号与数据组合
    valid_x_value: cross data_valid, value_coverage {
      ignore_bins invalid = !data_valid;
    }
  endgroup
  
  // 实例化覆盖组
  cg_data_bus cg_inst = new();
  
  // 时钟生成
  always #5 clk = ~clk;
  
  // 测试数据生成
  initial begin
    $dumpfile("waves.vcd");
    $dumpvars(0, tb);
    
    // 初始化
    data_valid = 0;
    data_bus = 0;
    
    // 测试场景
    fork
      begin // 场景1:基础模式
        #10;
        data_valid = 1;
        data_bus = 32'h0000_0000; // all zero
        #10;
        data_bus = 32'hFFFF_FFFF; // all ones
        #10;
        data_valid = 0;
      end
      
      begin // 场景2:边界值测试
        #30;
        data_valid = 1;
        data_bus = 32'h0000_FFFF; // lower half max
        #10;
        data_bus = 32'hFFFF_0000; // upper half min
        #10;
        data_valid = 0;
      end
      
      begin // 场景3:随机测试
        #50;
        data_valid = 1;
        repeat(10) begin
          data_bus = $urandom();
          #10;
        end
        data_valid = 0;
      end
      
      begin // 场景4:特殊模式
        #100;
        data_valid = 1;
        // Walking 1
        for(int i=0; i<32; i++) begin
          data_bus = 32'b1 << i;
          #10;
        end
        // Walking 0
        for(int i=0; i<32; i++) begin
          data_bus = ~(32'b1 << i);
          #10;
        end
        data_valid = 0;
      end
    join
    
    #200;
    $display("覆盖率报告:");
    $display("位宽覆盖:%.2f%%", cg_inst.bit_coverage.get_inst_coverage());
    $display("值域覆盖:%.2f%%", cg_inst.value_coverage.get_inst_coverage());
    $finish;
  end
endmodule

仿真与覆盖率分析

  1. 执行命令
xrun -coverage all data_bus_coverage.sv
  1. 预期日志输出
覆盖率报告:
位宽覆盖:98.44%
值域覆盖:95.31%
  1. 波形查看重点
时间(ns) | 信号变化
-------------------
10       | data_valid=1, data_bus=0
20       | data_bus=FFFF_FFFF
30       | data_valid=0
40       | data_valid=1, data_bus=0000_FFFF 
50       | data_bus=FFFF_0000
...      | 随机数据段
100      | Walking 1模式开始
1320     | Walking 0模式开始

覆盖点详细说明

  1. 位宽覆盖(bit_coverage)
  • ​实现原理:为每个bit位创建独立的分箱
  • ​验证目标:确保每个bit位都有0→1和1→0的变化
  • ​检查方法:
    bins bit_toggle[32] = {[0:1]} foreach(data_bus[i]);
  1. 值域覆盖(value_coverage)
  • ​关键分箱:
    1. 全零/全一模式
    2. 高低16位边界
    3. 单字节变化模式
    4. Walking 1/0模式
  1. 交叉覆盖(valid_x_value)
  • ​验证目标:确保只有data_valid有效时的数据被采样
  • ​实现方式:
    ignore_bins invalid = !data_valid;

覆盖率提升技巧

  1. 缺失覆盖分析
// 检查未覆盖的分箱
if (cg_inst.value_coverage.get_coverage() < 100) begin
  $display("未覆盖分箱:");
  cg_inst.value_coverage.get_inst_coverage_detail();
end
  1. 定向测试用例
// 补充测试单字节模式
data_bus = 32'hA5A5_A5A5;  // 交替模式
data_bus = 32'h1234_5678;  // 连续递增值
  1. 约束随机测试
// 使用随机化生成边界值
constraint edge_cases {
  data_bus inside {
    32'h0000_0000, 32'hFFFF_FFFF,
    32'h7FFF_FFFF, 32'h8000_0000
  };
}

常见错误排查

  1. 分箱过多导致覆盖不全
  • ​问题现象:值域覆盖始终低于预期
  • ​解决方案:合并相似分箱
    bins common_values = {[0:100], [1000:2000]};
  1. 采样时机错误
  • ​错误示例:在总线不稳定时采样
  • ​正确做法:添加采样条件
    covergroup cg_data_bus @(posedge clk iff data_valid);
  1. 交叉覆盖组合爆炸
  • ​优化方法:使用条件筛选
    cross valid, data {
      bins valid_high = (valid == 1) => data;
    }

示例四:

// 文件名:bus_coverage.sv
module bus_coverage;
  bit         clk;            // 时钟信号
  logic [31:0] data_bus;      // 32位数据总线
  bit         data_valid;     // 数据有效标志

  // ==============================================
  // 覆盖组定义:监控数据总线的位宽和值域
  // ==============================================
  covergroup data_bus_cg @(posedge clk iff data_valid);
    // ----------------------------
    // 位宽覆盖:检查特定比特位是否被置1
    // ----------------------------
    bit_coverage: coverpoint data_bus {
      bins bit0_set = {32'h00000001};   // 仅第0位为1
      bins bit31_set = {32'h80000000};  // 仅第31位为1
      bins middle_bits = {[32'h0000_0002 : 32'h7FFF_FFFE]}; // 中间位变化
    }

    // ----------------------------
    // 值域覆盖:分区间统计
    // ----------------------------
    value_coverage: coverpoint data_bus {
      // 特殊值
      bins all_zero = {32'h0000_0000};
      bins all_ones = {32'hFFFF_FFFF};
      // 边界值
      bins min_val  = {32'h8000_0000};  // 最小值(有符号)
      bins max_val  = {32'h7FFF_FFFF};  // 最大值(有符号)
      // 区间分箱
      bins low_range  = {[0    : 1000]};
      bins mid_range  = {[1001 : 1_000_000]};
      bins high_range = {[1_000_001 : 32'h7FFF_FFFF]};
    }

    // ----------------------------
    // 交叉覆盖:位宽与值域的交互
    // ----------------------------
    bit_x_value: cross bit_coverage, value_coverage {
      // 忽略无意义的组合(例如全0与bit31_set冲突)
      ignore_bins invalid = binsof(bit_coverage.bit31_set) && binsof(value_coverage.all_zero);
    }
  endgroup

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

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

  // ==============================================
  // 测试逻辑:生成数据并触发采样
  // ==============================================
  initial begin
    // 初始化
    data_valid = 0;
    data_bus   = 0;
    #10; // 等待时钟稳定

    // 生成测试数据
    $display("========== 开始测试 ==========");
    repeat(50) begin
      @(posedge clk);
      data_valid = 1;
      // 随机生成数据,覆盖不同场景
      if ($urandom_range(0, 9) < 3) begin
        // 30%概率生成特殊值
        case ($urandom_range(0, 3))
          0: data_bus = 32'h0000_0000;  // 全0
          1: data_bus = 32'hFFFF_FFFF;  // 全1
          2: data_bus = 32'h8000_0000;  // 最小值
          3: data_bus = 32'h7FFF_FFFF;  // 最大值
        endcase
      end else begin
        // 70%概率生成随机值
        data_bus = $urandom();
      end
      $display("[%0t] Data = 0x%08h", $time, data_bus);
      #1; // 保持数据稳定
      data_valid = 0;
    end

    $display("========== 测试结束 ==========");
    $finish;
  end
endmodule

仿真步骤

  1. 使用xrun运行仿真并收集覆盖率
xrun -sv -coverage all bus_coverage.sv +access+r
  • coverage all:启用代码和功能覆盖率收集。

  • +access+r:生成波形数据库。

  1. 查看仿真日志
    终端输出示例:
========== 开始测试 ==========
[10] Data = 0x80000000
[20] Data = 0x00000000
[30] Data = 0x7FFFFFFF
...
[250] Data = 0x12345678
========== 测试结束 ==========
  1. 查看波形
  • 使用SimVision打开生成的波形数据库(默认名为bus_coverage.shm)。
  • 添加以下信号观察:
    • clk:时钟信号。
    • data_bus:32位数据总线。
    • data_valid:数据有效标志。
  1. 覆盖率报告解析
    覆盖组结构
  • 位宽覆盖(bit_coverage):
    • bit0_set:检查最低位是否被置1。
    • bit31_set:检查最高位是否被置1。
    • middle_bits:中间30位是否变化。
  • 值域覆盖(value_coverage):
    • 特殊值(全0、全1、最小值、最大值)。
    • 区间分箱(低、中、高范围)。
  • 交叉覆盖(bit_x_value):
    • 检查位宽与值域的组合情况。

覆盖率分析

  • 目标覆盖率:
    • 位宽覆盖:100%覆盖bit0_set、bit31_set和middle_bits。
    • 值域覆盖:100%覆盖所有特殊值和区间。
  • 常见未覆盖场景:
    • 若测试数据未生成32’h0000_0001(仅最低位置1),则bit0_set未覆盖。
    • 若未生成32’h8000_0000(最小值),则min_val未覆盖。
  1. 扩展优化
    增加定向测试
// 在测试逻辑中补充定向测试数据
data_bus = 32'h0000_0001; // 确保bit0_set被覆盖
data_bus = 32'h1234_5678; // 中间位变化示例

使用断言辅助覆盖

// 断言:检查bit0_set是否被覆盖
assert property (@(posedge clk) 
  (data_bus == 32'h0000_0001) |-> (cg.bit_coverage.bit0_set.is_covered)
  else $error("bit0_set未覆盖!");
  1. 常见问题与解决

覆盖率未达到100%

  • 问题:某些特殊值(如全0)未被测试生成。
  • 解决:在测试逻辑中增加定向测试用例。

仿真速度慢

  • 问题:交叉覆盖导致组合爆炸。
  • 解决:简化交叉覆盖或使用ignore_bins。

http://www.kler.cn/a/561814.html

相关文章:

  • 5. grafana的Graph panel使用
  • C 语言中控制文件的读取或写入光标
  • P8772 [蓝桥杯 2022 省 A] 求和--简单题的陷阱——(不开long long见祖宗!!!
  • ElasticSearch公共方法封装
  • Django 视图函数中的 `response` 对象及类型扩写
  • 基于SpringBoot实现的宠物领养系统平台功能十一
  • 校园的网络安全
  • 策略模式在工作中的运用
  • 渗透测试实验
  • 【算法】 ‘abb‘ 型子序列问题——前后缀分解 python
  • Spark on Yarn 多机集群部署
  • RBAC授权
  • 【透视图像目标检测(4)】DD3D输出3D障碍物信息的过程
  • 【项目测试】博客系统—Selenium自动化测试、编写测试用例
  • 萌新学 Python 之闭包函数
  • low rank decomposition如何用于矩阵的分解
  • C++基础02(函数)
  • 编写一个程序,计算并输出1到100的和(Python版)
  • <02.25>Leetcode100
  • DeepSeek-R1技术全解析:如何以十分之一成本实现OpenAI级性能?