Coverage Exclusions & Illegal Bins
Not all bins are possible. Some combinations are invalid by protocol or design. Use illegal_bins and ignore_bins:
covergroup axi_cg;
cp_burst: coverpoint burst_type {
bins fixed = { 2'b00 };
bins incr = { 2'b01 };
bins wrap = { 2'b10 };
illegal_bins reserved = { 2'b11 }; // Not valid per spec
}
cp_len: coverpoint len {
bins small = { [0:15] };
bins medium = { [16:127] };
bins large = { [128:255] };
}
// Cross: illegal combination (WRAP + length > 64 not allowed)
cross burst_len: cross cp_burst, cp_len {
illegal_bins wrap_too_big =
binsof(cp_burst) matches { 2'b10 } &&
binsof(cp_len) matches { [128:255] };
}
endgroupillegal_bins: Marks impossible combinations. Simulator reports error if hit.
ignore_bins: Marks valid but uninteresting bins (don't count toward coverage %).
Merging Covergroups
When you have multiple monitors or agents, merge their coverage:
// Two separate monitors, each with own covergroup
class Write_Monitor; covergroup write_cg; ... endgroup endclass
class Read_Monitor; covergroup read_cg; ... endgroup endclass
// Merge in a test class
class Test;
Write_Monitor wr_mon;
Read_Monitor rd_mon;
covergroup merged_cg;
// This scope samples from both monitors
cp_combined: coverpoint
{wr_mon.active || rd_mon.active} { bins any = {1}; }
endgroup
function void report_coverage();
real total = 0.0;
real wr_cov = wr_mon.write_cg.get_coverage();
real rd_cov = rd_mon.read_cg.get_coverage();
total = (wr_cov + rd_cov) / 2.0; // Average
$display("Overall coverage: %0.1f%%", total);
endfunction
endclassCoverage Gap Analysis
After simulation, identify which bins weren't hit:
module protocol_tb();
Monitor mon = new();
initial begin
// Run tests...
#100000 $finish;
end
final begin
// Print uncovered bins
$display("=== Coverage Holes ===");
// Get coverage data
int total_bins = mon.cg.get_bin_count();
int covered_bins = 0;
// Report coverage percentage
real coverage = mon.cg.get_coverage();
$display("Coverage: %0.2f%% (%0d/%0d bins)",
coverage, (coverage/100*total_bins), total_bins);
// For uncovered cross combinations, write directed test
end
endmoduleDirected Tests for Coverage Closure
When random tests miss scenarios, write specific directed tests:
task close_coverage_gap();
// Analysis showed: READ at high address + long length = uncovered
bit [31:0] addr = 32'hFFFF_0000; // High address
bit [7:0] len = 255; // Long transfer
bit write = 0; // READ command
// Send explicitly
send_transaction(addr, len, write);
// Other gaps:
// WRITE with all byte masks
for(int mask = 0; mask < 256; mask++) begin
send_transaction(32'h1000_0000, 1, 1, mask);
end
endtaskCoverage Goals & Thresholds
Plan for realistic coverage targets:
Typical coverage targets:
• Individual coverage points: 95-100%
• Cross-coverage: 80-95% (some combinations naturally rare)
• Full functional coverage: 75-90%
• Code coverage (lines, branches): 100%
• Individual coverage points: 95-100%
• Cross-coverage: 80-95% (some combinations naturally rare)
• Full functional coverage: 75-90%
• Code coverage (lines, branches): 100%
Key Takeaways
- ✅ Use
illegal_binsto mark impossible scenarios - ✅ Use
ignore_binsfor valid but uninteresting cases - ✅ Analyze coverage reports to find gaps
- ✅ Write directed tests to close remaining gaps
- ✅ Coverage != completeness, but it's a pragmatic measure
- ✅ Perfect coverage is impossible; aim for 80-90%
Tomorrow (Day 15): Coverage-driven randomization — let coverage guide which tests to generate.