Subscribers are basically listeners of an analysis port. They subscribe to a broadcaster and receive objects whenever an item is broadcasted via the connected analysis port. A uvm_component class does not have an in-built analysis port, while a uvm_subscriber is an extended version with an analysis port named analysis_export.

Class definition

 
virtual class uvm_subscriber #(type T=int) extends uvm_component;
  typedef uvm_subscriber #(T) this_type;
 
  uvm_analysis_imp #(T, this_type) analysis_export;
 
  function new (string name, uvm_component parent);
    super.new (name, parent);
    analysis_export = new ("analysis_imp", this);
  endfunction
 
  pure virtual function void write (T, t);
endclass
 

Use Case

In a typical case, an agent would have a TLM analysis port for it's monitor to share the data object it collected on the agent's interface with other testbench components. So it is easier to create a user class inherited from uvm_subscriber and use the in-built analysis_export implementation to connect to the analysis port of the agent. For example, you could have functional coverage groups and coverpoints in a subscriber and have that sampled whenever it receives an object from the agent.

 
class my_coverage extends uvm_subscriber #(bus_pkt);
 
  covergroup cg_bus;
    ...
  endgroup
 
  virtual function void write (bus_pkt pkt);
    cg_bus.sample ();
  endfunction
endclass
 
class my_env extends uvm_env;
  ...
  virtual function void connect_phase (uvm_phase phase);
    super.connect_phase (phase);
    my_agent.custom_ap.connect (my_cov.analysis_export);
  endfunction
endclass
 

It is not mandatory to inherit from uvm_subscriber, but it is a recommended practice so that there exists a uniform way through which a component can connect with an analysis port.

You may also like:

You consent to our cookies if you continue to use our website. To know more about cookies, see our privacy policy. I accept cookies from this site.

Agree