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

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

SystemVerilog【六】功能覆盖率详解

📖 扩展学习资源:

  • SystemVerilog常用语法学习 - CSDN

  • SystemVerilog学习【一】数据类型详解 - CSDN

  • SystemVerilog学习【二】接口(interface)详解 - CSDN

  • SystemVerilog学习【三】类和面向对象编程详解 - CSDN

  • SystemVerilog学习【四】约束随机化编程详解 - CSDN

  • SystemVerilog学习【五】断言详解 - CSDN


文章目录

  • SystemVerilog【六】功能覆盖率详解
    • 1. 功能覆盖率概述
      • 1.1 什么是功能覆盖率
      • 1.2 如何在验证中使用功能覆盖率
      • 2.2 covergroup参数
      • 2.3 covergroup采样
    • 3. coverpoint
      • 3.1 coverpoint的定义
      • 3.2 bins for value
      • 3.3 bins for sequence
      • 3.4 wildcard、ignore_bins、illegal_bins
    • 4 交叉覆盖率
      • 4.1 cross定义
      • 4.2 排除部分cross bin
      • 4.3 精细的交叉覆盖率指定
    • 5. 覆盖率选项
      • 5.1 基本覆盖率选项
    • 6. 系统方法
      • 6.1 覆盖率查询方法
    • 7. 计算方法
      • 7.1 基本覆盖率计算
    • 8. SystemVerilog与传统Verilog的对比
      • 8.1 语法简洁性对比
      • 8.2 功能完整性对比
      • 8.3 开发效率对比
      • 8.4 维护性对比
      • 8.5 性能对比
      • 8.6 工具支持对比
      • 8.7 学习曲线对比
      • 8.8 实际应用建议
    • 9. 总结
      • 9.1 核心优势
      • 9.2 关键概念回顾
      • 9.3 最佳实践
      • 9.4 发展趋势
      • 9.5 结语
    • 10. 综合示例:FIFO验证中的功能覆盖率
      • 10.1 FIFO设计模块
      • 10.2 完整的功能覆盖率验证
      • 10.3 传统Verilog等价实现对比
      • 10.4 示例总结

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) beginif (sample_enable) begintotal_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;elsedata_high_count = data_high_count + 1;mode_count[mode] = mode_count[mode] + 1;endend// 手动计算覆盖率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++) beginif (mode_count[i] > 0)$display("模式%d已覆盖: %d次", i, mode_count[i]);endendtask
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;endgroupmemory_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("建议:增加地址边界测试用例");endif (data_cov < 90.0) begin$display("建议:增加特殊数据值测试");endif (total_cov >= 95.0) begin$display("验证目标达成,可以考虑收敛");end else begin$display("需要继续测试,目标覆盖率: 95%%");endendtask// 定期检查覆盖率initial beginrepeat (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;// 带选项的covergroupcovergroup 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// 实例化不同选项的covergroupoptions_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个地址binverilog_bin_t data_bins[4];  // 4个数据bininteger total_samples;initial begin// 初始化选项global_opts.goal = 95;global_opts.at_least = 2;global_opts.weight = 1;global_opts.name = "manual_coverage";// 初始化binsfor (int i = 0; i < 4; i++) beginaddr_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;endend// 手动统计和选项控制always @(posedge clk) beginif (!reset && (read || write)) begintotal_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++;endcasecase (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++;endcaseendend// 手动计算覆盖率task calculate_manual_coverage;integer covered_bins;real coverage_percent;covered_bins = 0;// 检查地址binsfor (int i = 0; i < 4; i++) beginif (addr_bins[i].count >= addr_bins[i].target_hits) beginaddr_bins[i].covered = 1;covered_bins++;endend// 检查数据binsfor (int i = 0; i < 4; i++) beginif (data_bins[i].count >= data_bins[i].target_hits) begindata_bins[i].covered = 1;covered_bins++;endendcoverage_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);endendtask// 测试序列initial beginreset = 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;endgroupfunction new();auto_sample_cg = new();manual_sample_cg = new();endfunction// 条件采样函数function void conditional_sample();if (addr > 8'h80) beginmanual_sample_cg.sample();endendfunction// 延迟采样task delayed_sample();#10;  // 延迟10个时间单位manual_sample_cg.sample();endtaskendclass// 实例化covergroupclk_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) beginif (!reset) beginsample_counter++;// 每10个周期采样一次if (sample_counter % 10 == 0) beginsample_enable = 1;manual_inst.sample();end else beginsample_enable = 0;endendend// 条件采样控制always @(posedge clk) beginif (valid && (addr > 8'h80)) begin// 高地址时进行额外采样manual_inst.sample();endif (read && write) begin// 错误条件时采样$display("错误:同时读写,时间: %t", $time);manual_inst.sample();endend// 传统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) beginif (!reset) begin// 基本采样verilog_stats.total_samples++;// 条件采样if (valid) beginverilog_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]++;endcaseendendend// 状态变化检测(手动)logic [1:0] prev_state;always @(posedge clk) beginif (state != prev_state) begin$display("状态变化: %d -> %d, 时间: %t", prev_state, state, $time);// 手动记录状态转换endprev_state = state;end// 测试序列initial beginreset = 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) beginstate = $random % 4;end// 手动采样示例if ($random % 5 == 0) beginmanual_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);// 基本coverpointbasic_addr_cp: coverpoint addr;// 带标签的coverpointlabeled_data_cp: coverpoint data {bins zero = {8'h00};bins non_zero = {[8'h01:8'hFF]};}// 表达式coverpointaddr_high_cp: coverpoint addr[7:4] {bins low_nibble  = {[4'h0:4'h7]};bins high_nibble = {[4'h8:4'hF]};}// 多信号组合coverpointoperation_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};}// 条件coverpointconditional_data_cp: coverpoint data iff (valid && (read || write)) {bins data_ranges[] = {[0:63], [64:127], [128:191], [192:255]};}// 函数调用coverpointfunction 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;                   // 最高优先级endfunctionpriority_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};}// 枚举类型coverpointtypedef 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};}// 位选择coverpointbit_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};}// 算术表达式coverpointsum_cp: coverpoint (addr + data) {bins low_sum  = {[0:127]};bins high_sum = {[128:511]};}// 逻辑表达式coverpointlogic_cp: coverpoint (addr & data) {bins zero_and    = {8'h00};bins partial_and = {[8'h01:8'hFE]};bins full_and    = {8'hFF};}endgroup// 实例化covergroupcoverpoint_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;endfunctionalways @(posedge clk) beginif (!reset) beginverilog_stats.total_samples++;// 基本地址统计verilog_stats.addr_count[addr]++;// 数据分类if (data == 8'h00)verilog_stats.zero_data_count++;elseverilog_stats.non_zero_data_count++;// 地址高位if (addr[7:4] <= 4'h7)verilog_stats.low_nibble_count++;elseverilog_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)) begincase (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]++;endcaseend// 优先级统计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++;elseverilog_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++;endcaseendend// 测试序列initial beginreset = 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) begincase ($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;endcaseend// 特殊测试场景if ($random % 20 == 0) begin// 边界值测试addr = ($random % 2) ? 8'h00 : 8'hFF;data = ($random % 2) ? 8'h00 : 8'hFF;endend// 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);// 单值binsaddr_single_cp: coverpoint addr {bins zero = {8'h00};bins max  = {8'hFF};bins mid  = {8'h80};}// 多值binsaddr_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};}// 范围binsaddr_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]};    // 保留命令自动分组}// 条件binsconditional_bins_cp: coverpoint data {bins low_data  = {[0:127]} iff (read);bins high_data = {[128:255]} iff (write);}// 默认binsdefault_bins_cp: coverpoint addr {bins defined_values = {8'h00, 8'h55, 8'hAA, 8'hFF};bins default;  // 捕获所有其他值}// 表达式binsexpression_bins_cp: coverpoint (addr[7:4]) {bins low_nibble  = {[4'h0:4'h7]};bins high_nibble = {[4'h8:4'hF]};}// 组合信号binscombo_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);// 位模式binsbit_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};}// 算术binsarithmetic_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};}// 函数返回值binsfunction logic [2:0] get_addr_type(logic [7:0] addr);if (addr == 8'h00) return 3'b001;        // NULLelse if (addr[0] == 1'b0) return 3'b010; // EVENelse if (addr[7] == 1'b1) return 3'b100; // HIGH_ODDelse return 3'b011;                      // LOW_ODDendfunctionaddr_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// 实例化covergroupvalue_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;endfunctionfunction 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;endcaseendfunctionfunction bit is_special_value(logic [7:0] value);case (value)8'h00, 8'h55, 8'hAA, 8'hFF: return 1;default: return 0;endcaseendfunctionalways @(posedge clk) beginif (!reset) beginverilog_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: beginif (cmd >= 4'hB && cmd <= 4'hF)verilog_stats.reserved_cmd_count[cmd - 4'hB]++;endendcase// 条件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++;elseverilog_stats.default_count++;// 表达式bins统计if (addr[7:4] <= 4'h7)verilog_stats.low_nibble_count++;elseverilog_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]++;enddefault: beginif ((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]++;endendcase// 地址类型统计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]++;endcaseendend// 覆盖率计算函数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 beginreset = 1;addr = 8'h00;data = 8'h00;cmd = 4'h0;read = 0;write = 0;#20 reset = 0;// 系统性测试各种bins$display("开始bins覆盖率测试...");// 测试单值binsrepeat (10) begin@(posedge clk);addr = 8'h00;  // 测试零值endrepeat (10) begin@(posedge clk);addr = 8'hFF;  // 测试最大值endrepeat (10) begin@(posedge clk);addr = 8'h80;  // 测试中间值end// 测试特殊值binsforeach (val_cg.addr_multi_cp.special_values[i]) beginrepeat (5) begin@(posedge clk);case (i)0: addr = 8'h00;1: addr = 8'h55;2: addr = 8'hAA;3: addr = 8'hFF;endcaseendend// 测试2的幂值repeat (5) begin@(posedge clk);addr = 8'h01;endrepeat (5) begin@(posedge clk);addr = 8'h02;endrepeat (5) begin@(posedge clk);addr = 8'h04;end// 测试范围binsrepeat (20) begin@(posedge clk);addr = $random % 64;      // 低范围endrepeat (20) begin@(posedge clk);addr = 64 + ($random % 64); // 中范围end// 测试条件binsrepeat (30) begin@(posedge clk);read = 1;write = 0;data = $random % 128;     // 低数据值endrepeat (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);// 基本序列binsstate_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);}// 多步序列binsmulti_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);}// 重复序列binsrepeat_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个周期}// 通配符序列binswildcard_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]);}// 条件序列binsconditional_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);}// 复杂序列binscomplex_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// 实例化covergroupsequence_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) beginif (reset) beginprev_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 beginverilog_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) begincase (state)2'b00: verilog_stats.idle_repeat_count++;2'b01: verilog_stats.active_repeat_count++;2'b10: verilog_stats.busy_repeat_count++;endcaseend 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: beginif (state == 2'b00) verilog_stats.normal_flow_state = verilog_stats.SEQ_STEP1;endverilog_stats.SEQ_STEP1: beginif (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;endverilog_stats.SEQ_STEP2: beginif (state == 2'b10) verilog_stats.normal_flow_state = verilog_stats.SEQ_STEP3;else verilog_stats.normal_flow_state = verilog_stats.SEQ_IDLE;endverilog_stats.SEQ_STEP3: beginif (state == 2'b00) beginverilog_stats.normal_flow_count++;verilog_stats.normal_flow_state = verilog_stats.SEQ_STEP1;end else beginverilog_stats.normal_flow_state = verilog_stats.SEQ_IDLE;endendendcase// 多步序列状态机 - 快速循环case (verilog_stats.quick_cycle_state)verilog_stats.SEQ_IDLE: beginif (state == 2'b00) verilog_stats.quick_cycle_state = verilog_stats.SEQ_STEP1;endverilog_stats.SEQ_STEP1: beginif (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;endverilog_stats.SEQ_STEP2: beginif (state == 2'b00) beginverilog_stats.quick_cycle_count++;verilog_stats.quick_cycle_state = verilog_stats.SEQ_STEP1;end else beginverilog_stats.quick_cycle_state = verilog_stats.SEQ_IDLE;endendendcase// 更新前一个状态prev_state = state;prev_addr = addr;prev_data = data;prev_read = read;prev_write = write;endend// 测试序列initial beginreset = 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;endrepeat (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位为0000wildcard bins addr_pattern_1 = {8'b0001????};  // 低4位任意,高4位为0001wildcard bins addr_pattern_f = {8'b1111????};  // 低4位任意,高4位为1111wildcard 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位匹配1010wildcard bins pattern_?a = {8'b????1010};       // 低4位匹配1010wildcard 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_binsaddr_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}}; // 无效组合}// 条件通配符binsconditional_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};}// 状态相关的特殊binsstate_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// 实例化covergroupspecial_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));endfunctionfunction 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) beginif (reset) beginverilog_stats = '{default: 0};end else beginverilog_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]++;  // ????1010else if (wildcard_match_8bit(data, 8'b00000000, 8'b01010101))verilog_stats.data_pattern_counts[3]++;  // ?0?0?0?0else 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: beginverilog_stats.illegal_mode_detected++;verilog_stats.error_count++;$error("检测到非法模式: %b", mode);endendcase// 组合模式检测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}: beginverilog_stats.illegal_combo_detected++;verilog_stats.error_count++;$error("检测到非法组合: addr[7:4]=%h, data[3:0]=%h", addr[7:4], data[3:0]);endendcase// 条件通配符检测if (valid) beginif (addr[0] == 1'b0)verilog_stats.valid_even_count++;elseverilog_stats.valid_odd_count++;end else beginverilog_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++;  // 忽略测试模式endcasecase (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) beginverilog_stats.error_pattern_detected++;verilog_stats.error_count++;$error("检测到错误模式,数据值: %h", data);endendend// 覆盖率计算函数function real calculate_wildcard_coverage(integer pattern_counts[], integer total_patterns);integer hit_patterns = 0;for (int i = 0; i < total_patterns; i++) beginif (pattern_counts[i] > 0) hit_patterns++;endreturn (total_patterns > 0) ? (real'(hit_patterns) / real'(total_patterns) * 100.0) : 0.0;endfunction// 测试序列initial beginreset = 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);endcaseend// 测试模式(包含非法值)$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);// 优先级coverpointpriority_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]};}// 数据模式coverpointdata_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};}// 状态coverpointstate_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// 实例化covergroupcross_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;  // sequential3'b001: return 1;  // random3'b010: return 2;  // fixed3'b011: return 3;  // burst3'b100: return 4;  // wrapdefault: return 5; // reservedendcaseendfunctionfunction integer map_data_size(logic [1:0] size);return size;  // 直接映射 0-3endfunctionfunction integer map_burst_type(logic [1:0] burst);return burst;  // 直接映射 0-3endfunctionfunction integer map_priority(logic [3:0] prio);if (prio <= 4'h3) return 0;      // lowelse if (prio <= 4'h7) return 1; // mediumelse if (prio <= 4'hB) return 2; // highelse return 3;                   // criticalendfunctionfunction integer map_data_pattern(logic [7:0] data_val);if (data_val == 8'h00) return 0;           // zeroelse if (data_val <= 8'h3F) return 1;     // low_valueselse if (data_val <= 8'hBF) return 2;     // mid_valueselse if (data_val <= 8'hFE) return 3;     // high_valueselse return 4;                            // max (8'hFF)endfunctionfunction integer map_state(logic valid_sig, logic ready_sig);return {valid_sig, ready_sig};  // 直接映射到0-3endfunction// 手动实现交叉覆盖率统计always @(posedge clk) beginif (reset) beginverilog_cross_stats = '{default: 0};end else beginautomatic 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) beginverilog_cross_stats.addr_data_hits++;endverilog_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) beginverilog_cross_stats.addr_data_burst_hits++;endverilog_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) beginverilog_cross_stats.full_transaction_hits++;endverilog_cross_stats.full_transaction_hypercube[addr_idx][data_idx][burst_idx][rw_idx]++;// 条件交叉统计 - 仅在valid && ready时统计if (valid && ready) beginverilog_cross_stats.valid_condition_count++;if (verilog_cross_stats.valid_transaction_matrix[addr_idx][data_idx][rw_idx] == 0) beginverilog_cross_stats.valid_transaction_hits++;endverilog_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) beginverilog_cross_stats.priority_data_hits++;endverilog_cross_stats.priority_data_matrix[prio_idx][pattern_idx]++;// 优先级 x 状态if (verilog_cross_stats.priority_state_matrix[prio_idx][state_idx] == 0) beginverilog_cross_stats.priority_state_hits++;endverilog_cross_stats.priority_state_matrix[prio_idx][state_idx]++;// 数据模式 x 状态if (verilog_cross_stats.data_state_matrix[pattern_idx][state_idx] == 0) beginverilog_cross_stats.data_state_hits++;endverilog_cross_stats.data_state_matrix[pattern_idx][state_idx]++;// 完整三维交叉 - 优先级 x 数据模式 x 状态if (verilog_cross_stats.complete_cube[prio_idx][pattern_idx][state_idx] == 0) beginverilog_cross_stats.complete_hits++;endverilog_cross_stats.complete_cube[prio_idx][pattern_idx][state_idx]++;endend// 覆盖率计算函数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 beginreset = 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++) beginfor (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);endend// 测试三维交叉$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++) beginfor (int pattern = 0; pattern < 5; pattern++) beginfor (int state = 0; state < 4; state++) begin@(posedge clk);case (prio)0: priority = $random % 4;        // low1: priority = 4 + ($random % 4);  // medium2: priority = 8 + ($random % 4);  // high3: priority = 12 + ($random % 4); // criticalendcasecase (pattern)0: data = 8'h00;                    // zero1: data = 1 + ($random % 63);       // low_values2: data = 64 + ($random % 128);     // mid_values3: data = 192 + ($random % 62);     // high_values4: data = 8'hFF;                    // maxendcase{valid, ready} = state;addr_type = $random % 6;data_size = $random % 4;burst_type = $random % 4;read_write = $random % 2;endendend// 随机压力测试$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);// 命令类型coverpointcmd_cp: coverpoint cmd_type {bins read = {2'b00};bins write = {2'b01};bins rmw = {2'b10};     // read-modify-writebins reserved = {2'b11};}// 地址模式coverpointaddr_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};}// 数据宽度coverpointwidth_cp: coverpoint data_width {bins byte_width = {2'b00};bins half_word = {2'b01};bins word = {2'b10};bins double_word = {2'b11};}// 突发长度coverpointburst_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};}// 缓存使能coverpointcache_cp: coverpoint cache_enable {bins disabled = {1'b0};bins enabled = {1'b1};}// 保护级别coverpointprot_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// 实例化covergroupcross_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;endfunctionfunction 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;endfunctionfunction 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;endfunctionfunction bit is_cache_prot_valid(logic cache, logic [1:0] prot);// 调试模式下禁用缓存if (prot == 2'b11 && cache == 1'b1) return 0;return 1;endfunctionfunction 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) beginif (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) beginif (reset) beginverilog_exclude_stats = '{default: 0};end else beginverilog_exclude_stats.total_samples++;// 检查并统计各种交叉组合if (is_cmd_addr_valid(cmd_type, addr_mode)) beginif (!verilog_exclude_stats.cmd_addr_matrix[cmd_type][addr_mode]) beginverilog_exclude_stats.cmd_addr_valid_combinations++;verilog_exclude_stats.cmd_addr_matrix[cmd_type][addr_mode] = 1;endend else beginverilog_exclude_stats.cmd_addr_excluded++;endif (is_cmd_addr_width_valid(cmd_type, addr_mode, data_width)) beginif (!verilog_exclude_stats.cmd_addr_width_cube[cmd_type][addr_mode][data_width]) beginverilog_exclude_stats.cmd_addr_width_valid_combinations++;verilog_exclude_stats.cmd_addr_width_cube[cmd_type][addr_mode][data_width] = 1;endend else beginverilog_exclude_stats.cmd_addr_width_excluded++;endif (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; // invalidif (burst_idx < 4 && !verilog_exclude_stats.addr_burst_matrix[addr_mode][burst_idx]) beginverilog_exclude_stats.addr_burst_valid_combinations++;verilog_exclude_stats.addr_burst_matrix[addr_mode][burst_idx] = 1;endend else beginverilog_exclude_stats.addr_burst_excluded++;endif (is_cache_prot_valid(cache_enable, protection)) beginif (!verilog_exclude_stats.cache_prot_matrix[cache_enable][protection]) beginverilog_exclude_stats.cache_prot_valid_combinations++;verilog_exclude_stats.cache_prot_matrix[cache_enable][protection] = 1;endend else beginverilog_exclude_stats.cache_prot_excluded++;endif (is_complex_valid(cmd_type, addr_mode, data_width, cache_enable)) beginverilog_exclude_stats.complex_valid_combinations++;end else beginverilog_exclude_stats.complex_excluded++;end// 条件排除逻辑if (protection == 2'b10 && (addr_mode == 3'b100 || cmd_type == 2'b10) && cache_enable == 1'b0) beginverilog_exclude_stats.conditional_excluded++;end else if (protection == 2'b00 && (addr_mode == 3'b101 || addr_mode == 3'b110)) beginverilog_exclude_stats.conditional_excluded++;end else beginverilog_exclude_stats.conditional_valid_combinations++;endverilog_exclude_stats.valid_samples++;endend// 测试序列initial beginreset = 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++) beginfor (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);endendend// 测试特定的排除场景$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);// 操作码coverpointopcode_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};}// 操作数类型coverpointoperand_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 coverpointreg_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]};}// 寻址模式coverpointaddr_mode_cp: coverpoint addressing_mode {bins direct = {2'b00};bins indirect = {2'b01};bins indexed = {2'b10};bins relative = {2'b11};}// 条件码coverpointcondition_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};}// 异常使能coverpointexception_cp: coverpoint exception_enable {bins disabled = {1'b0};bins enabled = {1'b1};}// 特权级别coverpointprivilege_cp: coverpoint privilege_level {bins user = {2'b00};bins supervisor = {2'b01};bins kernel = {2'b10};bins hypervisor = {2'b11};}// 立即数值coverpointimmediate_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));}// 复杂的四维交叉 - 带权重的binscomplex_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 {// 使用表达式定义复杂的binsbins 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 {// 只在特定条件下生效的binsbins arith_small_imm = binsof(opcode_cp.arithmetic) && binsof(immediate_cp.small) iff (operand_type == 2'b01); // register_immbins 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// 实例化covergroupfine_cross_cg fine_cg = new();// 传统Verilog的等价实现(极其复杂)typedef struct {// 精细交叉统计结构integer opcode_operand_stats[7];  // 7个指定的binsinteger opcode_reg_addr_stats[9]; // 9个指定的binsinteger condition_privilege_stats[4]; // 4个主要bins组integer operand_immediate_stats[10]; // 10个立即数相关binsinteger complex_four_way_stats[5]; // 5个四维交叉binsinteger expression_stats[4]; // 4个表达式binsinteger 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_anydefault: return -1; // invalid or ignoredendcaseendfunctionfunction 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 // arithmeticif (reg_id <= 4'h3 && addr == 2'b00) return 1; // arith_low_directif (reg_id >= 4'h4 && reg_id <= 4'h7 && addr == 2'b01) return 1; // arith_mid_indirectif (reg_id >= 4'h8 && reg_id <= 4'hB && addr == 2'b10) return 1; // arith_high_indexedend3'b011, 3'b100: begin // logicalif (addr == 2'b00) return 1; // logic_any_directif (reg_id >= 4'hC) return 1; // logic_special_anyend3'b101, 3'b110: begin // memoryif (reg_id >= 4'hC && addr == 2'b01) return 1; // mem_special_indirectif (addr == 2'b10 || addr == 2'b11) return 1; // mem_any_indexed/relativeend3'b111: begin // controlif (reg_id >= 4'hC && addr == 2'b00) return 1; // control_special_directendendcasereturn 0;endfunctionfunction 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_arithif ((op == 3'b101 || op == 3'b110) && operand == 2'b10 && priv == 2'b10 && exc == 1'b1)return 10; // critical_kernel_memif (priv == 2'b01 && exc == 1'b1)return 5; // medium_supervisorif (priv == 2'b00 && exc == 1'b0)return 1; // low_userif (priv == 2'b11)return 8; // special_hypervisorreturn 1; // default weightendfunctionfunction 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_regs3'b011, 3'b100: return (reg_id % 2 == 1); // logical_odd_regs3'b101, 3'b110: return (reg_id == 4'h1 || reg_id == 4'h2 || reg_id == 4'h4 || reg_id == 4'h8); // memory_power_of_two3'b111: return (reg_id == 4'h1 || reg_id == 4'h2 || reg_id == 4'h3 || reg_id == 4'h5 || reg_id == 4'h8); // control_fibonacciendcasereturn 0;endfunctionfunction 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_imm3'b011, 3'b100: return (operand == 2'b01 && exc == 1'b0 && imm == 8'h00); // logic_zero_imm3'b101, 3'b110: return (operand == 2'b11 && priv >= 2'b01 && imm >= 8'h80 && imm <= 8'hFE); // mem_large_immendcasereturn 0;endfunction// 手动实现精细交叉覆盖率统计always @(posedge clk) beginif (reset) beginverilog_fine_stats = '{default: 0};end else beginautomatic 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) beginverilog_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 bins3'b011, 3'b100: verilog_fine_stats.opcode_reg_addr_stats[1]++; // logical bins3'b101, 3'b110: verilog_fine_stats.opcode_reg_addr_stats[2]++; // memory bins3'b111: verilog_fine_stats.opcode_reg_addr_stats[3]++; // control binsendcaseend// 条件-特权级别交叉统计case (privilege_level)2'b00: if (!exception_enable) verilog_fine_stats.condition_privilege_stats[0]++; // user_basic2'b01: if (exception_enable) verilog_fine_stats.condition_privilege_stats[1]++; // supervisor_extended2'b10: if (exception_enable) verilog_fine_stats.condition_privilege_stats[2]++; // kernel_full2'b11: if (exception_enable) verilog_fine_stats.condition_privilege_stats[3]++; // hypervisor_specialendcase// 操作数-立即数交叉统计if (operand_type == 2'b01 || operand_type == 2'b11) begin // 只有立即数操作数case (immediate_value)8'h00: verilog_fine_stats.operand_immediate_stats[0]++; // zero8'h01: case(8'h0F) verilog_fine_stats.operand_immediate_stats[1]++; endcase // small// ... 其他立即数范围的统计endcaseend// 权重统计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)) beginverilog_fine_stats.expression_matches++;case (opcode)3'b000, 3'b001, 3'b010: verilog_fine_stats.expression_stats[0]++; // arithmetic_even3'b011, 3'b100: verilog_fine_stats.expression_stats[1]++; // logical_odd3'b101, 3'b110: verilog_fine_stats.expression_stats[2]++; // memory_power_of_two3'b111: verilog_fine_stats.expression_stats[3]++; // control_fibonacciendcaseend// 条件表达式评估if (evaluate_conditional_expression(opcode, immediate_value, operand_type, exception_enable, privilege_level)) beginverilog_fine_stats.conditional_hits++;case (opcode)3'b000, 3'b001, 3'b010: verilog_fine_stats.conditional_expression_stats[0]++; // arith_small_imm3'b011, 3'b100: verilog_fine_stats.conditional_expression_stats[1]++; // logic_zero_imm3'b101, 3'b110: verilog_fine_stats.conditional_expression_stats[2]++; // mem_large_immendcaseend else beginverilog_fine_stats.conditional_misses++;endverilog_fine_stats.valid_combinations++;endend// 测试序列initial beginreset = 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;      // 检测重叠的binsoption.auto_bin_max = 64;       // 自动bin的最大数量option.cross_num_print_missing = 10; // 打印缺失交叉的数量// 数据coverpoint with optionsdata_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 optionsmode_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};}// 使能coverpointenable_cp: coverpoint enable {option.weight = 1;option.comment = "使能信号覆盖";bins disabled = {1'b0};bins enabled = {1'b1};}// 地址coverpoint with auto binsaddress_cp: coverpoint address {option.auto_bin_max = 16;   // 限制自动bin数量option.weight = 4;option.comment = "地址空间覆盖";}// 交叉覆盖with optionsdata_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// 实例化covergroupbasic_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: 权重5total_weighted_hits += verilog_options_stats.weighted_hits[0] * 5;total_possible_weight += 4 * 5; // 4个bins * 权重5// 模式coverpoint: 权重3total_weighted_hits += verilog_options_stats.weighted_hits[1] * 3;total_possible_weight += 4 * 3; // 4个bins * 权重3// 使能coverpoint: 权重1total_weighted_hits += verilog_options_stats.weighted_hits[2] * 1;total_possible_weight += 2 * 1; // 2个bins * 权重1// 地址coverpoint: 权重4total_weighted_hits += verilog_options_stats.weighted_hits[3] * 4;total_possible_weight += 16 * 4; // 16个auto bins * 权重4return 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 = 3for (int i = 0; i < 4; i++) beginverilog_options_stats.at_least_met[0][i] = (verilog_options_stats.actual_hits[0][i] >= 3);end// 模式coverpoint: at_least = 1for (int i = 0; i < 4; i++) beginverilog_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++) beginverilog_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++) beginverilog_options_stats.at_least_met[3][i] = (verilog_options_stats.actual_hits[3][i] >= 2);endendfunction// 重叠检测函数function bit detect_bin_overlap(logic [3:0] data_val);// 简化的重叠检测逻辑// 在实际实现中,这会更复杂case (data_val)4'h3: begin // 边界值,可能重叠verilog_options_stats.overlap_detected++;return 1;end4'h7: begin // 另一个边界值verilog_options_stats.overlap_detected++;return 1;end4'hB: begin // 第三个边界值verilog_options_stats.overlap_detected++;return 1;enddefault: return 0;endcaseendfunction// 自动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++;endendfunction// 交叉覆盖检查函数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_modeverilog_options_stats.cross_ignored_combinations++;return 0;endreturn 1;endfunction// 主要的覆盖率统计逻辑always @(posedge clk) beginif (reset) beginverilog_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; // dataverilog_options_stats.coverage_goals[1] = 90;  // modeverilog_options_stats.coverage_goals[2] = 95;  // enableverilog_options_stats.coverage_goals[3] = 95;  // address// 设置最小命中要求verilog_options_stats.min_hits_required[0] = 3; // dataverilog_options_stats.min_hits_required[1] = 1; // modeverilog_options_stats.min_hits_required[2] = 2; // enableverilog_options_stats.min_hits_required[3] = 2; // addressend else beginverilog_options_stats.total_samples++;verilog_options_stats.per_instance_samples++;// 数据coverpoint统计case (data)4'h0, 4'h1, 4'h2, 4'h3: beginverilog_options_stats.actual_hits[0][0]++; // low binif (verilog_options_stats.actual_hits[0][0] >= verilog_options_stats.min_hits_required[0])verilog_options_stats.weighted_hits[0] = 1;end4'h4, 4'h5, 4'h6, 4'h7: beginverilog_options_stats.actual_hits[0][1]++; // mid binif (verilog_options_stats.actual_hits[0][1] >= verilog_options_stats.min_hits_required[0])verilog_options_stats.weighted_hits[0] = 2;end4'h8, 4'h9, 4'hA, 4'hB: beginverilog_options_stats.actual_hits[0][2]++; // high binif (verilog_options_stats.actual_hits[0][2] >= verilog_options_stats.min_hits_required[0])verilog_options_stats.weighted_hits[0] = 3;end4'hC, 4'hD, 4'hE, 4'hF: beginverilog_options_stats.actual_hits[0][3]++; // max binif (verilog_options_stats.actual_hits[0][3] >= verilog_options_stats.min_hits_required[0])verilog_options_stats.weighted_hits[0] = 4;endendcase// 模式coverpoint统计verilog_options_stats.actual_hits[1][mode]++;if (verilog_options_stats.actual_hits[1][mode] >= verilog_options_stats.min_hits_required[1]) begincase (mode)2'b00: verilog_options_stats.weighted_hits[1] |= 1; // read_mode2'b01: verilog_options_stats.weighted_hits[1] |= 2; // write_mode2'b10: verilog_options_stats.weighted_hits[1] |= 4; // test_mode2'b11: verilog_options_stats.weighted_hits[1] |= 8; // debug_modeendcaseend// 使能coverpoint统计verilog_options_stats.actual_hits[2][enable]++;if (verilog_options_stats.actual_hits[2][enable] >= verilog_options_stats.min_hits_required[2]) beginverilog_options_stats.weighted_hits[2] |= (enable ? 2 : 1);end// 地址coverpoint统计(简化的自动bin)automatic int addr_bin = address % 16; // 简化映射到16个binsverilog_options_stats.actual_hits[3][addr_bin]++;if (verilog_options_stats.actual_hits[3][addr_bin] >= verilog_options_stats.min_hits_required[3]) beginverilog_options_stats.weighted_hits[3] |= (1 << addr_bin);end// 管理自动binsmanage_auto_bins(address);// 重叠检测if (detect_bin_overlap(data)) beginverilog_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++;endend// 测试序列initial beginreset = 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 binend$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++) beginrepeat (3) begin // 满足at_least=3的要求@(posedge clk);case (i)0: data = 4'h1; // low1: data = 4'h5; // mid2: data = 4'h9; // high3: data = 4'hD; // maxendcaseendend$display("    数据coverpoint应达到100%目标");// 测试交叉覆盖选项$display("\n  测试交叉覆盖选项:");for (int d = 0; d < 4; d++) beginfor (int m = 0; m < 4; m++) begin// 跳过忽略的组合 (max data && debug mode)if (d == 3 && m == 3) begin$display("    跳过忽略的组合: 最大数据 + 调试模式");continue;endrepeat (2) begin // 满足交叉的at_least=2要求@(posedge clk);case (d)0: data = 4'h1; // low1: data = 4'h5; // mid2: data = 4'h9; // high3: data = 4'hD; // maxendcasemode = m;endendend$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] ? "✓" : "✗");endend$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);}endgroupsystem_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 binsinteger mode_bin_hits[4];    // 4个mode binsinteger enable_bin_hits[2];  // 2个enable binsinteger 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;elsereturn 0.0;endfunction// 获取coverpoint覆盖率function real get_coverpoint_coverage(string cp_name);case (cp_name)"data_cp": beginif (verilog_sys_methods.data_total_bins > 0)return real'(verilog_sys_methods.data_covered_bins) / real'(verilog_sys_methods.data_total_bins) * 100.0;elsereturn 0.0;end"mode_cp": beginif (verilog_sys_methods.mode_total_bins > 0)return real'(verilog_sys_methods.mode_covered_bins) / real'(verilog_sys_methods.mode_total_bins) * 100.0;elsereturn 0.0;end"enable_cp": beginif (verilog_sys_methods.enable_total_bins > 0)return real'(verilog_sys_methods.enable_covered_bins) / real'(verilog_sys_methods.enable_total_bins) * 100.0;elsereturn 0.0;enddefault: return 0.0;endcaseendfunction// 获取交叉覆盖率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;elsereturn 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;endfunctionfunction 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++) beginif (verilog_sys_methods.data_bin_hits[i] > 0)verilog_sys_methods.data_covered_bins++;endverilog_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++) beginif (verilog_sys_methods.mode_bin_hits[i] > 0)verilog_sys_methods.mode_covered_bins++;endverilog_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++) beginif (verilog_sys_methods.enable_bin_hits[i] > 0)verilog_sys_methods.enable_covered_bins++;endverilog_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++;endverilog_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) beginif (reset) beginverilog_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+15start_coverage();end else if (!verilog_sys_methods.coverage_stopped) beginverilog_sys_methods.total_samples++;// 更新data coverpoint命中case (data)4'h0, 4'h1, 4'h2, 4'h3: verilog_sys_methods.data_bin_hits[0]++; // low4'h4, 4'h5, 4'h6, 4'h7: verilog_sys_methods.data_bin_hits[1]++; // mid4'h8, 4'h9, 4'hA, 4'hB: verilog_sys_methods.data_bin_hits[2]++; // high4'hC, 4'hD, 4'hE, 4'hF: verilog_sys_methods.data_bin_hits[3]++; // maxendcase// 更新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();endend// 测试序列initial beginreset = 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++) beginfor (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; // low1: data = 4'h5; // mid2: data = 4'h9; // high3: data = 4'hD; // maxendcasemode = m;$display("    数据bin=%d, 模式=%d, 交叉覆盖率=%0.2f%%", d, m, sys_cg.data_mode_cross.get_coverage());endend// 测试覆盖率控制方法$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个binsdata_cp: coverpoint data {option.weight = 4;  // 权重为4bins 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个binsmode_cp: coverpoint mode {option.weight = 2;  // 权重为2bins read_mode = {2'b00};bins write_mode = {2'b01};bins test_mode = {2'b10};bins debug_mode = {2'b11};}// 使能coverpoint - 2个binsenable_cp: coverpoint enable {option.weight = 1;  // 权重为1bins disabled = {1'b0};bins enabled = {1'b1};}// 优先级coverpoint - 8个binspriority_cp: coverpoint priority {option.weight = 3;  // 权重为3bins 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;  // 权重为5ignore_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;  // 权重为8ignore_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);}endgroupcalculation_cg calc_cg = new();// 传统Verilog的覆盖率计算实现typedef struct {// 基本bin统计integer data_bins_total;        // 4integer data_bins_covered;integer data_bin_hits[4];real data_coverage;integer data_weight;            // 4integer mode_bins_total;        // 4integer mode_bins_covered;integer mode_bin_hits[4];real mode_coverage;integer mode_weight;            // 2integer enable_bins_total;      // 2integer enable_bins_covered;integer enable_bin_hits[2];real enable_coverage;integer enable_weight;          // 1integer priority_bins_total;    // 8integer 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; // 5integer 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;elsereturn 0.0;endfunction// 计算各coverpoint的覆盖率function void calculate_individual_coverages();// 数据coverpoint覆盖率verilog_calc.data_bins_covered = 0;for (int i = 0; i < 4; i++) beginif (verilog_calc.data_bin_hits[i] > 0)verilog_calc.data_bins_covered++;endverilog_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++) beginif (verilog_calc.mode_bin_hits[i] > 0)verilog_calc.mode_bins_covered++;endverilog_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++) beginif (verilog_calc.enable_bin_hits[i] > 0)verilog_calc.enable_bins_covered++;endverilog_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++) beginif (verilog_calc.priority_bin_hits[i] > 0)verilog_calc.priority_bins_covered++;endverilog_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++) beginif (verilog_calc.data_mode_cross_hits[i] > 0)verilog_calc.data_mode_cross_covered++;endverilog_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++) beginif (verilog_calc.triple_cross_hits[i] > 0)verilog_calc.triple_cross_covered++;endverilog_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) beginverilog_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++) beginverilog_calc.coverage_trend[i] = verilog_calc.coverage_trend[i+1];endverilog_calc.coverage_trend[99] = verilog_calc.weighted_coverage;endendfunction// 获取交叉覆盖索引(简化映射)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;endfunctionfunction 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 && disabledreturn -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) beginif (reset) beginverilog_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; // 62verilog_calc.total_weight = 4 + 2 + 1 + 3 + 5 + 8; // 23end else beginverilog_calc.total_samples++;// 更新各coverpoint的bin命中// 数据binscase (data)4'h0, 4'h1, 4'h2, 4'h3: verilog_calc.data_bin_hits[0]++; // low4'h4, 4'h5, 4'h6, 4'h7: verilog_calc.data_bin_hits[1]++; // mid4'h8, 4'h9, 4'hA, 4'hB: verilog_calc.data_bin_hits[2]++; // high4'hC, 4'hD, 4'hE, 4'hF: verilog_calc.data_bin_hits[3]++; // maxendcase// 模式binsverilog_calc.mode_bin_hits[mode]++;// 使能binsverilog_calc.enable_bin_hits[enable]++;// 优先级binsverilog_calc.priority_bin_hits[priority]++;// 数据-模式交叉binsautomatic 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]++;// 三路交叉binsautomatic 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();endend// 测试序列initial beginreset = 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; // low1: data = 4'h5; // mid2: data = 4'h9; // high3: data = 4'hD; // maxendcase$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++) beginfor (int m = 0; m < 4; m++) begin// 跳过忽略的组合if (d == 3 && m == 3) continue;@(posedge clk);case (d)0: data = 4'h1; // low1: data = 4'h5; // mid2: data = 4'h9; // high3: data = 4'hD; // maxendcasemode = 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());endend// 阶段6:测试三路交叉覆盖$display("\n阶段6:测试三路交叉覆盖(部分)");for (int d = 0; d < 2; d++) begin // 只测试部分组合for (int m = 0; m < 2; m++) beginfor (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; // low1: data = 4'h5; // midendcasemode = 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());endendend// 随机压力测试$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]);endend$finish;end
endmodule

