1.Introduction to Functional Coverage
Functional coverage measures what has been tested in the design, unlike code coverage, which measures how much code has been executed. It ensures that all specified functionalities are verified. code vs functional coverage
Key Concepts:
- Covergroup: A container for coverage points, crosses, and options.
- Coverpoint: A variable or expression being tracked.
- Bins: Value ranges or transitions for coverpoints.
- Cross Coverage: Tracks combinations of multiple coverpoints.
- Sampling: Triggering coverage collection at specific events.
Coverpoint Bins Explained in Simple Terms
Let me break down coverpoints and bins in the easiest way possible.
What is a Coverpoint?
Imagine you're testing a TV remote control. A coverpoint is like making a checklist for each button:
- Power button
- Volume up/down
- Channel up/down
Each of these is a separate thing you want to test.
What are Bins?
Bins are like boxes where you group similar tests together.
Real-World Example: Testing a Volume Control
Your TV has volume levels from 0 to 100. Instead of checking every single number (which would take forever), you group them into bins:
coverpoint volume { bins mute = {0}; // Only volume 0 bins low = {[1:30]}; // Volume 1-30 in one box bins medium = {[31:70]}; // Volume 31-70 in another box bins max = {100}; // Only volume 100 }
This way, instead of tracking 100 separate numbers, you only track 4 bins:
- Mute (0)
- Low (1-30)
- Medium (31-70)
- Max (100)
Different Types of Bins (With Simple Examples)
1. Fixed Value Bins
You care about specific exact values.
Example: Testing traffic lights:
coverpoint traffic_light { bins red = {0}; // 0 = Red bins yellow = {1}; // 1 = Yellow bins green = {2}; // 2 = Green }
2. Range Bins
Group a range of values together.
Example: Testing temperature sensor:
coverpoint temperature { bins freezing = {[-20:0]}; // -20°C to 0°C bins cold = {[1:15]}; // 1°C to 15°C bins warm = {[16:25]}; // 16°C to 25°C bins hot = {[26:50]}; // 26°C to 50°C }
3. Wildcard Bins (Don’t Care About Some Bits)
Use ? to ignore bits.
Example: Testing a 4-bit command where last 2 bits don’t matter:
coverpoint command { wildcard bins start_cmd = {4'b10??}; // Matches 1000, 1001, 1010, 1011 }
4. Illegal Bins (Should Never Happen)
Mark values that are not allowed.
Example: A 2-bit mode where 11 is invalid:
coverpoint mode { bins valid[] = {0, 1, 2}; // 00, 01, 10 illegal_bins invalid = {3}; // 11 is illegal }
If this happens, the simulator will report an error.
5. Transition Bins (Sequences)
Track if a signal changes in a certain way.
Example: Testing a power state machine:
coverpoint power_state { bins off_to_on = (0 => 1); // Must go from OFF(0) to ON(1) bins on_to_off = (1 => 0); // Must go from ON(1) to OFF(0) }
How Does This Work in Real Verification?
Let’s say you’re testing a car dashboard:
Step 1: Define Coverpoints
You care about:
- Speed (0-200 km/h)
- Fuel level (Empty, Low, Medium, Full)
- Engine temperature (Cold, Normal, Hot)
Step 2: Group into Bins
covergroup car_dashboard_cg; // Speed bins speed_cp: coverpoint speed { bins stopped = {0}; bins slow = {[1:60]}; bins medium = {[61:120]}; bins fast = {[121:200]}; } // Fuel level bins fuel_cp: coverpoint fuel { bins empty = {0}; bins low = {[1:30]}; bins medium = {[31:70]}; bins full = {[71:100]}; } // Cross coverage: Speed + Fuel speed_x_fuel: cross speed_cp, fuel_cp; endgroup
Step 3: What the Simulator Checks
The simulator will track:
- Did the car go fast (121-200 km/h) with low fuel (1-30%)?
- Did it ever stop (0 km/h) with full tank (71-100%)?
- Did we miss any combination?
Key Takeaways
- Coverpoint = A feature to track (e.g., speed, temperature).
- Bins = Groupings of values (e.g., "slow speed" = 1-60 km/h).
- Cross coverage = Checks combinations (e.g., "high speed + low fuel").
- Illegal bins = Values that should never happen (error if they do).
- Transition bins = Tracks sequences (e.g., "off → on").
2. Types of Functional Coverage
(A) Covergroup-Based Coverage
- Point Coverage: Tracks individual variables.
- Cross Coverage: Tracks relationships between variables.
- Transition Coverage: Tracks sequences of values.
(B) UVM Callback-Based Coverage
- Used for higher-level scenario coverage (e.g., protocol states, error injection).
3. Covergroup Syntax & Usage
Basic Syntax:
covergroup <covergroup_name> [ ( [args] ) ] [ @(event) ]; [<coverpoint_definitions>] [<cross_definitions>] [<options>] endgroup
Example:
covergroup addr_cov @(posedge clk); addr_cp: coverpoint addr { bins low = {[0:15]}; bins mid = {[16:31]}; bins high = {[32:47]}; } endgroup
4. Coverpoint Binning Strategies
(A) Automatic Binning
If no bins are specified, SystemVerilog creates bins automatically.
coverpoint data; // Auto-bins for all possible values (0-255 for 8-bit)
(B) Explicit Binning
Manually define ranges or specific values.
coverpoint cmd { bins read = {0}; bins write = {1}; bins reset = {2}; illegal_bins invalid = {3}; // Marks invalid values }
(C) Range Binning
coverpoint addr { bins low = {[0:31]}; bins mid = {[32:63]}; bins high = {[64:127]}; }
(D) Wildcard Binning
Use wildcard to ignore certain bits.
coverpoint status { wildcard bins even = {3'b??0}; // Any value where LSB=0 }
(E) Transition Coverage
Tracks value sequences.
coverpoint state { bins s0_to_s1 = (0 => 1); bins s1_to_s2 = (1 => 2); }
5. Cross Coverage
Tracks combinations of two or more coverpoints.
Basic Syntax:
cross <coverpoint1>, <coverpoint2> [, ...];
Example:
covergroup cmd_addr_cov; cmd_cp: coverpoint cmd { bins read = {0}; bins write = {1}; } addr_cp: coverpoint addr { bins low = {[0:31]}; bins high = {[32:63]}; } cmd_x_addr: cross cmd_cp, addr_cp; endgroup
Ignoring Unwanted Crosses
cmd_x_addr: cross cmd_cp, addr_cp { ignore_bins wr_high = binsof(addr_cp.high) && binsof(cmd_cp.write); }
6. Sampling Functional Coverage
(A) Using Events
covergroup data_cov @(posedge clk); coverpoint data; endgroup
(B) Manual Sampling
covergroup data_cov; coverpoint data; endgroup data_cov cg = new(); cg.sample(); // Manually trigger coverage
(C) Sampling in UVM Monitor
class my_monitor extends uvm_monitor; packet pkt; packet_cg cg; virtual task run_phase(uvm_phase phase); cg = new(); forever begin @(posedge vif.clk); pkt = get_packet_from_interface(); cg.sample(); // Sample coverage end endtask endclass
7. UVM Functional Coverage Flow (Full Example)
Step 1: Define a Transaction with Coverage
class packet extends uvm_sequence_item; rand bit [3:0] cmd; rand bit [7:0] addr; rand bit [31:0] data; // Define covergroup covergroup pkt_cg; option.per_instance = 1; // Track per instance option.comment = "Packet coverage"; // Coverpoints cmd_cp: coverpoint cmd { bins read = {0}; bins write = {1}; bins burst = {2}; illegal_bins invalid = {[3:15]}; } addr_cp: coverpoint addr { bins low = {[0:127]}; bins high = {[128:255]}; } // Cross coverage cmd_x_addr: cross cmd_cp, addr_cp; endgroup function new(string name = "packet"); super.new(name); pkt_cg = new(); // Instantiate covergroup endfunction `uvm_object_utils(packet) endclass
Step 2: UVM Monitor Sampling Coverage
class my_monitor extends uvm_monitor; `uvm_component_utils(my_monitor) uvm_analysis_port #(packet) ap; virtual my_intf vif; packet pkt; function new(string name, uvm_component parent); super.new(name, parent); ap = new("ap", this); endfunction task run_phase(uvm_phase phase); forever begin @(posedge vif.clk); pkt = packet::type_id::create("pkt"); // Capture signals pkt.cmd = vif.cmd; pkt.addr = vif.addr; pkt.data = vif.data; pkt.pkt_cg.sample(); // Sample coverage ap.write(pkt); // Send to scoreboard end endtask endclass
Step 3: UVM Scoreboard with Scenario Coverage
class my_scoreboard extends uvm_scoreboard; `uvm_component_utils(my_scoreboard) uvm_analysis_imp #(packet, my_scoreboard) sb_export; // Scenario coverage covergroup scenario_cov; burst_read: coverpoint {packet.cmd == 2 && packet.addr inside {[100:200]}}; back_to_back_write: coverpoint {packet.cmd == 1} { bins consecutive = (1 => 1); } endgroup function new(string name, uvm_component parent); super.new(name, parent); sb_export = new("sb_export", this); scenario_cov = new(); endfunction function void write(packet pkt); // Check transaction if (pkt.cmd == 0 && pkt.addr == 8'hFF) `uvm_error("SCBD", "Read from reserved address") // Sample scenario coverage scenario_cov.sample(); endfunction endclass
Step 4: UVM Environment Integration
class my_env extends uvm_env; `uvm_component_utils(my_env) my_agent agent; my_scoreboard scbd; function void build_phase(uvm_phase phase); agent = my_agent::type_id::create("agent", this); scbd = my_scoreboard::type_id::create("scbd", this); endfunction function void connect_phase(uvm_phase phase); agent.monitor.ap.connect(scbd.sb_export); endfunction endclass
8. Coverage Options & Methods
(A) Common Covergroup Options
Option | Description |
---|---|
per_instance=1 | Tracks coverage per instance |
weight=value | Assigns weight to covergroup |
comment="text" | Adds a comment for reports |
(B) Coverage Methods
Method | Description |
---|---|
sample() | Triggers coverage sampling |
get_coverage() | Returns coverage percentage |
start() / stop() | Enables/disables coverage |
$coverage_save("file.ucdb") | Saves coverage to a file |
9. Generating Coverage Reports
(A) Using Simulator Commands
# Questa vsim -coverage -c top -do "run -all; coverage save coverage.ucdb; quit" # VCS urg -dir simv.vdb -report coverage_report
(B) UVM Report Hook
function void end_of_elaboration_phase(uvm_phase phase); $coverage_save("final_coverage.ucdb"); endfunction
10. Best Practices
- Focus on functional requirements, not just RTL code.
- Use meaningful bins (avoid auto-binning unless necessary).
- Cross coverage should be relevant (don’t cross everything).
- Use illegal_bins to catch invalid scenarios.
- Review coverage holes and update tests accordingly.
Conclusion
Functional coverage in UVM ensures that all specified design functionalities are verified. By following this guide, you can:
- Define covergroups, coverpoints, and cross coverage.
- Sample coverage in UVM monitors and scoreboards.
- Generate reports to track verification progress.
This structured approach ensures high-quality verification with measurable results. 🚀