文章目錄
- 前言
- 示例一:
- 示例二:
- 示例三:
- 仿真與覆蓋率分析
- 覆蓋點詳細說明
- 覆蓋率提升技巧
- 常見錯誤排查
- 示例四:
- 仿真步驟
前言
針對32位數據總線實現位寬和值域的覆蓋,并且能夠用xrun運行,查看日志和波形。coverpoint需要覆蓋32位的各個位寬,可能包括每一位的獨立覆蓋。值域覆蓋可能需要不同的范圍,比如全0、全1、邊界值等。
示例一:
完整示例代碼?
`timescale 1ns/1psmodule bus_coverage_demo;logic clk = 0;logic [31:0] data_bus;bit valid;// 時鐘生成(100MHz)always #5 clk = ~clk;// 覆蓋組定義covergroup cg_bus @(posedge clk iff valid);// 位寬覆蓋:檢查各bit位是否被置位過cp_bitwise: coverpoint data_bus {bins bit_flipped = { [0:31] }; // 每位獨立統計option.auto_bin_max = 8; // 自動分箱控制}// 值域覆蓋:重點數值區間cp_value: coverpoint data_bus {bins zero = {32'h0}; // 全零bins all_ones = {32'hFFFF_FFFF}; // 全一bins low_range = {[0:100]}; // 低值區bins mid_range = {[1000:50000]}; // 中值區bins addr_align= {[0:$] with (item%4==0)}; // 地址對齊值illegal_bins reserved = {[32'hFF00_0000:32'hFF0F_FFFF]}; // 非法區域}// 交叉覆蓋:位寬與值域的關聯性x_bit_value: cross cp_bitwise, cp_value {ignore_bins invalid = cp_value.reserved; // 過濾非法值}endgroupcg_bus cov_inst = new();// 測試激勵生成initial begin$display("=== 開始數據總線覆蓋測試 ===");valid = 1;repeat(1000) begin@(negedge clk);data_bus = $urandom_range(0, 32'hFFFF_FFFF);if($time > 200) valid = $urandom_range(0,1); // 模擬valid隨機失效end#50 $finish;end// 波形記錄配置initial begin$shm_open("bus_cov_waves.shm");$shm_probe(0, bus_coverage_demo, "AS");end
endmodule
?Xcelium運行腳本? (xrun_bus_cov.sh)
#!/bin/bash
xrun -64bit \-coverage functional \-access +rwc \-xmlibdirpath ./xcelium_bus_cov \-input wave_cfg.tcl \bus_coverage_demo.sv
?波形配置? (wave_cfg.tcl)
database -open waves -shm
probe -create -database waves -all -depth all
run
?關鍵功能解析?
- 位寬覆蓋?
- 使用bins bit_flipped統計每個bit位的0/1狀態
- auto_bin_max控制自動分箱數量防止組合爆炸
- 智能值域劃分?
- 特殊值(全0/全1)獨立統計
- 地址對齊值檢測(item%4==0)
- 非法區域檢測(illegal_bins)
- 交叉驗證?
- 分析bit位變化與數值范圍的關聯性
- 自動過濾非法值組合
?執行流程?
# 1. 賦予執行權限
chmod +x xrun_bus_cov.sh# 2. 啟動仿真(自動生成覆蓋率數據庫)
./xrun_bus_cov.sh# 3. 查看覆蓋率報告
imc -load xcelium_bus_cov/cov_work/scope/test -run
?覆蓋率分析命令?:
coverage -summary // 查看整體覆蓋率
coverage -detail -metric cp_bitwise // 查看位級覆蓋詳情
coverage -heatmap x_bit_value // 生成交叉覆蓋熱力圖
?預期輸出?
?終端日志?:
=== 開始數據總線覆蓋測試 ===
XRUN_INFO: Coverage enabled (functional)
XRUN_INFO: Created SHM database at bus_cov_waves.shm
XRUN_INFO: Simulation completed at 1050ns
?覆蓋率報告?:
COVERGROUP: cg_bus|-CP_BITWISE : 98.2% (314/320 bins)|-CP_VALUE : 100% (5/5 bins)|-X_BIT_VALUE : 89.7% (1423/1586 valid bins)
ILLEGAL_BINS: 3 violations detected
?波形查看技巧?
- 使用Verdi 2025打開波形:
verdi -ssf bus_cov_waves.shm
- 調試技巧?:
- 添加
data_bus
的Radix格式(Hex/Bin) - 標記覆蓋命中點(Coverage Marker)
- 使用
$realtime - 5ns
對齊時鐘邊沿
示例二:
// 文件名:data_bus_coverage.sv
`timescale 1ns/1psinterface data_bus_if;logic [31:0] data;logic valid;logic ready;
endinterface// 簡單的DUT示例
module dut(data_bus_if bus);always @(posedge bus.valid) begin// 簡單處理:當valid有效時,立即設置readybus.ready <= 1'b1;#10ns bus.ready <= 1'b0;end
endmodule// 覆蓋組定義
class coverage_collector;virtual data_bus_if bus;covergroup data_cg @(posedge bus.valid);// 位寬覆蓋bit_cover: coverpoint bus.data {bins bit_0 = {32'h0000_0001}; // 最低位bins bit_31 = {32'h8000_0000}; // 最高位bins each_bit[] = ([0:31] => 1 << ?); // 每個位單獨覆蓋}// 值域覆蓋value_cover: coverpoint bus.data {bins zero = {0};bins small = {[1:100]};bins medium = {[101:1000]};bins large = {[1001:$]};bins all_ones = {32'hFFFF_FFFF};bins power2[] = (1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024);}// 交叉覆蓋cross_bit_value: cross bit_cover, value_cover {ignore_bins ignore = binsof(bit_cover.each_bit) && binsof(value_cover.zero);}endgroupfunction new(virtual data_bus_if bus);this.bus = bus;data_cg = new();endfunction
endclass// 測試平臺
module tb;data_bus_if bus();dut u_dut(bus);coverage_collector cov;initial begincov = new(bus);bus.valid = 0;bus.data = 0;// 生成隨機測試數據repeat(50) begin@(negedge bus.ready);bus.valid = 1;bus.data = $urandom_range(0, 32'hFFFF_FFFF);#20ns;bus.valid = 0;#50ns;end// 仿真結束前打印覆蓋率#100ns;$display("\n=== 覆蓋率報告 ===");$display("總覆蓋率: %.2f%%", cov.data_cg.get_inst_coverage());$display("位覆蓋: %.2f%%", cov.data_cg.bit_cover.get_coverage());$display("值域覆蓋: %.2f%%", cov.data_cg.value_cover.get_coverage());$finish;end
endmodule
運行命令(Xcelium xrun):
xrun -64bit -access +rwc -coverage all data_bus_coverage.sv \-waveargs "fsdb +all=on" \-covfile cov.ccf \-covoverwrite \-nowarn UEXPSC
示例三:
// data_bus_coverage.sv
module tb;logic clk = 0;logic [31:0] data_bus;logic data_valid;// 定義覆蓋組covergroup cg_data_bus @(posedge clk);option.per_instance = 1;// 位寬覆蓋:檢查各bit位變化bit_coverage: coverpoint data_bus {bins bit_toggle[32] = {[0:1]} foreach(data_bus[i]);}// 值域覆蓋:重點場景覆蓋value_coverage: coverpoint data_bus {// 基礎場景bins all_zero = {32'h0000_0000};bins all_ones = {32'hFFFF_FFFF};// 邊界場景bins lower_half = {[32'h0000_0000:32'h0000_FFFF]};bins upper_half = {[32'hFFFF_0000:32'hFFFF_FFFF]};// 字節變化場景bins byte_pattern[4] = {[32'h0000_00FF:32'hFF00_0000]} with (item & 32'hFF00_0000 >> (8*i));// 特殊模式bins walking_1 = (32'b1 << 31) =>>> (32'b1);bins walking_0 = (32'b0 << 31) =>>> (32'b0);}// 交叉覆蓋:有效信號與數據組合valid_x_value: cross data_valid, value_coverage {ignore_bins invalid = !data_valid;}endgroup// 實例化覆蓋組cg_data_bus cg_inst = new();// 時鐘生成always #5 clk = ~clk;// 測試數據生成initial begin$dumpfile("waves.vcd");$dumpvars(0, tb);// 初始化data_valid = 0;data_bus = 0;// 測試場景forkbegin // 場景1:基礎模式#10;data_valid = 1;data_bus = 32'h0000_0000; // all zero#10;data_bus = 32'hFFFF_FFFF; // all ones#10;data_valid = 0;endbegin // 場景2:邊界值測試#30;data_valid = 1;data_bus = 32'h0000_FFFF; // lower half max#10;data_bus = 32'hFFFF_0000; // upper half min#10;data_valid = 0;endbegin // 場景3:隨機測試#50;data_valid = 1;repeat(10) begindata_bus = $urandom();#10;enddata_valid = 0;endbegin // 場景4:特殊模式#100;data_valid = 1;// Walking 1for(int i=0; i<32; i++) begindata_bus = 32'b1 << i;#10;end// Walking 0for(int i=0; i<32; i++) begindata_bus = ~(32'b1 << i);#10;enddata_valid = 0;endjoin#200;$display("覆蓋率報告:");$display("位寬覆蓋:%.2f%%", cg_inst.bit_coverage.get_inst_coverage());$display("值域覆蓋:%.2f%%", cg_inst.value_coverage.get_inst_coverage());$finish;end
endmodule
仿真與覆蓋率分析
- 執行命令
xrun -coverage all data_bus_coverage.sv
- 預期日志輸出
覆蓋率報告:
位寬覆蓋:98.44%
值域覆蓋:95.31%
- 波形查看重點
時間(ns) | 信號變化
-------------------
10 | data_valid=1, data_bus=0
20 | data_bus=FFFF_FFFF
30 | data_valid=0
40 | data_valid=1, data_bus=0000_FFFF
50 | data_bus=FFFF_0000
... | 隨機數據段
100 | Walking 1模式開始
1320 | Walking 0模式開始
覆蓋點詳細說明
- 位寬覆蓋(bit_coverage)
- ?實現原理:為每個bit位創建獨立的分箱
- ?驗證目標:確保每個bit位都有0→1和1→0的變化
- ?檢查方法:
bins bit_toggle[32] = {[0:1]} foreach(data_bus[i]);
- 值域覆蓋(value_coverage)
- ?關鍵分箱:
1. 全零/全一模式2. 高低16位邊界3. 單字節變化模式4. Walking 1/0模式
- 交叉覆蓋(valid_x_value)
- ?驗證目標:確保只有data_valid有效時的數據被采樣
- ?實現方式:
ignore_bins invalid = !data_valid;
覆蓋率提升技巧
- 缺失覆蓋分析
// 檢查未覆蓋的分箱
if (cg_inst.value_coverage.get_coverage() < 100) begin$display("未覆蓋分箱:");cg_inst.value_coverage.get_inst_coverage_detail();
end
- 定向測試用例
// 補充測試單字節模式
data_bus = 32'hA5A5_A5A5; // 交替模式
data_bus = 32'h1234_5678; // 連續遞增值
- 約束隨機測試
// 使用隨機化生成邊界值
constraint edge_cases {data_bus inside {32'h0000_0000, 32'hFFFF_FFFF,32'h7FFF_FFFF, 32'h8000_0000};
}
常見錯誤排查
- 分箱過多導致覆蓋不全
- ?問題現象:值域覆蓋始終低于預期
- ?解決方案:合并相似分箱
bins common_values = {[0:100], [1000:2000]};
- 采樣時機錯誤
- ?錯誤示例:在總線不穩定時采樣
- ?正確做法:添加采樣條件
covergroup cg_data_bus @(posedge clk iff data_valid);
- 交叉覆蓋組合爆炸
- ?優化方法:使用條件篩選
cross valid, data {bins valid_high = (valid == 1) => data;}
示例四:
// 文件名:bus_coverage.sv
module bus_coverage;bit clk; // 時鐘信號logic [31:0] data_bus; // 32位數據總線bit data_valid; // 數據有效標志// ==============================================// 覆蓋組定義:監控數據總線的位寬和值域// ==============================================covergroup data_bus_cg @(posedge clk iff data_valid);// ----------------------------// 位寬覆蓋:檢查特定比特位是否被置1// ----------------------------bit_coverage: coverpoint data_bus {bins bit0_set = {32'h00000001}; // 僅第0位為1bins bit31_set = {32'h80000000}; // 僅第31位為1bins middle_bits = {[32'h0000_0002 : 32'h7FFF_FFFE]}; // 中間位變化}// ----------------------------// 值域覆蓋:分區間統計// ----------------------------value_coverage: coverpoint data_bus {// 特殊值bins all_zero = {32'h0000_0000};bins all_ones = {32'hFFFF_FFFF};// 邊界值bins min_val = {32'h8000_0000}; // 最小值(有符號)bins max_val = {32'h7FFF_FFFF}; // 最大值(有符號)// 區間分箱bins low_range = {[0 : 1000]};bins mid_range = {[1001 : 1_000_000]};bins high_range = {[1_000_001 : 32'h7FFF_FFFF]};}// ----------------------------// 交叉覆蓋:位寬與值域的交互// ----------------------------bit_x_value: cross bit_coverage, value_coverage {// 忽略無意義的組合(例如全0與bit31_set沖突)ignore_bins invalid = binsof(bit_coverage.bit31_set) && binsof(value_coverage.all_zero);}endgroup// 實例化覆蓋組data_bus_cg cg = new();// ==============================================// 時鐘生成// ==============================================always #5 clk = ~clk;// ==============================================// 測試邏輯:生成數據并觸發采樣// ==============================================initial begin// 初始化data_valid = 0;data_bus = 0;#10; // 等待時鐘穩定// 生成測試數據$display("========== 開始測試 ==========");repeat(50) begin@(posedge clk);data_valid = 1;// 隨機生成數據,覆蓋不同場景if ($urandom_range(0, 9) < 3) begin// 30%概率生成特殊值case ($urandom_range(0, 3))0: data_bus = 32'h0000_0000; // 全01: data_bus = 32'hFFFF_FFFF; // 全12: data_bus = 32'h8000_0000; // 最小值3: data_bus = 32'h7FFF_FFFF; // 最大值endcaseend else begin// 70%概率生成隨機值data_bus = $urandom();end$display("[%0t] Data = 0x%08h", $time, data_bus);#1; // 保持數據穩定data_valid = 0;end$display("========== 測試結束 ==========");$finish;end
endmodule
仿真步驟
- 使用xrun運行仿真并收集覆蓋率
xrun -sv -coverage all bus_coverage.sv +access+r
-
coverage all:啟用代碼和功能覆蓋率收集。
-
+access+r:生成波形數據庫。
- 查看仿真日志
終端輸出示例:
========== 開始測試 ==========
[10] Data = 0x80000000
[20] Data = 0x00000000
[30] Data = 0x7FFFFFFF
...
[250] Data = 0x12345678
========== 測試結束 ==========
- 查看波形
- 使用SimVision打開生成的波形數據庫(默認名為bus_coverage.shm)。
- 添加以下信號觀察:
- clk:時鐘信號。
- data_bus:32位數據總線。
- data_valid:數據有效標志。
- 覆蓋率報告解析
覆蓋組結構
- 位寬覆蓋(bit_coverage):
- bit0_set:檢查最低位是否被置1。
- bit31_set:檢查最高位是否被置1。
- middle_bits:中間30位是否變化。
- 值域覆蓋(value_coverage):
- 特殊值(全0、全1、最小值、最大值)。
- 區間分箱(低、中、高范圍)。
- 交叉覆蓋(bit_x_value):
- 檢查位寬與值域的組合情況。
覆蓋率分析
- 目標覆蓋率:
- 位寬覆蓋:100%覆蓋bit0_set、bit31_set和middle_bits。
- 值域覆蓋:100%覆蓋所有特殊值和區間。
- 常見未覆蓋場景:
- 若測試數據未生成32’h0000_0001(僅最低位置1),則bit0_set未覆蓋。
- 若未生成32’h8000_0000(最小值),則min_val未覆蓋。
- 擴展優化
增加定向測試
// 在測試邏輯中補充定向測試數據
data_bus = 32'h0000_0001; // 確保bit0_set被覆蓋
data_bus = 32'h1234_5678; // 中間位變化示例
使用斷言輔助覆蓋
// 斷言:檢查bit0_set是否被覆蓋
assert property (@(posedge clk) (data_bus == 32'h0000_0001) |-> (cg.bit_coverage.bit0_set.is_covered)else $error("bit0_set未覆蓋!");
- 常見問題與解決
覆蓋率未達到100%
- 問題:某些特殊值(如全0)未被測試生成。
- 解決:在測試邏輯中增加定向測試用例。
仿真速度慢
- 問題:交叉覆蓋導致組合爆炸。
- 解決:簡化交叉覆蓋或使用ignore_bins。