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()`.
Coverage in UVM
In UVM, coverage collectors are typically implemented as subscribers that listen to analysis ports from monitors.
Architecture
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);