Coverage in UVM

In UVM, coverage collectors are typically implemented as subscribers that listen to analysis ports from monitors.

Architecture

1. Monitor: Observes signal pins, assembles a transaction object (Sequence Item), and broadcasts it via an Analysis Port.
2. Subscriber: Connected to the monitor's port. It has a `write()` function that receives the object and calls `covergroup.sample()`.

The UVM Subscriber Class

class my_coverage_collector extends uvm_subscriber #(my_transaction);
    `uvm_component_utils(my_coverage_collector)

    // Helper variables to map transaction data
    bit [7:0] local_addr;
    bit [1:0] local_mode;

    // Covergroup definition
    covergroup cg_trans;
        option.per_instance = 1;
        cp_addr: coverpoint local_addr;
        cp_mode: coverpoint local_mode;
    endgroup

    // Constructor
    function new(string name, uvm_component parent);
        super.new(name, parent);
        cg_trans = new();
    endfunction

    // Analysis Port Write Method (Receiver)
    // This is called automatically when Monitor broadcasts
    function void write(my_transaction t);
        // Map transaction fields to local variables
        local_addr = t.addr;
        local_mode = t.mode;

        // Sample!
        cg_trans.sample();
    endfunction

endclass

Common Interview Questions

Q: Where should coverage be implemented in UVM?
Coverage should be implemented in a component connected to the Monitor (like a Subscriber or Scoreboard), NOT in the Driver or Sequencer. This ensures you cover what actually happened on the bus, not just what you intended to send.
Q: How do you connect the monitor to the coverage collector?
In the Agent or Environment connect_phase:
monitor.ap.connect(coverage_collector.analysis_export);