The monitor is responsible for capturing signal information from DUT ports and translating it into class objects which can be sent to other verification components in the environment via TLM interfaces. The monitor functionality should be limited to basic monitoring that is always required. It may have knobs to enable/disable basic protocol checking and coverage collection. High level functional checking should be done outside the monitor, in a scoreboard.


A monitor should have the following functions :

  • Collect bus information through a virtual interface
  • Collected data can be used for protocol checking and coverage
  • Collected data is exported via an analysis port

Here's an example of a uvm monitor.

class my_monitor extends uvm_monitor;
   `uvm_component_utils (my_monitor)
   virtual dut_if   vif;
   bit              enable_check = 1;
   uvm_analysis_port #(my_data)   mon_analysis_port;
   function new (string name, uvm_component parent= null); (name, parent);
   virtual function void build_phase (uvm_phase phase);
      super.build_phase (phase);
      // Create an instance of the analysis port
      mon_analysis_port = new ("mon_analysis_port", this);
      // Get virtual interface handle from the configuration DB
      if (! uvm_config_db #(virtual dut_if) :: get (this, "", "vif", vif)) begin
         `uvm_error (get_type_name (), "DUT interface not found")
   virtual task run_phase (uvm_phase phase);
      my_data  data_obj = my_data::type_id::create ("data_obj", this);
      forever begin
         @ ([Some event when data at DUT port is valid]); =;
         data_obj.addr = vif.addr;
         // If protocol checker is enabled, perform checks
         if (enable_check) 
            check_protocol ();
         // Send data object through the analysis port
         mon_analysis_port.write (data_obj);
   virtual function void check_protocol ();
      // Function to check basic protocol specs

Note the following from the example above :

  • Monitor is extended from uvm_monitor
  • Virtual interface handle is declared as vif and assigned from UVM database via uvm_config_db::get()
  • Additional knobs are provided for enabling/disabling protocol checker (enable_check) and coverage (enable_coverage)
  • Coverage group is defined as cg_trans and will be sampled during run phase
  • During run_phase(), data from interface is captured into local class object, protocol check is performed when enabled, and coverage group is sampled when enabled
  • Data object class is broadcast to other verification components via the analysis port
The knobs can be disabled from the test by using UVM database.

uvm_config_db #(bit) :: set (this, "*.agt0.monitor", "enable_check", 0);
uvm_config_db #(bit) :: set (this, "*.agt0.monitor", "enable_coverage", 0);


This class should be used as the base class for user-defined monitors. Doing so will :

  • Allows you to distinguish monitors from other component types also using its inheritance
  • Any future changes and additions to the base UVM monitor class will be automatically included in your derived class


Refer to Class Definitions for method declarations of this class.

Was this article helpful ?