UVM Monitor

A UVM monitor is a passive component designed to observe and extract data from the DUT without influencing its behavior. It operates independently and does not drive any signals to the DUT. Instead, it listens to interface signals, converts them into transaction level signals and sends them to analysis components or other parts of the testbench like scoreboard or subscriber.

A user-defined monitor class is extended from uvm_monitor. uvm_monitor is inherited by uvm_component.

class <monitor_name> extends uvm_monitor;

Key Responsibilities of a UVM Monitor

  1. Signal Observation: Monitors continuously observe interface signals of the DUT.
  2. Protocol Decoding: They convert low-level signal transitions into meaningful transactions based on the protocol.
  3. Transaction Forwarding: Monitors send these transactions to the testbench environment, typically via TLM analysis ports.
  4. Coverage Collection: They can also collect functional coverage information by tracking observed activity.

Structure of a UVM Monitor

A UVM monitor generally includes:

  • Analysis Port: A uvm_analysis_port used to broadcast observed transactions to subscribers (e.g., scoreboard or coverage).
  • Interface Handle: A handle to the interface connecting the monitor to the DUT signals.
  • Build Phase: Interface is getting connect to virtual interface using uvm_config_db get() method.
  • Run Phase: A task that observes signals, performs protocol decoding, and creates transactions. Write method is used to send the sampled signals to the scoreboard.

Example: Implementing a UVM Monitor

Let’s implement a simple UVM monitor.

class p_monitor extends uvm_monitor;
  `uvm_component_utils(p_monitor)
  
  virtual p_interface vif;
  
  uvm_analysis_port #(p_transaction) p_collect_port;
  p_transaction p_collected;
  
  function new(string name, uvm_component parent);
    super.new(name,parent);
    p_collected = new();
  endfunction:new
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    p_collect_port = p_transaction::type_id::create("p_collect_port",this);
    if (!uvm_config_db#(virtual p_interface)::get(this,"","vif",vif))
      begin
        `uvm_error("build_phase", "no virtual interface specified for this monitor insatance")
      end
  endfunction
  
  virtual task run_phase(uvm_phase phase);
   forever begin
    p_collect_port.write(p_collected);
   end
  endtask:run_phase

endclass