8. SystemVerilog与传统Verilog的对比

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

8.1 语法简洁性对比

SystemVerilog的优势:

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

传统Verilog的局限:

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

8.2 功能完整性对比

功能特性SystemVerilog传统Verilog
基本覆盖点✅ 原生支持❌ 需手动实现
交叉覆盖✅ 内建支持❌ 复杂手动逻辑
条件覆盖iff关键字❌ 需额外判断逻辑
权重设置option.weight❌ 需手动加权计算
忽略binsignore_bins❌ 需手动排除逻辑
非法binsillegal_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 beginclk = 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 beginbasic_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();endendtask// 定向测试任务task automatic directed_test();// 测试填满FIFOrepeat(DEPTH + 2) begin@(posedge clk);wr_en <= 1;rd_en <= 0;wr_data <= $random();end// 测试排空FIFOrepeat(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();endendtask// ========================================// 覆盖率监控和报告// ========================================// 覆盖率监控任务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;endendendtask// ========================================// 主测试流程// ========================================initial begin// 初始化rst_n = 0;wr_en = 0;rd_en = 0;wr_data = 0;// 复位repeat(5) @(posedge clk);rst_n = 1;// 启动覆盖率监控forkmonitor_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;endendmodule

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) beginif (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;// ... 数十行报告生成代码endtaskendmodule

10.4 示例总结

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

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

相关文章:

  • 【动态规划】简单多状态 dp 问题
  • 【lucene】advanceShallow (int target) 与advance(int target)
  • Kea DHCP高危漏洞CVE-2025-40779:单个数据包即可导致服务器崩溃
  • workflow/http_parser源码解密:HTTP解析器的双倍扩容与零拷贝策略
  • R 语言 eulerr 包绘制韦恩图:比例精准
  • 机器学习(讲解)
  • 使用MySQL计算斐波那契数列
  • 开源工具新玩法:cpolar提升Penpot协作流畅度
  • Spark入门:从零到能跑的实战教程
  • 基于Spring Session + Redis + JWT的单点登录实现
  • 在Ubuntu中安装配置MySql Server
  • [p2p-Magnet] docs | HTTP API与Web界面 | 搜索查询引擎
  • PyTorch 张量核心知识点
  • 引入资源即针对于不同的屏幕尺寸,调用不同的css文件
  • KubeBlocks For MySQL 云原生设计分享
  • 三大压测工具对比:Siege/ab/Wrk实战指南
  • SpringBoot系列之实现高效批量写入数据
  • 基础IO详解
  • 【前缀和】
  • Pandas的数据结构
  • 第十七章 Java基础-常用API-System
  • [p2p-Magnet] 数据模型(GORM) | DHT爬虫 | 分类器
  • React Hook+Ts+Antd+SpringBoot实现分片上传(前端)
  • 数据湖与数据仓库
  • Qt 中日志级别
  • ArcGIS+Fragstats:土地利用统计分析、景观格局指数计算与地图制图
  • Android Keystore签名文件详解与安全防护
  • AI视频生成工具全景对比:元宝AI、即梦AI、清影AI和Vidu AI
  • 【贪心 单调栈】P10334 [UESTCPC 2024] 饮料|普及+
  • 工业 5G + AI:智能制造的未来引擎