SystemVerilog学习【六】功能覆盖率详解

发布于:2025-08-30 ⋅ 阅读:(14) ⋅ 点赞:(0)

SystemVerilog【六】功能覆盖率详解

📖 扩展学习资源:


1. 功能覆盖率概述

1.1 什么是功能覆盖率

功能覆盖率(Functional Coverage)是SystemVerilog中用于衡量验证完整性的重要机制。与代码覆盖率不同,功能覆盖率关注的是设计功能点是否被充分验证,而不仅仅是代码是否被执行。

传统Verilog的局限性:

  • 缺乏内建的覆盖率机制
  • 需要手动编写复杂的统计代码
  • 难以准确衡量验证完整性
  • 覆盖率数据收集困难

SystemVerilog功能覆盖率的优势:

  • 内建的covergroup和coverpoint语法
  • 自动化的覆盖率数据收集
  • 灵活的bins定义和交叉覆盖
  • 与仿真工具集成的覆盖率报告
// 传统Verilog的覆盖率统计(复杂且易出错)
module verilog_coverage_example;
    reg [7:0] data;
    reg [1:0] mode;
    
    // 手动统计变量
    integer data_low_count = 0;
    integer data_mid_count = 0;
    integer data_high_count = 0;
    integer mode_count[0:3];
    integer total_samples = 0;
    
    always @(posedge clk) begin
        if (sample_enable) begin
            total_samples = total_samples + 1;
            
            // 手动分类统计
            if (data < 8'h40)
                data_low_count = data_low_count + 1;
            else if (data < 8'h80)
                data_mid_count = data_mid_count + 1;
            else
                data_high_count = data_high_count + 1;
            
            mode_count[mode] = mode_count[mode] + 1;
        end
    end
    
    // 手动计算覆盖率
    task calculate_coverage;
        real data_coverage, mode_coverage;
        integer i;
        
        $display("=== 手动覆盖率统计 ===");
        $display("总采样数: %d", total_samples);
        
        // 数据覆盖率
        if (data_low_count > 0) $display("数据低段已覆盖");
        if (data_mid_count > 0) $display("数据中段已覆盖");
        if (data_high_count > 0) $display("数据高段已覆盖");
        
        // 模式覆盖率
        for (i = 0; i < 4; i++) begin
            if (mode_count[i] > 0)
                $display("模式%d已覆盖: %d次", i, mode_count[i]);
        end
    endtask
endmodule

// SystemVerilog功能覆盖率(简洁明了)
module systemverilog_coverage_example;
    logic [7:0] data;
    logic [1:0] mode;
    logic clk, sample_enable;
    
    // 定义覆盖率组
    covergroup data_mode_cg @(posedge clk iff sample_enable);
        // 数据覆盖点
        data_cp: coverpoint data {
            bins low  = {[8'h00:8'h3F]};
            bins mid  = {[8'h40:8'h7F]};
            bins high = {[8'h80:8'hFF]};
        }
        
        // 模式覆盖点
        mode_cp: coverpoint mode {
            bins mode0 = {2'b00};
            bins mode1 = {2'b01};
            bins mode2 = {2'b10};
            bins mode3 = {2'b11};
        }
        
        // 交叉覆盖
        data_mode_cross: cross data_cp, mode_cp;
    endgroup
    
    // 实例化覆盖率组
    data_mode_cg cg_inst = new();
    
    // 自动覆盖率报告
    final begin
        $display("=== SystemVerilog覆盖率报告 ===");
        $display("总体覆盖率: %0.2f%%", cg_inst.get_coverage());
        $display("数据覆盖率: %0.2f%%", cg_inst.data_cp.get_coverage());
        $display("模式覆盖率: %0.2f%%", cg_inst.mode_cp.get_coverage());
        $display("交叉覆盖率: %0.2f%%", cg_inst.data_mode_cross.get_coverage());
    end
endmodule

1.2 如何在验证中使用功能覆盖率

功能覆盖率在验证中的主要用途:

  1. 验证完整性评估:确保所有功能点都被测试
  2. 测试用例指导:识别未覆盖的功能点,指导测试用例生成
  3. 回归测试优化:基于覆盖率数据优化测试套件
  4. 验证收敛判断:作为验证完成的重要指标
module verification_flow_example;
    // 设计接口信号
    logic clk, reset;
    logic [7:0] addr, data;
    logic read, write, ready;
    logic [1:0] burst_type;
    
    // 验证环境中的覆盖率定义
    covergroup memory_transaction_cg @(posedge clk iff (read || write));
        // 地址覆盖
        addr_cp: coverpoint addr {
            bins low_addr    = {[8'h00:8'h3F]};
            bins mid_addr    = {[8'h40:8'h7F]};
            bins high_addr   = {[8'h80:8'hBF]};
            bins special_addr = {8'hC0, 8'hFF};
        }
        
        // 数据覆盖
        data_cp: coverpoint data {
            bins zero        = {8'h00};
            bins low_data    = {[8'h01:8'h7F]};
            bins high_data   = {[8'h80:8'hFE]};
            bins all_ones    = {8'hFF};
        }
        
        // 操作类型覆盖
        operation_cp: coverpoint {read, write} {
            bins read_op  = {2'b10};
            bins write_op = {2'b01};
            illegal_bins invalid = {2'b00, 2'b11};
        }
        
        // 突发类型覆盖
        burst_cp: coverpoint burst_type {
            bins single = {2'b00};
            bins incr   = {2'b01};
            bins wrap   = {2'b10};
            bins fixed  = {2'b11};
        }
        
        // 关键交叉覆盖
        addr_operation_cross: cross addr_cp, operation_cp {
            ignore_bins ignore_special_read = binsof(addr_cp.special_addr) && 
                                            binsof(operation_cp.read_op);
        }
        
        data_burst_cross: cross data_cp, burst_cp;
    endgroup
    
    memory_transaction_cg mem_cg = new();
    
    // 验证任务:检查覆盖率并生成报告
    task check_coverage_and_guide_testing;
        real addr_cov, data_cov, op_cov, burst_cov, total_cov;
        
        total_cov = mem_cg.get_coverage();
        addr_cov = mem_cg.addr_cp.get_coverage();
        data_cov = mem_cg.data_cp.get_coverage();
        op_cov = mem_cg.operation_cp.get_coverage();
        burst_cov = mem_cg.burst_cp.get_coverage();
        
        $display("\n=== 覆盖率指导报告 ===");
        $display("总体覆盖率: %0.2f%%", total_cov);
        $display("地址覆盖率: %0.2f%%", addr_cov);
        $display("数据覆盖率: %0.2f%%", data_cov);
        $display("操作覆盖率: %0.2f%%", op_cov);
        $display("突发覆盖率: %0.2f%%", burst_cov);
        
        // 基于覆盖率指导测试
        if (addr_cov < 90.0) begin
            $display("建议:增加地址边界测试用例");
        end
        
        if (data_cov < 90.0) begin
            $display("建议:增加特殊数据值测试");
        end
        
        if (total_cov >= 95.0) begin
            $display("验证目标达成,可以考虑收敛");
        end else begin
            $display("需要继续测试,目标覆盖率: 95%%");
        end
    endtask
    
    // 定期检查覆盖率
    initial begin
        repeat (1000) @(posedge clk);
        check_coverage_and_guide_testing();
        
        repeat (1000) @(posedge clk);
        check_coverage_and_guide_testing();
        
        $finish;
    end
endmodule

2.2 covergroup参数

covergroup支持多种参数来控制覆盖率的行为和采样方式。

module covergroup_options_example;
    logic clk, reset;
    logic [7:0] addr, data;
    logic read, write;
    
    // 带选项的covergroup
    covergroup options_cg @(posedge clk iff !reset);
        // 全局选项设置
        option.per_instance = 1;     // 每个实例独立统计
        option.goal = 95;            // 目标覆盖率95%
        option.name = "addr_data_coverage";  // 覆盖率组名称
        option.comment = "地址和数据覆盖率分析";  // 注释
        option.at_least = 2;         // 每个bin至少命中2次
        option.detect_overlap = 1;   // 检测bin重叠
        option.auto_bin_max = 64;    // 自动bin的最大数量
        
        // 地址覆盖点
        addr_cp: coverpoint addr {
            option.at_least = 3;     // 覆盖点级别的选项
            option.goal = 90;
            
            bins low_addr  = {[8'h00:8'h3F]};
            bins mid_addr  = {[8'h40:8'h7F]};
            bins high_addr = {[8'h80:8'hBF]};
            bins special   = {8'hC0, 8'hFF};
        }
        
        // 数据覆盖点
        data_cp: coverpoint data {
            option.weight = 2;       // 权重设置
            option.goal = 100;       // 目标100%覆盖
            
            bins zero      = {8'h00};
            bins powers_of_2[] = {8'h01, 8'h02, 8'h04, 8'h08,
                                 8'h10, 8'h20, 8'h40, 8'h80};
            bins high_data = {[8'h81:8'hFE]};
            bins all_ones  = {8'hFF};
        }
        
        // 操作覆盖点
        operation_cp: coverpoint {read, write} {
            bins read_only  = {2'b10};
            bins write_only = {2'b01};
            illegal_bins both = {2'b11};
            ignore_bins idle  = {2'b00};
        }
        
        // 交叉覆盖
        addr_data_cross: cross addr_cp, data_cp {
            option.goal = 80;        // 交叉覆盖目标80%
            option.at_least = 1;     // 至少命中1次
            
            // 忽略某些组合
            ignore_bins ignore_special_zero = 
                binsof(addr_cp.special) && binsof(data_cp.zero);
        }
    endgroup
    
    // 类型级别的covergroup选项
    covergroup type_options_cg @(posedge clk);
        type_option.goal = 85;       // 类型级别目标
        type_option.comment = "类型级别覆盖率";
        type_option.strobe = 1;      // 使用strobe采样
        
        addr_cp: coverpoint addr {
            bins addr_ranges[] = {[0:63], [64:127], [128:191], [192:255]};
        }
    endgroup
    
    // 实例化不同选项的covergroup
    options_cg opt_cg1 = new();
    options_cg opt_cg2 = new();
    type_options_cg type_cg = new();
    
    // 动态选项修改
    initial begin
        // 运行时修改选项
        opt_cg1.option.goal = 98;    // 修改目标覆盖率
        opt_cg1.addr_cp.option.at_least = 5;  // 修改最小命中次数
        
        // 不同实例可以有不同设置
        opt_cg2.option.goal = 90;
        opt_cg2.data_cp.option.weight = 3;
    end
    
    // 传统Verilog的等价实现(非常复杂)
    typedef struct {
        integer goal;
        integer at_least;
        integer weight;
        string name;
        string comment;
    } verilog_option_t;
    
    typedef struct {
        integer count;
        integer target_hits;
        real weight;
        bit covered;
    } verilog_bin_t;
    
    // 手动实现选项控制
    verilog_option_t global_opts;
    verilog_bin_t addr_bins[4];  // 4个地址bin
    verilog_bin_t data_bins[4];  // 4个数据bin
    integer total_samples;
    
    initial begin
        // 初始化选项
        global_opts.goal = 95;
        global_opts.at_least = 2;
        global_opts.weight = 1;
        global_opts.name = "manual_coverage";
        
        // 初始化bins
        for (int i = 0; i < 4; i++) begin
            addr_bins[i].target_hits = global_opts.at_least;
            addr_bins[i].weight = global_opts.weight;
            data_bins[i].target_hits = global_opts.at_least;
            data_bins[i].weight = global_opts.weight;
        end
    end
    
    // 手动统计和选项控制
    always @(posedge clk) begin
        if (!reset && (read || write)) begin
            total_samples++;
            
            // 手动分类和计数
            case (addr[7:6])
                2'b00: addr_bins[0].count++;
                2'b01: addr_bins[1].count++;
                2'b10: addr_bins[2].count++;
                2'b11: addr_bins[3].count++;
            endcase
            
            case (data[7:6])
                2'b00: data_bins[0].count++;
                2'b01: data_bins[1].count++;
                2'b10: data_bins[2].count++;
                2'b11: data_bins[3].count++;
            endcase
        end
    end
    
    // 手动计算覆盖率
    task calculate_manual_coverage;
        integer covered_bins;
        real coverage_percent;
        
        covered_bins = 0;
        
        // 检查地址bins
        for (int i = 0; i < 4; i++) begin
            if (addr_bins[i].count >= addr_bins[i].target_hits) begin
                addr_bins[i].covered = 1;
                covered_bins++;
            end
        end
        
        // 检查数据bins
        for (int i = 0; i < 4; i++) begin
            if (data_bins[i].count >= data_bins[i].target_hits) begin
                data_bins[i].covered = 1;
                covered_bins++;
            end
        end
        
        coverage_percent = (covered_bins * 100.0) / 8.0;  // 总共8个bins
        
        $display("手动覆盖率计算: %0.2f%% (目标: %d%%)", 
                coverage_percent, global_opts.goal);
        
        if (coverage_percent >= global_opts.goal) begin
            $display("覆盖率目标已达成!");
        end else begin
            $display("还需要 %0.2f%% 才能达到目标", 
                    global_opts.goal - coverage_percent);
        end
    endtask
    
    // 测试序列
    initial begin
        reset = 1;
        read = 0;
        write = 0;
        addr = 8'h00;
        data = 8'h00;
        
        #20 reset = 0;
        
        // 生成测试数据
        repeat (200) begin
            @(posedge clk);
            addr = $random;
            data = $random;
            read = $random % 2;
            write = !read && ($random % 2);
        end
        
        // SystemVerilog覆盖率报告
        $display("\n=== SystemVerilog选项控制覆盖率 ===");
        $display("实例1覆盖率: %0.2f%% (目标: %d%%)", 
                opt_cg1.get_coverage(), opt_cg1.option.goal);
        $display("实例2覆盖率: %0.2f%% (目标: %d%%)", 
                opt_cg2.get_coverage(), opt_cg2.option.goal);
        $display("类型覆盖率: %0.2f%% (目标: %d%%)", 
                type_cg.get_coverage(), type_cg.type_option.goal);
        
        // 详细的覆盖点报告
        $display("\n地址覆盖点详情:");
        $display("  覆盖率: %0.2f%%, 目标: %d%%, 最小命中: %d",
                opt_cg1.addr_cp.get_coverage(),
                opt_cg1.addr_cp.option.goal,
                opt_cg1.addr_cp.option.at_least);
        
        $display("数据覆盖点详情:");
        $display("  覆盖率: %0.2f%%, 权重: %d",
                opt_cg1.data_cp.get_coverage(),
                opt_cg1.data_cp.option.weight);
        
        // 传统方法的覆盖率计算
        $display("\n=== 传统Verilog手动计算 ===");
        calculate_manual_coverage();
        
        $finish;
    end
endmodule

2.3 covergroup采样

covergroup的采样控制决定了何时收集覆盖率数据。

module covergroup_sampling_example;
    logic clk, reset;
    logic [7:0] addr, data;
    logic read, write, valid;
    logic [1:0] state;
    
    // 时钟边沿采样
    covergroup clk_edge_cg @(posedge clk);
        addr_cp: coverpoint addr;
        data_cp: coverpoint data;
    endgroup
    
    // 条件采样
    covergroup conditional_cg @(posedge clk iff valid);
        addr_cp: coverpoint addr {
            bins low  = {[0:127]};
            bins high = {[128:255]};
        }
    endgroup
    
    // 复杂条件采样
    covergroup complex_cond_cg @(posedge clk iff (valid && !reset && (read || write)));
        operation_cp: coverpoint {read, write} {
            bins read_op  = {2'b10};
            bins write_op = {2'b01};
        }
        
        addr_cp: coverpoint addr {
            bins aligned   = {[0:255]} iff (addr[1:0] == 2'b00);
            bins unaligned = {[0:255]} iff (addr[1:0] != 2'b00);
        }
    endgroup
    
    // 信号变化采样
    covergroup signal_change_cg @(state);
        state_cp: coverpoint state {
            bins idle   = {2'b00};
            bins active = {2'b01};
            bins busy   = {2'b10};
            bins error  = {2'b11};
        }
    endgroup
    
    // 多事件采样
    covergroup multi_event_cg @(posedge clk, negedge reset);
        reset_cp: coverpoint reset {
            bins active   = {1'b0};
            bins inactive = {1'b1};
        }
    endgroup
    
    // 手动采样控制
    covergroup manual_cg;
        addr_cp: coverpoint addr {
            bins ranges[] = {[0:63], [64:127], [128:191], [192:255]};
        }
        
        data_cp: coverpoint data {
            bins patterns[] = {8'h00, 8'hFF, 8'hAA, 8'h55};
        }
    endgroup
    
    // 类中的采样控制
    class sampling_control_class;
        rand logic [7:0] addr;
        rand logic [7:0] data;
        rand logic read_write;
        
        // 自动采样
        covergroup auto_sample_cg;
            addr_cp: coverpoint addr;
            data_cp: coverpoint data;
            rw_cp: coverpoint read_write;
        endgroup
        
        // 手动采样
        covergroup manual_sample_cg;
            addr_cp: coverpoint addr;
            data_cp: coverpoint data;
        endgroup
        
        function new();
            auto_sample_cg = new();
            manual_sample_cg = new();
        endfunction
        
        // 条件采样函数
        function void conditional_sample();
            if (addr > 8'h80) begin
                manual_sample_cg.sample();
            end
        endfunction
        
        // 延迟采样
        task delayed_sample();
            #10;  // 延迟10个时间单位
            manual_sample_cg.sample();
        endtask
    endclass
    
    // 实例化covergroup
    clk_edge_cg clk_cg = new();
    conditional_cg cond_cg = new();
    complex_cond_cg complex_cg = new();
    signal_change_cg sig_cg = new();
    multi_event_cg multi_cg = new();
    manual_cg manual_inst = new();
    sampling_control_class sample_obj = new();
    
    // 采样控制逻辑
    logic sample_enable;
    integer sample_counter;
    
    // 周期性采样控制
    always @(posedge clk) begin
        if (!reset) begin
            sample_counter++;
            
            // 每10个周期采样一次
            if (sample_counter % 10 == 0) begin
                sample_enable = 1;
                manual_inst.sample();
            end else begin
                sample_enable = 0;
            end
        end
    end
    
    // 条件采样控制
    always @(posedge clk) begin
        if (valid && (addr > 8'h80)) begin
            // 高地址时进行额外采样
            manual_inst.sample();
        end
        
        if (read && write) begin
            // 错误条件时采样
            $display("错误:同时读写,时间: %t", $time);
            manual_inst.sample();
        end
    end
    
    // 传统Verilog的采样控制(复杂)
    typedef struct {
        integer addr_samples[4];  // 4个地址范围
        integer data_samples[4];  // 4个数据模式
        integer total_samples;
        integer conditional_samples;
    } verilog_sampling_t;
    
    verilog_sampling_t verilog_stats;
    
    // 手动实现采样控制
    always @(posedge clk) begin
        if (!reset) begin
            // 基本采样
            verilog_stats.total_samples++;
            
            // 条件采样
            if (valid) begin
                verilog_stats.conditional_samples++;
                
                // 手动分类
                case (addr[7:6])
                    2'b00: verilog_stats.addr_samples[0]++;
                    2'b01: verilog_stats.addr_samples[1]++;
                    2'b10: verilog_stats.addr_samples[2]++;
                    2'b11: verilog_stats.addr_samples[3]++;
                endcase
                
                // 数据模式检测
                case (data)
                    8'h00: verilog_stats.data_samples[0]++;
                    8'hFF: verilog_stats.data_samples[1]++;
                    8'hAA: verilog_stats.data_samples[2]++;
                    8'h55: verilog_stats.data_samples[3]++;
                endcase
            end
        end
    end
    
    // 状态变化检测(手动)
    logic [1:0] prev_state;
    always @(posedge clk) begin
        if (state != prev_state) begin
            $display("状态变化: %d -> %d, 时间: %t", prev_state, state, $time);
            // 手动记录状态转换
        end
        prev_state = state;
    end
    
    // 测试序列
    initial begin
        reset = 1;
        valid = 0;
        read = 0;
        write = 0;
        addr = 8'h00;
        data = 8'h00;
        state = 2'b00;
        sample_counter = 0;
        
        #20 reset = 0;
        
        // 测试不同的采样场景
        repeat (50) begin
            @(posedge clk);
            
            // 随机生成信号
            valid = $random % 2;
            read = $random % 2;
            write = $random % 2;
            addr = $random;
            data = $random;
            
            // 状态机
            if ($random % 10 == 0) begin
                state = $random % 4;
            end
            
            // 手动采样示例
            if ($random % 5 == 0) begin
                manual_inst.sample();
            end
            
            // 类对象采样
            sample_obj.addr = addr;
            sample_obj.data = data;
            sample_obj.read_write = read;
            sample_obj.conditional_sample();
        end
        
        // 覆盖率报告
        $display("\n=== SystemVerilog采样覆盖率报告 ===");
        $display("时钟边沿采样: %0.2f%%", clk_cg.get_coverage());
        $display("条件采样: %0.2f%%", cond_cg.get_coverage());
        $display("复杂条件采样: %0.2f%%", complex_cg.get_coverage());
        $display("信号变化采样: %0.2f%%", sig_cg.get_coverage());
        $display("多事件采样: %0.2f%%", multi_cg.get_coverage());
        $display("手动采样: %0.2f%%", manual_inst.get_coverage());
        $display("类自动采样: %0.2f%%", sample_obj.auto_sample_cg.get_coverage());
        $display("类手动采样: %0.2f%%", sample_obj.manual_sample_cg.get_coverage());
        
        // 传统Verilog采样统计
        $display("\n=== 传统Verilog采样统计 ===");
        $display("总采样数: %d", verilog_stats.total_samples);
        $display("条件采样数: %d", verilog_stats.conditional_samples);
        $display("地址采样分布: [%d, %d, %d, %d]",
                verilog_stats.addr_samples[0], verilog_stats.addr_samples[1],
                verilog_stats.addr_samples[2], verilog_stats.addr_samples[3]);
        $display("数据模式采样: [%d, %d, %d, %d]",
                verilog_stats.data_samples[0], verilog_stats.data_samples[1],
                verilog_stats.data_samples[2], verilog_stats.data_samples[3]);
        
        $finish;
    end
endmodule

3. coverpoint

3.1 coverpoint的定义

coverpoint是covergroup中的基本覆盖单元,用于定义对特定信号或表达式的覆盖要求。

module coverpoint_definition_example;
    logic clk, reset;
    logic [7:0] addr, data;
    logic [3:0] cmd;
    logic read, write, valid;
    logic [1:0] burst_type;
    
    covergroup coverpoint_examples_cg @(posedge clk iff !reset);
        // 基本coverpoint
        basic_addr_cp: coverpoint addr;
        
        // 带标签的coverpoint
        labeled_data_cp: coverpoint data {
            bins zero = {8'h00};
            bins non_zero = {[8'h01:8'hFF]};
        }
        
        // 表达式coverpoint
        addr_high_cp: coverpoint addr[7:4] {
            bins low_nibble  = {[4'h0:4'h7]};
            bins high_nibble = {[4'h8:4'hF]};
        }
        
        // 多信号组合coverpoint
        operation_cp: coverpoint {read, write, valid} {
            bins valid_read  = {3'b101};
            bins valid_write = {3'b011};
            bins invalid_ops = {3'b111, 3'b001};
            bins idle        = {3'b000};
        }
        
        // 条件coverpoint
        conditional_data_cp: coverpoint data iff (valid && (read || write)) {
            bins data_ranges[] = {[0:63], [64:127], [128:191], [192:255]};
        }
        
        // 函数调用coverpoint
        function logic [2:0] get_priority(logic [7:0] addr);
            if (addr < 8'h40) return 3'b001;      // 低优先级
            else if (addr < 8'h80) return 3'b010; // 中优先级
            else if (addr < 8'hC0) return 3'b100; // 高优先级
            else return 3'b111;                   // 最高优先级
        endfunction
        
        priority_cp: coverpoint get_priority(addr) {
            bins low_pri    = {3'b001};
            bins mid_pri    = {3'b010};
            bins high_pri   = {3'b100};
            bins max_pri    = {3'b111};
        }
        
        // 枚举类型coverpoint
        typedef enum logic [1:0] {
            IDLE = 2'b00,
            READ = 2'b01,
            WRITE = 2'b10,
            ERROR = 2'b11
        } state_e;
        
        state_e current_state;
        
        state_cp: coverpoint current_state {
            bins idle_state  = {IDLE};
            bins read_state  = {READ};
            bins write_state = {WRITE};
            bins error_state = {ERROR};
        }
        
        // 位选择coverpoint
        bit_pattern_cp: coverpoint {addr[7], addr[0]} {
            bins pattern_00 = {2'b00};
            bins pattern_01 = {2'b01};
            bins pattern_10 = {2'b10};
            bins pattern_11 = {2'b11};
        }
        
        // 算术表达式coverpoint
        sum_cp: coverpoint (addr + data) {
            bins low_sum  = {[0:127]};
            bins high_sum = {[128:511]};
        }
        
        // 逻辑表达式coverpoint
        logic_cp: coverpoint (addr & data) {
            bins zero_and    = {8'h00};
            bins partial_and = {[8'h01:8'hFE]};
            bins full_and    = {8'hFF};
        }
    endgroup
    
    // 实例化covergroup
    coverpoint_examples_cg cp_cg = new();
    
    // 传统Verilog的等价实现(极其复杂)
    typedef struct {
        // 基本地址统计
        integer addr_count[256];
        
        // 数据分类统计
        integer zero_data_count;
        integer non_zero_data_count;
        
        // 地址高位统计
        integer low_nibble_count;
        integer high_nibble_count;
        
        // 操作组合统计
        integer valid_read_count;
        integer valid_write_count;
        integer invalid_ops_count;
        integer idle_count;
        
        // 条件数据统计
        integer cond_data_ranges[4];
        
        // 优先级统计
        integer priority_counts[4];
        
        // 状态统计
        integer state_counts[4];
        
        // 位模式统计
        integer bit_pattern_counts[4];
        
        // 表达式统计
        integer low_sum_count;
        integer high_sum_count;
        integer zero_and_count;
        integer partial_and_count;
        integer full_and_count;
        
        integer total_samples;
    } verilog_coverpoint_stats_t;
    
    verilog_coverpoint_stats_t verilog_stats;
    
    // 手动实现coverpoint功能
    function logic [2:0] manual_get_priority(logic [7:0] addr);
        if (addr < 8'h40) return 3'b001;
        else if (addr < 8'h80) return 3'b010;
        else if (addr < 8'hC0) return 3'b100;
        else return 3'b111;
    endfunction
    
    always @(posedge clk) begin
        if (!reset) begin
            verilog_stats.total_samples++;
            
            // 基本地址统计
            verilog_stats.addr_count[addr]++;
            
            // 数据分类
            if (data == 8'h00)
                verilog_stats.zero_data_count++;
            else
                verilog_stats.non_zero_data_count++;
            
            // 地址高位
            if (addr[7:4] <= 4'h7)
                verilog_stats.low_nibble_count++;
            else
                verilog_stats.high_nibble_count++;
            
            // 操作组合
            case ({read, write, valid})
                3'b101: verilog_stats.valid_read_count++;
                3'b011: verilog_stats.valid_write_count++;
                3'b111, 3'b001: verilog_stats.invalid_ops_count++;
                3'b000: verilog_stats.idle_count++;
            endcase
            
            // 条件数据统计
            if (valid && (read || write)) begin
                case (data[7:6])
                    2'b00: verilog_stats.cond_data_ranges[0]++;
                    2'b01: verilog_stats.cond_data_ranges[1]++;
                    2'b10: verilog_stats.cond_data_ranges[2]++;
                    2'b11: verilog_stats.cond_data_ranges[3]++;
                endcase
            end
            
            // 优先级统计
            case (manual_get_priority(addr))
                3'b001: verilog_stats.priority_counts[0]++;
                3'b010: verilog_stats.priority_counts[1]++;
                3'b100: verilog_stats.priority_counts[2]++;
                3'b111: verilog_stats.priority_counts[3]++;
            endcase
            
            // 位模式统计
            case ({addr[7], addr[0]})
                2'b00: verilog_stats.bit_pattern_counts[0]++;
                2'b01: verilog_stats.bit_pattern_counts[1]++;
                2'b10: verilog_stats.bit_pattern_counts[2]++;
                2'b11: verilog_stats.bit_pattern_counts[3]++;
            endcase
            
            // 算术表达式统计
            if ((addr + data) <= 127)
                verilog_stats.low_sum_count++;
            else
                verilog_stats.high_sum_count++;
            
            // 逻辑表达式统计
            case (addr & data)
                8'h00: verilog_stats.zero_and_count++;
                8'hFF: verilog_stats.full_and_count++;
                default: verilog_stats.partial_and_count++;
            endcase
        end
    end
    
    // 测试序列
    initial begin
        reset = 1;
        addr = 8'h00;
        data = 8'h00;
        cmd = 4'h0;
        read = 0;
        write = 0;
        valid = 0;
        burst_type = 2'b00;
        cp_cg.current_state = cp_cg.IDLE;
        
        #20 reset = 0;
        
        // 生成各种测试场景
        repeat (300) begin
            @(posedge clk);
            
            // 随机生成基本信号
            addr = $random;
            data = $random;
            valid = $random % 2;
            read = $random % 2;
            write = !read && ($random % 2);
            
            // 状态机转换
            if ($random % 10 == 0) begin
                case ($random % 4)
                    0: cp_cg.current_state = cp_cg.IDLE;
                    1: cp_cg.current_state = cp_cg.READ;
                    2: cp_cg.current_state = cp_cg.WRITE;
                    3: cp_cg.current_state = cp_cg.ERROR;
                endcase
            end
            
            // 特殊测试场景
            if ($random % 20 == 0) begin
                // 边界值测试
                addr = ($random % 2) ? 8'h00 : 8'hFF;
                data = ($random % 2) ? 8'h00 : 8'hFF;
            end
        end
        
        // SystemVerilog覆盖率报告
        $display("\n=== SystemVerilog Coverpoint覆盖率报告 ===");
        $display("总体覆盖率: %0.2f%%", cp_cg.get_coverage());
        $display("基本地址覆盖率: %0.2f%%", cp_cg.basic_addr_cp.get_coverage());
        $display("标签数据覆盖率: %0.2f%%", cp_cg.labeled_data_cp.get_coverage());
        $display("地址高位覆盖率: %0.2f%%", cp_cg.addr_high_cp.get_coverage());
        $display("操作组合覆盖率: %0.2f%%", cp_cg.operation_cp.get_coverage());
        $display("条件数据覆盖率: %0.2f%%", cp_cg.conditional_data_cp.get_coverage());
        $display("优先级覆盖率: %0.2f%%", cp_cg.priority_cp.get_coverage());
        $display("状态覆盖率: %0.2f%%", cp_cg.state_cp.get_coverage());
        $display("位模式覆盖率: %0.2f%%", cp_cg.bit_pattern_cp.get_coverage());
        $display("算术表达式覆盖率: %0.2f%%", cp_cg.sum_cp.get_coverage());
        $display("逻辑表达式覆盖率: %0.2f%%", cp_cg.logic_cp.get_coverage());
        
        // 传统Verilog统计报告
        $display("\n=== 传统Verilog Coverpoint统计 ===");
        $display("总采样数: %d", verilog_stats.total_samples);
        $display("零数据计数: %d", verilog_stats.zero_data_count);
        $display("非零数据计数: %d", verilog_stats.non_zero_data_count);
        $display("低位计数: %d", verilog_stats.low_nibble_count);
        $display("高位计数: %d", verilog_stats.high_nibble_count);
        $display("有效读计数: %d", verilog_stats.valid_read_count);
        $display("有效写计数: %d", verilog_stats.valid_write_count);
        $display("无效操作计数: %d", verilog_stats.invalid_ops_count);
        $display("空闲计数: %d", verilog_stats.idle_count);
        
        $finish;
    end
endmodule

3.2 bins for value

bins用于定义coverpoint中的覆盖桶,将信号值分组进行覆盖率统计。

module bins_for_value_example;
    logic clk, reset;
    logic [7:0] addr, data;
    logic [3:0] cmd;
    logic read, write;
    
    covergroup value_bins_cg @(posedge clk iff !reset);
        // 单值bins
        addr_single_cp: coverpoint addr {
            bins zero = {8'h00};
            bins max  = {8'hFF};
            bins mid  = {8'h80};
        }
        
        // 多值bins
        addr_multi_cp: coverpoint addr {
            bins special_values = {8'h00, 8'h55, 8'hAA, 8'hFF};
            bins power_of_2 = {8'h01, 8'h02, 8'h04, 8'h08, 8'h10, 8'h20, 8'h40, 8'h80};
        }
        
        // 范围bins
        addr_range_cp: coverpoint addr {
            bins low_range  = {[8'h00:8'h3F]};
            bins mid_range  = {[8'h40:8'h7F]};
            bins high_range = {[8'h80:8'hBF]};
            bins top_range  = {[8'hC0:8'hFF]};
        }
        
        // 自动bins数组
        data_auto_cp: coverpoint data {
            bins auto_bins[] = {[0:255]};  // 自动创建256个bins
        }
        
        // 限制自动bins数量
        data_limited_cp: coverpoint data {
            bins limited_bins[16] = {[0:255]};  // 创建16个bins,每个覆盖16个值
        }
        
        // 混合bins定义
        cmd_mixed_cp: coverpoint cmd {
            bins read_cmd   = {4'h0, 4'h1};     // 读命令
            bins write_cmd  = {4'h2, 4'h3};     // 写命令
            bins config_cmd = {[4'h4:4'h7]};    // 配置命令范围
            bins debug_cmd  = {4'h8, 4'h9, 4'hA}; // 调试命令
            bins reserved[] = {[4'hB:4'hF]};    // 保留命令自动分组
        }
        
        // 条件bins
        conditional_bins_cp: coverpoint data {
            bins low_data  = {[0:127]} iff (read);
            bins high_data = {[128:255]} iff (write);
        }
        
        // 默认bins
        default_bins_cp: coverpoint addr {
            bins defined_values = {8'h00, 8'h55, 8'hAA, 8'hFF};
            bins default;  // 捕获所有其他值
        }
        
        // 表达式bins
        expression_bins_cp: coverpoint (addr[7:4]) {
            bins low_nibble  = {[4'h0:4'h7]};
            bins high_nibble = {[4'h8:4'hF]};
        }
        
        // 组合信号bins
        combo_bins_cp: coverpoint {read, write} {
            bins read_only  = {2'b10};
            bins write_only = {2'b01};
            bins idle       = {2'b00};
            // 注意:{2'b11} 将在illegal_bins中定义
        }
    endgroup
    
    // 高级bins示例
    covergroup advanced_bins_cg @(posedge clk);
        // 位模式bins
        bit_pattern_cp: coverpoint addr {
            bins all_zeros = {8'b00000000};
            bins all_ones  = {8'b11111111};
            bins alternating1 = {8'b10101010};
            bins alternating2 = {8'b01010101};
            bins single_bit[] = {8'b00000001, 8'b00000010, 8'b00000100, 8'b00001000,
                                8'b00010000, 8'b00100000, 8'b01000000, 8'b10000000};
        }
        
        // 算术bins
        arithmetic_cp: coverpoint (addr + data) {
            bins sum_zero     = {0};
            bins sum_low      = {[1:127]};
            bins sum_mid      = {[128:383]};
            bins sum_high     = {[384:510]};
            bins sum_max      = {511};
        }
        
        // 函数返回值bins
        function logic [2:0] get_addr_type(logic [7:0] addr);
            if (addr == 8'h00) return 3'b001;        // NULL
            else if (addr[0] == 1'b0) return 3'b010; // EVEN
            else if (addr[7] == 1'b1) return 3'b100; // HIGH_ODD
            else return 3'b011;                      // LOW_ODD
        endfunction
        
        addr_type_cp: coverpoint get_addr_type(addr) {
            bins null_addr = {3'b001};
            bins even_addr = {3'b010};
            bins low_odd   = {3'b011};
            bins high_odd  = {3'b100};
        }
    endgroup
    
    // 实例化covergroup
    value_bins_cg val_cg = new();
    advanced_bins_cg adv_cg = new();
    
    // 传统Verilog的等价实现(非常复杂)
    typedef struct {
        // 单值统计
        integer zero_count, max_count, mid_count;
        
        // 多值统计
        integer special_values_count;
        integer power_of_2_count;
        
        // 范围统计
        integer low_range_count, mid_range_count;
        integer high_range_count, top_range_count;
        
        // 自动bins模拟
        integer auto_bins_count[256];
        integer limited_bins_count[16];
        
        // 混合bins统计
        integer read_cmd_count, write_cmd_count;
        integer config_cmd_count, debug_cmd_count;
        integer reserved_cmd_count[5];
        
        // 条件bins统计
        integer low_data_read_count, high_data_write_count;
        
        // 默认bins统计
        integer defined_values_count, default_count;
        
        // 表达式bins统计
        integer low_nibble_count, high_nibble_count;
        
        // 组合bins统计
        integer read_only_count, write_only_count, idle_count;
        
        // 高级bins统计
        integer bit_pattern_counts[12];  // 各种位模式
        integer arithmetic_counts[5];    // 算术结果分组
        integer addr_type_counts[4];     // 地址类型
        
        integer total_samples;
    } verilog_bins_stats_t;
    
    verilog_bins_stats_t verilog_stats;
    
    // 手动实现bins功能
    function logic [2:0] manual_get_addr_type(logic [7:0] addr);
        if (addr == 8'h00) return 3'b001;
        else if (addr[0] == 1'b0) return 3'b010;
        else if (addr[7] == 1'b1) return 3'b100;
        else return 3'b011;
    endfunction
    
    function bit is_power_of_2(logic [7:0] value);
        case (value)
            8'h01, 8'h02, 8'h04, 8'h08, 8'h10, 8'h20, 8'h40, 8'h80: return 1;
            default: return 0;
        endcase
    endfunction
    
    function bit is_special_value(logic [7:0] value);
        case (value)
            8'h00, 8'h55, 8'hAA, 8'hFF: return 1;
            default: return 0;
        endcase
    endfunction
    
    always @(posedge clk) begin
        if (!reset) begin
            verilog_stats.total_samples++;
            
            // 单值bins统计
            case (addr)
                8'h00: verilog_stats.zero_count++;
                8'hFF: verilog_stats.max_count++;
                8'h80: verilog_stats.mid_count++;
            endcase
            
            // 多值bins统计
            if (is_special_value(addr))
                verilog_stats.special_values_count++;
            if (is_power_of_2(addr))
                verilog_stats.power_of_2_count++;
            
            // 范围bins统计
            if (addr >= 8'h00 && addr <= 8'h3F)
                verilog_stats.low_range_count++;
            else if (addr >= 8'h40 && addr <= 8'h7F)
                verilog_stats.mid_range_count++;
            else if (addr >= 8'h80 && addr <= 8'hBF)
                verilog_stats.high_range_count++;
            else if (addr >= 8'hC0 && addr <= 8'hFF)
                verilog_stats.top_range_count++;
            
            // 自动bins模拟
            verilog_stats.auto_bins_count[addr]++;
            verilog_stats.limited_bins_count[addr[7:4]]++;
            
            // 混合bins统计
            case (cmd)
                4'h0, 4'h1: verilog_stats.read_cmd_count++;
                4'h2, 4'h3: verilog_stats.write_cmd_count++;
                4'h4, 4'h5, 4'h6, 4'h7: verilog_stats.config_cmd_count++;
                4'h8, 4'h9, 4'hA: verilog_stats.debug_cmd_count++;
                default: begin
                    if (cmd >= 4'hB && cmd <= 4'hF)
                        verilog_stats.reserved_cmd_count[cmd - 4'hB]++;
                end
            endcase
            
            // 条件bins统计
            if (read && data <= 127)
                verilog_stats.low_data_read_count++;
            if (write && data >= 128)
                verilog_stats.high_data_write_count++;
            
            // 默认bins统计
            if (is_special_value(addr))
                verilog_stats.defined_values_count++;
            else
                verilog_stats.default_count++;
            
            // 表达式bins统计
            if (addr[7:4] <= 4'h7)
                verilog_stats.low_nibble_count++;
            else
                verilog_stats.high_nibble_count++;
            
            // 组合bins统计
            case ({read, write})
                2'b10: verilog_stats.read_only_count++;
                2'b01: verilog_stats.write_only_count++;
                2'b00: verilog_stats.idle_count++;
            endcase
            
            // 位模式统计
            case (addr)
                8'b00000000: verilog_stats.bit_pattern_counts[0]++;
                8'b11111111: verilog_stats.bit_pattern_counts[1]++;
                8'b10101010: verilog_stats.bit_pattern_counts[2]++;
                8'b01010101: verilog_stats.bit_pattern_counts[3]++;
                8'b00000001: verilog_stats.bit_pattern_counts[4]++;
                8'b00000010: verilog_stats.bit_pattern_counts[5]++;
                8'b00000100: verilog_stats.bit_pattern_counts[6]++;
                8'b00001000: verilog_stats.bit_pattern_counts[7]++;
                8'b00010000: verilog_stats.bit_pattern_counts[8]++;
                8'b00100000: verilog_stats.bit_pattern_counts[9]++;
                8'b01000000: verilog_stats.bit_pattern_counts[10]++;
                8'b10000000: verilog_stats.bit_pattern_counts[11]++;
            endcase
            
            // 算术bins统计
            case (addr + data)
                0: verilog_stats.arithmetic_counts[0]++;
                1, 2, 3, 4, 5, 6, 7, 8, 9, 10: begin  // 简化范围检查
                    if ((addr + data) >= 1 && (addr + data) <= 127)
                        verilog_stats.arithmetic_counts[1]++;
                end
                default: begin
                    if ((addr + data) >= 128 && (addr + data) <= 383)
                        verilog_stats.arithmetic_counts[2]++;
                    else if ((addr + data) >= 384 && (addr + data) <= 510)
                        verilog_stats.arithmetic_counts[3]++;
                    else if ((addr + data) == 511)
                        verilog_stats.arithmetic_counts[4]++;
                end
            endcase
            
            // 地址类型统计
            case (manual_get_addr_type(addr))
                3'b001: verilog_stats.addr_type_counts[0]++;
                3'b010: verilog_stats.addr_type_counts[1]++;
                3'b011: verilog_stats.addr_type_counts[2]++;
                3'b100: verilog_stats.addr_type_counts[3]++;
            endcase
        end
    end
    
    // 覆盖率计算函数
    function real calculate_bin_coverage(integer bin_count, integer total_samples, integer min_hits);
        if (total_samples == 0) return 0.0;
        return (bin_count >= min_hits) ? 100.0 : 0.0;
    endfunction
    
    // 测试序列
    initial begin
        reset = 1;
        addr = 8'h00;
        data = 8'h00;
        cmd = 4'h0;
        read = 0;
        write = 0;
        
        #20 reset = 0;
        
        // 系统性测试各种bins
        $display("开始bins覆盖率测试...");
        
        // 测试单值bins
        repeat (10) begin
            @(posedge clk);
            addr = 8'h00;  // 测试零值
        end
        
        repeat (10) begin
            @(posedge clk);
            addr = 8'hFF;  // 测试最大值
        end
        
        repeat (10) begin
            @(posedge clk);
            addr = 8'h80;  // 测试中间值
        end
        
        // 测试特殊值bins
        foreach (val_cg.addr_multi_cp.special_values[i]) begin
            repeat (5) begin
                @(posedge clk);
                case (i)
                    0: addr = 8'h00;
                    1: addr = 8'h55;
                    2: addr = 8'hAA;
                    3: addr = 8'hFF;
                endcase
            end
        end
        
        // 测试2的幂值
        repeat (5) begin
            @(posedge clk);
            addr = 8'h01;
        end
        repeat (5) begin
            @(posedge clk);
            addr = 8'h02;
        end
        repeat (5) begin
            @(posedge clk);
            addr = 8'h04;
        end
        
        // 测试范围bins
        repeat (20) begin
            @(posedge clk);
            addr = $random % 64;      // 低范围
        end
        
        repeat (20) begin
            @(posedge clk);
            addr = 64 + ($random % 64); // 中范围
        end
        
        // 测试条件bins
        repeat (30) begin
            @(posedge clk);
            read = 1;
            write = 0;
            data = $random % 128;     // 低数据值
        end
        
        repeat (30) begin
            @(posedge clk);
            read = 0;
            write = 1;
            data = 128 + ($random % 128); // 高数据值
        end
        
        // 随机测试
        repeat (200) begin
            @(posedge clk);
            addr = $random;
            data = $random;
            cmd = $random % 16;
            read = $random % 2;
            write = !read && ($random % 2);
        end
        
        // SystemVerilog覆盖率报告
        $display("\n=== SystemVerilog Bins覆盖率报告 ===");
        $display("总体覆盖率: %0.2f%%", val_cg.get_coverage());
        $display("单值地址覆盖率: %0.2f%%", val_cg.addr_single_cp.get_coverage());
        $display("多值地址覆盖率: %0.2f%%", val_cg.addr_multi_cp.get_coverage());
        $display("范围地址覆盖率: %0.2f%%", val_cg.addr_range_cp.get_coverage());
        $display("自动数据覆盖率: %0.2f%%", val_cg.data_auto_cp.get_coverage());
        $display("限制数据覆盖率: %0.2f%%", val_cg.data_limited_cp.get_coverage());
        $display("混合命令覆盖率: %0.2f%%", val_cg.cmd_mixed_cp.get_coverage());
        $display("条件bins覆盖率: %0.2f%%", val_cg.conditional_bins_cp.get_coverage());
        $display("默认bins覆盖率: %0.2f%%", val_cg.default_bins_cp.get_coverage());
        $display("表达式bins覆盖率: %0.2f%%", val_cg.expression_bins_cp.get_coverage());
        $display("组合bins覆盖率: %0.2f%%", val_cg.combo_bins_cp.get_coverage());
        
        $display("\n高级bins覆盖率:");
        $display("位模式覆盖率: %0.2f%%", adv_cg.bit_pattern_cp.get_coverage());
        $display("算术覆盖率: %0.2f%%", adv_cg.arithmetic_cp.get_coverage());
        $display("地址类型覆盖率: %0.2f%%", adv_cg.addr_type_cp.get_coverage());
        
        // 传统Verilog统计报告
        $display("\n=== 传统Verilog Bins统计 ===");
        $display("总采样数: %d", verilog_stats.total_samples);
        $display("零值计数: %d", verilog_stats.zero_count);
        $display("最大值计数: %d", verilog_stats.max_count);
        $display("中间值计数: %d", verilog_stats.mid_count);
        $display("特殊值计数: %d", verilog_stats.special_values_count);
        $display("2的幂计数: %d", verilog_stats.power_of_2_count);
        $display("范围统计: [%d, %d, %d, %d]",
                verilog_stats.low_range_count, verilog_stats.mid_range_count,
                verilog_stats.high_range_count, verilog_stats.top_range_count);
        $display("条件统计: 低数据读=%d, 高数据写=%d",
                verilog_stats.low_data_read_count, verilog_stats.high_data_write_count);
        
        $finish;
    end
endmodule

3.3 bins for sequence

SystemVerilog支持序列bins,用于捕获信号值的时序变化模式。

module bins_for_sequence_example;
    logic clk, reset;
    logic [7:0] addr, data;
    logic [1:0] state;
    logic read, write, valid;
    
    covergroup sequence_bins_cg @(posedge clk iff !reset);
        // 基本序列bins
        state_sequence_cp: coverpoint state {
            bins idle_to_active = (2'b00 => 2'b01);
            bins active_to_busy = (2'b01 => 2'b10);
            bins busy_to_idle   = (2'b10 => 2'b00);
            bins error_recovery = (2'b11 => 2'b00);
        }
        
        // 多步序列bins
        multi_step_cp: coverpoint state {
            bins normal_flow = (2'b00 => 2'b01 => 2'b10 => 2'b00);
            bins quick_cycle = (2'b00 => 2'b01 => 2'b00);
            bins error_flow  = (2'b00 => 2'b01 => 2'b11 => 2'b00);
        }
        
        // 重复序列bins
        repeat_sequence_cp: coverpoint state {
            bins stay_idle   = (2'b00[*2:5]);     // 保持idle状态2-5个周期
            bins stay_active = (2'b01[*1:3]);     // 保持active状态1-3个周期
            bins stay_busy   = (2'b10[*2:10]);    // 保持busy状态2-10个周期
        }
        
        // 通配符序列bins
        wildcard_sequence_cp: coverpoint addr[7:4] {
            bins ascending = (4'h0 => 4'h1 => 4'h2 => 4'h3);
            bins descending = (4'hF => 4'hE => 4'hD => 4'hC);
            bins any_to_zero = ([4'h1:4'hF] => 4'h0);
            bins zero_to_any = (4'h0 => [4'h1:4'hF]);
        }
        
        // 条件序列bins
        conditional_sequence_cp: coverpoint data {
            bins inc_sequence = ([0:254] => [1:255]) iff (valid);
            bins dec_sequence = ([1:255] => [0:254]) iff (valid);
            bins reset_sequence = ([1:255] => 0) iff (!valid);
        }
        
        // 复杂序列bins
        complex_sequence_cp: coverpoint {read, write} {
            bins read_burst  = (2'b10[*3:8]);     // 连续读3-8次
            bins write_burst = (2'b01[*2:5]);     // 连续写2-5次
            bins rw_pattern  = (2'b10 => 2'b01 => 2'b10 => 2'b01); // 读写交替
            bins idle_active = (2'b00[*1:3] => 2'b10[*1:2] => 2'b00[*1:3]);
        }
        
        // 开放序列bins(goto重复)
        goto_sequence_cp: coverpoint state {
            bins any_path_to_error = ([2'b00:2'b10] [-> 1] => 2'b11);
            bins recovery_attempts = (2'b11 [-> 1:5] => 2'b00);
        }
    endgroup
    
    // 高级序列bins示例
    covergroup advanced_sequence_cg @(posedge clk);
        // 地址序列模式
        addr_pattern_cp: coverpoint addr {
            bins addr_increment = ([0:254] => [1:255]);
            bins addr_decrement = ([1:255] => [0:254]);
            bins addr_wrap = (8'hFF => 8'h00);
            bins addr_jump = ([0:127] => [128:255]);
        }
        
        // 数据变化序列
        data_change_cp: coverpoint data {
            bins data_double = ([1:127] => [2:254]);  // 近似翻倍
            bins data_half   = ([2:254] => [1:127]);  // 近似减半
            bins data_invert = (8'h00 => 8'hFF, 8'hFF => 8'h00);
        }
        
        // 状态机序列
        state_machine_cp: coverpoint state {
            bins full_cycle = (2'b00 => 2'b01 => 2'b10 => 2'b00);
            bins error_entry = ([2'b00:2'b10] => 2'b11);
            bins error_exit = (2'b11 => [2'b00:2'b10]);
            bins loop_active = (2'b01[*2] => 2'b10[*2] => 2'b01[*2]);
        }
    endgroup
    
    // 实例化covergroup
    sequence_bins_cg seq_cg = new();
    advanced_sequence_cg adv_seq_cg = new();
    
    // 传统Verilog的序列检测(极其复杂)
    typedef struct {
        // 状态转换统计
        integer idle_to_active_count;
        integer active_to_busy_count;
        integer busy_to_idle_count;
        integer error_recovery_count;
        
        // 多步序列统计
        integer normal_flow_count;
        integer quick_cycle_count;
        integer error_flow_count;
        
        // 重复序列统计
        integer stay_idle_count;
        integer stay_active_count;
        integer stay_busy_count;
        
        // 序列检测状态
        integer idle_repeat_count;
        integer active_repeat_count;
        integer busy_repeat_count;
        
        // 复杂序列状态机
        typedef enum {
            SEQ_IDLE,
            SEQ_STEP1,
            SEQ_STEP2,
            SEQ_STEP3,
            SEQ_COMPLETE
        } sequence_state_e;
        
        sequence_state_e normal_flow_state;
        sequence_state_e quick_cycle_state;
        sequence_state_e error_flow_state;
        
        integer total_samples;
    } verilog_sequence_stats_t;
    
    verilog_sequence_stats_t verilog_stats;
    
    // 前一个状态记录
    logic [1:0] prev_state;
    logic [7:0] prev_addr, prev_data;
    logic prev_read, prev_write;
    
    // 手动序列检测逻辑
    always @(posedge clk) begin
        if (reset) begin
            prev_state = 2'b00;
            prev_addr = 8'h00;
            prev_data = 8'h00;
            prev_read = 0;
            prev_write = 0;
            verilog_stats.idle_repeat_count = 0;
            verilog_stats.active_repeat_count = 0;
            verilog_stats.busy_repeat_count = 0;
            verilog_stats.normal_flow_state = verilog_stats.SEQ_IDLE;
            verilog_stats.quick_cycle_state = verilog_stats.SEQ_IDLE;
            verilog_stats.error_flow_state = verilog_stats.SEQ_IDLE;
        end else begin
            verilog_stats.total_samples++;
            
            // 基本状态转换检测
            if (prev_state == 2'b00 && state == 2'b01)
                verilog_stats.idle_to_active_count++;
            else if (prev_state == 2'b01 && state == 2'b10)
                verilog_stats.active_to_busy_count++;
            else if (prev_state == 2'b10 && state == 2'b00)
                verilog_stats.busy_to_idle_count++;
            else if (prev_state == 2'b11 && state == 2'b00)
                verilog_stats.error_recovery_count++;
            
            // 重复状态检测
            if (state == prev_state) begin
                case (state)
                    2'b00: verilog_stats.idle_repeat_count++;
                    2'b01: verilog_stats.active_repeat_count++;
                    2'b10: verilog_stats.busy_repeat_count++;
                endcase
            end else begin
                // 检查重复序列完成
                if (prev_state == 2'b00 && verilog_stats.idle_repeat_count >= 2 && verilog_stats.idle_repeat_count <= 5)
                    verilog_stats.stay_idle_count++;
                if (prev_state == 2'b01 && verilog_stats.active_repeat_count >= 1 && verilog_stats.active_repeat_count <= 3)
                    verilog_stats.stay_active_count++;
                if (prev_state == 2'b10 && verilog_stats.busy_repeat_count >= 2 && verilog_stats.busy_repeat_count <= 10)
                    verilog_stats.stay_busy_count++;
                
                // 重置计数器
                verilog_stats.idle_repeat_count = 0;
                verilog_stats.active_repeat_count = 0;
                verilog_stats.busy_repeat_count = 0;
            end
            
            // 多步序列状态机 - 正常流程
            case (verilog_stats.normal_flow_state)
                verilog_stats.SEQ_IDLE: begin
                    if (state == 2'b00) verilog_stats.normal_flow_state = verilog_stats.SEQ_STEP1;
                end
                verilog_stats.SEQ_STEP1: begin
                    if (state == 2'b01) verilog_stats.normal_flow_state = verilog_stats.SEQ_STEP2;
                    else if (state != 2'b00) verilog_stats.normal_flow_state = verilog_stats.SEQ_IDLE;
                end
                verilog_stats.SEQ_STEP2: begin
                    if (state == 2'b10) verilog_stats.normal_flow_state = verilog_stats.SEQ_STEP3;
                    else verilog_stats.normal_flow_state = verilog_stats.SEQ_IDLE;
                end
                verilog_stats.SEQ_STEP3: begin
                    if (state == 2'b00) begin
                        verilog_stats.normal_flow_count++;
                        verilog_stats.normal_flow_state = verilog_stats.SEQ_STEP1;
                    end else begin
                        verilog_stats.normal_flow_state = verilog_stats.SEQ_IDLE;
                    end
                end
            endcase
            
            // 多步序列状态机 - 快速循环
            case (verilog_stats.quick_cycle_state)
                verilog_stats.SEQ_IDLE: begin
                    if (state == 2'b00) verilog_stats.quick_cycle_state = verilog_stats.SEQ_STEP1;
                end
                verilog_stats.SEQ_STEP1: begin
                    if (state == 2'b01) verilog_stats.quick_cycle_state = verilog_stats.SEQ_STEP2;
                    else if (state != 2'b00) verilog_stats.quick_cycle_state = verilog_stats.SEQ_IDLE;
                end
                verilog_stats.SEQ_STEP2: begin
                    if (state == 2'b00) begin
                        verilog_stats.quick_cycle_count++;
                        verilog_stats.quick_cycle_state = verilog_stats.SEQ_STEP1;
                    end else begin
                        verilog_stats.quick_cycle_state = verilog_stats.SEQ_IDLE;
                    end
                end
            endcase
            
            // 更新前一个状态
            prev_state = state;
            prev_addr = addr;
            prev_data = data;
            prev_read = read;
            prev_write = write;
        end
    end
    
    // 测试序列
    initial begin
        reset = 1;
        state = 2'b00;
        addr = 8'h00;
        data = 8'h00;
        read = 0;
        write = 0;
        valid = 0;
        
        #20 reset = 0;
        
        $display("开始序列bins测试...");
        
        // 测试基本状态转换
        @(posedge clk); state = 2'b00;  // idle
        @(posedge clk); state = 2'b01;  // idle -> active
        @(posedge clk); state = 2'b10;  // active -> busy
        @(posedge clk); state = 2'b00;  // busy -> idle
        
        // 测试错误恢复
        @(posedge clk); state = 2'b01;  // active
        @(posedge clk); state = 2'b11;  // error
        @(posedge clk); state = 2'b00;  // error -> idle
        
        // 测试多步序列 - 正常流程
        @(posedge clk); state = 2'b00;  // idle
        @(posedge clk); state = 2'b01;  // active
        @(posedge clk); state = 2'b10;  // busy
        @(posedge clk); state = 2'b00;  // idle (完成正常流程)
        
        // 测试快速循环
        @(posedge clk); state = 2'b00;  // idle
        @(posedge clk); state = 2'b01;  // active
        @(posedge clk); state = 2'b00;  // idle (完成快速循环)
        
        // 测试重复序列
        repeat (3) @(posedge clk) state = 2'b00;  // 保持idle 3个周期
        repeat (2) @(posedge clk) state = 2'b01;  // 保持active 2个周期
        repeat (4) @(posedge clk) state = 2'b10;  // 保持busy 4个周期
        @(posedge clk); state = 2'b00;
        
        // 测试地址序列
        valid = 1;
        for (int i = 0; i < 10; i++) begin
            @(posedge clk);
            addr = i;
        end
        
        // 测试地址回绕
        @(posedge clk); addr = 8'hFF;
        @(posedge clk); addr = 8'h00;
        
        // 测试数据序列
        for (int i = 100; i > 90; i--) begin
            @(posedge clk);
            data = i;
        end
        
        // 测试读写序列
        repeat (4) begin
            @(posedge clk); read = 1; write = 0;
        end
        
        repeat (3) begin
            @(posedge clk); read = 0; write = 1;
        end
        
        // 测试读写交替
        repeat (2) begin
            @(posedge clk); read = 1; write = 0;
            @(posedge clk); read = 0; write = 1;
        end
        
        // 随机测试
        repeat (100) begin
            @(posedge clk);
            state = $random % 4;
            addr = $random;
            data = $random;
            read = $random % 2;
            write = !read && ($random % 2);
            valid = $random % 2;
        end
        
        // SystemVerilog覆盖率报告
        $display("\n=== SystemVerilog序列Bins覆盖率报告 ===");
        $display("总体覆盖率: %0.2f%%", seq_cg.get_coverage());
        $display("状态序列覆盖率: %0.2f%%", seq_cg.state_sequence_cp.get_coverage());
        $display("多步序列覆盖率: %0.2f%%", seq_cg.multi_step_cp.get_coverage());
        $display("重复序列覆盖率: %0.2f%%", seq_cg.repeat_sequence_cp.get_coverage());
        $display("通配符序列覆盖率: %0.2f%%", seq_cg.wildcard_sequence_cp.get_coverage());
        $display("条件序列覆盖率: %0.2f%%", seq_cg.conditional_sequence_cp.get_coverage());
        $display("复杂序列覆盖率: %0.2f%%", seq_cg.complex_sequence_cp.get_coverage());
        $display("Goto序列覆盖率: %0.2f%%", seq_cg.goto_sequence_cp.get_coverage());
        
        $display("\n高级序列覆盖率:");
        $display("地址模式覆盖率: %0.2f%%", adv_seq_cg.addr_pattern_cp.get_coverage());
        $display("数据变化覆盖率: %0.2f%%", adv_seq_cg.data_change_cp.get_coverage());
        $display("状态机覆盖率: %0.2f%%", adv_seq_cg.state_machine_cp.get_coverage());
        
        // 传统Verilog序列统计
        $display("\n=== 传统Verilog序列统计 ===");
        $display("总采样数: %d", verilog_stats.total_samples);
        $display("状态转换统计:");
        $display("  idle->active: %d", verilog_stats.idle_to_active_count);
        $display("  active->busy: %d", verilog_stats.active_to_busy_count);
        $display("  busy->idle: %d", verilog_stats.busy_to_idle_count);
        $display("  error->idle: %d", verilog_stats.error_recovery_count);
        $display("多步序列统计:");
        $display("  正常流程: %d", verilog_stats.normal_flow_count);
        $display("  快速循环: %d", verilog_stats.quick_cycle_count);
        $display("重复序列统计:");
        $display("  保持idle: %d", verilog_stats.stay_idle_count);
        $display("  保持active: %d", verilog_stats.stay_active_count);
        $display("  保持busy: %d", verilog_stats.stay_busy_count);
        
        $finish;
    end
endmodule

3.4 wildcard、ignore_bins、illegal_bins

SystemVerilog提供了特殊的bins类型来处理通配符匹配、忽略特定值和标记非法值。

module wildcard_ignore_illegal_bins_example;
    logic clk, reset;
    logic [7:0] addr, data;
    logic [3:0] opcode;
    logic [1:0] mode;
    logic valid, error;
    
    covergroup special_bins_cg @(posedge clk iff !reset);
        // 通配符bins - 使用?匹配任意位
        addr_wildcard_cp: coverpoint addr {
            wildcard bins addr_pattern_0 = {8'b0000????};  // 低4位任意,高4位为0000
            wildcard bins addr_pattern_1 = {8'b0001????};  // 低4位任意,高4位为0001
            wildcard bins addr_pattern_f = {8'b1111????};  // 低4位任意,高4位为1111
            wildcard bins even_addr = {8'b???????0};      // 最低位为0(偶数)
            wildcard bins odd_addr  = {8'b???????1};      // 最低位为1(奇数)
        }
        
        // 通配符bins - 复杂模式
        data_wildcard_cp: coverpoint data {
            wildcard bins pattern_aa = {8'b10101010};       // 精确匹配
            wildcard bins pattern_a? = {8'b1010????};       // 高4位匹配1010
            wildcard bins pattern_?a = {8'b????1010};       // 低4位匹配1010
            wildcard bins pattern_alt = {8'b?0?0?0?0};      // 交替模式
            wildcard bins high_bit_set = {8'b1???????};    // 最高位为1
        }
        
        // ignore_bins - 忽略特定值,不参与覆盖率计算
        opcode_ignore_cp: coverpoint opcode {
            bins valid_opcodes = {[4'h0:4'h7]};            // 有效操作码
            bins extended_opcodes = {4'h8, 4'h9, 4'hA};    // 扩展操作码
            ignore_bins reserved = {4'hB, 4'hC};           // 保留操作码,忽略
            ignore_bins debug_only = {4'hD};               // 仅调试用,忽略
            ignore_bins future_use = {4'hE, 4'hF};         // 未来使用,忽略
        }
        
        // illegal_bins - 标记非法值,出现时报告错误
        mode_illegal_cp: coverpoint mode {
            bins normal_mode = {2'b00};                    // 正常模式
            bins test_mode   = {2'b01};                    // 测试模式
            bins debug_mode  = {2'b10};                    // 调试模式
            illegal_bins forbidden = {2'b11};              // 非法模式
        }
        
        // 组合使用通配符和ignore_bins
        addr_data_combo_cp: coverpoint {addr[7:4], data[3:0]} {
            wildcard bins high_addr_low_data = {8'b1111????};
            wildcard bins low_addr_high_data = {8'b0000????};
            bins specific_combo = {{4'h5}, {4'hA}};
            ignore_bins test_patterns = {{4'hF}, {4'hF}};  // 测试模式,忽略
            illegal_bins invalid_combo = {{4'h0}, {4'h0}}; // 无效组合
        }
        
        // 条件通配符bins
        conditional_wildcard_cp: coverpoint addr {
            wildcard bins valid_even = {8'b???????0} iff (valid);
            wildcard bins valid_odd  = {8'b???????1} iff (valid);
            ignore_bins invalid_data = {[8'h00:8'hFF]} iff (!valid);
        }
        
        // 复杂通配符模式
        complex_pattern_cp: coverpoint data {
            wildcard bins nibble_match_0 = {8'b0000????};
            wildcard bins nibble_match_1 = {8'b0001????};
            wildcard bins nibble_match_2 = {8'b0010????};
            wildcard bins nibble_match_3 = {8'b0011????};
            wildcard bins high_nibbles = {8'b????0000, 8'b????0001, 8'b????0010, 8'b????0011};
            ignore_bins test_nibbles = {8'b1110????, 8'b1111????};
            illegal_bins error_patterns = {8'b????????} iff (error);
        }
    endgroup
    
    // 高级特殊bins示例
    covergroup advanced_special_cg @(posedge clk);
        // 多层通配符
        multi_wildcard_cp: coverpoint {addr[7:6], addr[1:0]} {
            wildcard bins pattern_00 = {4'b00??};
            wildcard bins pattern_01 = {4'b01??};
            wildcard bins pattern_10 = {4'b10??};
            wildcard bins pattern_11 = {4'b11??};
            wildcard bins specific = {4'b?0?1, 4'b?1?0};
        }
        
        // 范围通配符
        range_wildcard_cp: coverpoint addr {
            wildcard bins low_range = {8'b000?????, 8'b001?????};
            wildcard bins mid_range = {8'b010?????, 8'b011?????};
            wildcard bins high_range = {8'b100?????, 8'b101?????};
            wildcard bins top_range = {8'b110?????, 8'b111?????};
            ignore_bins reserved_range = {[8'hF0:8'hFE]};
            illegal_bins error_addr = {8'hFF};
        }
        
        // 状态相关的特殊bins
        state_special_cp: coverpoint {valid, error, mode} {
            bins normal_states = {{1'b1, 1'b0, 2'b00}, {1'b1, 1'b0, 2'b01}};
            bins debug_states = {{1'b1, 1'b0, 2'b10}};
            ignore_bins transitional = {{1'b0, 1'b0, 2'b??}};
            illegal_bins error_states = {{1'b?, 1'b1, 2'b??}};
        }
    endgroup
    
    // 实例化covergroup
    special_bins_cg spec_cg = new();
    advanced_special_cg adv_spec_cg = new();
    
    // 传统Verilog的等价实现(极其复杂且容易出错)
    typedef struct {
        // 通配符模式统计
        integer addr_pattern_counts[5];  // 各种地址模式
        integer data_pattern_counts[5];  // 各种数据模式
        
        // 有效操作码统计
        integer valid_opcode_count;
        integer extended_opcode_count;
        // 注意:忽略的操作码不统计
        
        // 模式统计(排除非法值)
        integer normal_mode_count;
        integer test_mode_count;
        integer debug_mode_count;
        integer illegal_mode_detected;
        
        // 组合模式统计
        integer combo_pattern_counts[3];
        integer ignored_combo_count;
        integer illegal_combo_detected;
        
        // 条件模式统计
        integer valid_even_count, valid_odd_count;
        integer invalid_ignored_count;
        
        // 复杂模式统计
        integer nibble_counts[4];
        integer high_nibble_counts[4];
        integer test_nibble_ignored;
        integer error_pattern_detected;
        
        integer total_samples;
        integer error_count;
    } verilog_special_stats_t;
    
    verilog_special_stats_t verilog_stats;
    
    // 通配符匹配函数
    function bit wildcard_match_8bit(logic [7:0] value, logic [7:0] pattern, logic [7:0] mask);
        return ((value & mask) == (pattern & mask));
    endfunction
    
    function bit wildcard_match_4bit(logic [3:0] value, logic [3:0] pattern, logic [3:0] mask);
        return ((value & mask) == (pattern & mask));
    endfunction
    
    // 手动实现特殊bins逻辑
    always @(posedge clk) begin
        if (reset) begin
            verilog_stats = '{default: 0};
        end else begin
            verilog_stats.total_samples++;
            
            // 地址通配符模式检测
            if (wildcard_match_8bit(addr, 8'b00000000, 8'b11110000))
                verilog_stats.addr_pattern_counts[0]++;  // 0000????
            else if (wildcard_match_8bit(addr, 8'b00010000, 8'b11110000))
                verilog_stats.addr_pattern_counts[1]++;  // 0001????
            else if (wildcard_match_8bit(addr, 8'b11110000, 8'b11110000))
                verilog_stats.addr_pattern_counts[2]++;  // 1111????
            
            if (wildcard_match_8bit(addr, 8'b00000000, 8'b00000001))
                verilog_stats.addr_pattern_counts[3]++;  // ???????0 (偶数)
            else if (wildcard_match_8bit(addr, 8'b00000001, 8'b00000001))
                verilog_stats.addr_pattern_counts[4]++;  // ???????1 (奇数)
            
            // 数据通配符模式检测
            if (data == 8'b10101010)
                verilog_stats.data_pattern_counts[0]++;  // 精确匹配
            else if (wildcard_match_8bit(data, 8'b10100000, 8'b11110000))
                verilog_stats.data_pattern_counts[1]++;  // 1010????
            else if (wildcard_match_8bit(data, 8'b00001010, 8'b00001111))
                verilog_stats.data_pattern_counts[2]++;  // ????1010
            else if (wildcard_match_8bit(data, 8'b00000000, 8'b01010101))
                verilog_stats.data_pattern_counts[3]++;  // ?0?0?0?0
            else if (wildcard_match_8bit(data, 8'b10000000, 8'b10000000))
                verilog_stats.data_pattern_counts[4]++;  // 1???????
            
            // 操作码统计(忽略特定值)
            case (opcode)
                4'h0, 4'h1, 4'h2, 4'h3, 4'h4, 4'h5, 4'h6, 4'h7:
                    verilog_stats.valid_opcode_count++;
                4'h8, 4'h9, 4'hA:
                    verilog_stats.extended_opcode_count++;
                4'hB, 4'hC, 4'hD, 4'hE, 4'hF:
                    ; // 忽略这些值,不统计
            endcase
            
            // 模式统计(检测非法值)
            case (mode)
                2'b00: verilog_stats.normal_mode_count++;
                2'b01: verilog_stats.test_mode_count++;
                2'b10: verilog_stats.debug_mode_count++;
                2'b11: begin
                    verilog_stats.illegal_mode_detected++;
                    verilog_stats.error_count++;
                    $error("检测到非法模式: %b", mode);
                end
            endcase
            
            // 组合模式检测
            case ({addr[7:4], data[3:0]})
                {4'hF, 4'h0}, {4'hF, 4'h1}, {4'hF, 4'h2}, {4'hF, 4'h3},
                {4'hF, 4'h4}, {4'hF, 4'h5}, {4'hF, 4'h6}, {4'hF, 4'h7},
                {4'hF, 4'h8}, {4'hF, 4'h9}, {4'hF, 4'hA}, {4'hF, 4'hB},
                {4'hF, 4'hC}, {4'hF, 4'hD}, {4'hF, 4'hE}, {4'hF, 4'hF}:
                    verilog_stats.combo_pattern_counts[0]++;  // 高地址低数据
                {4'h0, 4'h0}, {4'h0, 4'h1}, {4'h0, 4'h2}, {4'h0, 4'h3},
                {4'h0, 4'h4}, {4'h0, 4'h5}, {4'h0, 4'h6}, {4'h0, 4'h7},
                {4'h0, 4'h8}, {4'h0, 4'h9}, {4'h0, 4'hA}, {4'h0, 4'hB},
                {4'h0, 4'hC}, {4'h0, 4'hD}, {4'h0, 4'hE}, {4'h0, 4'hF}:
                    verilog_stats.combo_pattern_counts[1]++;  // 低地址高数据
                {4'h5, 4'hA}:
                    verilog_stats.combo_pattern_counts[2]++;  // 特定组合
                {4'hF, 4'hF}:
                    verilog_stats.ignored_combo_count++;      // 忽略的测试模式
                {4'h0, 4'h0}: begin
                    verilog_stats.illegal_combo_detected++;
                    verilog_stats.error_count++;
                    $error("检测到非法组合: addr[7:4]=%h, data[3:0]=%h", addr[7:4], data[3:0]);
                end
            endcase
            
            // 条件通配符检测
            if (valid) begin
                if (addr[0] == 1'b0)
                    verilog_stats.valid_even_count++;
                else
                    verilog_stats.valid_odd_count++;
            end else begin
                verilog_stats.invalid_ignored_count++;  // 无效时忽略
            end
            
            // 复杂模式检测
            case (data[7:4])
                4'h0: verilog_stats.nibble_counts[0]++;
                4'h1: verilog_stats.nibble_counts[1]++;
                4'h2: verilog_stats.nibble_counts[2]++;
                4'h3: verilog_stats.nibble_counts[3]++;
                4'hE, 4'hF: verilog_stats.test_nibble_ignored++;  // 忽略测试模式
            endcase
            
            case (data[3:0])
                4'h0: verilog_stats.high_nibble_counts[0]++;
                4'h1: verilog_stats.high_nibble_counts[1]++;
                4'h2: verilog_stats.high_nibble_counts[2]++;
                4'h3: verilog_stats.high_nibble_counts[3]++;
            endcase
            
            // 错误模式检测
            if (error) begin
                verilog_stats.error_pattern_detected++;
                verilog_stats.error_count++;
                $error("检测到错误模式,数据值: %h", data);
            end
        end
    end
    
    // 覆盖率计算函数
    function real calculate_wildcard_coverage(integer pattern_counts[], integer total_patterns);
        integer hit_patterns = 0;
        for (int i = 0; i < total_patterns; i++) begin
            if (pattern_counts[i] > 0) hit_patterns++;
        end
        return (total_patterns > 0) ? (real'(hit_patterns) / real'(total_patterns) * 100.0) : 0.0;
    endfunction
    
    // 测试序列
    initial begin
        reset = 1;
        addr = 8'h00;
        data = 8'h00;
        opcode = 4'h0;
        mode = 2'b00;
        valid = 1;
        error = 0;
        
        #20 reset = 0;
        
        $display("开始特殊bins测试...");
        
        // 测试通配符地址模式
        $display("\n测试地址通配符模式:");
        @(posedge clk); addr = 8'b00000101;  // 0000???? 模式
        @(posedge clk); addr = 8'b00010011;  // 0001???? 模式
        @(posedge clk); addr = 8'b11111000;  // 1111???? 模式
        @(posedge clk); addr = 8'b10101010;  // 偶数地址
        @(posedge clk); addr = 8'b10101011;  // 奇数地址
        
        // 测试数据通配符模式
        $display("测试数据通配符模式:");
        @(posedge clk); data = 8'b10101010;  // 精确匹配
        @(posedge clk); data = 8'b10100111;  // 1010???? 模式
        @(posedge clk); data = 8'b11111010;  // ????1010 模式
        @(posedge clk); data = 8'b00000000;  // ?0?0?0?0 模式
        @(posedge clk); data = 8'b10110101;  // 1??????? 模式
        
        // 测试有效操作码
        $display("测试操作码(包含忽略值):");
        for (int i = 0; i < 16; i++) begin
            @(posedge clk);
            opcode = i;
            case (i)
                4'hB, 4'hC, 4'hD, 4'hE, 4'hF:
                    $display("  操作码 %h 被忽略", i);
                default:
                    $display("  操作码 %h 有效", i);
            endcase
        end
        
        // 测试模式(包含非法值)
        $display("测试模式(包含非法值):");
        @(posedge clk); mode = 2'b00;  // 正常模式
        @(posedge clk); mode = 2'b01;  // 测试模式
        @(posedge clk); mode = 2'b10;  // 调试模式
        
        $display("尝试非法模式(应该报错):");
        @(posedge clk); mode = 2'b11;  // 非法模式
        
        // 测试组合模式
        $display("测试组合模式:");
        @(posedge clk); addr = 8'hF5; data = 8'h3A;  // 高地址任意数据
        @(posedge clk); addr = 8'h05; data = 8'hFA;  // 低地址任意数据
        @(posedge clk); addr = 8'h5A; data = 8'hA5;  // 特定组合
        @(posedge clk); addr = 8'hFF; data = 8'hFF;  // 忽略的测试模式
        
        $display("尝试非法组合(应该报错):");
        @(posedge clk); addr = 8'h00; data = 8'h00;  // 非法组合
        
        // 测试条件通配符
        $display("测试条件通配符:");
        valid = 1;
        @(posedge clk); addr = 8'h42;  // 有效偶数
        @(posedge clk); addr = 8'h43;  // 有效奇数
        
        valid = 0;
        @(posedge clk); addr = 8'h44;  // 无效,应被忽略
        @(posedge clk); addr = 8'h45;  // 无效,应被忽略
        
        // 测试复杂模式
        $display("测试复杂模式:");
        valid = 1;
        @(posedge clk); data = 8'h00;  // nibble 0
        @(posedge clk); data = 8'h10;  // nibble 1
        @(posedge clk); data = 8'h20;  // nibble 2
        @(posedge clk); data = 8'h30;  // nibble 3
        @(posedge clk); data = 8'hE0;  // 忽略的测试nibble
        @(posedge clk); data = 8'hF0;  // 忽略的测试nibble
        
        // 测试错误模式
        $display("测试错误模式(应该报错):");
        error = 1;
        @(posedge clk); data = 8'h55;  // 错误状态下的任意数据
        error = 0;
        
        // 随机测试
        $display("随机测试:");
        repeat (100) begin
            @(posedge clk);
            addr = $random;
            data = $random;
            opcode = $random % 16;
            mode = $random % 4;
            valid = $random % 2;
            error = ($random % 20) == 0;  // 5%概率出现错误
        end
        
        // SystemVerilog覆盖率报告
        $display("\n=== SystemVerilog特殊Bins覆盖率报告 ===");
        $display("总体覆盖率: %0.2f%%", spec_cg.get_coverage());
        $display("地址通配符覆盖率: %0.2f%%", spec_cg.addr_wildcard_cp.get_coverage());
        $display("数据通配符覆盖率: %0.2f%%", spec_cg.data_wildcard_cp.get_coverage());
        $display("操作码覆盖率(忽略保留值): %0.2f%%", spec_cg.opcode_ignore_cp.get_coverage());
        $display("模式覆盖率(排除非法值): %0.2f%%", spec_cg.mode_illegal_cp.get_coverage());
        $display("组合覆盖率: %0.2f%%", spec_cg.addr_data_combo_cp.get_coverage());
        $display("条件通配符覆盖率: %0.2f%%", spec_cg.conditional_wildcard_cp.get_coverage());
        $display("复杂模式覆盖率: %0.2f%%", spec_cg.complex_pattern_cp.get_coverage());
        
        $display("\n高级特殊bins覆盖率:");
        $display("多层通配符覆盖率: %0.2f%%", adv_spec_cg.multi_wildcard_cp.get_coverage());
        $display("范围通配符覆盖率: %0.2f%%", adv_spec_cg.range_wildcard_cp.get_coverage());
        $display("状态特殊覆盖率: %0.2f%%", adv_spec_cg.state_special_cp.get_coverage());
        
        // 传统Verilog统计报告
        $display("\n=== 传统Verilog特殊Bins统计 ===");
        $display("总采样数: %d", verilog_stats.total_samples);
        $display("错误计数: %d", verilog_stats.error_count);
        
        $display("地址模式统计:");
        $display("  0000????: %d", verilog_stats.addr_pattern_counts[0]);
        $display("  0001????: %d", verilog_stats.addr_pattern_counts[1]);
        $display("  1111????: %d", verilog_stats.addr_pattern_counts[2]);
        $display("  偶数地址: %d", verilog_stats.addr_pattern_counts[3]);
        $display("  奇数地址: %d", verilog_stats.addr_pattern_counts[4]);
        
        $display("数据模式统计:");
        $display("  精确匹配: %d", verilog_stats.data_pattern_counts[0]);
        $display("  1010????: %d", verilog_stats.data_pattern_counts[1]);
        $display("  ????1010: %d", verilog_stats.data_pattern_counts[2]);
        $display("  ?0?0?0?0: %d", verilog_stats.data_pattern_counts[3]);
        $display("  1???????: %d", verilog_stats.data_pattern_counts[4]);
        
        $display("操作码统计(忽略保留值):");
        $display("  有效操作码: %d", verilog_stats.valid_opcode_count);
        $display("  扩展操作码: %d", verilog_stats.extended_opcode_count);
        
        $display("模式统计:");
        $display("  正常模式: %d", verilog_stats.normal_mode_count);
        $display("  测试模式: %d", verilog_stats.test_mode_count);
        $display("  调试模式: %d", verilog_stats.debug_mode_count);
        $display("  非法模式检测: %d", verilog_stats.illegal_mode_detected);
        
        $display("条件统计:");
        $display("  有效偶数: %d", verilog_stats.valid_even_count);
        $display("  有效奇数: %d", verilog_stats.valid_odd_count);
        $display("  无效忽略: %d", verilog_stats.invalid_ignored_count);
        
        $display("复杂模式统计:");
        $display("  Nibble统计: [%d, %d, %d, %d]",
                verilog_stats.nibble_counts[0], verilog_stats.nibble_counts[1],
                verilog_stats.nibble_counts[2], verilog_stats.nibble_counts[3]);
        $display("  测试nibble忽略: %d", verilog_stats.test_nibble_ignored);
        $display("  错误模式检测: %d", verilog_stats.error_pattern_detected);
        
        // 覆盖率计算
        $display("\n手动计算的覆盖率:");
        $display("地址模式覆盖率: %0.2f%%", calculate_wildcard_coverage(verilog_stats.addr_pattern_counts, 5));
        $display("数据模式覆盖率: %0.2f%%", calculate_wildcard_coverage(verilog_stats.data_pattern_counts, 5));
        
        $finish;
    end
endmodule

4 交叉覆盖率

交叉覆盖率(Cross Coverage)用于检测多个变量之间的组合覆盖情况,确保所有重要的变量组合都被测试到。

4.1 cross定义

module cross_coverage_example;
    logic clk, reset;
    logic [2:0] addr_type;
    logic [1:0] data_size;
    logic [1:0] burst_type;
    logic read_write;
    logic [3:0] priority;
    logic valid, ready;
    logic [7:0] data;
    
    covergroup cross_basic_cg @(posedge clk iff !reset);
        // 基本coverpoint定义
        addr_type_cp: coverpoint addr_type {
            bins sequential = {3'b000};
            bins random = {3'b001};
            bins fixed = {3'b010};
            bins burst = {3'b011};
            bins wrap = {3'b100};
            bins reserved = {[3'b101:3'b111]};
        }
        
        data_size_cp: coverpoint data_size {
            bins byte_size = {2'b00};
            bins half_word = {2'b01};
            bins word = {2'b10};
            bins double_word = {2'b11};
        }
        
        burst_type_cp: coverpoint burst_type {
            bins single = {2'b00};
            bins incr = {2'b01};
            bins wrap4 = {2'b10};
            bins wrap8 = {2'b11};
        }
        
        rw_cp: coverpoint read_write {
            bins read = {1'b0};
            bins write = {1'b1};
        }
        
        // 基本交叉覆盖率 - 地址类型与数据大小
        addr_data_cross: cross addr_type_cp, data_size_cp;
        
        // 三变量交叉覆盖率
        addr_data_burst_cross: cross addr_type_cp, data_size_cp, burst_type_cp;
        
        // 四变量交叉覆盖率
        full_transaction_cross: cross addr_type_cp, data_size_cp, burst_type_cp, rw_cp;
        
        // 带条件的交叉覆盖率
        valid_transaction_cross: cross addr_type_cp, data_size_cp, rw_cp iff (valid && ready);
    endgroup
    
    // 高级交叉覆盖率示例
    covergroup cross_advanced_cg @(posedge clk);
        // 优先级coverpoint
        priority_cp: coverpoint priority {
            bins low = {[4'h0:4'h3]};
            bins medium = {[4'h4:4'h7]};
            bins high = {[4'h8:4'hB]};
            bins critical = {[4'hC:4'hF]};
        }
        
        // 数据模式coverpoint
        data_pattern_cp: coverpoint data {
            bins zero = {8'h00};
            bins low_values = {[8'h01:8'h3F]};
            bins mid_values = {[8'h40:8'hBF]};
            bins high_values = {[8'hC0:8'hFE]};
            bins max = {8'hFF};
        }
        
        // 状态coverpoint
        state_cp: coverpoint {valid, ready} {
            bins idle = {2'b00};
            bins waiting = {2'b10};
            bins ready_state = {2'b01};
            bins active = {2'b11};
        }
        
        // 复杂交叉覆盖率
        priority_data_cross: cross priority_cp, data_pattern_cp;
        priority_state_cross: cross priority_cp, state_cp;
        data_state_cross: cross data_pattern_cp, state_cp;
        
        // 全面交叉覆盖率
        complete_cross: cross priority_cp, data_pattern_cp, state_cp;
    endgroup
    
    // 实例化covergroup
    cross_basic_cg basic_cross = new();
    cross_advanced_cg advanced_cross = new();
    
    // 传统Verilog的等价实现(非常复杂)
    typedef struct {
        // 二维交叉统计 - 地址类型 x 数据大小
        integer addr_data_matrix[6][4];  // 6种地址类型 x 4种数据大小
        
        // 三维交叉统计 - 地址类型 x 数据大小 x 突发类型
        integer addr_data_burst_cube[6][4][4];
        
        // 四维交叉统计 - 地址类型 x 数据大小 x 突发类型 x 读写
        integer full_transaction_hypercube[6][4][4][2];
        
        // 条件交叉统计
        integer valid_transaction_matrix[6][4][2];
        integer valid_condition_count;
        
        // 高级交叉统计
        integer priority_data_matrix[4][5];  // 4种优先级 x 5种数据模式
        integer priority_state_matrix[4][4]; // 4种优先级 x 4种状态
        integer data_state_matrix[5][4];     // 5种数据模式 x 4种状态
        integer complete_cube[4][5][4];      // 完整三维交叉
        
        // 统计计数器
        integer total_samples;
        integer valid_samples;
        
        // 覆盖率统计
        integer addr_data_hits;
        integer addr_data_burst_hits;
        integer full_transaction_hits;
        integer valid_transaction_hits;
        integer priority_data_hits;
        integer priority_state_hits;
        integer data_state_hits;
        integer complete_hits;
    } verilog_cross_stats_t;
    
    verilog_cross_stats_t verilog_cross_stats;
    
    // 映射函数
    function integer map_addr_type(logic [2:0] addr);
        case (addr)
            3'b000: return 0;  // sequential
            3'b001: return 1;  // random
            3'b010: return 2;  // fixed
            3'b011: return 3;  // burst
            3'b100: return 4;  // wrap
            default: return 5; // reserved
        endcase
    endfunction
    
    function integer map_data_size(logic [1:0] size);
        return size;  // 直接映射 0-3
    endfunction
    
    function integer map_burst_type(logic [1:0] burst);
        return burst;  // 直接映射 0-3
    endfunction
    
    function integer map_priority(logic [3:0] prio);
        if (prio <= 4'h3) return 0;      // low
        else if (prio <= 4'h7) return 1; // medium
        else if (prio <= 4'hB) return 2; // high
        else return 3;                   // critical
    endfunction
    
    function integer map_data_pattern(logic [7:0] data_val);
        if (data_val == 8'h00) return 0;           // zero
        else if (data_val <= 8'h3F) return 1;     // low_values
        else if (data_val <= 8'hBF) return 2;     // mid_values
        else if (data_val <= 8'hFE) return 3;     // high_values
        else return 4;                            // max (8'hFF)
    endfunction
    
    function integer map_state(logic valid_sig, logic ready_sig);
        return {valid_sig, ready_sig};  // 直接映射到0-3
    endfunction
    
    // 手动实现交叉覆盖率统计
    always @(posedge clk) begin
        if (reset) begin
            verilog_cross_stats = '{default: 0};
        end else begin
            automatic integer addr_idx = map_addr_type(addr_type);
            automatic integer data_idx = map_data_size(data_size);
            automatic integer burst_idx = map_burst_type(burst_type);
            automatic integer rw_idx = read_write;
            automatic integer prio_idx = map_priority(priority);
            automatic integer pattern_idx = map_data_pattern(data);
            automatic integer state_idx = map_state(valid, ready);
            
            verilog_cross_stats.total_samples++;
            
            // 二维交叉统计 - 地址类型 x 数据大小
            if (verilog_cross_stats.addr_data_matrix[addr_idx][data_idx] == 0) begin
                verilog_cross_stats.addr_data_hits++;
            end
            verilog_cross_stats.addr_data_matrix[addr_idx][data_idx]++;
            
            // 三维交叉统计 - 地址类型 x 数据大小 x 突发类型
            if (verilog_cross_stats.addr_data_burst_cube[addr_idx][data_idx][burst_idx] == 0) begin
                verilog_cross_stats.addr_data_burst_hits++;
            end
            verilog_cross_stats.addr_data_burst_cube[addr_idx][data_idx][burst_idx]++;
            
            // 四维交叉统计 - 完整事务
            if (verilog_cross_stats.full_transaction_hypercube[addr_idx][data_idx][burst_idx][rw_idx] == 0) begin
                verilog_cross_stats.full_transaction_hits++;
            end
            verilog_cross_stats.full_transaction_hypercube[addr_idx][data_idx][burst_idx][rw_idx]++;
            
            // 条件交叉统计 - 仅在valid && ready时统计
            if (valid && ready) begin
                verilog_cross_stats.valid_condition_count++;
                if (verilog_cross_stats.valid_transaction_matrix[addr_idx][data_idx][rw_idx] == 0) begin
                    verilog_cross_stats.valid_transaction_hits++;
                end
                verilog_cross_stats.valid_transaction_matrix[addr_idx][data_idx][rw_idx]++;
                verilog_cross_stats.valid_samples++;
            end
            
            // 高级交叉统计 - 优先级 x 数据模式
            if (verilog_cross_stats.priority_data_matrix[prio_idx][pattern_idx] == 0) begin
                verilog_cross_stats.priority_data_hits++;
            end
            verilog_cross_stats.priority_data_matrix[prio_idx][pattern_idx]++;
            
            // 优先级 x 状态
            if (verilog_cross_stats.priority_state_matrix[prio_idx][state_idx] == 0) begin
                verilog_cross_stats.priority_state_hits++;
            end
            verilog_cross_stats.priority_state_matrix[prio_idx][state_idx]++;
            
            // 数据模式 x 状态
            if (verilog_cross_stats.data_state_matrix[pattern_idx][state_idx] == 0) begin
                verilog_cross_stats.data_state_hits++;
            end
            verilog_cross_stats.data_state_matrix[pattern_idx][state_idx]++;
            
            // 完整三维交叉 - 优先级 x 数据模式 x 状态
            if (verilog_cross_stats.complete_cube[prio_idx][pattern_idx][state_idx] == 0) begin
                verilog_cross_stats.complete_hits++;
            end
            verilog_cross_stats.complete_cube[prio_idx][pattern_idx][state_idx]++;
        end
    end
    
    // 覆盖率计算函数
    function real calculate_cross_coverage(integer hits, integer total_bins);
        return (total_bins > 0) ? (real'(hits) / real'(total_bins) * 100.0) : 0.0;
    endfunction
    
    // 测试序列
    initial begin
        reset = 1;
        addr_type = 3'b000;
        data_size = 2'b00;
        burst_type = 2'b00;
        read_write = 1'b0;
        priority = 4'h0;
        valid = 0;
        ready = 0;
        data = 8'h00;
        
        #20 reset = 0;
        
        $display("开始交叉覆盖率测试...");
        
        // 系统性测试所有基本组合
        $display("\n系统性测试地址类型和数据大小组合:");
        for (int addr = 0; addr < 6; addr++) begin
            for (int size = 0; size < 4; size++) begin
                @(posedge clk);
                addr_type = addr;
                data_size = size;
                burst_type = $random % 4;
                read_write = $random % 2;
                priority = $random % 16;
                data = $random;
                valid = 1;
                ready = 1;
                $display("  测试组合: addr_type=%d, data_size=%d", addr, size);
            end
        end
        
        // 测试三维交叉
        $display("\n测试三维交叉覆盖率:");
        repeat (50) begin
            @(posedge clk);
            addr_type = $random % 6;
            data_size = $random % 4;
            burst_type = $random % 4;
            read_write = $random % 2;
            priority = $random % 16;
            data = $random;
            valid = $random % 2;
            ready = $random % 2;
        end
        
        // 测试条件交叉覆盖率
        $display("\n测试条件交叉覆盖率(valid && ready):");
        valid = 1;
        ready = 1;
        repeat (30) begin
            @(posedge clk);
            addr_type = $random % 6;
            data_size = $random % 4;
            read_write = $random % 2;
            priority = $random % 16;
            data = $random;
        end
        
        // 测试高级交叉组合
        $display("\n测试高级交叉组合:");
        for (int prio = 0; prio < 4; prio++) begin
            for (int pattern = 0; pattern < 5; pattern++) begin
                for (int state = 0; state < 4; state++) begin
                    @(posedge clk);
                    case (prio)
                        0: priority = $random % 4;        // low
                        1: priority = 4 + ($random % 4);  // medium
                        2: priority = 8 + ($random % 4);  // high
                        3: priority = 12 + ($random % 4); // critical
                    endcase
                    
                    case (pattern)
                        0: data = 8'h00;                    // zero
                        1: data = 1 + ($random % 63);       // low_values
                        2: data = 64 + ($random % 128);     // mid_values
                        3: data = 192 + ($random % 62);     // high_values
                        4: data = 8'hFF;                    // max
                    endcase
                    
                    {valid, ready} = state;
                    
                    addr_type = $random % 6;
                    data_size = $random % 4;
                    burst_type = $random % 4;
                    read_write = $random % 2;
                end
            end
        end
        
        // 随机压力测试
        $display("\n随机压力测试:");
        repeat (200) begin
            @(posedge clk);
            addr_type = $random % 8;  // 包含无效值
            data_size = $random % 4;
            burst_type = $random % 4;
            read_write = $random % 2;
            priority = $random % 16;
            data = $random;
            valid = $random % 2;
            ready = $random % 2;
        end
        
        // SystemVerilog交叉覆盖率报告
        $display("\n=== SystemVerilog交叉覆盖率报告 ===");
        $display("基本交叉覆盖率组:");
        $display("  总体覆盖率: %0.2f%%", basic_cross.get_coverage());
        $display("  地址-数据交叉: %0.2f%%", basic_cross.addr_data_cross.get_coverage());
        $display("  地址-数据-突发交叉: %0.2f%%", basic_cross.addr_data_burst_cross.get_coverage());
        $display("  完整事务交叉: %0.2f%%", basic_cross.full_transaction_cross.get_coverage());
        $display("  有效事务交叉: %0.2f%%", basic_cross.valid_transaction_cross.get_coverage());
        
        $display("\n高级交叉覆盖率组:");
        $display("  总体覆盖率: %0.2f%%", advanced_cross.get_coverage());
        $display("  优先级-数据交叉: %0.2f%%", advanced_cross.priority_data_cross.get_coverage());
        $display("  优先级-状态交叉: %0.2f%%", advanced_cross.priority_state_cross.get_coverage());
        $display("  数据-状态交叉: %0.2f%%", advanced_cross.data_state_cross.get_coverage());
        $display("  完整交叉: %0.2f%%", advanced_cross.complete_cross.get_coverage());
        
        // 传统Verilog交叉统计报告
        $display("\n=== 传统Verilog交叉统计 ===");
        $display("总采样数: %d", verilog_cross_stats.total_samples);
        $display("有效采样数: %d", verilog_cross_stats.valid_samples);
        
        $display("\n交叉覆盖率统计:");
        $display("  地址-数据交叉命中: %d/24 (%.2f%%)", 
                verilog_cross_stats.addr_data_hits,
                calculate_cross_coverage(verilog_cross_stats.addr_data_hits, 24));
        $display("  地址-数据-突发交叉命中: %d/96 (%.2f%%)", 
                verilog_cross_stats.addr_data_burst_hits,
                calculate_cross_coverage(verilog_cross_stats.addr_data_burst_hits, 96));
        $display("  完整事务交叉命中: %d/192 (%.2f%%)", 
                verilog_cross_stats.full_transaction_hits,
                calculate_cross_coverage(verilog_cross_stats.full_transaction_hits, 192));
        $display("  有效事务交叉命中: %d/48 (%.2f%%)", 
                verilog_cross_stats.valid_transaction_hits,
                calculate_cross_coverage(verilog_cross_stats.valid_transaction_hits, 48));
        $display("  优先级-数据交叉命中: %d/20 (%.2f%%)", 
                verilog_cross_stats.priority_data_hits,
                calculate_cross_coverage(verilog_cross_stats.priority_data_hits, 20));
        $display("  优先级-状态交叉命中: %d/16 (%.2f%%)", 
                verilog_cross_stats.priority_state_hits,
                calculate_cross_coverage(verilog_cross_stats.priority_state_hits, 16));
        $display("  数据-状态交叉命中: %d/20 (%.2f%%)", 
                verilog_cross_stats.data_state_hits,
                calculate_cross_coverage(verilog_cross_stats.data_state_hits, 20));
        $display("  完整三维交叉命中: %d/80 (%.2f%%)", 
                verilog_cross_stats.complete_hits,
                calculate_cross_coverage(verilog_cross_stats.complete_hits, 80));
        
        // 详细矩阵显示(部分)
        $display("\n地址-数据交叉矩阵(前3x3):");
        for (int i = 0; i < 3; i++) begin
            $write("  [%d]: ", i);
            for (int j = 0; j < 3; j++) begin
                $write("%3d ", verilog_cross_stats.addr_data_matrix[i][j]);
            end
            $display("");
        end
        
        $finish;
    end
endmodule

4.2 排除部分cross bin

在实际应用中,某些交叉组合可能是无效的或不需要测试的,SystemVerilog提供了多种方式来排除这些组合。

module cross_exclusion_example;
    logic clk, reset;
    logic [1:0] cmd_type;
    logic [2:0] addr_mode;
    logic [1:0] data_width;
    logic [3:0] burst_len;
    logic cache_enable;
    logic [1:0] protection;
    
    covergroup cross_exclude_cg @(posedge clk iff !reset);
        // 命令类型coverpoint
        cmd_cp: coverpoint cmd_type {
            bins read = {2'b00};
            bins write = {2'b01};
            bins rmw = {2'b10};     // read-modify-write
            bins reserved = {2'b11};
        }
        
        // 地址模式coverpoint
        addr_cp: coverpoint addr_mode {
            bins linear = {3'b000};
            bins burst = {3'b001};
            bins wrap = {3'b010};
            bins fixed = {3'b011};
            bins stream = {3'b100};
            bins reserved1 = {3'b101};
            bins reserved2 = {3'b110};
            bins invalid = {3'b111};
        }
        
        // 数据宽度coverpoint
        width_cp: coverpoint data_width {
            bins byte_width = {2'b00};
            bins half_word = {2'b01};
            bins word = {2'b10};
            bins double_word = {2'b11};
        }
        
        // 突发长度coverpoint
        burst_cp: coverpoint burst_len {
            bins single = {4'h1};
            bins short_burst = {[4'h2:4'h4]};
            bins medium_burst = {[4'h5:4'h8]};
            bins long_burst = {[4'h9:4'hF]};
            bins invalid = {4'h0};
        }
        
        // 缓存使能coverpoint
        cache_cp: coverpoint cache_enable {
            bins disabled = {1'b0};
            bins enabled = {1'b1};
        }
        
        // 保护级别coverpoint
        prot_cp: coverpoint protection {
            bins user = {2'b00};
            bins supervisor = {2'b01};
            bins secure = {2'b10};
            bins debug = {2'b11};
        }
        
        // 基本交叉覆盖率,排除无效组合
        cmd_addr_cross: cross cmd_cp, addr_cp {
            // 排除保留命令与所有地址模式的组合
            ignore_bins reserved_cmd = binsof(cmd_cp.reserved);
            
            // 排除无效地址模式与所有命令的组合
            ignore_bins invalid_addr = binsof(addr_cp.invalid);
            
            // 排除特定的无效组合
            ignore_bins rmw_fixed = binsof(cmd_cp.rmw) && binsof(addr_cp.fixed);
            ignore_bins rmw_stream = binsof(cmd_cp.rmw) && binsof(addr_cp.stream);
            
            // 排除保留地址模式
            ignore_bins reserved_addr = binsof(addr_cp.reserved1) || binsof(addr_cp.reserved2);
        }
        
        // 命令、地址、数据宽度三维交叉,带复杂排除条件
        cmd_addr_width_cross: cross cmd_cp, addr_cp, width_cp {
            // 排除所有包含保留/无效值的组合
            ignore_bins invalid_combinations = 
                binsof(cmd_cp.reserved) ||
                binsof(addr_cp.invalid) ||
                binsof(addr_cp.reserved1) ||
                binsof(addr_cp.reserved2);
            
            // 排除特定的硬件限制组合
            ignore_bins rmw_restrictions = 
                binsof(cmd_cp.rmw) && (
                    binsof(addr_cp.fixed) ||
                    binsof(addr_cp.stream) ||
                    binsof(width_cp.byte_width)
                );
            
            // 排除流模式的限制
            ignore_bins stream_restrictions = 
                binsof(addr_cp.stream) && (
                    binsof(width_cp.byte_width) ||
                    binsof(width_cp.half_word)
                );
            
            // 排除包装模式的限制
            ignore_bins wrap_restrictions = 
                binsof(addr_cp.wrap) && binsof(width_cp.double_word);
        }
        
        // 突发相关交叉,排除不合理的突发组合
        addr_burst_cross: cross addr_cp, burst_cp {
            // 排除无效突发长度
            ignore_bins invalid_burst = binsof(burst_cp.invalid);
            
            // 线性模式不支持长突发
            ignore_bins linear_long = 
                binsof(addr_cp.linear) && binsof(burst_cp.long_burst);
            
            // 固定模式只支持单次传输
            ignore_bins fixed_multi = 
                binsof(addr_cp.fixed) && (
                    binsof(burst_cp.short_burst) ||
                    binsof(burst_cp.medium_burst) ||
                    binsof(burst_cp.long_burst)
                );
            
            // 包装模式有特定的突发长度限制
            ignore_bins wrap_invalid = 
                binsof(addr_cp.wrap) && (
                    binsof(burst_cp.single) ||
                    binsof(burst_cp.long_burst)
                );
            
            // 流模式不支持短突发
            ignore_bins stream_short = 
                binsof(addr_cp.stream) && binsof(burst_cp.short_burst);
        }
        
        // 缓存和保护级别交叉
        cache_prot_cross: cross cache_cp, prot_cp {
            // 调试模式下禁用缓存
            ignore_bins debug_cached = 
                binsof(cache_cp.enabled) && binsof(prot_cp.debug);
        }
        
        // 复杂的四维交叉,带多重排除条件
        complex_cross: cross cmd_cp, addr_cp, width_cp, cache_cp {
            // 基本无效组合排除
            ignore_bins basic_invalid = 
                binsof(cmd_cp.reserved) ||
                binsof(addr_cp.invalid) ||
                binsof(addr_cp.reserved1) ||
                binsof(addr_cp.reserved2);
            
            // RMW命令的限制
            ignore_bins rmw_limits = 
                binsof(cmd_cp.rmw) && (
                    binsof(addr_cp.fixed) ||
                    binsof(addr_cp.stream) ||
                    (binsof(width_cp.byte_width) && binsof(cache_cp.enabled))
                );
            
            // 缓存相关限制
            ignore_bins cache_limits = 
                binsof(cache_cp.enabled) && (
                    binsof(addr_cp.fixed) ||
                    (binsof(addr_cp.stream) && binsof(width_cp.byte_width))
                );
            
            // 特定的架构限制
            ignore_bins arch_limits = 
                (binsof(addr_cp.wrap) && binsof(width_cp.double_word)) ||
                (binsof(addr_cp.stream) && binsof(width_cp.half_word) && binsof(cache_cp.disabled));
        }
        
        // 使用条件表达式的排除
        conditional_cross: cross cmd_cp, addr_cp, prot_cp {
            // 使用iff条件排除某些组合
            ignore_bins secure_restrictions = 
                binsof(prot_cp.secure) && (
                    binsof(addr_cp.stream) ||
                    binsof(cmd_cp.rmw)
                ) iff (cache_enable == 1'b0);
            
            // 用户模式的限制
            ignore_bins user_restrictions = 
                binsof(prot_cp.user) && (
                    binsof(addr_cp.reserved1) ||
                    binsof(addr_cp.reserved2)
                );
        }
    endgroup
    
    // 实例化covergroup
    cross_exclude_cg exclude_cg = new();
    
    // 传统Verilog实现(需要手动处理所有排除逻辑)
    typedef struct {
        // 有效组合计数器
        integer cmd_addr_valid_combinations;
        integer cmd_addr_width_valid_combinations;
        integer addr_burst_valid_combinations;
        integer cache_prot_valid_combinations;
        integer complex_valid_combinations;
        integer conditional_valid_combinations;
        
        // 排除组合计数器
        integer cmd_addr_excluded;
        integer cmd_addr_width_excluded;
        integer addr_burst_excluded;
        integer cache_prot_excluded;
        integer complex_excluded;
        integer conditional_excluded;
        
        // 总计数器
        integer total_samples;
        integer valid_samples;
        
        // 具体的有效组合矩阵(简化版)
        bit cmd_addr_matrix[4][8];        // 4命令 x 8地址模式
        bit cmd_addr_width_cube[4][8][4]; // 4命令 x 8地址 x 4宽度
        bit addr_burst_matrix[8][5];      // 8地址 x 5突发类型
        bit cache_prot_matrix[2][4];      // 2缓存 x 4保护
    } verilog_exclude_stats_t;
    
    verilog_exclude_stats_t verilog_exclude_stats;
    
    // 排除逻辑检查函数
    function bit is_cmd_addr_valid(logic [1:0] cmd, logic [2:0] addr);
        // 检查命令-地址组合是否有效
        if (cmd == 2'b11) return 0;  // 保留命令
        if (addr == 3'b111) return 0; // 无效地址
        if (addr == 3'b101 || addr == 3'b110) return 0; // 保留地址
        if (cmd == 2'b10 && (addr == 3'b011 || addr == 3'b100)) return 0; // RMW限制
        return 1;
    endfunction
    
    function bit is_cmd_addr_width_valid(logic [1:0] cmd, logic [2:0] addr, logic [1:0] width);
        // 首先检查基本的命令-地址有效性
        if (!is_cmd_addr_valid(cmd, addr)) return 0;
        
        // RMW命令的宽度限制
        if (cmd == 2'b10 && width == 2'b00) return 0; // RMW不支持字节宽度
        
        // 流模式的宽度限制
        if (addr == 3'b100 && (width == 2'b00 || width == 2'b01)) return 0;
        
        // 包装模式的宽度限制
        if (addr == 3'b010 && width == 2'b11) return 0;
        
        return 1;
    endfunction
    
    function bit is_addr_burst_valid(logic [2:0] addr, logic [3:0] burst);
        // 检查地址-突发组合是否有效
        if (burst == 4'h0) return 0; // 无效突发长度
        if (addr == 3'b111) return 0; // 无效地址
        
        // 线性模式不支持长突发
        if (addr == 3'b000 && burst >= 4'h9) return 0;
        
        // 固定模式只支持单次传输
        if (addr == 3'b011 && burst != 4'h1) return 0;
        
        // 包装模式的突发限制
        if (addr == 3'b010 && (burst == 4'h1 || burst >= 4'h9)) return 0;
        
        // 流模式不支持短突发
        if (addr == 3'b100 && (burst >= 4'h2 && burst <= 4'h4)) return 0;
        
        return 1;
    endfunction
    
    function bit is_cache_prot_valid(logic cache, logic [1:0] prot);
        // 调试模式下禁用缓存
        if (prot == 2'b11 && cache == 1'b1) return 0;
        return 1;
    endfunction
    
    function bit is_complex_valid(logic [1:0] cmd, logic [2:0] addr, logic [1:0] width, logic cache);
        // 基本有效性检查
        if (!is_cmd_addr_width_valid(cmd, addr, width)) return 0;
        
        // RMW命令的缓存限制
        if (cmd == 2'b10 && width == 2'b00 && cache == 1'b1) return 0;
        
        // 缓存相关限制
        if (cache == 1'b1) begin
            if (addr == 3'b011) return 0; // 固定模式不支持缓存
            if (addr == 3'b100 && width == 2'b00) return 0; // 流模式字节宽度不支持缓存
        end
        
        // 特定架构限制
        if (addr == 3'b010 && width == 2'b11) return 0; // 包装模式双字限制
        if (addr == 3'b100 && width == 2'b01 && cache == 1'b0) return 0; // 流模式半字无缓存限制
        
        return 1;
    endfunction
    
    // 手动实现排除逻辑的统计
    always @(posedge clk) begin
        if (reset) begin
            verilog_exclude_stats = '{default: 0};
        end else begin
            verilog_exclude_stats.total_samples++;
            
            // 检查并统计各种交叉组合
            if (is_cmd_addr_valid(cmd_type, addr_mode)) begin
                if (!verilog_exclude_stats.cmd_addr_matrix[cmd_type][addr_mode]) begin
                    verilog_exclude_stats.cmd_addr_valid_combinations++;
                    verilog_exclude_stats.cmd_addr_matrix[cmd_type][addr_mode] = 1;
                end
            end else begin
                verilog_exclude_stats.cmd_addr_excluded++;
            end
            
            if (is_cmd_addr_width_valid(cmd_type, addr_mode, data_width)) begin
                if (!verilog_exclude_stats.cmd_addr_width_cube[cmd_type][addr_mode][data_width]) begin
                    verilog_exclude_stats.cmd_addr_width_valid_combinations++;
                    verilog_exclude_stats.cmd_addr_width_cube[cmd_type][addr_mode][data_width] = 1;
                end
            end else begin
                verilog_exclude_stats.cmd_addr_width_excluded++;
            end
            
            if (is_addr_burst_valid(addr_mode, burst_len)) begin
                // 映射突发长度到索引
                automatic integer burst_idx;
                if (burst_len == 4'h1) burst_idx = 0;
                else if (burst_len >= 4'h2 && burst_len <= 4'h4) burst_idx = 1;
                else if (burst_len >= 4'h5 && burst_len <= 4'h8) burst_idx = 2;
                else if (burst_len >= 4'h9 && burst_len <= 4'hF) burst_idx = 3;
                else burst_idx = 4; // invalid
                
                if (burst_idx < 4 && !verilog_exclude_stats.addr_burst_matrix[addr_mode][burst_idx]) begin
                    verilog_exclude_stats.addr_burst_valid_combinations++;
                    verilog_exclude_stats.addr_burst_matrix[addr_mode][burst_idx] = 1;
                end
            end else begin
                verilog_exclude_stats.addr_burst_excluded++;
            end
            
            if (is_cache_prot_valid(cache_enable, protection)) begin
                if (!verilog_exclude_stats.cache_prot_matrix[cache_enable][protection]) begin
                    verilog_exclude_stats.cache_prot_valid_combinations++;
                    verilog_exclude_stats.cache_prot_matrix[cache_enable][protection] = 1;
                end
            end else begin
                verilog_exclude_stats.cache_prot_excluded++;
            end
            
            if (is_complex_valid(cmd_type, addr_mode, data_width, cache_enable)) begin
                verilog_exclude_stats.complex_valid_combinations++;
            end else begin
                verilog_exclude_stats.complex_excluded++;
            end
            
            // 条件排除逻辑
            if (protection == 2'b10 && (addr_mode == 3'b100 || cmd_type == 2'b10) && cache_enable == 1'b0) begin
                verilog_exclude_stats.conditional_excluded++;
            end else if (protection == 2'b00 && (addr_mode == 3'b101 || addr_mode == 3'b110)) begin
                verilog_exclude_stats.conditional_excluded++;
            end else begin
                verilog_exclude_stats.conditional_valid_combinations++;
            end
            
            verilog_exclude_stats.valid_samples++;
        end
    end
    
    // 测试序列
    initial begin
        reset = 1;
        cmd_type = 2'b00;
        addr_mode = 3'b000;
        data_width = 2'b00;
        burst_len = 4'h1;
        cache_enable = 1'b0;
        protection = 2'b00;
        
        #20 reset = 0;
        
        $display("开始交叉排除测试...");
        
        // 系统性测试所有可能的组合
        $display("\n系统性测试所有命令-地址组合:");
        for (int cmd = 0; cmd < 4; cmd++) begin
            for (int addr = 0; addr < 8; addr++) begin
                @(posedge clk);
                cmd_type = cmd;
                addr_mode = addr;
                data_width = $random % 4;
                burst_len = 1 + ($random % 15);
                cache_enable = $random % 2;
                protection = $random % 4;
                
                if (is_cmd_addr_valid(cmd_type, addr_mode)) begin
                    $display("  有效组合: cmd=%d, addr=%d", cmd, addr);
                end else begin
                    $display("  排除组合: cmd=%d, addr=%d", cmd, addr);
                end
            end
        end
        
        // 测试特定的排除场景
        $display("\n测试特定排除场景:");
        
        // 测试保留命令
        @(posedge clk); cmd_type = 2'b11; addr_mode = 3'b000;
        $display("  保留命令测试: 应被排除");
        
        // 测试无效地址
        @(posedge clk); cmd_type = 2'b00; addr_mode = 3'b111;
        $display("  无效地址测试: 应被排除");
        
        // 测试RMW限制
        @(posedge clk); cmd_type = 2'b10; addr_mode = 3'b011; data_width = 2'b00;
        $display("  RMW固定地址测试: 应被排除");
        
        // 测试缓存-保护限制
        @(posedge clk); cache_enable = 1'b1; protection = 2'b11;
        $display("  调试模式缓存测试: 应被排除");
        
        // 随机测试
        $display("\n随机测试:");
        repeat (100) begin
            @(posedge clk);
            cmd_type = $random % 4;
            addr_mode = $random % 8;
            data_width = $random % 4;
            burst_len = $random % 16;
            cache_enable = $random % 2;
            protection = $random % 4;
        end
        
        // SystemVerilog排除覆盖率报告
        $display("\n=== SystemVerilog排除覆盖率报告 ===");
        $display("总体覆盖率: %0.2f%%", exclude_cg.get_coverage());
        $display("命令-地址交叉: %0.2f%%", exclude_cg.cmd_addr_cross.get_coverage());
        $display("命令-地址-宽度交叉: %0.2f%%", exclude_cg.cmd_addr_width_cross.get_coverage());
        $display("地址-突发交叉: %0.2f%%", exclude_cg.addr_burst_cross.get_coverage());
        $display("缓存-保护交叉: %0.2f%%", exclude_cg.cache_prot_cross.get_coverage());
        $display("复杂交叉: %0.2f%%", exclude_cg.complex_cross.get_coverage());
        $display("条件交叉: %0.2f%%", exclude_cg.conditional_cross.get_coverage());
        
        // 传统Verilog排除统计报告
        $display("\n=== 传统Verilog排除统计 ===");
        $display("总采样数: %d", verilog_exclude_stats.total_samples);
        $display("有效采样数: %d", verilog_exclude_stats.valid_samples);
        
        $display("\n有效组合统计:");
        $display("  命令-地址有效组合: %d", verilog_exclude_stats.cmd_addr_valid_combinations);
        $display("  命令-地址-宽度有效组合: %d", verilog_exclude_stats.cmd_addr_width_valid_combinations);
        $display("  地址-突发有效组合: %d", verilog_exclude_stats.addr_burst_valid_combinations);
        $display("  缓存-保护有效组合: %d", verilog_exclude_stats.cache_prot_valid_combinations);
        $display("  复杂有效组合: %d", verilog_exclude_stats.complex_valid_combinations);
        $display("  条件有效组合: %d", verilog_exclude_stats.conditional_valid_combinations);
        
        $display("\n排除组合统计:");
        $display("  命令-地址排除: %d", verilog_exclude_stats.cmd_addr_excluded);
        $display("  命令-地址-宽度排除: %d", verilog_exclude_stats.cmd_addr_width_excluded);
        $display("  地址-突发排除: %d", verilog_exclude_stats.addr_burst_excluded);
        $display("  缓存-保护排除: %d", verilog_exclude_stats.cache_prot_excluded);
        $display("  复杂排除: %d", verilog_exclude_stats.complex_excluded);
        $display("  条件排除: %d", verilog_exclude_stats.conditional_excluded);
        
        $finish;
    end
endmodule

4.3 精细的交叉覆盖率指定

在复杂的验证场景中,我们需要对交叉覆盖率进行更精细的控制,包括指定特定的交叉组合、设置权重、定义自定义bins等。

module fine_grained_cross_example;
    logic clk, reset;
    logic [2:0] opcode;
    logic [1:0] operand_type;
    logic [3:0] register_id;
    logic [1:0] addressing_mode;
    logic [2:0] condition_code;
    logic exception_enable;
    logic [1:0] privilege_level;
    logic [7:0] immediate_value;
    
    covergroup fine_cross_cg @(posedge clk iff !reset);
        // 操作码coverpoint
        opcode_cp: coverpoint opcode {
            bins arithmetic = {3'b000, 3'b001, 3'b010};
            bins logical = {3'b011, 3'b100};
            bins memory = {3'b101, 3'b110};
            bins control = {3'b111};
        }
        
        // 操作数类型coverpoint
        operand_cp: coverpoint operand_type {
            bins register_reg = {2'b00};
            bins register_imm = {2'b01};
            bins memory_reg = {2'b10};
            bins memory_imm = {2'b11};
        }
        
        // 寄存器ID coverpoint
        reg_cp: coverpoint register_id {
            bins low_regs = {[4'h0:4'h3]};
            bins mid_regs = {[4'h4:4'h7]};
            bins high_regs = {[4'h8:4'hB]};
            bins special_regs = {[4'hC:4'hF]};
        }
        
        // 寻址模式coverpoint
        addr_mode_cp: coverpoint addressing_mode {
            bins direct = {2'b00};
            bins indirect = {2'b01};
            bins indexed = {2'b10};
            bins relative = {2'b11};
        }
        
        // 条件码coverpoint
        condition_cp: coverpoint condition_code {
            bins always = {3'b000};
            bins zero = {3'b001};
            bins negative = {3'b010};
            bins carry = {3'b011};
            bins overflow = {3'b100};
            bins parity = {3'b101};
            bins greater = {3'b110};
            bins less = {3'b111};
        }
        
        // 异常使能coverpoint
        exception_cp: coverpoint exception_enable {
            bins disabled = {1'b0};
            bins enabled = {1'b1};
        }
        
        // 特权级别coverpoint
        privilege_cp: coverpoint privilege_level {
            bins user = {2'b00};
            bins supervisor = {2'b01};
            bins kernel = {2'b10};
            bins hypervisor = {2'b11};
        }
        
        // 立即数值coverpoint
        immediate_cp: coverpoint immediate_value {
            bins zero = {8'h00};
            bins small = {[8'h01:8'h0F]};
            bins medium = {[8'h10:8'h7F]};
            bins large = {[8'h80:8'hFE]};
            bins max = {8'hFF};
        }
        
        // 基本的精细交叉覆盖率 - 指定特定bins组合
        opcode_operand_cross: cross opcode_cp, operand_cp {
            // 只关注特定的有意义组合
            bins arithmetic_reg_reg = binsof(opcode_cp.arithmetic) && binsof(operand_cp.register_reg);
            bins arithmetic_reg_imm = binsof(opcode_cp.arithmetic) && binsof(operand_cp.register_imm);
            bins logical_reg_reg = binsof(opcode_cp.logical) && binsof(operand_cp.register_reg);
            bins logical_reg_imm = binsof(opcode_cp.logical) && binsof(operand_cp.register_imm);
            bins memory_mem_reg = binsof(opcode_cp.memory) && binsof(operand_cp.memory_reg);
            bins memory_mem_imm = binsof(opcode_cp.memory) && binsof(operand_cp.memory_imm);
            bins control_any = binsof(opcode_cp.control);
            
            // 排除不合理的组合
            ignore_bins invalid_memory_combinations = 
                binsof(opcode_cp.memory) && (
                    binsof(operand_cp.register_reg) ||
                    binsof(operand_cp.register_imm)
                );
        }
        
        // 复杂的三维交叉 - 操作码、寄存器、寻址模式
        opcode_reg_addr_cross: cross opcode_cp, reg_cp, addr_mode_cp {
            // 算术操作的寄存器使用模式
            bins arith_low_direct = binsof(opcode_cp.arithmetic) && binsof(reg_cp.low_regs) && binsof(addr_mode_cp.direct);
            bins arith_mid_indirect = binsof(opcode_cp.arithmetic) && binsof(reg_cp.mid_regs) && binsof(addr_mode_cp.indirect);
            bins arith_high_indexed = binsof(opcode_cp.arithmetic) && binsof(reg_cp.high_regs) && binsof(addr_mode_cp.indexed);
            
            // 逻辑操作的寄存器使用模式
            bins logic_any_direct = binsof(opcode_cp.logical) && binsof(addr_mode_cp.direct);
            bins logic_special_any = binsof(opcode_cp.logical) && binsof(reg_cp.special_regs);
            
            // 内存操作的特殊组合
            bins mem_special_indirect = binsof(opcode_cp.memory) && binsof(reg_cp.special_regs) && binsof(addr_mode_cp.indirect);
            bins mem_any_indexed = binsof(opcode_cp.memory) && binsof(addr_mode_cp.indexed);
            bins mem_any_relative = binsof(opcode_cp.memory) && binsof(addr_mode_cp.relative);
            
            // 控制操作的限制
            bins control_special_direct = binsof(opcode_cp.control) && binsof(reg_cp.special_regs) && binsof(addr_mode_cp.direct);
            
            // 排除不合理的组合
            ignore_bins invalid_control = binsof(opcode_cp.control) && (
                binsof(addr_mode_cp.indirect) ||
                binsof(addr_mode_cp.indexed) ||
                binsof(addr_mode_cp.relative)
            );
        }
        
        // 条件执行的精细交叉
        condition_privilege_cross: cross condition_cp, privilege_cp, exception_cp {
            // 用户模式的条件限制
            bins user_basic_conditions = binsof(privilege_cp.user) && (
                binsof(condition_cp.always) ||
                binsof(condition_cp.zero) ||
                binsof(condition_cp.negative)
            ) && binsof(exception_cp.disabled);
            
            // 管理员模式的扩展条件
            bins supervisor_extended = binsof(privilege_cp.supervisor) && (
                binsof(condition_cp.carry) ||
                binsof(condition_cp.overflow) ||
                binsof(condition_cp.parity)
            );
            
            // 内核模式的完整条件支持
            bins kernel_full_conditions = binsof(privilege_cp.kernel) && (
                binsof(condition_cp.greater) ||
                binsof(condition_cp.less)
            ) && binsof(exception_cp.enabled);
            
            // 虚拟化模式的特殊处理
            bins hypervisor_special = binsof(privilege_cp.hypervisor) && binsof(exception_cp.enabled);
            
            // 排除危险组合
            ignore_bins dangerous_user = binsof(privilege_cp.user) && binsof(exception_cp.enabled) && (
                binsof(condition_cp.carry) ||
                binsof(condition_cp.overflow)
            );
        }
        
        // 立即数相关的精细交叉
        operand_immediate_cross: cross operand_cp, immediate_cp {
            // 只有立即数操作数类型才关心立即数值
            bins reg_imm_zero = binsof(operand_cp.register_imm) && binsof(immediate_cp.zero);
            bins reg_imm_small = binsof(operand_cp.register_imm) && binsof(immediate_cp.small);
            bins reg_imm_medium = binsof(operand_cp.register_imm) && binsof(immediate_cp.medium);
            bins reg_imm_large = binsof(operand_cp.register_imm) && binsof(immediate_cp.large);
            bins reg_imm_max = binsof(operand_cp.register_imm) && binsof(immediate_cp.max);
            
            bins mem_imm_zero = binsof(operand_cp.memory_imm) && binsof(immediate_cp.zero);
            bins mem_imm_small = binsof(operand_cp.memory_imm) && binsof(immediate_cp.small);
            bins mem_imm_medium = binsof(operand_cp.memory_imm) && binsof(immediate_cp.medium);
            bins mem_imm_large = binsof(operand_cp.memory_imm) && binsof(immediate_cp.large);
            bins mem_imm_max = binsof(operand_cp.memory_imm) && binsof(immediate_cp.max);
            
            // 排除非立即数操作数与立即数值的组合
            ignore_bins non_immediate = (
                binsof(operand_cp.register_reg) ||
                binsof(operand_cp.memory_reg)
            );
        }
        
        // 复杂的四维交叉 - 带权重的bins
        complex_four_way_cross: cross opcode_cp, operand_cp, privilege_cp, exception_cp {
            // 高优先级的关键组合
            bins critical_kernel_arith = binsof(opcode_cp.arithmetic) && 
                                        binsof(operand_cp.register_reg) && 
                                        binsof(privilege_cp.kernel) && 
                                        binsof(exception_cp.enabled) with (item.weight = 10);
            
            bins critical_kernel_mem = binsof(opcode_cp.memory) && 
                                      binsof(operand_cp.memory_reg) && 
                                      binsof(privilege_cp.kernel) && 
                                      binsof(exception_cp.enabled) with (item.weight = 10);
            
            // 中等优先级的组合
            bins medium_supervisor = binsof(privilege_cp.supervisor) && 
                                   binsof(exception_cp.enabled) with (item.weight = 5);
            
            // 低优先级的用户模式组合
            bins low_user = binsof(privilege_cp.user) && 
                           binsof(exception_cp.disabled) with (item.weight = 1);
            
            // 特殊的虚拟化组合
            bins special_hypervisor = binsof(privilege_cp.hypervisor) with (item.weight = 8);
            
            // 排除不支持的组合
            ignore_bins unsupported = binsof(opcode_cp.control) && 
                                     binsof(operand_cp.memory_imm);
        }
        
        // 使用表达式的精细交叉
        expression_cross: cross opcode_cp, reg_cp {
            // 使用表达式定义复杂的bins
            bins arithmetic_even_regs = binsof(opcode_cp.arithmetic) && 
                                       binsof(reg_cp) intersect {[4'h0:4'hF]} with 
                                       (register_id % 2 == 0);
            
            bins logical_odd_regs = binsof(opcode_cp.logical) && 
                                   binsof(reg_cp) intersect {[4'h0:4'hF]} with 
                                   (register_id % 2 == 1);
            
            bins memory_power_of_two = binsof(opcode_cp.memory) && 
                                      binsof(reg_cp) intersect {4'h1, 4'h2, 4'h4, 4'h8};
            
            bins control_fibonacci = binsof(opcode_cp.control) && 
                                    binsof(reg_cp) intersect {4'h1, 4'h1, 4'h2, 4'h3, 4'h5, 4'h8};
        }
        
        // 条件表达式的交叉
        conditional_expression_cross: cross opcode_cp, immediate_cp {
            // 只在特定条件下生效的bins
            bins arith_small_imm = binsof(opcode_cp.arithmetic) && 
                                  binsof(immediate_cp.small) iff 
                                  (operand_type == 2'b01); // register_imm
            
            bins logic_zero_imm = binsof(opcode_cp.logical) && 
                                 binsof(immediate_cp.zero) iff 
                                 (operand_type == 2'b01 && exception_enable == 1'b0);
            
            bins mem_large_imm = binsof(opcode_cp.memory) && 
                                binsof(immediate_cp.large) iff 
                                (operand_type == 2'b11 && privilege_level >= 2'b01);
        }
    endgroup
    
    // 实例化covergroup
    fine_cross_cg fine_cg = new();
    
    // 传统Verilog的等价实现(极其复杂)
    typedef struct {
        // 精细交叉统计结构
        integer opcode_operand_stats[7];  // 7个指定的bins
        integer opcode_reg_addr_stats[9]; // 9个指定的bins
        integer condition_privilege_stats[4]; // 4个主要bins组
        integer operand_immediate_stats[10]; // 10个立即数相关bins
        integer complex_four_way_stats[5]; // 5个四维交叉bins
        integer expression_stats[4]; // 4个表达式bins
        integer conditional_expression_stats[3]; // 3个条件表达式bins
        
        // 权重统计
        integer weighted_coverage_points;
        integer total_weight;
        
        // 条件统计
        integer conditional_hits;
        integer conditional_misses;
        
        // 表达式评估计数
        integer expression_evaluations;
        integer expression_matches;
        
        // 总体统计
        integer total_samples;
        integer valid_combinations;
    } verilog_fine_stats_t;
    
    verilog_fine_stats_t verilog_fine_stats;
    
    // 复杂的映射和检查函数
    function integer map_opcode_operand_bin(logic [2:0] op, logic [1:0] operand);
        case ({op, operand})
            {3'b000, 2'b00}, {3'b001, 2'b00}, {3'b010, 2'b00}: return 0; // arithmetic_reg_reg
            {3'b000, 2'b01}, {3'b001, 2'b01}, {3'b010, 2'b01}: return 1; // arithmetic_reg_imm
            {3'b011, 2'b00}, {3'b100, 2'b00}: return 2; // logical_reg_reg
            {3'b011, 2'b01}, {3'b100, 2'b01}: return 3; // logical_reg_imm
            {3'b101, 2'b10}, {3'b110, 2'b10}: return 4; // memory_mem_reg
            {3'b101, 2'b11}, {3'b110, 2'b11}: return 5; // memory_mem_imm
            {3'b111, 2'b00}, {3'b111, 2'b01}, {3'b111, 2'b10}, {3'b111, 2'b11}: return 6; // control_any
            default: return -1; // invalid or ignored
        endcase
    endfunction
    
    function bit is_valid_opcode_reg_addr(logic [2:0] op, logic [3:0] reg_id, logic [1:0] addr);
        // 复杂的有效性检查逻辑
        case (op)
            3'b000, 3'b001, 3'b010: begin // arithmetic
                if (reg_id <= 4'h3 && addr == 2'b00) return 1; // arith_low_direct
                if (reg_id >= 4'h4 && reg_id <= 4'h7 && addr == 2'b01) return 1; // arith_mid_indirect
                if (reg_id >= 4'h8 && reg_id <= 4'hB && addr == 2'b10) return 1; // arith_high_indexed
            end
            3'b011, 3'b100: begin // logical
                if (addr == 2'b00) return 1; // logic_any_direct
                if (reg_id >= 4'hC) return 1; // logic_special_any
            end
            3'b101, 3'b110: begin // memory
                if (reg_id >= 4'hC && addr == 2'b01) return 1; // mem_special_indirect
                if (addr == 2'b10 || addr == 2'b11) return 1; // mem_any_indexed/relative
            end
            3'b111: begin // control
                if (reg_id >= 4'hC && addr == 2'b00) return 1; // control_special_direct
            end
        endcase
        return 0;
    endfunction
    
    function integer get_bin_weight(logic [2:0] op, logic [1:0] operand, logic [1:0] priv, logic exc);
        // 根据组合返回权重
        if ((op == 3'b000 || op == 3'b001 || op == 3'b010) && operand == 2'b00 && priv == 2'b10 && exc == 1'b1)
            return 10; // critical_kernel_arith
        if ((op == 3'b101 || op == 3'b110) && operand == 2'b10 && priv == 2'b10 && exc == 1'b1)
            return 10; // critical_kernel_mem
        if (priv == 2'b01 && exc == 1'b1)
            return 5; // medium_supervisor
        if (priv == 2'b00 && exc == 1'b0)
            return 1; // low_user
        if (priv == 2'b11)
            return 8; // special_hypervisor
        return 1; // default weight
    endfunction
    
    function bit evaluate_expression_bin(logic [2:0] op, logic [3:0] reg_id);
        case (op)
            3'b000, 3'b001, 3'b010: return (reg_id % 2 == 0); // arithmetic_even_regs
            3'b011, 3'b100: return (reg_id % 2 == 1); // logical_odd_regs
            3'b101, 3'b110: return (reg_id == 4'h1 || reg_id == 4'h2 || reg_id == 4'h4 || reg_id == 4'h8); // memory_power_of_two
            3'b111: return (reg_id == 4'h1 || reg_id == 4'h2 || reg_id == 4'h3 || reg_id == 4'h5 || reg_id == 4'h8); // control_fibonacci
        endcase
        return 0;
    endfunction
    
    function bit evaluate_conditional_expression(logic [2:0] op, logic [7:0] imm, logic [1:0] operand, logic exc, logic [1:0] priv);
        case (op)
            3'b000, 3'b001, 3'b010: return (operand == 2'b01 && imm >= 8'h01 && imm <= 8'h0F); // arith_small_imm
            3'b011, 3'b100: return (operand == 2'b01 && exc == 1'b0 && imm == 8'h00); // logic_zero_imm
            3'b101, 3'b110: return (operand == 2'b11 && priv >= 2'b01 && imm >= 8'h80 && imm <= 8'hFE); // mem_large_imm
        endcase
        return 0;
    endfunction
    
    // 手动实现精细交叉覆盖率统计
    always @(posedge clk) begin
        if (reset) begin
            verilog_fine_stats = '{default: 0};
        end else begin
            automatic integer opcode_operand_bin = map_opcode_operand_bin(opcode, operand_type);
            automatic integer current_weight = get_bin_weight(opcode, operand_type, privilege_level, exception_enable);
            
            verilog_fine_stats.total_samples++;
            
            // 操作码-操作数交叉统计
            if (opcode_operand_bin >= 0) begin
                verilog_fine_stats.opcode_operand_stats[opcode_operand_bin]++;
            end
            
            // 操作码-寄存器-地址模式交叉统计
            if (is_valid_opcode_reg_addr(opcode, register_id, addressing_mode)) begin
                // 简化的统计,实际应该有更详细的分类
                case (opcode)
                    3'b000, 3'b001, 3'b010: verilog_fine_stats.opcode_reg_addr_stats[0]++; // arithmetic bins
                    3'b011, 3'b100: verilog_fine_stats.opcode_reg_addr_stats[1]++; // logical bins
                    3'b101, 3'b110: verilog_fine_stats.opcode_reg_addr_stats[2]++; // memory bins
                    3'b111: verilog_fine_stats.opcode_reg_addr_stats[3]++; // control bins
                endcase
            end
            
            // 条件-特权级别交叉统计
            case (privilege_level)
                2'b00: if (!exception_enable) verilog_fine_stats.condition_privilege_stats[0]++; // user_basic
                2'b01: if (exception_enable) verilog_fine_stats.condition_privilege_stats[1]++; // supervisor_extended
                2'b10: if (exception_enable) verilog_fine_stats.condition_privilege_stats[2]++; // kernel_full
                2'b11: if (exception_enable) verilog_fine_stats.condition_privilege_stats[3]++; // hypervisor_special
            endcase
            
            // 操作数-立即数交叉统计
            if (operand_type == 2'b01 || operand_type == 2'b11) begin // 只有立即数操作数
                case (immediate_value)
                    8'h00: verilog_fine_stats.operand_immediate_stats[0]++; // zero
                    8'h01: case(8'h0F) verilog_fine_stats.operand_immediate_stats[1]++; endcase // small
                    // ... 其他立即数范围的统计
                endcase
            end
            
            // 权重统计
            verilog_fine_stats.weighted_coverage_points += current_weight;
            verilog_fine_stats.total_weight += current_weight;
            
            // 表达式评估
            verilog_fine_stats.expression_evaluations++;
            if (evaluate_expression_bin(opcode, register_id)) begin
                verilog_fine_stats.expression_matches++;
                case (opcode)
                    3'b000, 3'b001, 3'b010: verilog_fine_stats.expression_stats[0]++; // arithmetic_even
                    3'b011, 3'b100: verilog_fine_stats.expression_stats[1]++; // logical_odd
                    3'b101, 3'b110: verilog_fine_stats.expression_stats[2]++; // memory_power_of_two
                    3'b111: verilog_fine_stats.expression_stats[3]++; // control_fibonacci
                endcase
            end
            
            // 条件表达式评估
            if (evaluate_conditional_expression(opcode, immediate_value, operand_type, exception_enable, privilege_level)) begin
                verilog_fine_stats.conditional_hits++;
                case (opcode)
                    3'b000, 3'b001, 3'b010: verilog_fine_stats.conditional_expression_stats[0]++; // arith_small_imm
                    3'b011, 3'b100: verilog_fine_stats.conditional_expression_stats[1]++; // logic_zero_imm
                    3'b101, 3'b110: verilog_fine_stats.conditional_expression_stats[2]++; // mem_large_imm
                endcase
            end else begin
                verilog_fine_stats.conditional_misses++;
            end
            
            verilog_fine_stats.valid_combinations++;
        end
    end
    
    // 测试序列
    initial begin
        reset = 1;
        opcode = 3'b000;
        operand_type = 2'b00;
        register_id = 4'h0;
        addressing_mode = 2'b00;
        condition_code = 3'b000;
        exception_enable = 1'b0;
        privilege_level = 2'b00;
        immediate_value = 8'h00;
        
        #20 reset = 0;
        
        $display("开始精细交叉覆盖率测试...");
        
        // 系统性测试指定的bins组合
        $display("\n测试操作码-操作数精细组合:");
        
        // 算术-寄存器组合
        @(posedge clk); opcode = 3'b000; operand_type = 2'b00;
        $display("  算术-寄存器组合");
        
        // 算术-立即数组合
        @(posedge clk); opcode = 3'b001; operand_type = 2'b01; immediate_value = 8'h05;
        $display("  算术-立即数组合");
        
        // 逻辑-寄存器组合
        @(posedge clk); opcode = 3'b011; operand_type = 2'b00;
        $display("  逻辑-寄存器组合");
        
        // 内存-内存寄存器组合
        @(posedge clk); opcode = 3'b101; operand_type = 2'b10;
        $display("  内存-内存寄存器组合");
        
        // 控制指令组合
        @(posedge clk); opcode = 3'b111; operand_type = 2'b00;
        $display("  控制指令组合");
        
        // 测试权重相关的组合
        $display("\n测试权重相关组合:");
        
        // 高权重:内核模式算术操作
        @(posedge clk); 
        opcode = 3'b000; operand_type = 2'b00; privilege_level = 2'b10; exception_enable = 1'b1;
        $display("  高权重:内核模式算术操作 (权重=10)");
        
        // 高权重:内核模式内存操作
        @(posedge clk); 
        opcode = 3'b101; operand_type = 2'b10; privilege_level = 2'b10; exception_enable = 1'b1;
        $display("  高权重:内核模式内存操作 (权重=10)");
        
        // 中等权重:管理员模式
        @(posedge clk); 
        privilege_level = 2'b01; exception_enable = 1'b1;
        $display("  中等权重:管理员模式 (权重=5)");
        
        // 特殊权重:虚拟化模式
        @(posedge clk); 
        privilege_level = 2'b11;
        $display("  特殊权重:虚拟化模式 (权重=8)");
        
        // 测试表达式bins
        $display("\n测试表达式bins:");
        
        // 算术操作 + 偶数寄存器
        for (int i = 0; i < 16; i += 2) begin
            @(posedge clk);
            opcode = 3'b000; register_id = i;
            $display("  算术操作 + 偶数寄存器: reg=%d", i);
        end
        
        // 逻辑操作 + 奇数寄存器
        for (int i = 1; i < 16; i += 2) begin
            @(posedge clk);
            opcode = 3'b011; register_id = i;
            $display("  逻辑操作 + 奇数寄存器: reg=%d", i);
        end
        
        // 内存操作 + 2的幂寄存器
        @(posedge clk); opcode = 3'b101; register_id = 4'h1;
        @(posedge clk); opcode = 3'b101; register_id = 4'h2;
        @(posedge clk); opcode = 3'b101; register_id = 4'h4;
        @(posedge clk); opcode = 3'b101; register_id = 4'h8;
        $display("  内存操作 + 2的幂寄存器");
        
        // 控制操作 + 斐波那契寄存器
        @(posedge clk); opcode = 3'b111; register_id = 4'h1;
        @(posedge clk); opcode = 3'b111; register_id = 4'h2;
        @(posedge clk); opcode = 3'b111; register_id = 4'h3;
        @(posedge clk); opcode = 3'b111; register_id = 4'h5;
        @(posedge clk); opcode = 3'b111; register_id = 4'h8;
        $display("  控制操作 + 斐波那契寄存器");
        
        // 测试条件表达式bins
        $display("\n测试条件表达式bins:");
        
        // 算术 + 小立即数 (条件:operand_type == register_imm)
        @(posedge clk); 
        opcode = 3'b000; operand_type = 2'b01; immediate_value = 8'h05;
        $display("  算术 + 小立即数 (满足条件)");
        
        // 逻辑 + 零立即数 (条件:operand_type == register_imm && exception_enable == 0)
        @(posedge clk); 
        opcode = 3'b011; operand_type = 2'b01; immediate_value = 8'h00; exception_enable = 1'b0;
        $display("  逻辑 + 零立即数 (满足条件)");
        
        // 内存 + 大立即数 (条件:operand_type == memory_imm && privilege_level >= supervisor)
        @(posedge clk); 
        opcode = 3'b101; operand_type = 2'b11; immediate_value = 8'h90; privilege_level = 2'b01;
        $display("  内存 + 大立即数 (满足条件)");
        
        // 随机压力测试
        $display("\n随机压力测试:");
        repeat (100) begin
            @(posedge clk);
            opcode = $random % 8;
            operand_type = $random % 4;
            register_id = $random % 16;
            addressing_mode = $random % 4;
            condition_code = $random % 8;
            exception_enable = $random % 2;
            privilege_level = $random % 4;
            immediate_value = $random;
        end
        
        // SystemVerilog精细覆盖率报告
        $display("\n=== SystemVerilog精细覆盖率报告 ===");
        $display("总体覆盖率: %0.2f%%", fine_cg.get_coverage());
        $display("操作码-操作数交叉: %0.2f%%", fine_cg.opcode_operand_cross.get_coverage());
        $display("操作码-寄存器-地址交叉: %0.2f%%", fine_cg.opcode_reg_addr_cross.get_coverage());
        $display("条件-特权级别交叉: %0.2f%%", fine_cg.condition_privilege_cross.get_coverage());
        $display("操作数-立即数交叉: %0.2f%%", fine_cg.operand_immediate_cross.get_coverage());
        $display("复杂四维交叉: %0.2f%%", fine_cg.complex_four_way_cross.get_coverage());
        $display("表达式交叉: %0.2f%%", fine_cg.expression_cross.get_coverage());
        $display("条件表达式交叉: %0.2f%%", fine_cg.conditional_expression_cross.get_coverage());
        
        // 传统Verilog精细统计报告
        $display("\n=== 传统Verilog精细统计 ===");
        $display("总采样数: %d", verilog_fine_stats.total_samples);
        $display("有效组合数: %d", verilog_fine_stats.valid_combinations);
        $display("总权重: %d", verilog_fine_stats.total_weight);
        $display("加权覆盖点: %d", verilog_fine_stats.weighted_coverage_points);
        
        $display("\n表达式评估统计:");
        $display("  表达式评估次数: %d", verilog_fine_stats.expression_evaluations);
        $display("  表达式匹配次数: %d", verilog_fine_stats.expression_matches);
        $display("  表达式匹配率: %0.2f%%", 
                real'(verilog_fine_stats.expression_matches) / real'(verilog_fine_stats.expression_evaluations) * 100.0);
        
        $display("\n条件表达式统计:");
        $display("  条件命中: %d", verilog_fine_stats.conditional_hits);
        $display("  条件未命中: %d", verilog_fine_stats.conditional_misses);
        $display("  条件命中率: %0.2f%%", 
                real'(verilog_fine_stats.conditional_hits) / 
                real'(verilog_fine_stats.conditional_hits + verilog_fine_stats.conditional_misses) * 100.0);
        
        $display("\n操作码-操作数bins统计:");
        for (int i = 0; i < 7; i++) begin
            $display("  Bin[%d]: %d hits", i, verilog_fine_stats.opcode_operand_stats[i]);
        end
        
        $display("\n表达式bins统计:");
        $display("  算术偶数寄存器: %d", verilog_fine_stats.expression_stats[0]);
        $display("  逻辑奇数寄存器: %d", verilog_fine_stats.expression_stats[1]);
        $display("  内存2的幂寄存器: %d", verilog_fine_stats.expression_stats[2]);
        $display("  控制斐波那契寄存器: %d", verilog_fine_stats.expression_stats[3]);
        
        $finish;
    end
endmodule

5. 覆盖率选项

覆盖率选项允许我们精确控制覆盖率的收集行为,包括目标、权重、采样条件等。SystemVerilog提供了丰富的选项来定制覆盖率收集。

5.1 基本覆盖率选项

module coverage_options_example;
    logic clk, reset;
    logic [3:0] data;
    logic [1:0] mode;
    logic enable;
    logic [7:0] address;
    logic [15:0] value;
    
    // 基本覆盖率选项示例
    covergroup basic_options_cg @(posedge clk iff !reset);
        // 全局选项设置
        option.per_instance = 1;        // 每个实例独立统计
        option.goal = 95;               // 覆盖率目标95%
        option.name = "basic_coverage"; // 覆盖组名称
        option.comment = "基本功能覆盖率收集"; // 注释
        option.at_least = 2;            // 每个bin至少命中2次
        option.detect_overlap = 1;      // 检测重叠的bins
        option.auto_bin_max = 64;       // 自动bin的最大数量
        option.cross_num_print_missing = 10; // 打印缺失交叉的数量
        
        // 数据coverpoint with options
        data_cp: coverpoint data {
            option.weight = 5;          // 权重设置
            option.goal = 100;          // 个别目标
            option.comment = "数据值覆盖";
            option.at_least = 3;        // 至少命中3次
            
            bins low = {[4'h0:4'h3]};
            bins mid = {[4'h4:4'h7]};
            bins high = {[4'h8:4'hB]};
            bins max = {[4'hC:4'hF]};
        }
        
        // 模式coverpoint with different options
        mode_cp: coverpoint mode {
            option.weight = 3;
            option.goal = 90;
            option.comment = "操作模式覆盖";
            option.at_least = 1;
            
            bins read_mode = {2'b00};
            bins write_mode = {2'b01};
            bins test_mode = {2'b10};
            bins debug_mode = {2'b11};
        }
        
        // 使能coverpoint
        enable_cp: coverpoint enable {
            option.weight = 1;
            option.comment = "使能信号覆盖";
            
            bins disabled = {1'b0};
            bins enabled = {1'b1};
        }
        
        // 地址coverpoint with auto bins
        address_cp: coverpoint address {
            option.auto_bin_max = 16;   // 限制自动bin数量
            option.weight = 4;
            option.comment = "地址空间覆盖";
        }
        
        // 交叉覆盖with options
        data_mode_cross: cross data_cp, mode_cp {
            option.weight = 10;         // 交叉覆盖权重
            option.goal = 85;           // 交叉覆盖目标
            option.comment = "数据-模式交叉覆盖";
            option.at_least = 2;        // 交叉至少命中2次
            
            // 忽略某些组合
            ignore_bins invalid_combinations = 
                binsof(data_cp.max) && binsof(mode_cp.debug_mode);
        }
    endgroup
    
    // 实例化covergroup
    basic_options_cg basic_cg = new();
    
    // 传统Verilog的等价实现
    typedef struct {
        // 基本统计
        integer total_samples;
        integer valid_samples;
        
        // 权重相关
        integer weighted_hits[4];       // 对应4个coverpoint的权重命中
        integer total_weight;
        real weighted_coverage;
        
        // 目标相关
        integer coverage_goals[4];      // 各coverpoint的目标
        real actual_coverage[4];        // 实际覆盖率
        bit goals_met[4];              // 目标是否达成
        
        // at_least相关
        integer min_hits_required[4];   // 最小命中次数要求
        integer actual_hits[4][16];     // 实际命中次数(假设最多16个bins)
        bit at_least_met[4][16];       // 最小命中是否满足
        
        // 交叉覆盖统计
        integer cross_total_combinations;
        integer cross_hit_combinations;
        integer cross_ignored_combinations;
        real cross_coverage;
        
        // 重叠检测
        integer overlap_detected;
        integer overlap_warnings;
        
        // 自动bin统计
        integer auto_bins_created;
        integer auto_bin_max_limit;
        
        // 实例统计
        string instance_name;
        integer per_instance_samples;
    } verilog_options_stats_t;
    
    verilog_options_stats_t verilog_options_stats;
    
    // 权重计算函数
    function real calculate_weighted_coverage();
        integer total_weighted_hits = 0;
        integer total_possible_weight = 0;
        
        // 数据coverpoint: 权重5
        total_weighted_hits += verilog_options_stats.weighted_hits[0] * 5;
        total_possible_weight += 4 * 5; // 4个bins * 权重5
        
        // 模式coverpoint: 权重3
        total_weighted_hits += verilog_options_stats.weighted_hits[1] * 3;
        total_possible_weight += 4 * 3; // 4个bins * 权重3
        
        // 使能coverpoint: 权重1
        total_weighted_hits += verilog_options_stats.weighted_hits[2] * 1;
        total_possible_weight += 2 * 1; // 2个bins * 权重1
        
        // 地址coverpoint: 权重4
        total_weighted_hits += verilog_options_stats.weighted_hits[3] * 4;
        total_possible_weight += 16 * 4; // 16个auto bins * 权重4
        
        return real'(total_weighted_hits) / real'(total_possible_weight) * 100.0;
    endfunction
    
    // 目标检查函数
    function void check_coverage_goals();
        // 数据coverpoint目标检查 (100%)
        verilog_options_stats.actual_coverage[0] = real'(verilog_options_stats.weighted_hits[0]) / 4.0 * 100.0;
        verilog_options_stats.goals_met[0] = (verilog_options_stats.actual_coverage[0] >= 100.0);
        
        // 模式coverpoint目标检查 (90%)
        verilog_options_stats.actual_coverage[1] = real'(verilog_options_stats.weighted_hits[1]) / 4.0 * 100.0;
        verilog_options_stats.goals_met[1] = (verilog_options_stats.actual_coverage[1] >= 90.0);
        
        // 使能coverpoint目标检查 (95% - 全局默认)
        verilog_options_stats.actual_coverage[2] = real'(verilog_options_stats.weighted_hits[2]) / 2.0 * 100.0;
        verilog_options_stats.goals_met[2] = (verilog_options_stats.actual_coverage[2] >= 95.0);
        
        // 地址coverpoint目标检查 (95% - 全局默认)
        verilog_options_stats.actual_coverage[3] = real'(verilog_options_stats.weighted_hits[3]) / 16.0 * 100.0;
        verilog_options_stats.goals_met[3] = (verilog_options_stats.actual_coverage[3] >= 95.0);
    endfunction
    
    // at_least检查函数
    function void check_at_least_requirements();
        // 数据coverpoint: at_least = 3
        for (int i = 0; i < 4; i++) begin
            verilog_options_stats.at_least_met[0][i] = (verilog_options_stats.actual_hits[0][i] >= 3);
        end
        
        // 模式coverpoint: at_least = 1
        for (int i = 0; i < 4; i++) begin
            verilog_options_stats.at_least_met[1][i] = (verilog_options_stats.actual_hits[1][i] >= 1);
        end
        
        // 使能coverpoint: at_least = 2 (全局默认)
        for (int i = 0; i < 2; i++) begin
            verilog_options_stats.at_least_met[2][i] = (verilog_options_stats.actual_hits[2][i] >= 2);
        end
        
        // 地址coverpoint: at_least = 2 (全局默认)
        for (int i = 0; i < 16; i++) begin
            verilog_options_stats.at_least_met[3][i] = (verilog_options_stats.actual_hits[3][i] >= 2);
        end
    endfunction
    
    // 重叠检测函数
    function bit detect_bin_overlap(logic [3:0] data_val);
        // 简化的重叠检测逻辑
        // 在实际实现中,这会更复杂
        case (data_val)
            4'h3: begin // 边界值,可能重叠
                verilog_options_stats.overlap_detected++;
                return 1;
            end
            4'h7: begin // 另一个边界值
                verilog_options_stats.overlap_detected++;
                return 1;
            end
            4'hB: begin // 第三个边界值
                verilog_options_stats.overlap_detected++;
                return 1;
            end
            default: return 0;
        endcase
    endfunction
    
    // 自动bin管理函数
    function void manage_auto_bins(logic [7:0] addr);
        // 简化的自动bin管理
        if (verilog_options_stats.auto_bins_created < verilog_options_stats.auto_bin_max_limit) begin
            // 创建新的自动bin(简化逻辑)
            verilog_options_stats.auto_bins_created++;
        end
    endfunction
    
    // 交叉覆盖检查函数
    function bit is_valid_cross_combination(logic [3:0] data_val, logic [1:0] mode_val);
        // 检查是否为忽略的组合
        if (data_val >= 4'hC && mode_val == 2'b11) begin // max data && debug_mode
            verilog_options_stats.cross_ignored_combinations++;
            return 0;
        end
        return 1;
    endfunction
    
    // 主要的覆盖率统计逻辑
    always @(posedge clk) begin
        if (reset) begin
            verilog_options_stats = '{default: 0};
            verilog_options_stats.instance_name = "basic_coverage_instance";
            verilog_options_stats.auto_bin_max_limit = 16;
            
            // 设置目标
            verilog_options_stats.coverage_goals[0] = 100; // data
            verilog_options_stats.coverage_goals[1] = 90;  // mode
            verilog_options_stats.coverage_goals[2] = 95;  // enable
            verilog_options_stats.coverage_goals[3] = 95;  // address
            
            // 设置最小命中要求
            verilog_options_stats.min_hits_required[0] = 3; // data
            verilog_options_stats.min_hits_required[1] = 1; // mode
            verilog_options_stats.min_hits_required[2] = 2; // enable
            verilog_options_stats.min_hits_required[3] = 2; // address
        end else begin
            verilog_options_stats.total_samples++;
            verilog_options_stats.per_instance_samples++;
            
            // 数据coverpoint统计
            case (data)
                4'h0, 4'h1, 4'h2, 4'h3: begin
                    verilog_options_stats.actual_hits[0][0]++; // low bin
                    if (verilog_options_stats.actual_hits[0][0] >= verilog_options_stats.min_hits_required[0])
                        verilog_options_stats.weighted_hits[0] = 1;
                end
                4'h4, 4'h5, 4'h6, 4'h7: begin
                    verilog_options_stats.actual_hits[0][1]++; // mid bin
                    if (verilog_options_stats.actual_hits[0][1] >= verilog_options_stats.min_hits_required[0])
                        verilog_options_stats.weighted_hits[0] = 2;
                end
                4'h8, 4'h9, 4'hA, 4'hB: begin
                    verilog_options_stats.actual_hits[0][2]++; // high bin
                    if (verilog_options_stats.actual_hits[0][2] >= verilog_options_stats.min_hits_required[0])
                        verilog_options_stats.weighted_hits[0] = 3;
                end
                4'hC, 4'hD, 4'hE, 4'hF: begin
                    verilog_options_stats.actual_hits[0][3]++; // max bin
                    if (verilog_options_stats.actual_hits[0][3] >= verilog_options_stats.min_hits_required[0])
                        verilog_options_stats.weighted_hits[0] = 4;
                end
            endcase
            
            // 模式coverpoint统计
            verilog_options_stats.actual_hits[1][mode]++;
            if (verilog_options_stats.actual_hits[1][mode] >= verilog_options_stats.min_hits_required[1]) begin
                case (mode)
                    2'b00: verilog_options_stats.weighted_hits[1] |= 1; // read_mode
                    2'b01: verilog_options_stats.weighted_hits[1] |= 2; // write_mode
                    2'b10: verilog_options_stats.weighted_hits[1] |= 4; // test_mode
                    2'b11: verilog_options_stats.weighted_hits[1] |= 8; // debug_mode
                endcase
            end
            
            // 使能coverpoint统计
            verilog_options_stats.actual_hits[2][enable]++;
            if (verilog_options_stats.actual_hits[2][enable] >= verilog_options_stats.min_hits_required[2]) begin
                verilog_options_stats.weighted_hits[2] |= (enable ? 2 : 1);
            end
            
            // 地址coverpoint统计(简化的自动bin)
            automatic int addr_bin = address % 16; // 简化映射到16个bins
            verilog_options_stats.actual_hits[3][addr_bin]++;
            if (verilog_options_stats.actual_hits[3][addr_bin] >= verilog_options_stats.min_hits_required[3]) begin
                verilog_options_stats.weighted_hits[3] |= (1 << addr_bin);
            end
            
            // 管理自动bins
            manage_auto_bins(address);
            
            // 重叠检测
            if (detect_bin_overlap(data)) begin
                verilog_options_stats.overlap_warnings++;
            end
            
            // 交叉覆盖统计
            verilog_options_stats.cross_total_combinations++;
            if (is_valid_cross_combination(data, mode)) begin
                // 简化的交叉统计
                verilog_options_stats.cross_hit_combinations++;
            end
            
            // 计算覆盖率
            verilog_options_stats.weighted_coverage = calculate_weighted_coverage();
            verilog_options_stats.cross_coverage = 
                real'(verilog_options_stats.cross_hit_combinations) / 
                real'(verilog_options_stats.cross_total_combinations - verilog_options_stats.cross_ignored_combinations) * 100.0;
            
            // 检查目标和at_least要求
            check_coverage_goals();
            check_at_least_requirements();
            
            verilog_options_stats.valid_samples++;
        end
    end
    
    // 测试序列
    initial begin
        reset = 1;
        data = 4'h0;
        mode = 2'b00;
        enable = 1'b0;
        address = 8'h00;
        value = 16'h0000;
        
        #20 reset = 0;
        
        $display("开始覆盖率选项测试...");
        
        // 系统性测试各种选项
        $display("\n测试基本覆盖率选项:");
        
        // 测试权重不同的coverpoint
        $display("  测试权重设置:");
        for (int i = 0; i < 16; i++) begin
            @(posedge clk);
            data = i;
            mode = i % 4;
            enable = i % 2;
            address = i * 16;
            $display("    数据=%d, 模式=%d, 使能=%d, 地址=%d", data, mode, enable, address);
        end
        
        // 测试at_least要求
        $display("\n  测试at_least要求:");
        // 数据coverpoint需要至少3次命中
        repeat (5) begin
            @(posedge clk); data = 4'h0; // low bin
            @(posedge clk); data = 4'h5; // mid bin
            @(posedge clk); data = 4'hA; // high bin
            @(posedge clk); data = 4'hF; // max bin
        end
        $display("    完成数据bins的多次命中测试");
        
        // 模式coverpoint只需要至少1次命中
        @(posedge clk); mode = 2'b00; // read
        @(posedge clk); mode = 2'b01; // write
        @(posedge clk); mode = 2'b10; // test
        @(posedge clk); mode = 2'b11; // debug
        $display("    完成模式bins的单次命中测试");
        
        // 测试目标设置
        $display("\n  测试覆盖率目标:");
        // 确保数据coverpoint达到100%目标
        for (int i = 0; i < 4; i++) begin
            repeat (3) begin // 满足at_least=3的要求
                @(posedge clk);
                case (i)
                    0: data = 4'h1; // low
                    1: data = 4'h5; // mid
                    2: data = 4'h9; // high
                    3: data = 4'hD; // max
                endcase
            end
        end
        $display("    数据coverpoint应达到100%目标");
        
        // 测试交叉覆盖选项
        $display("\n  测试交叉覆盖选项:");
        for (int d = 0; d < 4; d++) begin
            for (int m = 0; m < 4; m++) begin
                // 跳过忽略的组合 (max data && debug mode)
                if (d == 3 && m == 3) begin
                    $display("    跳过忽略的组合: 最大数据 + 调试模式");
                    continue;
                end
                
                repeat (2) begin // 满足交叉的at_least=2要求
                    @(posedge clk);
                    case (d)
                        0: data = 4'h1; // low
                        1: data = 4'h5; // mid
                        2: data = 4'h9; // high
                        3: data = 4'hD; // max
                    endcase
                    mode = m;
                end
            end
        end
        $display("    完成交叉覆盖测试");
        
        // 测试重叠检测
        $display("\n  测试重叠检测:");
        @(posedge clk); data = 4'h3; // 边界值,可能触发重叠检测
        @(posedge clk); data = 4'h7; // 另一个边界值
        @(posedge clk); data = 4'hB; // 第三个边界值
        $display("    测试边界值的重叠检测");
        
        // 测试自动bin限制
        $display("\n  测试自动bin限制:");
        for (int i = 0; i < 20; i++) begin // 超过auto_bin_max=16的限制
            @(posedge clk);
            address = i * 13; // 使用不同的地址模式
        end
        $display("    测试自动bin数量限制");
        
        // 随机压力测试
        $display("\n随机压力测试:");
        repeat (200) begin
            @(posedge clk);
            data = $random % 16;
            mode = $random % 4;
            enable = $random % 2;
            address = $random;
            value = $random;
        end
        
        // SystemVerilog覆盖率选项报告
        $display("\n=== SystemVerilog覆盖率选项报告 ===");
        $display("总体覆盖率: %0.2f%%", basic_cg.get_coverage());
        $display("数据coverpoint覆盖率: %0.2f%% (目标: %0.2f%%)", 
                basic_cg.data_cp.get_coverage(), 100.0);
        $display("模式coverpoint覆盖率: %0.2f%% (目标: %0.2f%%)", 
                basic_cg.mode_cp.get_coverage(), 90.0);
        $display("使能coverpoint覆盖率: %0.2f%% (目标: %0.2f%%)", 
                basic_cg.enable_cp.get_coverage(), 95.0);
        $display("地址coverpoint覆盖率: %0.2f%% (目标: %0.2f%%)", 
                basic_cg.address_cp.get_coverage(), 95.0);
        $display("交叉覆盖率: %0.2f%% (目标: %0.2f%%)", 
                basic_cg.data_mode_cross.get_coverage(), 85.0);
        
        // 传统Verilog选项统计报告
        $display("\n=== 传统Verilog选项统计 ===");
        $display("实例名称: %s", verilog_options_stats.instance_name);
        $display("总采样数: %d", verilog_options_stats.total_samples);
        $display("有效采样数: %d", verilog_options_stats.valid_samples);
        $display("实例采样数: %d", verilog_options_stats.per_instance_samples);
        
        $display("\n权重覆盖率统计:");
        $display("  加权覆盖率: %0.2f%%", verilog_options_stats.weighted_coverage);
        $display("  数据权重命中: %d (权重: 5)", verilog_options_stats.weighted_hits[0]);
        $display("  模式权重命中: %d (权重: 3)", verilog_options_stats.weighted_hits[1]);
        $display("  使能权重命中: %d (权重: 1)", verilog_options_stats.weighted_hits[2]);
        $display("  地址权重命中: %d (权重: 4)", verilog_options_stats.weighted_hits[3]);
        
        $display("\n目标达成情况:");
        $display("  数据目标 (%d%%): %s (实际: %0.2f%%)", 
                verilog_options_stats.coverage_goals[0],
                verilog_options_stats.goals_met[0] ? "达成" : "未达成",
                verilog_options_stats.actual_coverage[0]);
        $display("  模式目标 (%d%%): %s (实际: %0.2f%%)", 
                verilog_options_stats.coverage_goals[1],
                verilog_options_stats.goals_met[1] ? "达成" : "未达成",
                verilog_options_stats.actual_coverage[1]);
        $display("  使能目标 (%d%%): %s (实际: %0.2f%%)", 
                verilog_options_stats.coverage_goals[2],
                verilog_options_stats.goals_met[2] ? "达成" : "未达成",
                verilog_options_stats.actual_coverage[2]);
        $display("  地址目标 (%d%%): %s (实际: %0.2f%%)", 
                verilog_options_stats.coverage_goals[3],
                verilog_options_stats.goals_met[3] ? "达成" : "未达成",
                verilog_options_stats.actual_coverage[3]);
        
        $display("\n最小命中要求检查:");
        for (int cp = 0; cp < 4; cp++) begin
            $display("  Coverpoint %d (要求: %d次):", cp, verilog_options_stats.min_hits_required[cp]);
            for (int bin = 0; bin < (cp == 3 ? 16 : (cp == 2 ? 2 : 4)); bin++) begin
                $display("    Bin[%d]: %d次 %s", bin, 
                        verilog_options_stats.actual_hits[cp][bin],
                        verilog_options_stats.at_least_met[cp][bin] ? "✓" : "✗");
            end
        end
        
        $display("\n交叉覆盖统计:");
        $display("  总交叉组合: %d", verilog_options_stats.cross_total_combinations);
        $display("  命中交叉组合: %d", verilog_options_stats.cross_hit_combinations);
        $display("  忽略交叉组合: %d", verilog_options_stats.cross_ignored_combinations);
        $display("  交叉覆盖率: %0.2f%%", verilog_options_stats.cross_coverage);
        
        $display("\n高级选项统计:");
        $display("  重叠检测次数: %d", verilog_options_stats.overlap_detected);
        $display("  重叠警告数: %d", verilog_options_stats.overlap_warnings);
        $display("  自动bin创建数: %d", verilog_options_stats.auto_bins_created);
        $display("  自动bin最大限制: %d", verilog_options_stats.auto_bin_max_limit);
        
        $finish;
    end
endmodule

6. 系统方法

SystemVerilog提供了丰富的系统方法来查询和控制覆盖率收集,这些方法使得覆盖率分析更加灵活和强大。

6.1 覆盖率查询方法

module coverage_system_methods_example;
    logic clk, reset;
    logic [3:0] data;
    logic [1:0] mode;
    logic enable;
    logic [7:0] address;
    
    // 覆盖组定义
    covergroup system_methods_cg @(posedge clk iff !reset);
        option.per_instance = 1;
        option.name = "system_methods_coverage";
        option.comment = "系统方法演示覆盖组";
        
        data_cp: coverpoint data {
            bins low = {[4'h0:4'h3]};
            bins mid = {[4'h4:4'h7]};
            bins high = {[4'h8:4'hB]};
            bins max = {[4'hC:4'hF]};
        }
        
        mode_cp: coverpoint mode {
            bins read_mode = {2'b00};
            bins write_mode = {2'b01};
            bins test_mode = {2'b10};
            bins debug_mode = {2'b11};
        }
        
        enable_cp: coverpoint enable {
            bins disabled = {1'b0};
            bins enabled = {1'b1};
        }
        
        data_mode_cross: cross data_cp, mode_cp {
            ignore_bins invalid = binsof(data_cp.max) && binsof(mode_cp.debug_mode);
        }
    endgroup
    
    system_methods_cg sys_cg = new();
    
    // 传统Verilog的等价实现
    typedef struct {
        // 基本统计信息
        integer total_bins;
        integer covered_bins;
        integer total_samples;
        real coverage_percentage;
        
        // 各coverpoint的统计
        integer data_total_bins;
        integer data_covered_bins;
        real data_coverage;
        
        integer mode_total_bins;
        integer mode_covered_bins;
        real mode_coverage;
        
        integer enable_total_bins;
        integer enable_covered_bins;
        real enable_coverage;
        
        // 交叉覆盖统计
        integer cross_total_bins;
        integer cross_covered_bins;
        real cross_coverage;
        
        // 实例信息
        string instance_name;
        string type_name;
        
        // 选项信息
        integer per_instance_option;
        string comment;
        
        // bin命中统计
        integer data_bin_hits[4];    // 4个data bins
        integer mode_bin_hits[4];    // 4个mode bins
        integer enable_bin_hits[2];  // 2个enable bins
        integer cross_bin_hits[15];  // 16-1个交叉bins(排除1个忽略的)
        
        // 状态信息
        bit coverage_started;
        bit coverage_stopped;
        integer start_time;
        integer stop_time;
    } verilog_system_methods_t;
    
    verilog_system_methods_t verilog_sys_methods;
    
    // 获取总体覆盖率
    function real get_total_coverage();
        integer total_covered = verilog_sys_methods.data_covered_bins + 
                               verilog_sys_methods.mode_covered_bins + 
                               verilog_sys_methods.enable_covered_bins + 
                               verilog_sys_methods.cross_covered_bins;
        integer total_possible = verilog_sys_methods.data_total_bins + 
                                verilog_sys_methods.mode_total_bins + 
                                verilog_sys_methods.enable_total_bins + 
                                verilog_sys_methods.cross_total_bins;
        
        if (total_possible > 0)
            return real'(total_covered) / real'(total_possible) * 100.0;
        else
            return 0.0;
    endfunction
    
    // 获取coverpoint覆盖率
    function real get_coverpoint_coverage(string cp_name);
        case (cp_name)
            "data_cp": begin
                if (verilog_sys_methods.data_total_bins > 0)
                    return real'(verilog_sys_methods.data_covered_bins) / real'(verilog_sys_methods.data_total_bins) * 100.0;
                else
                    return 0.0;
            end
            "mode_cp": begin
                if (verilog_sys_methods.mode_total_bins > 0)
                    return real'(verilog_sys_methods.mode_covered_bins) / real'(verilog_sys_methods.mode_total_bins) * 100.0;
                else
                    return 0.0;
            end
            "enable_cp": begin
                if (verilog_sys_methods.enable_total_bins > 0)
                    return real'(verilog_sys_methods.enable_covered_bins) / real'(verilog_sys_methods.enable_total_bins) * 100.0;
                else
                    return 0.0;
            end
            default: return 0.0;
        endcase
    endfunction
    
    // 获取交叉覆盖率
    function real get_cross_coverage();
        if (verilog_sys_methods.cross_total_bins > 0)
            return real'(verilog_sys_methods.cross_covered_bins) / real'(verilog_sys_methods.cross_total_bins) * 100.0;
        else
            return 0.0;
    endfunction
    
    // 获取实例名称
    function string get_instance_name();
        return verilog_sys_methods.instance_name;
    endfunction
    
    // 获取类型名称
    function string get_type_name();
        return verilog_sys_methods.type_name;
    endfunction
    
    // 设置实例名称
    function void set_instance_name(string name);
        verilog_sys_methods.instance_name = name;
    endfunction
    
    // 开始覆盖率收集
    function void start_coverage();
        verilog_sys_methods.coverage_started = 1;
        verilog_sys_methods.coverage_stopped = 0;
        verilog_sys_methods.start_time = $time;
    endfunction
    
    // 停止覆盖率收集
    function void stop_coverage();
        verilog_sys_methods.coverage_stopped = 1;
        verilog_sys_methods.stop_time = $time;
    endfunction
    
    // 获取选项值
    function integer get_option_per_instance();
        return verilog_sys_methods.per_instance_option;
    endfunction
    
    function string get_option_comment();
        return verilog_sys_methods.comment;
    endfunction
    
    // 更新覆盖率统计
    function void update_coverage_stats();
        // 更新data coverpoint统计
        verilog_sys_methods.data_covered_bins = 0;
        for (int i = 0; i < 4; i++) begin
            if (verilog_sys_methods.data_bin_hits[i] > 0)
                verilog_sys_methods.data_covered_bins++;
        end
        verilog_sys_methods.data_coverage = get_coverpoint_coverage("data_cp");
        
        // 更新mode coverpoint统计
        verilog_sys_methods.mode_covered_bins = 0;
        for (int i = 0; i < 4; i++) begin
            if (verilog_sys_methods.mode_bin_hits[i] > 0)
                verilog_sys_methods.mode_covered_bins++;
        end
        verilog_sys_methods.mode_coverage = get_coverpoint_coverage("mode_cp");
        
        // 更新enable coverpoint统计
        verilog_sys_methods.enable_covered_bins = 0;
        for (int i = 0; i < 2; i++) begin
            if (verilog_sys_methods.enable_bin_hits[i] > 0)
                verilog_sys_methods.enable_covered_bins++;
        end
        verilog_sys_methods.enable_coverage = get_coverpoint_coverage("enable_cp");
        
        // 更新交叉覆盖统计
        verilog_sys_methods.cross_covered_bins = 0;
        for (int i = 0; i < 15; i++) begin // 排除1个忽略的组合
            if (verilog_sys_methods.cross_bin_hits[i] > 0)
                verilog_sys_methods.cross_covered_bins++;
        end
        verilog_sys_methods.cross_coverage = get_cross_coverage();
        
        // 更新总体统计
        verilog_sys_methods.covered_bins = verilog_sys_methods.data_covered_bins + 
                                          verilog_sys_methods.mode_covered_bins + 
                                          verilog_sys_methods.enable_covered_bins + 
                                          verilog_sys_methods.cross_covered_bins;
        verilog_sys_methods.coverage_percentage = get_total_coverage();
    endfunction
    
    // 主要的覆盖率收集逻辑
    always @(posedge clk) begin
        if (reset) begin
            verilog_sys_methods = '{default: 0};
            verilog_sys_methods.instance_name = "sys_methods_instance";
            verilog_sys_methods.type_name = "system_methods_cg";
            verilog_sys_methods.comment = "系统方法演示覆盖组";
            verilog_sys_methods.per_instance_option = 1;
            
            // 设置总bin数
            verilog_sys_methods.data_total_bins = 4;
            verilog_sys_methods.mode_total_bins = 4;
            verilog_sys_methods.enable_total_bins = 2;
            verilog_sys_methods.cross_total_bins = 15; // 16-1个忽略的
            verilog_sys_methods.total_bins = 25; // 4+4+2+15
            
            start_coverage();
        end else if (!verilog_sys_methods.coverage_stopped) begin
            verilog_sys_methods.total_samples++;
            
            // 更新data coverpoint命中
            case (data)
                4'h0, 4'h1, 4'h2, 4'h3: verilog_sys_methods.data_bin_hits[0]++; // low
                4'h4, 4'h5, 4'h6, 4'h7: verilog_sys_methods.data_bin_hits[1]++; // mid
                4'h8, 4'h9, 4'hA, 4'hB: verilog_sys_methods.data_bin_hits[2]++; // high
                4'hC, 4'hD, 4'hE, 4'hF: verilog_sys_methods.data_bin_hits[3]++; // max
            endcase
            
            // 更新mode coverpoint命中
            verilog_sys_methods.mode_bin_hits[mode]++;
            
            // 更新enable coverpoint命中
            verilog_sys_methods.enable_bin_hits[enable]++;
            
            // 更新交叉覆盖命中(简化逻辑)
            if (!(data >= 4'hC && mode == 2'b11)) begin // 不是忽略的组合
                automatic int data_bin_idx = (data < 4'h4) ? 0 : (data < 4'h8) ? 1 : (data < 4'hC) ? 2 : 3;
                automatic int cross_idx = data_bin_idx * 4 + mode;
                if (cross_idx < 15) // 确保不超出数组边界
                    verilog_sys_methods.cross_bin_hits[cross_idx]++;
            end
            
            // 更新统计信息
            update_coverage_stats();
        end
    end
    
    // 测试序列
    initial begin
        reset = 1;
        data = 4'h0;
        mode = 2'b00;
        enable = 1'b0;
        address = 8'h00;
        
        #20 reset = 0;
        
        $display("开始系统方法测试...");
        
        // 基本系统方法测试
        $display("\n=== 基本系统方法测试 ===");
        
        // 初始状态查询
        $display("初始覆盖率状态:");
        $display("  总体覆盖率: %0.2f%%", sys_cg.get_coverage());
        $display("  数据coverpoint覆盖率: %0.2f%%", sys_cg.data_cp.get_coverage());
        $display("  模式coverpoint覆盖率: %0.2f%%", sys_cg.mode_cp.get_coverage());
        $display("  使能coverpoint覆盖率: %0.2f%%", sys_cg.enable_cp.get_coverage());
        $display("  交叉覆盖率: %0.2f%%", sys_cg.data_mode_cross.get_coverage());
        
        // 实例信息查询
        $display("\n实例信息:");
        $display("  实例名称: %s", sys_cg.get_inst_name());
        $display("  类型名称: %s", sys_cg.get_type_name());
        
        // 选项查询
        $display("\n选项信息:");
        $display("  per_instance选项: %d", sys_cg.get_option().per_instance);
        $display("  name选项: %s", sys_cg.get_option().name);
        $display("  comment选项: %s", sys_cg.get_option().comment);
        
        // 系统性测试各种数据
        $display("\n开始系统性测试...");
        
        // 测试数据coverpoint的所有bins
        $display("  测试数据coverpoint:");
        @(posedge clk); data = 4'h1; // low bin
        $display("    数据=0x%h, 覆盖率=%0.2f%%", data, sys_cg.data_cp.get_coverage());
        
        @(posedge clk); data = 4'h5; // mid bin
        $display("    数据=0x%h, 覆盖率=%0.2f%%", data, sys_cg.data_cp.get_coverage());
        
        @(posedge clk); data = 4'h9; // high bin
        $display("    数据=0x%h, 覆盖率=%0.2f%%", data, sys_cg.data_cp.get_coverage());
        
        @(posedge clk); data = 4'hD; // max bin
        $display("    数据=0x%h, 覆盖率=%0.2f%%", data, sys_cg.data_cp.get_coverage());
        
        // 测试模式coverpoint的所有bins
        $display("\n  测试模式coverpoint:");
        @(posedge clk); mode = 2'b00; // read
        $display("    模式=%b, 覆盖率=%0.2f%%", mode, sys_cg.mode_cp.get_coverage());
        
        @(posedge clk); mode = 2'b01; // write
        $display("    模式=%b, 覆盖率=%0.2f%%", mode, sys_cg.mode_cp.get_coverage());
        
        @(posedge clk); mode = 2'b10; // test
        $display("    模式=%b, 覆盖率=%0.2f%%", mode, sys_cg.mode_cp.get_coverage());
        
        @(posedge clk); mode = 2'b11; // debug
        $display("    模式=%b, 覆盖率=%0.2f%%", mode, sys_cg.mode_cp.get_coverage());
        
        // 测试使能coverpoint
        $display("\n  测试使能coverpoint:");
        @(posedge clk); enable = 1'b0; // disabled
        $display("    使能=%b, 覆盖率=%0.2f%%", enable, sys_cg.enable_cp.get_coverage());
        
        @(posedge clk); enable = 1'b1; // enabled
        $display("    使能=%b, 覆盖率=%0.2f%%", enable, sys_cg.enable_cp.get_coverage());
        
        // 测试交叉覆盖
        $display("\n  测试交叉覆盖:");
        for (int d = 0; d < 4; d++) begin
            for (int m = 0; m < 4; m++) begin
                // 跳过忽略的组合
                if (d == 3 && m == 3) begin
                    $display("    跳过忽略的组合: 数据bin=%d, 模式=%d", d, m);
                    continue;
                end
                
                @(posedge clk);
                case (d)
                    0: data = 4'h1; // low
                    1: data = 4'h5; // mid
                    2: data = 4'h9; // high
                    3: data = 4'hD; // max
                endcase
                mode = m;
                
                $display("    数据bin=%d, 模式=%d, 交叉覆盖率=%0.2f%%", 
                        d, m, sys_cg.data_mode_cross.get_coverage());
            end
        end
        
        // 测试覆盖率控制方法
        $display("\n=== 覆盖率控制方法测试 ===");
        
        // 停止覆盖率收集
        $display("停止覆盖率收集...");
        sys_cg.stop();
        
        // 在停止状态下继续采样(应该不影响覆盖率)
        real coverage_before_stop = sys_cg.get_coverage();
        @(posedge clk); data = 4'h0; mode = 2'b00; enable = 1'b0;
        @(posedge clk); data = 4'h1; mode = 2'b01; enable = 1'b1;
        real coverage_after_stop = sys_cg.get_coverage();
        
        $display("  停止前覆盖率: %0.2f%%", coverage_before_stop);
        $display("  停止后覆盖率: %0.2f%%", coverage_after_stop);
        $display("  覆盖率是否变化: %s", (coverage_before_stop == coverage_after_stop) ? "否" : "是");
        
        // 重新开始覆盖率收集
        $display("\n重新开始覆盖率收集...");
        sys_cg.start();
        
        // 继续采样
        @(posedge clk); data = 4'h2; mode = 2'b10; enable = 1'b0;
        real coverage_after_restart = sys_cg.get_coverage();
        $display("  重启后覆盖率: %0.2f%%", coverage_after_restart);
        
        // 实例名称设置测试
        $display("\n=== 实例名称设置测试 ===");
        string original_name = sys_cg.get_inst_name();
        $display("原始实例名称: %s", original_name);
        
        sys_cg.set_inst_name("new_instance_name");
        string new_name = sys_cg.get_inst_name();
        $display("新实例名称: %s", new_name);
        
        // 随机压力测试
        $display("\n=== 随机压力测试 ===");
        repeat (100) begin
            @(posedge clk);
            data = $random % 16;
            mode = $random % 4;
            enable = $random % 2;
        end
        
        // 最终覆盖率报告
        $display("\n=== SystemVerilog系统方法最终报告 ===");
        $display("总体覆盖率: %0.2f%%", sys_cg.get_coverage());
        $display("数据coverpoint覆盖率: %0.2f%%", sys_cg.data_cp.get_coverage());
        $display("模式coverpoint覆盖率: %0.2f%%", sys_cg.mode_cp.get_coverage());
        $display("使能coverpoint覆盖率: %0.2f%%", sys_cg.enable_cp.get_coverage());
        $display("交叉覆盖率: %0.2f%%", sys_cg.data_mode_cross.get_coverage());
        $display("实例名称: %s", sys_cg.get_inst_name());
        $display("类型名称: %s", sys_cg.get_type_name());
        
        // 传统Verilog系统方法等价报告
        $display("\n=== 传统Verilog系统方法等价报告 ===");
        $display("总体覆盖率: %0.2f%%", get_total_coverage());
        $display("数据coverpoint覆盖率: %0.2f%%", get_coverpoint_coverage("data_cp"));
        $display("模式coverpoint覆盖率: %0.2f%%", get_coverpoint_coverage("mode_cp"));
        $display("使能coverpoint覆盖率: %0.2f%%", get_coverpoint_coverage("enable_cp"));
        $display("交叉覆盖率: %0.2f%%", get_cross_coverage());
        $display("实例名称: %s", get_instance_name());
        $display("类型名称: %s", get_type_name());
        $display("总采样数: %d", verilog_sys_methods.total_samples);
        $display("总bin数: %d", verilog_sys_methods.total_bins);
        $display("已覆盖bin数: %d", verilog_sys_methods.covered_bins);
        $display("覆盖率收集状态: %s", verilog_sys_methods.coverage_stopped ? "已停止" : "运行中");
        
        $display("\n详细bin命中统计:");
        $display("  数据bins: [%d, %d, %d, %d]", 
                verilog_sys_methods.data_bin_hits[0], verilog_sys_methods.data_bin_hits[1],
                verilog_sys_methods.data_bin_hits[2], verilog_sys_methods.data_bin_hits[3]);
        $display("  模式bins: [%d, %d, %d, %d]", 
                verilog_sys_methods.mode_bin_hits[0], verilog_sys_methods.mode_bin_hits[1],
                verilog_sys_methods.mode_bin_hits[2], verilog_sys_methods.mode_bin_hits[3]);
        $display("  使能bins: [%d, %d]", 
                verilog_sys_methods.enable_bin_hits[0], verilog_sys_methods.enable_bin_hits[1]);
        
        $finish;
    end
endmodule

7. 计算方法

覆盖率的计算是功能覆盖率分析的核心,SystemVerilog提供了多种计算方法来评估验证的完整性。

7.1 基本覆盖率计算

module coverage_calculation_example;
    logic clk, reset;
    logic [3:0] data;
    logic [1:0] mode;
    logic enable;
    logic [2:0] priority;
    logic [7:0] address;
    
    // 覆盖组定义
    covergroup calculation_cg @(posedge clk iff !reset);
        option.per_instance = 1;
        option.name = "calculation_coverage";
        option.comment = "覆盖率计算演示";
        
        // 数据coverpoint - 4个bins
        data_cp: coverpoint data {
            option.weight = 4;  // 权重为4
            bins low = {[4'h0:4'h3]};
            bins mid = {[4'h4:4'h7]};
            bins high = {[4'h8:4'hB]};
            bins max = {[4'hC:4'hF]};
        }
        
        // 模式coverpoint - 4个bins
        mode_cp: coverpoint mode {
            option.weight = 2;  // 权重为2
            bins read_mode = {2'b00};
            bins write_mode = {2'b01};
            bins test_mode = {2'b10};
            bins debug_mode = {2'b11};
        }
        
        // 使能coverpoint - 2个bins
        enable_cp: coverpoint enable {
            option.weight = 1;  // 权重为1
            bins disabled = {1'b0};
            bins enabled = {1'b1};
        }
        
        // 优先级coverpoint - 8个bins
        priority_cp: coverpoint priority {
            option.weight = 3;  // 权重为3
            bins prio0 = {3'b000};
            bins prio1 = {3'b001};
            bins prio2 = {3'b010};
            bins prio3 = {3'b011};
            bins prio4 = {3'b100};
            bins prio5 = {3'b101};
            bins prio6 = {3'b110};
            bins prio7 = {3'b111};
        }
        
        // 交叉覆盖 - 数据和模式
        data_mode_cross: cross data_cp, mode_cp {
            option.weight = 5;  // 权重为5
            ignore_bins invalid = binsof(data_cp.max) && binsof(mode_cp.debug_mode);
        }
        
        // 三路交叉覆盖
        data_mode_enable_cross: cross data_cp, mode_cp, enable_cp {
            option.weight = 8;  // 权重为8
            ignore_bins invalid1 = binsof(data_cp.max) && binsof(mode_cp.debug_mode);
            ignore_bins invalid2 = binsof(data_cp.low) && binsof(mode_cp.test_mode) && binsof(enable_cp.disabled);
        }
    endgroup
    
    calculation_cg calc_cg = new();
    
    // 传统Verilog的覆盖率计算实现
    typedef struct {
        // 基本bin统计
        integer data_bins_total;        // 4
        integer data_bins_covered;
        integer data_bin_hits[4];
        real data_coverage;
        integer data_weight;            // 4
        
        integer mode_bins_total;        // 4
        integer mode_bins_covered;
        integer mode_bin_hits[4];
        real mode_coverage;
        integer mode_weight;            // 2
        
        integer enable_bins_total;      // 2
        integer enable_bins_covered;
        integer enable_bin_hits[2];
        real enable_coverage;
        integer enable_weight;          // 1
        
        integer priority_bins_total;    // 8
        integer priority_bins_covered;
        integer priority_bin_hits[8];
        real priority_coverage;
        integer priority_weight;        // 3
        
        // 交叉覆盖统计
        integer data_mode_cross_total;  // 15 (16-1忽略)
        integer data_mode_cross_covered;
        integer data_mode_cross_hits[15];
        real data_mode_cross_coverage;
        integer data_mode_cross_weight; // 5
        
        integer triple_cross_total;     // 29 (32-3忽略)
        integer triple_cross_covered;
        integer triple_cross_hits[29];
        real triple_cross_coverage;
        integer triple_cross_weight;    // 8
        
        // 总体统计
        integer total_bins;
        integer total_covered_bins;
        real simple_coverage;           // 简单覆盖率
        real weighted_coverage;         // 加权覆盖率
        integer total_weight;
        integer total_weighted_hits;
        
        // 计算相关
        integer total_samples;
        real coverage_trend[100];       // 覆盖率趋势
        integer trend_index;
    } verilog_calculation_t;
    
    verilog_calculation_t verilog_calc;
    
    // 计算简单覆盖率(所有bins等权重)
    function real calculate_simple_coverage();
        return real'(verilog_calc.total_covered_bins) / real'(verilog_calc.total_bins) * 100.0;
    endfunction
    
    // 计算加权覆盖率
    function real calculate_weighted_coverage();
        integer total_possible_weight = 0;
        integer actual_weighted_hits = 0;
        
        // 数据coverpoint权重贡献
        total_possible_weight += verilog_calc.data_bins_total * verilog_calc.data_weight;
        actual_weighted_hits += verilog_calc.data_bins_covered * verilog_calc.data_weight;
        
        // 模式coverpoint权重贡献
        total_possible_weight += verilog_calc.mode_bins_total * verilog_calc.mode_weight;
        actual_weighted_hits += verilog_calc.mode_bins_covered * verilog_calc.mode_weight;
        
        // 使能coverpoint权重贡献
        total_possible_weight += verilog_calc.enable_bins_total * verilog_calc.enable_weight;
        actual_weighted_hits += verilog_calc.enable_bins_covered * verilog_calc.enable_weight;
        
        // 优先级coverpoint权重贡献
        total_possible_weight += verilog_calc.priority_bins_total * verilog_calc.priority_weight;
        actual_weighted_hits += verilog_calc.priority_bins_covered * verilog_calc.priority_weight;
        
        // 数据-模式交叉权重贡献
        total_possible_weight += verilog_calc.data_mode_cross_total * verilog_calc.data_mode_cross_weight;
        actual_weighted_hits += verilog_calc.data_mode_cross_covered * verilog_calc.data_mode_cross_weight;
        
        // 三路交叉权重贡献
        total_possible_weight += verilog_calc.triple_cross_total * verilog_calc.triple_cross_weight;
        actual_weighted_hits += verilog_calc.triple_cross_covered * verilog_calc.triple_cross_weight;
        
        if (total_possible_weight > 0)
            return real'(actual_weighted_hits) / real'(total_possible_weight) * 100.0;
        else
            return 0.0;
    endfunction
    
    // 计算各coverpoint的覆盖率
    function void calculate_individual_coverages();
        // 数据coverpoint覆盖率
        verilog_calc.data_bins_covered = 0;
        for (int i = 0; i < 4; i++) begin
            if (verilog_calc.data_bin_hits[i] > 0)
                verilog_calc.data_bins_covered++;
        end
        verilog_calc.data_coverage = real'(verilog_calc.data_bins_covered) / real'(verilog_calc.data_bins_total) * 100.0;
        
        // 模式coverpoint覆盖率
        verilog_calc.mode_bins_covered = 0;
        for (int i = 0; i < 4; i++) begin
            if (verilog_calc.mode_bin_hits[i] > 0)
                verilog_calc.mode_bins_covered++;
        end
        verilog_calc.mode_coverage = real'(verilog_calc.mode_bins_covered) / real'(verilog_calc.mode_bins_total) * 100.0;
        
        // 使能coverpoint覆盖率
        verilog_calc.enable_bins_covered = 0;
        for (int i = 0; i < 2; i++) begin
            if (verilog_calc.enable_bin_hits[i] > 0)
                verilog_calc.enable_bins_covered++;
        end
        verilog_calc.enable_coverage = real'(verilog_calc.enable_bins_covered) / real'(verilog_calc.enable_bins_total) * 100.0;
        
        // 优先级coverpoint覆盖率
        verilog_calc.priority_bins_covered = 0;
        for (int i = 0; i < 8; i++) begin
            if (verilog_calc.priority_bin_hits[i] > 0)
                verilog_calc.priority_bins_covered++;
        end
        verilog_calc.priority_coverage = real'(verilog_calc.priority_bins_covered) / real'(verilog_calc.priority_bins_total) * 100.0;
        
        // 数据-模式交叉覆盖率
        verilog_calc.data_mode_cross_covered = 0;
        for (int i = 0; i < 15; i++) begin
            if (verilog_calc.data_mode_cross_hits[i] > 0)
                verilog_calc.data_mode_cross_covered++;
        end
        verilog_calc.data_mode_cross_coverage = real'(verilog_calc.data_mode_cross_covered) / real'(verilog_calc.data_mode_cross_total) * 100.0;
        
        // 三路交叉覆盖率
        verilog_calc.triple_cross_covered = 0;
        for (int i = 0; i < 29; i++) begin
            if (verilog_calc.triple_cross_hits[i] > 0)
                verilog_calc.triple_cross_covered++;
        end
        verilog_calc.triple_cross_coverage = real'(verilog_calc.triple_cross_covered) / real'(verilog_calc.triple_cross_total) * 100.0;
    endfunction
    
    // 更新覆盖率趋势
    function void update_coverage_trend();
        if (verilog_calc.trend_index < 100) begin
            verilog_calc.coverage_trend[verilog_calc.trend_index] = verilog_calc.weighted_coverage;
            verilog_calc.trend_index++;
        end else begin
            // 滑动窗口
            for (int i = 0; i < 99; i++) begin
                verilog_calc.coverage_trend[i] = verilog_calc.coverage_trend[i+1];
            end
            verilog_calc.coverage_trend[99] = verilog_calc.weighted_coverage;
        end
    endfunction
    
    // 获取交叉覆盖索引(简化映射)
    function integer get_data_mode_cross_index(logic [3:0] data_val, logic [1:0] mode_val);
        integer data_bin = (data_val < 4'h4) ? 0 : (data_val < 4'h8) ? 1 : (data_val < 4'hC) ? 2 : 3;
        
        // 跳过忽略的组合 (max data && debug mode)
        if (data_bin == 3 && mode_val == 2'b11)
            return -1; // 无效索引
        
        integer cross_idx = data_bin * 4 + mode_val;
        // 调整索引以跳过忽略的组合
        if (cross_idx >= 15) cross_idx = cross_idx - 1;
        return cross_idx;
    endfunction
    
    function integer get_triple_cross_index(logic [3:0] data_val, logic [1:0] mode_val, logic enable_val);
        integer data_bin = (data_val < 4'h4) ? 0 : (data_val < 4'h8) ? 1 : (data_val < 4'hC) ? 2 : 3;
        
        // 检查忽略的组合
        if ((data_bin == 3 && mode_val == 2'b11) ||  // max data && debug mode
            (data_bin == 0 && mode_val == 2'b10 && enable_val == 1'b0)) // low data && test mode && disabled
            return -1;
        
        integer cross_idx = data_bin * 8 + mode_val * 2 + enable_val;
        // 简化的索引调整
        if (cross_idx >= 29) cross_idx = cross_idx - 3;
        return cross_idx;
    endfunction
    
    // 主要的覆盖率收集和计算逻辑
    always @(posedge clk) begin
        if (reset) begin
            verilog_calc = '{default: 0};
            
            // 初始化bin总数和权重
            verilog_calc.data_bins_total = 4;
            verilog_calc.data_weight = 4;
            verilog_calc.mode_bins_total = 4;
            verilog_calc.mode_weight = 2;
            verilog_calc.enable_bins_total = 2;
            verilog_calc.enable_weight = 1;
            verilog_calc.priority_bins_total = 8;
            verilog_calc.priority_weight = 3;
            verilog_calc.data_mode_cross_total = 15;
            verilog_calc.data_mode_cross_weight = 5;
            verilog_calc.triple_cross_total = 29;
            verilog_calc.triple_cross_weight = 8;
            
            verilog_calc.total_bins = 4 + 4 + 2 + 8 + 15 + 29; // 62
            verilog_calc.total_weight = 4 + 2 + 1 + 3 + 5 + 8; // 23
        end else begin
            verilog_calc.total_samples++;
            
            // 更新各coverpoint的bin命中
            // 数据bins
            case (data)
                4'h0, 4'h1, 4'h2, 4'h3: verilog_calc.data_bin_hits[0]++; // low
                4'h4, 4'h5, 4'h6, 4'h7: verilog_calc.data_bin_hits[1]++; // mid
                4'h8, 4'h9, 4'hA, 4'hB: verilog_calc.data_bin_hits[2]++; // high
                4'hC, 4'hD, 4'hE, 4'hF: verilog_calc.data_bin_hits[3]++; // max
            endcase
            
            // 模式bins
            verilog_calc.mode_bin_hits[mode]++;
            
            // 使能bins
            verilog_calc.enable_bin_hits[enable]++;
            
            // 优先级bins
            verilog_calc.priority_bin_hits[priority]++;
            
            // 数据-模式交叉bins
            automatic integer dm_cross_idx = get_data_mode_cross_index(data, mode);
            if (dm_cross_idx >= 0 && dm_cross_idx < 15)
                verilog_calc.data_mode_cross_hits[dm_cross_idx]++;
            
            // 三路交叉bins
            automatic integer triple_cross_idx = get_triple_cross_index(data, mode, enable);
            if (triple_cross_idx >= 0 && triple_cross_idx < 29)
                verilog_calc.triple_cross_hits[triple_cross_idx]++;
            
            // 计算各种覆盖率
            calculate_individual_coverages();
            
            // 更新总体统计
            verilog_calc.total_covered_bins = verilog_calc.data_bins_covered + 
                                             verilog_calc.mode_bins_covered + 
                                             verilog_calc.enable_bins_covered + 
                                             verilog_calc.priority_bins_covered + 
                                             verilog_calc.data_mode_cross_covered + 
                                             verilog_calc.triple_cross_covered;
            
            verilog_calc.simple_coverage = calculate_simple_coverage();
            verilog_calc.weighted_coverage = calculate_weighted_coverage();
            
            // 更新覆盖率趋势
            update_coverage_trend();
        end
    end
    
    // 测试序列
    initial begin
        reset = 1;
        data = 4'h0;
        mode = 2'b00;
        enable = 1'b0;
        priority = 3'b000;
        address = 8'h00;
        
        #20 reset = 0;
        
        $display("开始覆盖率计算测试...");
        
        // 初始状态
        $display("\n=== 初始覆盖率状态 ===");
        $display("SystemVerilog总体覆盖率: %0.2f%%", calc_cg.get_coverage());
        $display("传统Verilog简单覆盖率: %0.2f%%", calculate_simple_coverage());
        $display("传统Verilog加权覆盖率: %0.2f%%", calculate_weighted_coverage());
        
        // 系统性测试以观察覆盖率变化
        $display("\n=== 系统性覆盖率测试 ===");
        
        // 阶段1:测试数据coverpoint
        $display("\n阶段1:测试数据coverpoint");
        for (int i = 0; i < 4; i++) begin
            @(posedge clk);
            case (i)
                0: data = 4'h1; // low
                1: data = 4'h5; // mid
                2: data = 4'h9; // high
                3: data = 4'hD; // max
            endcase
            
            $display("  数据=0x%h, SV总体=%0.2f%%, 数据CP=%0.2f%%, Verilog简单=%0.2f%%, Verilog加权=%0.2f%%", 
                    data, calc_cg.get_coverage(), calc_cg.data_cp.get_coverage(), 
                    calculate_simple_coverage(), calculate_weighted_coverage());
        end
        
        // 阶段2:测试模式coverpoint
        $display("\n阶段2:测试模式coverpoint");
        for (int i = 0; i < 4; i++) begin
            @(posedge clk);
            mode = i;
            
            $display("  模式=%d, SV总体=%0.2f%%, 模式CP=%0.2f%%, Verilog简单=%0.2f%%, Verilog加权=%0.2f%%", 
                    mode, calc_cg.get_coverage(), calc_cg.mode_cp.get_coverage(), 
                    calculate_simple_coverage(), calculate_weighted_coverage());
        end
        
        // 阶段3:测试使能coverpoint
        $display("\n阶段3:测试使能coverpoint");
        for (int i = 0; i < 2; i++) begin
            @(posedge clk);
            enable = i;
            
            $display("  使能=%d, SV总体=%0.2f%%, 使能CP=%0.2f%%, Verilog简单=%0.2f%%, Verilog加权=%0.2f%%", 
                    enable, calc_cg.get_coverage(), calc_cg.enable_cp.get_coverage(), 
                    calculate_simple_coverage(), calculate_weighted_coverage());
        end
        
        // 阶段4:测试优先级coverpoint
        $display("\n阶段4:测试优先级coverpoint");
        for (int i = 0; i < 8; i++) begin
            @(posedge clk);
            priority = i;
            
            $display("  优先级=%d, SV总体=%0.2f%%, 优先级CP=%0.2f%%, Verilog简单=%0.2f%%, Verilog加权=%0.2f%%", 
                    priority, calc_cg.get_coverage(), calc_cg.priority_cp.get_coverage(), 
                    calculate_simple_coverage(), calculate_weighted_coverage());
        end
        
        // 阶段5:测试交叉覆盖
        $display("\n阶段5:测试数据-模式交叉覆盖");
        for (int d = 0; d < 4; d++) begin
            for (int m = 0; m < 4; m++) begin
                // 跳过忽略的组合
                if (d == 3 && m == 3) continue;
                
                @(posedge clk);
                case (d)
                    0: data = 4'h1; // low
                    1: data = 4'h5; // mid
                    2: data = 4'h9; // high
                    3: data = 4'hD; // max
                endcase
                mode = m;
                
                $display("  数据bin=%d, 模式=%d, SV交叉=%0.2f%%, Verilog简单=%0.2f%%, Verilog加权=%0.2f%%", 
                        d, m, calc_cg.data_mode_cross.get_coverage(), 
                        calculate_simple_coverage(), calculate_weighted_coverage());
            end
        end
        
        // 阶段6:测试三路交叉覆盖
        $display("\n阶段6:测试三路交叉覆盖(部分)");
        for (int d = 0; d < 2; d++) begin // 只测试部分组合
            for (int m = 0; m < 2; m++) begin
                for (int e = 0; e < 2; e++) begin
                    // 跳过忽略的组合
                    if (d == 0 && m == 2 && e == 0) continue; // low && test && disabled
                    
                    @(posedge clk);
                    case (d)
                        0: data = 4'h1; // low
                        1: data = 4'h5; // mid
                    endcase
                    mode = m;
                    enable = e;
                    
                    $display("  数据bin=%d, 模式=%d, 使能=%d, SV三路交叉=%0.2f%%, Verilog简单=%0.2f%%, Verilog加权=%0.2f%%", 
                            d, m, e, calc_cg.data_mode_enable_cross.get_coverage(), 
                            calculate_simple_coverage(), calculate_weighted_coverage());
                end
            end
        end
        
        // 随机压力测试
        $display("\n=== 随机压力测试 ===");
        repeat (200) begin
            @(posedge clk);
            data = $random % 16;
            mode = $random % 4;
            enable = $random % 2;
            priority = $random % 8;
            address = $random;
        end
        
        // 最终覆盖率计算报告
        $display("\n=== SystemVerilog覆盖率计算最终报告 ===");
        $display("总体覆盖率: %0.2f%%", calc_cg.get_coverage());
        $display("数据coverpoint覆盖率: %0.2f%% (权重: %d)", calc_cg.data_cp.get_coverage(), 4);
        $display("模式coverpoint覆盖率: %0.2f%% (权重: %d)", calc_cg.mode_cp.get_coverage(), 2);
        $display("使能coverpoint覆盖率: %0.2f%% (权重: %d)", calc_cg.enable_cp.get_coverage(), 1);
        $display("优先级coverpoint覆盖率: %0.2f%% (权重: %d)", calc_cg.priority_cp.get_coverage(), 3);
        $display("数据-模式交叉覆盖率: %0.2f%% (权重: %d)", calc_cg.data_mode_cross.get_coverage(), 5);
        $display("三路交叉覆盖率: %0.2f%% (权重: %d)", calc_cg.data_mode_enable_cross.get_coverage(), 8);
        
        // 传统Verilog覆盖率计算报告
        $display("\n=== 传统Verilog覆盖率计算报告 ===");
        $display("简单覆盖率: %0.2f%% (%d/%d bins)", 
                verilog_calc.simple_coverage, verilog_calc.total_covered_bins, verilog_calc.total_bins);
        $display("加权覆盖率: %0.2f%% (总权重: %d)", 
                verilog_calc.weighted_coverage, verilog_calc.total_weight);
        
        $display("\n详细coverpoint统计:");
        $display("  数据CP: %0.2f%% (%d/%d bins, 权重: %d)", 
                verilog_calc.data_coverage, verilog_calc.data_bins_covered, verilog_calc.data_bins_total, verilog_calc.data_weight);
        $display("  模式CP: %0.2f%% (%d/%d bins, 权重: %d)", 
                verilog_calc.mode_coverage, verilog_calc.mode_bins_covered, verilog_calc.mode_bins_total, verilog_calc.mode_weight);
        $display("  使能CP: %0.2f%% (%d/%d bins, 权重: %d)", 
                verilog_calc.enable_coverage, verilog_calc.enable_bins_covered, verilog_calc.enable_bins_total, verilog_calc.enable_weight);
        $display("  优先级CP: %0.2f%% (%d/%d bins, 权重: %d)", 
                verilog_calc.priority_coverage, verilog_calc.priority_bins_covered, verilog_calc.priority_bins_total, verilog_calc.priority_weight);
        $display("  数据-模式交叉: %0.2f%% (%d/%d bins, 权重: %d)", 
                verilog_calc.data_mode_cross_coverage, verilog_calc.data_mode_cross_covered, verilog_calc.data_mode_cross_total, verilog_calc.data_mode_cross_weight);
        $display("  三路交叉: %0.2f%% (%d/%d bins, 权重: %d)", 
                verilog_calc.triple_cross_coverage, verilog_calc.triple_cross_covered, verilog_calc.triple_cross_total, verilog_calc.triple_cross_weight);
        
        $display("\n计算统计信息:");
        $display("  总采样数: %d", verilog_calc.total_samples);
        $display("  覆盖率趋势记录数: %d", verilog_calc.trend_index > 100 ? 100 : verilog_calc.trend_index);
        
        if (verilog_calc.trend_index > 10) begin
            $display("  最近10次覆盖率趋势:");
            for (int i = (verilog_calc.trend_index > 100 ? 90 : verilog_calc.trend_index-10); 
                 i < (verilog_calc.trend_index > 100 ? 100 : verilog_calc.trend_index); i++) begin
                $display("    [%d]: %0.2f%%", i, verilog_calc.coverage_trend[i]);
            end
        end
        
        $finish;
    end
endmodule

8. SystemVerilog与传统Verilog的对比

通过前面章节的详细介绍,我们可以清楚地看到SystemVerilog在功能覆盖率方面相比传统Verilog的巨大优势。

8.1 语法简洁性对比

SystemVerilog的优势:

  • 声明式语法:使用covergroupcoverpointbins等关键字直接声明覆盖点
  • 自动化管理:自动处理覆盖率统计、计算和报告
  • 内建支持:原生支持交叉覆盖、条件覆盖、权重设置等高级特性
  • 简洁表达:复杂的覆盖需求可以用几行代码表达

传统Verilog的局限:

  • 手动实现:需要手动编写大量的统计逻辑和数据结构
  • 复杂维护:随着覆盖点增加,代码复杂度呈指数增长
  • 易出错:手动计算覆盖率容易出现逻辑错误
  • 可读性差:大量的统计代码掩盖了设计意图

8.2 功能完整性对比

功能特性 SystemVerilog 传统Verilog
基本覆盖点 ✅ 原生支持 ❌ 需手动实现
交叉覆盖 ✅ 内建支持 ❌ 复杂手动逻辑
条件覆盖 iff关键字 ❌ 需额外判断逻辑
权重设置 option.weight ❌ 需手动加权计算
忽略bins ignore_bins ❌ 需手动排除逻辑
非法bins illegal_bins ❌ 需手动检查逻辑
通配符匹配 wildcard bins ❌ 需复杂位操作
序列覆盖 ✅ 转换bins ❌ 需状态机实现
系统方法 ✅ 丰富的查询API ❌ 需自定义函数
覆盖率计算 ✅ 自动计算 ❌ 需手动实现算法
实例管理 ✅ 自动管理 ❌ 需手动跟踪
采样控制 ✅ 灵活的采样机制 ❌ 需手动控制逻辑

8.3 开发效率对比

SystemVerilog:

// 10行代码实现复杂的功能覆盖率
covergroup complex_cg @(posedge clk);
    data_cp: coverpoint data {
        bins low = {[0:31]};
        bins high = {[32:63]};
    }
    mode_cp: coverpoint mode;
    cross_coverage: cross data_cp, mode_cp {
        ignore_bins invalid = binsof(data_cp.high) && binsof(mode_cp) intersect {3};
    }
endgroup

传统Verilog:

// 需要200+行代码实现相同功能
// 包括:数据结构定义、统计逻辑、计算函数、
// 交叉覆盖映射、忽略逻辑、报告生成等

8.4 维护性对比

SystemVerilog的优势:

  • 自文档化:覆盖意图直接体现在代码中
  • 易于修改:添加新覆盖点只需几行代码
  • 自动一致性:工具自动保证统计逻辑的正确性
  • 标准化:统一的语法和语义

传统Verilog的问题:

  • 维护困难:修改覆盖需求需要同时修改多处代码
  • 一致性风险:手动逻辑容易出现不一致
  • 文档分离:覆盖意图与实现代码分离
  • 非标准化:不同项目可能有不同的实现方式

8.5 性能对比

SystemVerilog:

  • 优化编译:工具可以对覆盖率收集进行优化
  • 内存效率:自动优化内存使用
  • 运行时优化:智能采样和统计

传统Verilog:

  • 手动优化:需要手动优化性能
  • 内存开销:可能存在内存浪费
  • 运行时负担:复杂的统计逻辑影响仿真性能

8.6 工具支持对比

SystemVerilog:

  • EDA工具原生支持:主流仿真器都支持SystemVerilog覆盖率
  • 自动报告生成:工具自动生成详细的覆盖率报告
  • 图形化界面:可视化覆盖率分析
  • 数据库集成:覆盖率数据可以导入专业分析工具

传统Verilog:

  • 有限工具支持:需要额外的脚本和工具处理
  • 手动报告:需要自己编写报告生成逻辑
  • 分析困难:缺乏标准化的分析接口
  • 集成复杂:与其他工具集成需要额外工作

8.7 学习曲线对比

SystemVerilog:

  • 概念清晰:覆盖率概念直接映射到语法
  • 渐进学习:可以从简单覆盖点开始逐步学习
  • 丰富资源:大量的文档和示例
  • 标准化:IEEE标准保证一致性

传统Verilog:

  • 概念复杂:需要理解底层实现细节
  • 经验依赖:需要大量实践经验
  • 资源分散:缺乏统一的最佳实践
  • 项目特定:不同项目可能有不同的实现方式

8.8 实际应用建议

推荐使用SystemVerilog的场景:

  • 新项目开发
  • 复杂的验证需求
  • 需要详细覆盖率分析的项目
  • 团队协作的大型项目
  • 需要与现代EDA工具集成的项目

可能继续使用传统Verilog的场景:

  • 遗留项目维护(已有大量Verilog覆盖率代码)
  • 工具链限制(不支持SystemVerilog)
  • 简单的覆盖需求
  • 特殊的性能要求(需要精确控制)

9. 总结

SystemVerilog的功能覆盖率是现代硬件验证的重要工具,它通过以下特性大大提升了验证效率:

9.1 核心优势

  1. 声明式语法:直观表达覆盖意图
  2. 自动化管理:减少手动编码工作
  3. 丰富特性:支持复杂的覆盖需求
  4. 工具集成:与现代EDA工具无缝集成
  5. 标准化:IEEE标准保证一致性和可移植性

9.2 关键概念回顾

  • covergroup:覆盖组,组织相关的覆盖点
  • coverpoint:覆盖点,定义需要监控的信号或表达式
  • bins:覆盖桶,定义值的分组和统计
  • cross:交叉覆盖,监控多个变量的组合
  • 选项系统:灵活配置覆盖行为
  • 系统方法:查询和控制覆盖率收集

9.3 最佳实践

  1. 合理规划覆盖点:避免过度覆盖和覆盖不足
  2. 使用分层覆盖:从模块级到系统级的分层覆盖策略
  3. 利用交叉覆盖:关注关键的变量组合
  4. 设置合理权重:突出重要的覆盖点
  5. 定期分析报告:及时发现覆盖盲点
  6. 与断言结合:功能覆盖率与断言验证相辅相成

9.4 发展趋势

随着硬件设计复杂度的不断增加,SystemVerilog功能覆盖率将继续发展:

  • 智能覆盖率:AI辅助的覆盖点生成和分析
  • 形式化集成:与形式化验证方法的深度集成
  • 云端分析:基于云计算的大规模覆盖率分析
  • 实时反馈:仿真过程中的实时覆盖率指导

9.5 结语

SystemVerilog功能覆盖率作为现代硬件验证的基石,不仅提供了强大的技术能力,更重要的是改变了验证工程师的思维方式。从传统的"测试驱动"转向"覆盖率驱动",从手动统计转向自动化分析,这些变化使得验证工作更加科学、高效和可靠。

掌握SystemVerilog功能覆盖率,不仅是技术技能的提升,更是验证思维的升级。它帮助我们更好地理解设计、发现问题、提升质量,是每个硬件验证工程师必须掌握的核心技能。

通过本章的学习,读者应该能够:

  • 理解功能覆盖率的基本概念和重要性
  • 掌握covergroup和coverpoint的定义和使用
  • 熟练使用各种类型的bins
  • 理解和应用交叉覆盖
  • 配置和使用覆盖率选项
  • 利用系统方法进行覆盖率查询和控制
  • 理解覆盖率的计算方法
  • 认识SystemVerilog相对于传统Verilog的优势

这些知识将为后续的高级验证技术学习奠定坚实的基础。

10. 综合示例:FIFO验证中的功能覆盖率

下面通过一个完整的FIFO验证例子来展示功能覆盖率的实际应用:

10.1 FIFO设计模块

// FIFO设计模块
module fifo #(
    parameter DATA_WIDTH = 8,
    parameter DEPTH = 16
) (
    input  logic                    clk,
    input  logic                    rst_n,
    input  logic                    wr_en,
    input  logic                    rd_en,
    input  logic [DATA_WIDTH-1:0]  wr_data,
    output logic [DATA_WIDTH-1:0]  rd_data,
    output logic                    full,
    output logic                    empty,
    output logic [$clog2(DEPTH):0] count
);
    // FIFO实现代码...
endmodule

10.2 完整的功能覆盖率验证

// FIFO验证模块,包含完整的功能覆盖率
module fifo_tb;
    // 参数定义
    parameter DATA_WIDTH = 8;
    parameter DEPTH = 16;
    parameter CLK_PERIOD = 10;
    
    // 信号声明
    logic                    clk;
    logic                    rst_n;
    logic                    wr_en;
    logic                    rd_en;
    logic [DATA_WIDTH-1:0]  wr_data;
    logic [DATA_WIDTH-1:0]  rd_data;
    logic                    full;
    logic                    empty;
    logic [$clog2(DEPTH):0] count;
    
    // 时钟生成
    initial begin
        clk = 0;
        forever #(CLK_PERIOD/2) clk = ~clk;
    end
    
    // DUT实例化
    fifo #(
        .DATA_WIDTH(DATA_WIDTH),
        .DEPTH(DEPTH)
    ) dut (
        .clk(clk),
        .rst_n(rst_n),
        .wr_en(wr_en),
        .rd_en(rd_en),
        .wr_data(wr_data),
        .rd_data(rd_data),
        .full(full),
        .empty(empty),
        .count(count)
    );
    
    // ========================================
    // 功能覆盖率定义
    // ========================================
    
    // 1. 基本操作覆盖率
    covergroup basic_ops_cg @(posedge clk);
        option.per_instance = 1;
        option.name = "basic_operations";
        option.comment = "FIFO基本操作覆盖率";
        
        // 写使能覆盖
        wr_enable_cp: coverpoint wr_en {
            bins write_active = {1};
            bins write_inactive = {0};
        }
        
        // 读使能覆盖
        rd_enable_cp: coverpoint rd_en {
            bins read_active = {1};
            bins read_inactive = {0};
        }
        
        // 同时读写操作覆盖
        rw_operation_cp: cross wr_enable_cp, rd_enable_cp {
            bins idle = binsof(wr_enable_cp.write_inactive) && 
                       binsof(rd_enable_cp.read_inactive);
            bins write_only = binsof(wr_enable_cp.write_active) && 
                             binsof(rd_enable_cp.read_inactive);
            bins read_only = binsof(wr_enable_cp.write_inactive) && 
                            binsof(rd_enable_cp.read_active);
            bins simultaneous = binsof(wr_enable_cp.write_active) && 
                               binsof(rd_enable_cp.read_active);
        }
    endgroup
    
    // 2. FIFO状态覆盖率
    covergroup fifo_state_cg @(posedge clk);
        option.per_instance = 1;
        option.name = "fifo_states";
        option.comment = "FIFO状态转换覆盖率";
        
        // 空满状态覆盖
        empty_cp: coverpoint empty {
            bins empty_state = {1};
            bins not_empty = {0};
        }
        
        full_cp: coverpoint full {
            bins full_state = {1};
            bins not_full = {0};
        }
        
        // FIFO计数覆盖
        count_cp: coverpoint count {
            bins empty_count = {0};
            bins low_fill = {[1:DEPTH/4]};
            bins mid_fill = {[DEPTH/4+1:3*DEPTH/4]};
            bins high_fill = {[3*DEPTH/4+1:DEPTH-1]};
            bins full_count = {DEPTH};
        }
        
        // 状态组合覆盖
        state_combination: cross empty_cp, full_cp {
            bins normal_states = binsof(empty_cp.not_empty) && 
                                binsof(full_cp.not_full);
            bins empty_state = binsof(empty_cp.empty_state) && 
                              binsof(full_cp.not_full);
            bins full_state = binsof(empty_cp.not_empty) && 
                             binsof(full_cp.full_state);
            // 排除不可能的状态
            illegal_bins impossible = binsof(empty_cp.empty_state) && 
                                     binsof(full_cp.full_state);
        }
    endgroup
    
    // 3. 数据模式覆盖率
    covergroup data_pattern_cg @(posedge clk iff wr_en);
        option.per_instance = 1;
        option.name = "data_patterns";
        option.comment = "写入数据模式覆盖率";
        
        // 数据值覆盖
        data_value_cp: coverpoint wr_data {
            bins zero = {8'h00};
            bins all_ones = {8'hFF};
            bins low_values = {[8'h01:8'h7F]};
            bins high_values = {[8'h80:8'hFE]};
            bins alternating_01 = {8'h55};
            bins alternating_10 = {8'hAA};
        }
        
        // 数据位模式覆盖
        bit_pattern_cp: coverpoint wr_data {
            wildcard bins pattern_0x0x = {8'b0?0?0?0?};
            wildcard bins pattern_1x1x = {8'b1?1?1?1?};
            wildcard bins pattern_x01x = {8'b?01??01?};
            wildcard bins pattern_x10x = {8'b?10??10?};
        }
    endgroup
    
    // 4. 边界条件覆盖率
    covergroup boundary_cg @(posedge clk);
        option.per_instance = 1;
        option.name = "boundary_conditions";
        option.comment = "边界条件覆盖率";
        
        // 写操作边界条件
        write_boundary_cp: coverpoint {wr_en, full} {
            bins normal_write = {2'b10};  // 写使能且非满
            bins blocked_write = {2'b11}; // 写使能但已满
            bins no_write_empty = {2'b00}; // 不写且非满
            bins no_write_full = {2'b01};  // 不写且满
        }
        
        // 读操作边界条件
        read_boundary_cp: coverpoint {rd_en, empty} {
            bins normal_read = {2'b10};   // 读使能且非空
            bins blocked_read = {2'b11};  // 读使能但已空
            bins no_read_full = {2'b00};  // 不读且非空
            bins no_read_empty = {2'b01}; // 不读且空
        }
        
        // 边界转换覆盖
        boundary_transition: cross write_boundary_cp, read_boundary_cp {
            // 关注关键的边界组合
            bins fill_to_full = binsof(write_boundary_cp.normal_write) && 
                               binsof(read_boundary_cp.no_read_full);
            bins empty_to_fill = binsof(write_boundary_cp.normal_write) && 
                                binsof(read_boundary_cp.blocked_read);
            bins drain_to_empty = binsof(write_boundary_cp.no_write_empty) && 
                                 binsof(read_boundary_cp.normal_read);
            bins full_to_drain = binsof(write_boundary_cp.blocked_write) && 
                                binsof(read_boundary_cp.normal_read);
        }
    endgroup
    
    // 5. 序列操作覆盖率
    covergroup sequence_cg @(posedge clk);
        option.per_instance = 1;
        option.name = "operation_sequences";
        option.comment = "操作序列覆盖率";
        
        // 连续写操作序列
        write_sequence_cp: coverpoint wr_en {
            bins single_write = (0 => 1 => 0);
            bins double_write = (0 => 1 [*2] => 0);
            bins triple_write = (0 => 1 [*3] => 0);
            bins long_write = (0 => 1 [*4:8] => 0);
            bins continuous_write = (1 [*9:$]);
        }
        
        // 连续读操作序列
        read_sequence_cp: coverpoint rd_en {
            bins single_read = (0 => 1 => 0);
            bins double_read = (0 => 1 [*2] => 0);
            bins triple_read = (0 => 1 [*3] => 0);
            bins long_read = (0 => 1 [*4:8] => 0);
            bins continuous_read = (1 [*9:$]);
        }
        
        // 填充-排空序列
        fill_drain_cp: coverpoint {wr_en, rd_en} {
            bins fill_phase = (2'b00 => 2'b10 [*1:$] => 2'b00);
            bins drain_phase = (2'b00 => 2'b01 [*1:$] => 2'b00);
            bins alternating = (2'b10 => 2'b01) [*3:$];
            bins simultaneous = (2'b11 [*2:$]);
        }
    endgroup
    
    // 6. 性能相关覆盖率
    covergroup performance_cg @(posedge clk);
        option.per_instance = 1;
        option.name = "performance_metrics";
        option.comment = "性能指标覆盖率";
        
        // 吞吐量覆盖(连续操作周期数)
        throughput_cp: coverpoint {wr_en && !full, rd_en && !empty} {
            bins no_throughput = {2'b00};
            bins write_only = {2'b10};
            bins read_only = {2'b01};
            bins full_throughput = {2'b11};
            option.weight = 2; // 提高吞吐量覆盖的权重
        }
        
        // 利用率覆盖
        utilization_cp: coverpoint count {
            bins underutilized = {[0:DEPTH/8]};
            bins low_util = {[DEPTH/8+1:DEPTH/4]};
            bins medium_util = {[DEPTH/4+1:3*DEPTH/4]};
            bins high_util = {[3*DEPTH/4+1:DEPTH]};
        }
    endgroup
    
    // 7. 错误条件覆盖率
    covergroup error_cg @(posedge clk);
        option.per_instance = 1;
        option.name = "error_conditions";
        option.comment = "错误条件覆盖率";
        
        // 溢出尝试
        overflow_attempt_cp: coverpoint {wr_en, full} {
            bins normal_write = {2'b10};
            bins overflow_attempt = {2'b11};
            bins no_write = {2'b0?};
        }
        
        // 下溢尝试
        underflow_attempt_cp: coverpoint {rd_en, empty} {
            bins normal_read = {2'b10};
            bins underflow_attempt = {2'b11};
            bins no_read = {2'b0?};
        }
        
        // 错误组合
        error_combination: cross overflow_attempt_cp, underflow_attempt_cp {
            bins both_errors = binsof(overflow_attempt_cp.overflow_attempt) && 
                              binsof(underflow_attempt_cp.underflow_attempt);
            bins overflow_only = binsof(overflow_attempt_cp.overflow_attempt) && 
                                binsof(underflow_attempt_cp.normal_read);
            bins underflow_only = binsof(overflow_attempt_cp.normal_write) && 
                                 binsof(underflow_attempt_cp.underflow_attempt);
        }
    endgroup
    
    // ========================================
    // 覆盖组实例化和控制
    // ========================================
    
    // 实例化所有覆盖组
    basic_ops_cg basic_ops_inst;
    fifo_state_cg fifo_state_inst;
    data_pattern_cg data_pattern_inst;
    boundary_cg boundary_inst;
    sequence_cg sequence_inst;
    performance_cg performance_inst;
    error_cg error_inst;
    
    // 初始化覆盖组
    initial begin
        basic_ops_inst = new();
        fifo_state_inst = new();
        data_pattern_inst = new();
        boundary_inst = new();
        sequence_inst = new();
        performance_inst = new();
        error_inst = new();
        
        // 设置覆盖组选项
        basic_ops_inst.set_inst_name("basic_ops_coverage");
        fifo_state_inst.set_inst_name("fifo_state_coverage");
        data_pattern_inst.set_inst_name("data_pattern_coverage");
        boundary_inst.set_inst_name("boundary_coverage");
        sequence_inst.set_inst_name("sequence_coverage");
        performance_inst.set_inst_name("performance_coverage");
        error_inst.set_inst_name("error_coverage");
    end
    
    // ========================================
    // 测试激励生成
    // ========================================
    
    // 随机测试任务
    task automatic random_test(int num_cycles);
        for (int i = 0; i < num_cycles; i++) begin
            @(posedge clk);
            wr_en <= $random() % 2;
            rd_en <= $random() % 2;
            wr_data <= $random();
        end
    endtask
    
    // 定向测试任务
    task automatic directed_test();
        // 测试填满FIFO
        repeat(DEPTH + 2) begin
            @(posedge clk);
            wr_en <= 1;
            rd_en <= 0;
            wr_data <= $random();
        end
        
        // 测试排空FIFO
        repeat(DEPTH + 2) begin
            @(posedge clk);
            wr_en <= 0;
            rd_en <= 1;
        end
        
        // 测试同时读写
        repeat(20) begin
            @(posedge clk);
            wr_en <= 1;
            rd_en <= 1;
            wr_data <= $random();
        end
    endtask
    
    // ========================================
    // 覆盖率监控和报告
    // ========================================
    
    // 覆盖率监控任务
    task automatic monitor_coverage();
        real total_coverage;
        real individual_coverage;
        
        forever begin
            #1000; // 每1000个时间单位检查一次
            
            // 计算总体覆盖率
            total_coverage = ($get_coverage() + 
                            basic_ops_inst.get_coverage() +
                            fifo_state_inst.get_coverage() +
                            data_pattern_inst.get_coverage() +
                            boundary_inst.get_coverage() +
                            sequence_inst.get_coverage() +
                            performance_inst.get_coverage() +
                            error_inst.get_coverage()) / 8.0;
            
            $display("[%0t] 总体覆盖率: %0.2f%%", $time, total_coverage);
            
            // 显示各个覆盖组的覆盖率
            $display("  基本操作覆盖率: %0.2f%%", basic_ops_inst.get_coverage());
            $display("  FIFO状态覆盖率: %0.2f%%", fifo_state_inst.get_coverage());
            $display("  数据模式覆盖率: %0.2f%%", data_pattern_inst.get_coverage());
            $display("  边界条件覆盖率: %0.2f%%", boundary_inst.get_coverage());
            $display("  序列操作覆盖率: %0.2f%%", sequence_inst.get_coverage());
            $display("  性能指标覆盖率: %0.2f%%", performance_inst.get_coverage());
            $display("  错误条件覆盖率: %0.2f%%", error_inst.get_coverage());
            
            // 如果达到目标覆盖率,结束仿真
            if (total_coverage >= 95.0) begin
                $display("\n[%0t] 达到目标覆盖率 95%%, 仿真结束", $time);
                $finish;
            end
        end
    endtask
    
    // ========================================
    // 主测试流程
    // ========================================
    
    initial begin
        // 初始化
        rst_n = 0;
        wr_en = 0;
        rd_en = 0;
        wr_data = 0;
        
        // 复位
        repeat(5) @(posedge clk);
        rst_n = 1;
        
        // 启动覆盖率监控
        fork
            monitor_coverage();
        join_none
        
        // 执行测试
        $display("[%0t] 开始FIFO功能覆盖率测试", $time);
        
        // 定向测试
        $display("[%0t] 执行定向测试", $time);
        directed_test();
        
        // 随机测试
        $display("[%0t] 执行随机测试", $time);
        random_test(5000);
        
        // 等待覆盖率收集完成
        repeat(100) @(posedge clk);
        
        // 最终覆盖率报告
        $display("\n========== 最终覆盖率报告 ==========");
        $display("基本操作覆盖率: %0.2f%%", basic_ops_inst.get_coverage());
        $display("FIFO状态覆盖率: %0.2f%%", fifo_state_inst.get_coverage());
        $display("数据模式覆盖率: %0.2f%%", data_pattern_inst.get_coverage());
        $display("边界条件覆盖率: %0.2f%%", boundary_inst.get_coverage());
        $display("序列操作覆盖率: %0.2f%%", sequence_inst.get_coverage());
        $display("性能指标覆盖率: %0.2f%%", performance_inst.get_coverage());
        $display("错误条件覆盖率: %0.2f%%", error_inst.get_coverage());
        
        $finish;
    end
    
endmodule

10.3 传统Verilog等价实现对比

如果使用传统Verilog实现相同的功能覆盖率,需要大量的手动代码:

// 传统Verilog需要手动实现所有统计逻辑
module fifo_coverage_verilog;
    // 需要定义大量的计数器和统计变量
    integer write_active_count, write_inactive_count;
    integer read_active_count, read_inactive_count;
    integer idle_count, write_only_count, read_only_count, simultaneous_count;
    integer empty_state_count, full_state_count;
    integer zero_data_count, all_ones_count;
    // ... 数百个统计变量
    
    // 需要手动编写所有的统计逻辑
    always @(posedge clk) begin
        if (wr_en) write_active_count <= write_active_count + 1;
        else write_inactive_count <= write_inactive_count + 1;
        
        if (rd_en) read_active_count <= read_active_count + 1;
        else read_inactive_count <= read_inactive_count + 1;
        
        case ({wr_en, rd_en})
            2'b00: idle_count <= idle_count + 1;
            2'b10: write_only_count <= write_only_count + 1;
            2'b01: read_only_count <= read_only_count + 1;
            2'b11: simultaneous_count <= simultaneous_count + 1;
        endcase
        
        // ... 数百行类似的统计代码
    end
    
    // 需要手动编写覆盖率计算函数
    function real calculate_coverage;
        // 复杂的覆盖率计算逻辑
        // ... 数十行计算代码
    endfunction
    
    // 需要手动编写报告生成逻辑
    task generate_coverage_report;
        // ... 数十行报告生成代码
    endtask
    
endmodule

10.4 示例总结

这个FIFO验证示例展示了SystemVerilog功能覆盖率的强大能力:

  1. 全面覆盖:从基本操作到复杂序列,从正常情况到错误条件
  2. 分层组织:不同类型的覆盖点分组管理
  3. 自动化:自动统计、计算和报告
  4. 灵活配置:通过选项控制覆盖行为
  5. 实时监控:动态查询覆盖率进度
  6. 简洁表达:复杂的覆盖需求用简洁的语法表达