SystemVerilog Covergroups

The covergroup is the fundamental container for functional coverage. It encapsulates definitions of what you want to cover and specifies when sampling should occur.

Defining a Covergroup

A covergroup is similar to a class. It must be defined and then instantiated using the new() constructor to be active. It can be defined inside a module, program, interface, or class.

// Definition
covergroup cg_packet;
    // Coverpoints go here
    cp_length: coverpoint length;
endgroup

// Instantiation
cg_packet cg_inst = new();

Sampling Triggers

There are two main ways to tell a covergroup to sample data:

1. Event-Based Sampling

Specify an event (like a clock edge) in the definition. The covergroup automatically samples whenever the event occurs.

// Samples automatically on every posedge clk
covergroup cg_bus @(posedge clk);
    coverpoint ready;
endgroup

2. Manual Sampling (preferred in UVM)

Leave the event blank and call the built-in sample() method when you are ready explicitly.

class my_monitor;
    covergroup cg_trans;
        coverpoint addr;
    endgroup

    function new();
        cg_trans = new(); // Construct
    endfunction

    task run_phase();
        forever begin
            @(posedge vif.clk);
            if (vif.valid) begin
                // Explicitly sample only when valid is high
                cg_trans.sample(); 
            end
        end
    endtask
endclass

Passing Arguments

You can pass arguments to the new() constructor of a covergroup. This allows you to write generic covergroups and reuse them for different signals.

// Generic covergroup accepting arguments
covergroup cg_signal (ref bit [3:0] signal, input int max_val);
    cp_sig: coverpoint signal {
        bins valid_range = {[0:max_val]};
    }
endgroup

module tb;
    bit [3:0] a, b;
    
    initial begin
        // Pass 'a' by reference, max_val = 10
        cg_signal cg_a = new(a, 10);
        
        // Pass 'b' by reference, max_val = 5
        cg_signal cg_b = new(b, 5);
    end
endmodule

Why pass by reference (ref)?

Usually, you pass signals by ref so the covergroup sees the current value of the signal when sample() is called. If you pass by value (default), it would only sample the value present at construction time!

Common Interview Questions

Q: Can a covergroup be defined inside a package?
No. A covergroup must be defined inside a module, program, interface, or class. It cannot be defined at the package level.
Q: What happens if you don't instantiate a covergroup?
Nothing. Just like a class, if you don't call new(), the object doesn't exist, and no coverage will be collected.