Sampling Methods

Coverage is only as good as the data you feed it. Learn the difference between event-based regular sampling and procedural manual sampling relative to testbench events.

The .sample() Method

In modern UVM verification environments, we rarely use clock-based events directly in the covergroup definition. Instead, we define the covergroup with no arguments and call .sample() inside the Monitor component.

// 1. Define without event
covergroup cg_packet;
    cp_len: coverpoint pkt.len;
endgroup

// 2. Instantiate
cg_packet cg = new();

// 3. Sample procedurally
task run_phase;
    forever begin
        @(posedge vif.clk);
        if (vif.valid_out) begin
            // Capture data into packet object
            pkt.len = vif.data_len;
            
            // TRIGGGER COVERAGE NOW
            bg.sample();    
        end
    end
endtask

Enabling and Disabling

You can temporarily stop coverage collection.

  • start() / stop(): Enables or disables collection for a covergroup instance.
  • set_inst_name(string): Renames the instance for reporting (useful in loops).
initial begin
    cg_packet cg = new();
    
    // Don't collect during reset phase
    cg.stop();
    
    wait(!rst);
    
    // Start collecting now
    cg.start();
end

Common Interview Questions

Q: Why prefer .sample() over @(posedge clk)?
Using @(posedge clk) makes the covergroup constantly active on every clock, which can be computationally expensive if valid data is rare. Using .sample() allows you to trigger coverage only when a comprehensive transaction is fully assembled (e.g., at the end of a bus transfer), which is more efficient and meaningful.