UVM Monitor

The eyes and ears of the testbench. It passively observes signals and converts them into transactions.

The Passive Observer

What Does a Monitor Do?

The Simple Version: The Monitor is your testbench's "eyes and ears." It watches what's happening on your design's signals and reports it to other components.

Think of it like: A security camera. It passively observes and records everything without interfering with what's happening.

A UVM Monitor is the "Eyes and Ears" of your verification environment. Its primary job is to extract pin-level activity from the DUT and reconstruct it into high-level transaction objects. Crucially, a monitor is Passiveย—it must never drive or modify interface signals.

Key Characteristics:

  • Non-Intrusive: Samples signals without affecting simulation state.
  • Analysis Port (AP): Broadcasts reconstructed items to subscribers (Scoreboards, Coverage).
  • Shared Resource: Can be used by multiple testbench components simultaneously.

Sampling via Virtual Interfaces

Key Difference: Driver vs Monitor

Driver: Actively sends data TO your design (like a speaker)

Monitor: Passively watches data FROM your design (like a microphone)

Like the Driver, the Monitor uses a Virtual Interface (VIF). However, while the driver uses non-blocking assignments (<=) to drive cycles, the monitor uses blocking reads or clocking blocks to ensure stable sampling of signals.

Implementation: Protocol Reconstructor

class spi_monitor extends uvm_monitor;
    `uvm_component_utils(spi_monitor)
    virtual spi_if vif;
    uvm_analysis_port #(spi_item) mon_ap;
    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        mon_ap = new("mon_ap", this);
    endfunction
    task run_phase(uvm_phase phase);
        forever begin
            spi_item item = spi_item::type_id::create("item");
            // 1. Wait for start of transaction
            @(negedge vif.cs_n);
            // 2. Sample data bits over 8 clock cycles
            for (int i = 0; i < 8; i++) begin
                @(posedge vif.sclk);
                item.data[7-i] = vif.mosi;
            end
            // 3. COMPLETE: Reconstructed the object!
            // 4. BROADCAST: Send to anyone listening
            mon_ap.write(item);
        end
    endtask
endclass
                            

Analysis Port Mechanics

The mon_ap.write(item) call is the ONLY way a monitor should communicate with the outside world. It implement a Publisher-Subscriber pattern:

Why use Analysis Ports?

  • Many-to-One: Multiple scoreboards can connect to a single monitor.
  • Unblocking: The write() method is a void function. It returns instantly, ensuring the monitor never delays physical signal sampling.
  • Zero-Dependency: The monitor doesn't know who is listening (Scoreboard? Functional Cov?). This keeps the agent reusable.

Sampling Rule of Thumb

Always sample Monitor signals in the Observed Region (using clocking block input skews) to avoid race conditions with the Driver's signal transitions. This ensures your Monitor sees exactly what the DUT sees.